wayland_panel/src/main.rs

167 lines
4.2 KiB
Rust

use iced::Color;
use iced::Element;
use iced::Task;
use iced::widget::container;
use iced::widget::row;
use iced::widget::text;
use iced_layershell::daemon;
use iced_layershell::reexport::Anchor;
use iced_layershell::settings::LayerShellSettings;
use iced_layershell::settings::Settings;
use iced_layershell::to_layer_message;
use std::time::Duration;
pub fn main() -> Result<(), iced_layershell::Error> {
daemon(App::default, || "rbaw".into(), App::update, App::view)
.style(App::style)
.theme(App::theme)
.subscription(App::subscription)
.settings(Settings {
layer_settings: LayerShellSettings {
size: Some((0, 32)),
exclusive_zone: 32,
anchor: Anchor::Top | Anchor::Left | Anchor::Right,
start_mode: iced_layershell::settings::StartMode::AllScreens, // valid here in daemon
..Default::default()
},
..Default::default()
})
.run()
}
struct App {
time_widget: TimeWidget,
battery_widget: BatteryWidget,
}
impl Default for App {
fn default() -> Self {
let mut output = Self {
time_widget: Default::default(),
battery_widget: Default::default(),
};
let _ = output.update(Message::Clock);
output
}
}
impl App {
fn view(&self, _id: iced::window::Id) -> Element<'_, Message> {
let content = row![
self.time_widget.view(),
iced::widget::space().width(iced::Length::Fill),
self.battery_widget.view(),
]
.padding(iced::Padding::from([0, 5]))
.height(iced::Length::Fill)
.width(iced::Length::Fill)
.align_y(iced::Alignment::Center);
container(content).into()
}
fn update(&mut self, message: Message) -> Task<Message> {
if let Message::Clock = message {
self.time_widget.update();
}
Task::none()
}
fn style(&self, theme: &iced::Theme) -> iced::theme::Style {
iced::theme::Style {
background_color: Color::TRANSPARENT,
text_color: theme.palette().text,
}
}
fn theme(&self, _id: iced::window::Id) -> iced::Theme {
iced::Theme::GruvboxDark
}
fn subscription(&self) -> iced::Subscription<Message> {
iced::time::every(Duration::from_secs(1)).map(|_| Message::Clock)
}
}
trait PanelWidget {
fn update(&mut self);
fn view(&self) -> Element<'_, Message>;
}
#[derive(Default)]
struct BatteryWidget {
battery: Option<usize>,
}
impl PanelWidget for BatteryWidget {
fn update(&mut self) {
let file_content = std::fs::read_to_string(std::path::Path::new(
"/sys/class/power_supply/BAT0/capacity",
));
let Ok(file_string) = file_content else {
self.battery = None;
return;
};
let file_string = file_string.trim();
let Ok(value) = file_string.parse::<usize>() else {
self.battery = None;
return;
};
self.battery = Some(value);
}
fn view(&self) -> Element<'_, Message> {
match self.battery {
Some(battery) => text!("{} {}", battery.to_string(), Self::get_icon(battery)),
None => text("󱉞"),
}
.into()
}
}
impl BatteryWidget {
fn get_icon(battery: usize) -> &'static str {
match battery {
0..6 => "󰂎",
6..11 => "󰁺",
11..21 => "󰁻",
21..31 => "󰁼",
31..41 => "󰁽",
41..51 => "󰁾",
51..61 => "󰁿",
61..71 => "󰂀",
71..81 => "󰂁",
81..91 => "󰂂",
91..101 => "󰁹",
_ => "󰂃",
}
}
}
#[derive(Default)]
struct TimeWidget {
current_time: chrono::DateTime<chrono::Local>,
}
impl PanelWidget for TimeWidget {
fn update(&mut self) {
self.current_time = chrono::Local::now();
}
fn view(&self) -> Element<'_, Message> {
text!("{}", self.current_time.format("%H:%m")).into()
}
}
#[to_layer_message]
#[derive(Debug)]
enum Message {
IcedEvent(iced::Event),
Clock,
}