lots of basic widgets from text
This commit is contained in:
parent
146148a7cd
commit
ae1c1b82af
209
src/main.rs
209
src/main.rs
|
@ -1,14 +1,17 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use hyprland::data::Workspaces;
|
use hyprland::data::{Client, Workspace, Workspaces};
|
||||||
use hyprland::event_listener;
|
use hyprland::event_listener::{self, AsyncEventListener};
|
||||||
use hyprland::shared::{HyprData, WorkspaceType};
|
use hyprland::shared::{HyprData, HyprDataActiveOptional, HyprDataVec};
|
||||||
use iced::font::Weight;
|
use iced::font::Weight;
|
||||||
use iced::widget::{container, horizontal_space, row, text, Text};
|
use iced::futures::SinkExt;
|
||||||
|
use iced::stream;
|
||||||
|
use iced::widget::{container, horizontal_space, row, text};
|
||||||
use iced::{
|
use iced::{
|
||||||
time, Background, Border, Color, Element, Event, Font, Length, Shadow, Subscription, Task,
|
time, Background, Border, Color, Element, Event, Font, Length, Shadow, Subscription, Task,
|
||||||
Theme, Vector,
|
Vector,
|
||||||
};
|
};
|
||||||
|
|
||||||
use iced_layershell::build_pattern::{application, MainSettings};
|
use iced_layershell::build_pattern::{application, MainSettings};
|
||||||
|
@ -16,6 +19,7 @@ use iced_layershell::reexport::{Anchor, KeyboardInteractivity};
|
||||||
use iced_layershell::settings::LayerShellSettings;
|
use iced_layershell::settings::LayerShellSettings;
|
||||||
use iced_layershell::to_layer_message;
|
use iced_layershell::to_layer_message;
|
||||||
use iced_runtime::futures::event;
|
use iced_runtime::futures::event;
|
||||||
|
use miette::{IntoDiagnostic, Result};
|
||||||
use sysinfo::{Disks, System};
|
use sysinfo::{Disks, System};
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
|
@ -57,9 +61,6 @@ fn main() -> iced_layershell::Result {
|
||||||
|
|
||||||
application(Panel::namespace, Panel::update, Panel::view)
|
application(Panel::namespace, Panel::update, Panel::view)
|
||||||
.subscription(Panel::subscription)
|
.subscription(Panel::subscription)
|
||||||
.subscription(|_| {
|
|
||||||
time::every(time::Duration::from_millis(1000)).map(|_| Message::Time(Local::now()))
|
|
||||||
})
|
|
||||||
.settings(settings)
|
.settings(settings)
|
||||||
.style(Panel::style)
|
.style(Panel::style)
|
||||||
.run_with(Panel::new)
|
.run_with(Panel::new)
|
||||||
|
@ -70,12 +71,13 @@ struct Panel {
|
||||||
time: String,
|
time: String,
|
||||||
cpu: String,
|
cpu: String,
|
||||||
memory: String,
|
memory: String,
|
||||||
battery: String,
|
battery: Option<Battery>,
|
||||||
disk: String,
|
disk: String,
|
||||||
system: System,
|
system: System,
|
||||||
disks: Disks,
|
disks: Disks,
|
||||||
workspaces: Workspaces,
|
workspaces: Vec<Workspace>,
|
||||||
active_workspace: i32,
|
active_workspace: i32,
|
||||||
|
active_window: String,
|
||||||
apps: Vec<String>,
|
apps: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +87,9 @@ enum Message {
|
||||||
Launch(usize),
|
Launch(usize),
|
||||||
Time(DateTime<Local>),
|
Time(DateTime<Local>),
|
||||||
IcedEvent(Event),
|
IcedEvent(Event),
|
||||||
WorkspaceChange(WorkspaceType),
|
WorkspaceChange(Vec<Workspace>),
|
||||||
|
ActiveWorkspaceChange(event_listener::WorkspaceEventData),
|
||||||
|
ActiveWindowChange(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Panel {
|
impl Panel {
|
||||||
|
@ -94,18 +98,27 @@ impl Panel {
|
||||||
error!("Couldn't get hyprland info: {}", e);
|
error!("Couldn't get hyprland info: {}", e);
|
||||||
e
|
e
|
||||||
});
|
});
|
||||||
|
let active_window = Client::get_active().unwrap().unwrap().title;
|
||||||
|
let battery = match Battery::get() {
|
||||||
|
Ok(b) => Some(b),
|
||||||
|
Err(e) => {
|
||||||
|
error!("{e}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
system: System::new_all(),
|
system: System::new_all(),
|
||||||
disks: Disks::new_with_refreshed_list(),
|
disks: Disks::new_with_refreshed_list(),
|
||||||
workspaces: workspaces.unwrap(),
|
workspaces: workspaces.unwrap().to_vec(),
|
||||||
active_workspace: 1,
|
active_workspace: 1,
|
||||||
time: String::new(),
|
time: String::new(),
|
||||||
cpu: String::new(),
|
cpu: String::new(),
|
||||||
memory: String::new(),
|
memory: String::new(),
|
||||||
battery: String::new(),
|
|
||||||
disk: String::new(),
|
disk: String::new(),
|
||||||
apps: vec![String::new()],
|
apps: vec![String::new()],
|
||||||
|
active_window,
|
||||||
|
battery,
|
||||||
},
|
},
|
||||||
Task::none(),
|
Task::none(),
|
||||||
)
|
)
|
||||||
|
@ -129,6 +142,13 @@ impl Panel {
|
||||||
convert((disk.total_space() - disk.available_space()) as f64)
|
convert((disk.total_space() - disk.available_space()) as f64)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
self.battery = match Battery::get() {
|
||||||
|
Ok(b) => Some(b),
|
||||||
|
Err(e) => {
|
||||||
|
error!("{e}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
// let used_space = 393;
|
// let used_space = 393;
|
||||||
// self.disk = format!(" {}", used_space);
|
// self.disk = format!(" {}", used_space);
|
||||||
self.cpu = format!(" {}%", self.system.global_cpu_usage().round());
|
self.cpu = format!(" {}%", self.system.global_cpu_usage().round());
|
||||||
|
@ -149,26 +169,113 @@ impl Panel {
|
||||||
Message::IcedEvent(event) => {
|
Message::IcedEvent(event) => {
|
||||||
debug!(?event)
|
debug!(?event)
|
||||||
}
|
}
|
||||||
|
Message::WorkspaceChange(workspaces) => {
|
||||||
|
// debug!(?workspaces);
|
||||||
|
self.workspaces = workspaces;
|
||||||
|
}
|
||||||
|
Message::ActiveWorkspaceChange(data) => {
|
||||||
|
// debug!(?data);
|
||||||
|
self.active_workspace = data.id;
|
||||||
|
}
|
||||||
|
Message::ActiveWindowChange(w) => {
|
||||||
|
self.active_window = w;
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
Message::WorkspaceChange(workspace_type) => todo!(),
|
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
event::listen().map(Message::IcedEvent)
|
let iced_events = event::listen().map(Message::IcedEvent);
|
||||||
|
let timed_events =
|
||||||
|
time::every(time::Duration::from_millis(1000)).map(|_| Message::Time(Local::now()));
|
||||||
|
let hyprland_events = self.hyprland_subscription();
|
||||||
|
Subscription::batch([iced_events, timed_events, hyprland_events])
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn hyprland_subscription(&self) -> Subscription<Message> {
|
fn hyprland_subscription(&self) -> Subscription<Message> {
|
||||||
// let mut event_listener = event_listener::EventListener::new();
|
Subscription::run(|| {
|
||||||
// event_listener.add_workspace_changed_handler(|x| Message::WorkspaceChange(x));
|
stream::channel(1, |mut sender| async move {
|
||||||
// Subscription::run(|| event_listener.start_listener())
|
let mut workspaces = Workspaces::get_async()
|
||||||
// }
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
error!("Couldn't get hyprland info: {}", e);
|
||||||
|
e
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.to_vec();
|
||||||
|
workspaces.sort_by(|a, b| a.id.cmp(&b.id));
|
||||||
|
sender
|
||||||
|
.send(Message::WorkspaceChange(workspaces))
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
eprintln!("Trying to send workspaces failed with err: {err}");
|
||||||
|
});
|
||||||
|
if let Ok(window) = Client::get_active_async().await {
|
||||||
|
if let Some(w) = window {
|
||||||
|
sender
|
||||||
|
.send(Message::ActiveWindowChange(w.title.trim().to_owned()))
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
error!("Trying to send window failed with err: {e}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut listener = AsyncEventListener::new();
|
||||||
|
|
||||||
|
let senderx = sender.clone();
|
||||||
|
listener.add_active_window_changed_handler(move |data| {
|
||||||
|
let mut sender = senderx.clone();
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(data) = data {
|
||||||
|
sender
|
||||||
|
.send(Message::ActiveWindowChange(data.title))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let senderx = sender.clone();
|
||||||
|
listener.add_workspace_changed_handler(move |data| {
|
||||||
|
let mut sender = senderx.clone();
|
||||||
|
Box::pin(async move {
|
||||||
|
sender
|
||||||
|
.send(Message::ActiveWorkspaceChange(data))
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|e| error!("Error in sending: {e}"));
|
||||||
|
let mut workspaces = Workspaces::get_async()
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
error!("Couldn't get hyprland info: {}", e);
|
||||||
|
e
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.to_vec();
|
||||||
|
workspaces.sort_by(|a, b| a.id.cmp(&b.id));
|
||||||
|
sender
|
||||||
|
.send(Message::WorkspaceChange(workspaces))
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
eprintln!("Trying to send workspaces failed with err: {err}");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
listener
|
||||||
|
.start_listener_async()
|
||||||
|
.await
|
||||||
|
.expect("Failed to listen for hyprland events");
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let workspaces: Vec<Element<'_, Message>> = self
|
let workspaces: Vec<Element<'_, Message>> = self
|
||||||
.workspaces
|
.workspaces
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|w| w.name != "special:special")
|
||||||
.map(|w| {
|
.map(|w| {
|
||||||
text!("{}", {
|
text!("{}", {
|
||||||
match w.id {
|
match w.id {
|
||||||
|
@ -195,17 +302,39 @@ impl Panel {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let workspaces = row(workspaces).spacing(20).padding([0, 5]);
|
let workspaces = row(workspaces).spacing(20).padding([0, 5]);
|
||||||
|
|
||||||
|
let window = text!("{}", self.active_window).color(Color::parse("#57c7ff").unwrap());
|
||||||
let disk = text!("{}", self.disk).color(Color::parse("#ff9f43").unwrap());
|
let disk = text!("{}", self.disk).color(Color::parse("#ff9f43").unwrap());
|
||||||
let mem = text!("{}", self.memory).color(Color::parse("#f3f99d").unwrap());
|
let mem = text!("{}", self.memory).color(Color::parse("#f3f99d").unwrap());
|
||||||
let cpu = text!("{}", self.cpu).color(Color::parse("#57c7ff").unwrap());
|
let cpu = text!("{}", self.cpu).color(Color::parse("#57c7ff").unwrap());
|
||||||
let clock = text!("{}", self.time);
|
let clock = text!("{}", self.time);
|
||||||
let clock = clock.color(Color::parse("#5af78e").unwrap());
|
let clock = clock.color(Color::parse("#5af78e").unwrap());
|
||||||
|
|
||||||
|
let battery_icon = if let Some(battery) = &self.battery {
|
||||||
|
match battery.status {
|
||||||
|
BatteryStatus::Charging => "",
|
||||||
|
BatteryStatus::Charged => "",
|
||||||
|
BatteryStatus::Draining => "",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
let battery = text!(
|
||||||
|
"{} {}",
|
||||||
|
battery_icon,
|
||||||
|
if let Some(battery) = &self.battery {
|
||||||
|
battery.capacity.to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.color(Color::parse("#ff6ac1").unwrap());
|
||||||
|
|
||||||
let row = row!(
|
let row = row!(
|
||||||
container(workspaces),
|
container(row!(workspaces, window, horizontal_space()).spacing(10)),
|
||||||
container(horizontal_space()),
|
|
||||||
container(clock),
|
container(clock),
|
||||||
container(row!(horizontal_space(), disk, cpu, mem).spacing(5))
|
container(row!(horizontal_space(), disk, cpu, mem, battery).spacing(5))
|
||||||
)
|
)
|
||||||
.spacing(5)
|
.spacing(5)
|
||||||
.padding([0, 20]);
|
.padding([0, 20]);
|
||||||
|
@ -263,3 +392,37 @@ pub fn convert(num: f64) -> String {
|
||||||
let unit = units[exponent as usize];
|
let unit = units[exponent as usize];
|
||||||
format!("{}{} {}", negative, pretty_bytes, unit)
|
format!("{}{} {}", negative, pretty_bytes, unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Battery {
|
||||||
|
capacity: u8,
|
||||||
|
status: BatteryStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Battery {
|
||||||
|
fn get() -> Result<Battery> {
|
||||||
|
let capacity = read_to_string("/sys/class/power_supply/BAT1/capacity")
|
||||||
|
.into_diagnostic()?
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.into_diagnostic()?;
|
||||||
|
let status = match read_to_string("/sys/class/power_supply/BAT1/status")
|
||||||
|
.into_diagnostic()?
|
||||||
|
.trim()
|
||||||
|
{
|
||||||
|
"Not charging" => BatteryStatus::Charged,
|
||||||
|
"Discharging" => BatteryStatus::Draining,
|
||||||
|
"Charging" => BatteryStatus::Charging,
|
||||||
|
_ => BatteryStatus::Draining,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self { capacity, status })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum BatteryStatus {
|
||||||
|
Charging,
|
||||||
|
Charged,
|
||||||
|
Draining,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue