Add: Wifi widget
- Use `nmcli`
This commit is contained in:
parent
8851869f07
commit
61f7020fd3
@ -4,6 +4,7 @@ mod common;
|
|||||||
mod datewidget;
|
mod datewidget;
|
||||||
mod timewidget;
|
mod timewidget;
|
||||||
mod volumewidget;
|
mod volumewidget;
|
||||||
|
mod wifiwidget;
|
||||||
|
|
||||||
use crate::TopBar;
|
use crate::TopBar;
|
||||||
|
|
||||||
@ -13,7 +14,8 @@ pub fn install_callbacks(ui: &TopBar) {
|
|||||||
batterywidget::install(ui);
|
batterywidget::install(ui);
|
||||||
volumewidget::install(ui);
|
volumewidget::install(ui);
|
||||||
brightnesswidget::install(ui);
|
brightnesswidget::install(ui);
|
||||||
|
wifiwidget::install(ui);
|
||||||
|
|
||||||
// In the future:
|
// In the future:
|
||||||
// networkwidget::install(ui);
|
// weatherwidget::install(ui);
|
||||||
}
|
}
|
||||||
|
|||||||
104
src/widgets/wifiwidget.rs
Normal file
104
src/widgets/wifiwidget.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Wi-Fi widget backend. Polls NetworkManager every second using `nmcli`.
|
||||||
|
use super::common::run_cmd;
|
||||||
|
use crate::TopBar;
|
||||||
|
use slint::{ComponentHandle, SharedString, Timer, TimerMode};
|
||||||
|
use std::process::Command;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Run a shell command and capture stdout as a string
|
||||||
|
fn run_cmd_output(cmd: &str, args: &[&str]) -> Option<String> {
|
||||||
|
let out = Command::new(cmd).args(args).output().ok()?;
|
||||||
|
if !out.status.success() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return (connected: bool, ssid: String, signal: u8)
|
||||||
|
fn read_wifi_status() -> Option<(bool, String, u8)> {
|
||||||
|
// Fields: ACTIVE:SSID:SIGNAL
|
||||||
|
let out = run_cmd_output("nmcli", &["-t", "-f", "ACTIVE,SSID,SIGNAL", "dev", "wifi"])?;
|
||||||
|
for line in out.lines() {
|
||||||
|
let mut parts = line.split(':');
|
||||||
|
let active = parts.next()?.trim();
|
||||||
|
let ssid = parts.next().unwrap_or("").trim().to_string();
|
||||||
|
let signal = parts.next().unwrap_or("0").trim().parse().unwrap_or(0);
|
||||||
|
|
||||||
|
if active == "yes" {
|
||||||
|
return Some((true, ssid, signal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some((false, String::new(), 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if Wi-Fi hardware is enabled
|
||||||
|
fn wifi_enabled() -> bool {
|
||||||
|
// nmcli -t -f WIFI g → "enabled" or "disabled"
|
||||||
|
if let Some(out) = run_cmd_output("nmcli", &["-t", "-f", "WIFI", "g"]) {
|
||||||
|
return out.trim() == "enabled";
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Choose icon based on Wi-Fi signal
|
||||||
|
fn wifi_icon(signal: u8, connected: bool, enabled: bool) -> SharedString {
|
||||||
|
let icon = if !enabled {
|
||||||
|
"" // wifi off
|
||||||
|
} else if !connected {
|
||||||
|
"" // wifi on, no connection
|
||||||
|
} else {
|
||||||
|
match signal {
|
||||||
|
0..=20 => "",
|
||||||
|
21..=40 => "",
|
||||||
|
41..=60 => "",
|
||||||
|
61..=100 => "",
|
||||||
|
_ => "", // error/unexpected
|
||||||
|
}
|
||||||
|
};
|
||||||
|
SharedString::from(icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tooltip shown on hover
|
||||||
|
fn wifi_tooltip(connected: bool, ssid: &str, signal: u8, enabled: bool) -> String {
|
||||||
|
if !enabled {
|
||||||
|
"Wi-Fi: disabled".into()
|
||||||
|
} else if !connected {
|
||||||
|
"Wi-Fi: no internet".into()
|
||||||
|
} else {
|
||||||
|
format!("Wi-Fi: {ssid} ({signal}%)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Periodic Wi-Fi updater
|
||||||
|
fn start_wifi_updater(ui: &TopBar) {
|
||||||
|
let weak = ui.as_weak();
|
||||||
|
|
||||||
|
let timer = Box::leak(Box::new(Timer::default()));
|
||||||
|
|
||||||
|
// Update every second (connection quality can change quickly)
|
||||||
|
timer.start(TimerMode::Repeated, Duration::from_secs(1), move || {
|
||||||
|
if let Some(ui) = weak.upgrade() {
|
||||||
|
let enabled = wifi_enabled();
|
||||||
|
let (connected, ssid, signal) = read_wifi_status().unwrap_or((false, String::new(), 0));
|
||||||
|
|
||||||
|
let icon = wifi_icon(signal, connected, enabled);
|
||||||
|
let tooltip = wifi_tooltip(connected, &ssid, signal, enabled);
|
||||||
|
|
||||||
|
ui.set_wifi_icon(icon);
|
||||||
|
ui.set_wifi_tooltip(tooltip.into());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Install Wi-Fi click action + updater
|
||||||
|
pub fn install(ui: &TopBar) {
|
||||||
|
let weak = ui.as_weak();
|
||||||
|
|
||||||
|
ui.on_show_wifi(move || {
|
||||||
|
if weak.upgrade().is_some() {
|
||||||
|
run_cmd("xclock"); // Fix later
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
start_wifi_updater(ui);
|
||||||
|
}
|
||||||
@ -36,7 +36,7 @@ export component TopBar inherits Window {
|
|||||||
in property <color> volume_bg_clicked;*/
|
in property <color> volume_bg_clicked;*/
|
||||||
callback show_volume();
|
callback show_volume();
|
||||||
|
|
||||||
// brightness widget
|
// Brightness widget
|
||||||
in property <string> brightness_tooltip;
|
in property <string> brightness_tooltip;
|
||||||
in property <string> brightness_icon;
|
in property <string> brightness_icon;
|
||||||
/*in property <color> brightness_icon_color;
|
/*in property <color> brightness_icon_color;
|
||||||
@ -44,6 +44,15 @@ export component TopBar inherits Window {
|
|||||||
in property <color> brightness_bg_hover;
|
in property <color> brightness_bg_hover;
|
||||||
in property <color> brightness_bg_clicked;*/
|
in property <color> brightness_bg_clicked;*/
|
||||||
callback show_brightness();
|
callback show_brightness();
|
||||||
|
|
||||||
|
// Wifi widget
|
||||||
|
in property <string> wifi_tooltip;
|
||||||
|
in property <string> wifi_icon;
|
||||||
|
/*in property <color> wifi_icon_color: #ffffff;
|
||||||
|
in property <color> wifi_bg_normal: #8e9162;
|
||||||
|
in property <color> wifi_bg_hover: #6d8a4d;
|
||||||
|
in property <color> wifi_bg_clicked: #4a5f70;*/
|
||||||
|
callback show_wifi();
|
||||||
|
|
||||||
title: "chocobar";
|
title: "chocobar";
|
||||||
width: bar_width *1px;
|
width: bar_width *1px;
|
||||||
@ -88,6 +97,18 @@ export component TopBar inherits Window {
|
|||||||
|
|
||||||
HorizontalLayout {
|
HorizontalLayout {
|
||||||
alignment: end; // Right-align
|
alignment: end; // Right-align
|
||||||
|
|
||||||
|
// SquareIconWidget - Wifi
|
||||||
|
SquareIconWidget {
|
||||||
|
bar_height: root.bar_height;
|
||||||
|
icon_text: root.wifi_icon;
|
||||||
|
tooltip_text: root.wifi_tooltip;
|
||||||
|
/*icon_color: root.wifi_icon_color;
|
||||||
|
bg_normal: root.wifi_bg_normal;
|
||||||
|
bg_hover: root.wifi_bg_hover;
|
||||||
|
bg_clicked: root.wifi_bg_clicked;*/
|
||||||
|
square_btn_callback => root.show_wifi();
|
||||||
|
}
|
||||||
|
|
||||||
// SquareIconWidget - brightness
|
// SquareIconWidget - brightness
|
||||||
SquareIconWidget {
|
SquareIconWidget {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user