Add BatteryWidget
- Working battery icon - Read from `sys` files - Calculate values in Rust and pass it to Slint
This commit is contained in:
parent
48a116c547
commit
b0eaa42063
107
src/widgets/batterywidget.rs
Normal file
107
src/widgets/batterywidget.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use super::common::run_cmd;
|
||||
use crate::TopBar;
|
||||
use slint::{ComponentHandle, SharedString, Timer, TimerMode};
|
||||
use std::{fs, time::Duration};
|
||||
|
||||
// Read and trim a file
|
||||
fn read_sys(path: &str) -> String {
|
||||
fs::read_to_string(path)
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
// Convert battery state strings into normalized tokens
|
||||
fn normalize_status(s: &str) -> String {
|
||||
s.to_lowercase()
|
||||
.chars()
|
||||
.filter(char::is_ascii_alphabetic)
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Map numeric capacity → level tags
|
||||
fn capacity_level(cap: u8) -> String {
|
||||
match cap {
|
||||
0..=10 => "critical".into(),
|
||||
11..=25 => "low".into(),
|
||||
26..=75 => "normal".into(),
|
||||
76..=95 => "high".into(),
|
||||
_ => "full".into(),
|
||||
}
|
||||
}
|
||||
|
||||
// Choose icon from status + level
|
||||
fn select_icon(status: &str, level: &str) -> SharedString {
|
||||
let icon = match status {
|
||||
"charging" => match level {
|
||||
"critical" => "",
|
||||
"low" => "",
|
||||
"normal" => "",
|
||||
"high" => "",
|
||||
"full" => "",
|
||||
_ => "",
|
||||
},
|
||||
"discharging" => match level {
|
||||
"critical" => "",
|
||||
"low" => "",
|
||||
"normal" => "",
|
||||
"high" => "",
|
||||
"full" => "",
|
||||
_ => "",
|
||||
},
|
||||
"notcharging" => "",
|
||||
"full" => "",
|
||||
_ => "", // unknown fallback
|
||||
};
|
||||
|
||||
SharedString::from(icon)
|
||||
}
|
||||
|
||||
// Main battery updater logic
|
||||
fn start_battery_updater(ui: &TopBar) {
|
||||
let weak = ui.as_weak();
|
||||
|
||||
// Timer fires every second (battery can change quickly)
|
||||
let timer = Box::leak(Box::new(Timer::default()));
|
||||
|
||||
timer.start(TimerMode::Repeated, Duration::from_secs(1), move || {
|
||||
if let Some(ui) = weak.upgrade() {
|
||||
// Read sysfs values
|
||||
let cap_str = read_sys("/sys/class/power_supply/BAT0/capacity");
|
||||
let status_str = read_sys("/sys/class/power_supply/BAT0/status");
|
||||
let level_str = read_sys("/sys/class/power_supply/BAT0/capacity_level");
|
||||
|
||||
// Normalize values
|
||||
let status = normalize_status(&status_str);
|
||||
let cap: u8 = cap_str.parse().unwrap_or(0);
|
||||
let level = normalize_status(&level_str); // low, normal, full, etc.
|
||||
let level_calc = capacity_level(cap); // fallback level
|
||||
|
||||
// Prefer kernel level if valid; otherwise use cap-based level
|
||||
let final_level = if level.is_empty() { level_calc } else { level };
|
||||
|
||||
// Select icon
|
||||
let icon = select_icon(&status, &final_level);
|
||||
|
||||
// Update Slint properties
|
||||
ui.set_battery_status(status.into());
|
||||
ui.set_battery_capacity(cap.into());
|
||||
ui.set_battery_capacity_level(final_level.into());
|
||||
ui.set_battery_icon(icon);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Public entry: connect click callback + start updater
|
||||
pub fn install(ui: &TopBar) {
|
||||
let weak = ui.as_weak();
|
||||
|
||||
// Click → open battery monitor
|
||||
ui.on_show_battery(move || {
|
||||
if weak.upgrade().is_some() {
|
||||
run_cmd("xclock"); // Fix later
|
||||
}
|
||||
});
|
||||
|
||||
start_battery_updater(ui);
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
mod batterywidget;
|
||||
mod common;
|
||||
mod datewidget;
|
||||
mod timewidget;
|
||||
@ -7,8 +8,8 @@ use crate::TopBar;
|
||||
pub fn install_callbacks(ui: &TopBar) {
|
||||
timewidget::install(ui);
|
||||
datewidget::install(ui);
|
||||
batterywidget::install(ui);
|
||||
|
||||
// In the future:
|
||||
// networkwidget::install(ui);
|
||||
// batterywidget::install(ui);
|
||||
}
|
||||
|
||||
35
ui/battery-widget.slint
Normal file
35
ui/battery-widget.slint
Normal file
@ -0,0 +1,35 @@
|
||||
export component BatteryWidget {
|
||||
in property <int> bar_height;
|
||||
in property <string> battery_status; // charging / discharging / notcharging / unknown
|
||||
in property <int> battery_capacity; // numeric percentage
|
||||
in property <string> battery_capacity_level; // critical / low / normal / high / full
|
||||
in property <string> battery_icon;
|
||||
|
||||
callback show_battery();
|
||||
|
||||
height: bar_height * 1px;
|
||||
width: bar_height * 1px;
|
||||
|
||||
Rectangle {
|
||||
background: touch_area.pressed ? #4a5f70
|
||||
: touch_area.has-hover ? #6d8a4d
|
||||
: #8e9162;
|
||||
border-radius: 3px;
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
|
||||
Text {
|
||||
text: battery_icon;
|
||||
color: white;
|
||||
vertical-alignment: center;
|
||||
horizontal-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
touch_area := TouchArea {
|
||||
clicked => { show_battery(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import { TimeWidget } from "time-widget.slint";
|
||||
import { DateWidget } from "date-widget.slint";
|
||||
import { BatteryWidget } from "battery-widget.slint";
|
||||
|
||||
export component TopBar inherits Window {
|
||||
|
||||
@ -17,6 +18,14 @@ export component TopBar inherits Window {
|
||||
in-out property <string> date_text;
|
||||
callback show_calendar();
|
||||
|
||||
// Battery widget
|
||||
in property <string> battery_status;
|
||||
in property <int> battery_capacity;
|
||||
in property <string> battery_capacity_level;
|
||||
in property <string> battery_icon;
|
||||
callback show_battery();
|
||||
|
||||
|
||||
title: "chocobar";
|
||||
width: bar_width *1px;
|
||||
height: bar_height *1px;
|
||||
@ -61,6 +70,15 @@ export component TopBar inherits Window {
|
||||
HorizontalLayout {
|
||||
alignment: end; // Right-align
|
||||
|
||||
BatteryWidget {
|
||||
bar_height: root.bar_height;
|
||||
battery_status: root.battery_status;
|
||||
battery_capacity: root.battery_capacity;
|
||||
battery_capacity_level: root.battery_capacity_level;
|
||||
battery_icon: root.battery_icon;
|
||||
show_battery => root.show_battery();
|
||||
}
|
||||
|
||||
DateWidget {
|
||||
// Get from root
|
||||
date_text: root.date_text;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user