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