diff --git a/src/app.rs b/src/app.rs index a452061..f4f1958 100644 --- a/src/app.rs +++ b/src/app.rs @@ -38,13 +38,12 @@ impl App { if let Some(elem) = self .widgets .iter() - .find(|widget| widget.has_window(id)) - .map(|widget| widget.view(id)) + .find_map(|widget| widget.render_window(id)) { return elem; } - iced::widget::Row::with_children(self.widgets.iter().map(|widget| widget.view(id))) + iced::widget::Row::with_children(self.widgets.iter().filter_map(|widget| widget.view())) .padding(iced::Padding::from([0, 5])) .height(iced::Length::Fill) .width(iced::Length::Fill) diff --git a/src/widget.rs b/src/widget.rs index f200259..491de69 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -9,9 +9,9 @@ use crate::widgets::powerbutton::ShutdownEvents; pub trait PanelWidget { fn update(&mut self, message: &Message) -> Task; fn subscribe(&self) -> Subscription; - fn view(&self, id: iced::window::Id) -> Element<'_, Message>; - fn has_window(&self, _id: iced::window::Id) -> bool { - false + fn view(&self) -> Option>; + fn render_window(&self, _id: iced::window::Id) -> Option> { + None } } diff --git a/src/widgets/battery.rs b/src/widgets/battery.rs index bfe8ded..0d9bfa5 100644 --- a/src/widgets/battery.rs +++ b/src/widgets/battery.rs @@ -65,12 +65,11 @@ impl PanelWidget for BatteryWidget { }) } - fn view(&self, _id: iced::window::Id) -> Element<'_, Message> { + fn view(&self) -> Option> { match self.capacity { - Some(cap) => text!("{} {}", cap, Self::icon(cap)), - None => text!("󰂃"), + Some(cap) => Some(text!("{} {}", cap, Self::icon(cap)).into()), + None => None, } - .into() } } diff --git a/src/widgets/clock.rs b/src/widgets/clock.rs index d29f7d7..638410c 100644 --- a/src/widgets/clock.rs +++ b/src/widgets/clock.rs @@ -28,8 +28,8 @@ impl PanelWidget for ClockWidget { iced::time::every(Duration::from_secs(1)).map(|_| Message::Time) } - fn view(&self, _id: iced::window::Id) -> iced::Element<'_, Message> { + fn view(&self) -> Option> { let formatted_time = self.current_time.format("%H:%M"); - iced::widget::text!("{}", formatted_time).into() + Some(iced::widget::text!("{}", formatted_time).into()) } } diff --git a/src/widgets/power_management.rs b/src/widgets/power_management.rs index eb2ff3a..3724a2e 100644 --- a/src/widgets/power_management.rs +++ b/src/widgets/power_management.rs @@ -1,12 +1,20 @@ -use iced::{Subscription, Task, widget::text}; -use ppd::PpdProxyBlocking; +use iced::{ + Subscription, Task, + widget::{Column, button, text}, +}; +use iced_layershell::reexport::{Anchor, NewLayerShellSettings}; +use ppd::{PpdProxyBlocking, Result}; use zbus::blocking::Connection; use crate::widget::{Message, PanelWidget}; pub struct PowerManagementWidget<'a> { + connection: Option>, +} + +struct Connected<'a> { window: Option, - current_mode: usize, + current_mode: Box, modes: Box<[Box]>, proxy: PpdProxyBlocking<'a>, } @@ -19,28 +27,29 @@ pub enum PowerManagement { impl PowerManagementWidget<'_> { pub fn new() -> Self { + Self { + connection: Self::establish_connection().ok(), + } + } + + fn establish_connection<'a>() -> Result> { let conn = Connection::system().unwrap(); - let proxy = PpdProxyBlocking::new(&conn).unwrap(); + let proxy = PpdProxyBlocking::new(&conn)?; let modes: Box<[Box]> = proxy - .profiles() - .unwrap() + .profiles()? .iter() .map(|f| f.profile.clone().into_boxed_str()) .collect(); - let current_mode_str = proxy.active_profile().unwrap(); - let current_mode = modes - .iter() - .position(|m| m.as_ref() == current_mode_str.as_str()) - .unwrap(); + let current_mode = proxy.active_profile()?.into_boxed_str(); - Self { - window: None, - modes, + Ok(Connected { current_mode, + modes, proxy, - } + window: None, + }) } } @@ -50,18 +59,81 @@ impl PanelWidget for PowerManagementWidget<'_> { return Task::none(); }; - Task::none() + let Some(conn) = &mut self.connection else { + return Task::none(); + }; + + match msg { + PowerManagement::ToggleWindow => match conn.window { + Some(child) => { + conn.window = None; + Task::done(Message::RemoveWindow(child)) + } + None => { + let id = iced::window::Id::unique(); + conn.window = Some(id); + + Task::done(Message::NewLayerShell { + settings: NewLayerShellSettings { + size: Some((220, 400)), + anchor: Anchor::Top, + layer: iced_layershell::reexport::Layer::Overlay, + keyboard_interactivity: + iced_layershell::reexport::KeyboardInteractivity::OnDemand, + exclusive_zone: None, + ..Default::default() + }, + id, + }) + } + }, + + PowerManagement::SetMode(mode) => { + let _ = conn.proxy.set_active_profile(mode.into()); + + conn.current_mode = conn.proxy.active_profile().unwrap().into_boxed_str(); + Task::none() + } + } } fn subscribe(&self) -> iced::Subscription { Subscription::none() } - fn view(&self, _id: iced::window::Id) -> iced::Element<'_, crate::widget::Message> { - text!("{}", self.modes[self.current_mode]).into() + fn view(&self) -> Option> { + let Some(conn) = &self.connection else { + return None; + }; + + let output = button(text!("{}", conn.current_mode)) + .on_press(Message::PowerManagement(PowerManagement::ToggleWindow)) + .into(); + + Some(output) } - fn has_window(&self, id: iced::window::Id) -> bool { - self.window == Some(id) + fn render_window( + &self, + id: iced::window::Id, + ) -> Option> { + let Some(conn) = &self.connection else { + return None; + }; + + if conn.window != Some(id) { + return None; + } + + let output = Column::with_children(conn.modes.iter().map(|f| { + button(text!("{}", f)) + .on_press(Message::PowerManagement(PowerManagement::SetMode( + f.clone().into_string(), + ))) + .into() + })) + .into(); + + Some(output) } } diff --git a/src/widgets/powerbutton.rs b/src/widgets/powerbutton.rs index 841d5c3..ce29027 100644 --- a/src/widgets/powerbutton.rs +++ b/src/widgets/powerbutton.rs @@ -1,6 +1,6 @@ use crate::widget::{Message, PanelWidget}; use iced::{ - Subscription, Task, + Element, Subscription, Task, widget::{button, row, text}, }; use iced_layershell::reexport::{Anchor, NewLayerShellSettings}; @@ -67,24 +67,28 @@ impl PanelWidget for ShutdownWidget { Subscription::none() } - fn has_window(&self, id: iced::window::Id) -> bool { - self.window == Some(id) + fn render_window(&self, id: iced::window::Id) -> Option> { + if self.window != Some(id) { + return None; + } + + let output = row![ + text("Shut down?"), + button("✓").on_press(Message::ShutdownEvent(ShutdownEvents::ShutdownConfirmed)), + button("✗").on_press(Message::ShutdownEvent(ShutdownEvents::ShutdownCanceled)), + ] + .spacing(8) + .align_y(iced::Alignment::Center) + .into(); + + Some(output) } - fn view(&self, id: iced::window::Id) -> iced::Element<'_, crate::widget::Message> { - match self.window { - Some(child_id) if id == child_id => row![ - text("Shut down?"), - button("✓").on_press(Message::ShutdownEvent(ShutdownEvents::ShutdownConfirmed)), - button("✗").on_press(Message::ShutdownEvent(ShutdownEvents::ShutdownCanceled)), - ] - .spacing(8) - .align_y(iced::Alignment::Center) - .into(), + fn view(&self) -> Option> { + let output = button("⏻") + .on_press(Message::ShutdownEvent(ShutdownEvents::PowerButtonPressed)) + .into(); - _ => button("⏻") - .on_press(Message::ShutdownEvent(ShutdownEvents::PowerButtonPressed)) - .into(), - } + Some(output) } } diff --git a/src/widgets/spacer.rs b/src/widgets/spacer.rs index 68e720f..b0b9399 100644 --- a/src/widgets/spacer.rs +++ b/src/widgets/spacer.rs @@ -19,7 +19,7 @@ impl PanelWidget for Spacer { iced::Subscription::none() } - fn view(&self, _id: iced::window::Id) -> iced::Element<'_, crate::widget::Message> { - iced::widget::space().width(self.space).into() + fn view(&self) -> Option> { + Some(iced::widget::space().width(self.space).into()) } }