feat(bar): add battery and network widgets

This commit is contained in:
LGUG2Z
2024-08-27 20:00:40 -07:00
parent 92bb9f680b
commit 8e74e97706
5 changed files with 471 additions and 14 deletions

View File

@@ -0,0 +1,81 @@
use crate::widget::BarWidget;
use starship_battery::units::ratio::percent;
use starship_battery::Manager;
use starship_battery::State;
use std::time::Duration;
use std::time::Instant;
#[derive(Copy, Clone, Debug)]
pub struct BatteryConfig {
pub enable: bool,
}
impl From<BatteryConfig> for Battery {
fn from(value: BatteryConfig) -> Self {
let manager = Manager::new().unwrap();
let mut last_state = vec![];
let mut state = None;
if let Ok(mut batteries) = manager.batteries() {
if let Some(Ok(first)) = batteries.nth(0) {
let percentage = first.state_of_charge().get::<percent>();
match first.state() {
State::Charging => state = Some(BatteryState::Charging),
State::Discharging => state = Some(BatteryState::Discharging),
_ => {}
}
last_state.push(format!("{percentage}%"));
}
}
Self {
enable: value.enable,
manager,
last_state,
state: state.unwrap_or(BatteryState::Discharging),
last_updated: Instant::now(),
}
}
}
pub enum BatteryState {
Charging,
Discharging,
}
pub struct Battery {
pub enable: bool,
manager: Manager,
pub state: BatteryState,
last_state: Vec<String>,
last_updated: Instant,
}
impl BarWidget for Battery {
fn output(&mut self) -> Vec<String> {
let mut outputs = self.last_state.clone();
let now = Instant::now();
if now.duration_since(self.last_updated) > Duration::from_secs(10) {
outputs.clear();
if let Ok(mut batteries) = self.manager.batteries() {
if let Some(Ok(first)) = batteries.nth(0) {
let percentage = first.state_of_charge().get::<percent>();
match first.state() {
State::Charging => self.state = BatteryState::Charging,
State::Discharging => self.state = BatteryState::Discharging,
_ => {}
}
outputs.push(format!("{percentage}%"));
}
}
self.last_state.clone_from(&outputs);
self.last_updated = now;
}
outputs
}
}

View File

@@ -1,16 +1,23 @@
mod battery;
mod date;
mod media;
mod memory;
mod network;
mod storage;
mod time;
mod widget;
use crate::battery::Battery;
use crate::battery::BatteryConfig;
use crate::battery::BatteryState;
use crate::date::Date;
use crate::date::DateFormat;
use crate::media::Media;
use crate::media::MediaConfig;
use crate::memory::Memory;
use crate::memory::MemoryConfig;
use crate::network::Network;
use crate::network::NetworkConfig;
use crate::storage::Storage;
use crate::storage::StorageConfig;
use crate::time::TimeFormat;
@@ -71,6 +78,8 @@ pub struct Config {
storage: StorageConfig,
memory: MemoryConfig,
media: MediaConfig,
battery: BatteryConfig,
network: NetworkConfig,
}
fn main() -> eframe::Result<()> {
@@ -91,6 +100,11 @@ fn main() -> eframe::Result<()> {
storage: StorageConfig { enable: true },
memory: MemoryConfig { enable: true },
media: MediaConfig { enable: true },
battery: BatteryConfig { enable: true },
network: NetworkConfig {
enable: true,
show_data: true,
},
};
// TODO: ensure that config.monitor_index represents a valid komorebi monitor index
@@ -199,6 +213,8 @@ struct Komobar {
memory: Memory,
storage: Storage,
media: Media,
battery: Battery,
network: Network,
}
impl Komobar {
@@ -224,6 +240,8 @@ impl Komobar {
memory: Memory::from(config.memory),
storage: Storage::from(config.storage),
media: Media::from(config.media),
battery: Battery::from(config.battery),
network: Network::from(config.network),
}
}
}
@@ -352,6 +370,26 @@ impl eframe::App for Komobar {
// TODO: make the order configurable
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
if self.battery.enable {
let battery_output = self.battery.output();
if !battery_output.is_empty() {
for battery in battery_output {
let emoji = match self.battery.state {
BatteryState::Charging => "⚡️",
BatteryState::Discharging => "🔋",
};
ui.add(
Label::new(format!("{emoji} {battery}"))
.selectable(false)
.sense(Sense::click()),
);
}
ui.add_space(10.0);
}
}
if self.time.enable {
for time in self.time.output() {
if ui
@@ -388,6 +426,53 @@ impl eframe::App for Komobar {
ui.add_space(10.0);
}
if self.network.enable {
let network_output = self.network.output();
if !network_output.is_empty() {
match network_output.len() {
1 => {
if ui
.add(
Label::new(format!("📶 {}", network_output[0]))
.selectable(false)
.sense(Sense::click()),
)
.clicked()
{
if let Err(error) =
Command::new("cmd.exe").args(["/C", "ncpa"]).spawn()
{
eprintln!("{}", error)
}
}
}
2 => {
if ui
.add(
Label::new(format!(
"📶 {} - {}",
network_output[0], network_output[1]
))
.selectable(false)
.sense(Sense::click()),
)
.clicked()
{
if let Err(error) =
Command::new("cmd.exe").args(["/C", "ncpa"]).spawn()
{
eprintln!("{}", error)
}
};
}
_ => {}
}
ui.add_space(10.0);
}
}
if self.memory.enable {
for ram in self.memory.output() {
if ui

View File

@@ -0,0 +1,87 @@
use crate::widget::BarWidget;
use std::time::Duration;
use std::time::Instant;
use sysinfo::Networks;
#[derive(Copy, Clone, Debug)]
pub struct NetworkConfig {
pub enable: bool,
pub show_data: bool,
}
impl From<NetworkConfig> for Network {
fn from(value: NetworkConfig) -> Self {
let mut last_state = vec![];
let mut networks = Networks::new_with_refreshed_list();
if let Ok(interface) = netdev::get_default_interface() {
if let Some(friendly_name) = interface.friendly_name {
last_state.push(friendly_name.clone());
if value.show_data {
networks.refresh();
for (interface_name, data) in &networks {
if friendly_name.eq(interface_name) {
last_state.push(format!(
"{} MB (down) / {} MB (up)",
data.total_received() / 1024 / 1024,
data.total_transmitted() / 1024 / 1024,
))
}
}
}
}
}
Self {
enable: value.enable,
last_state,
networks,
show_data: value.show_data,
last_updated: Instant::now(),
}
}
}
pub struct Network {
pub enable: bool,
pub show_data: bool,
networks: Networks,
last_state: Vec<String>,
last_updated: Instant,
}
impl BarWidget for Network {
fn output(&mut self) -> Vec<String> {
let mut outputs = self.last_state.clone();
let now = Instant::now();
if now.duration_since(self.last_updated) > Duration::from_secs(10) {
outputs.clear();
if let Ok(interface) = netdev::get_default_interface() {
if let Some(friendly_name) = &interface.friendly_name {
outputs.push(friendly_name.clone());
if self.show_data {
self.networks.refresh();
for (interface_name, data) in &self.networks {
if friendly_name.eq(interface_name) {
outputs.push(format!(
"{} MB (down) / {} MB (up)",
data.total_received() / 1024 / 1024,
data.total_transmitted() / 1024 / 1024,
))
}
}
}
}
}
self.last_state.clone_from(&outputs);
self.last_updated = now;
}
outputs
}
}