Add: Wifi widget

- Use `nmcli`
This commit is contained in:
Candifloss 2025-11-23 12:14:40 +05:30
parent 8851869f07
commit 61f7020fd3
3 changed files with 129 additions and 2 deletions

View File

@ -4,6 +4,7 @@ mod common;
mod datewidget;
mod timewidget;
mod volumewidget;
mod wifiwidget;
use crate::TopBar;
@ -13,7 +14,8 @@ pub fn install_callbacks(ui: &TopBar) {
batterywidget::install(ui);
volumewidget::install(ui);
brightnesswidget::install(ui);
wifiwidget::install(ui);
// In the future:
// networkwidget::install(ui);
// weatherwidget::install(ui);
}

104
src/widgets/wifiwidget.rs Normal file
View 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);
}

View File

@ -36,7 +36,7 @@ export component TopBar inherits Window {
in property <color> volume_bg_clicked;*/
callback show_volume();
// brightness widget
// Brightness widget
in property <string> brightness_tooltip;
in property <string> brightness_icon;
/*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_clicked;*/
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";
width: bar_width *1px;
@ -88,6 +97,18 @@ export component TopBar inherits Window {
HorizontalLayout {
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 {