chocobar-x11/src/widgets/wifiwidget.rs
2025-11-23 12:14:40 +05:30

105 lines
3.1 KiB
Rust

// 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);
}