structural updates + power_management

This commit is contained in:
Jiří Maxmilián Stříbrný 2026-03-24 14:50:55 +01:00
parent 22670f6abd
commit c2c4881942
7 changed files with 125 additions and 51 deletions

View file

@ -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)

View file

@ -9,9 +9,9 @@ use crate::widgets::powerbutton::ShutdownEvents;
pub trait PanelWidget {
fn update(&mut self, message: &Message) -> Task<Message>;
fn subscribe(&self) -> Subscription<Message>;
fn view(&self, id: iced::window::Id) -> Element<'_, Message>;
fn has_window(&self, _id: iced::window::Id) -> bool {
false
fn view(&self) -> Option<Element<'_, Message>>;
fn render_window(&self, _id: iced::window::Id) -> Option<Element<'_, Message>> {
None
}
}

View file

@ -65,12 +65,11 @@ impl PanelWidget for BatteryWidget {
})
}
fn view(&self, _id: iced::window::Id) -> Element<'_, Message> {
fn view(&self) -> Option<Element<'_, Message>> {
match self.capacity {
Some(cap) => text!("{} {}", cap, Self::icon(cap)),
None => text!("󰂃"),
Some(cap) => Some(text!("{} {}", cap, Self::icon(cap)).into()),
None => None,
}
.into()
}
}

View file

@ -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<iced::Element<'_, Message>> {
let formatted_time = self.current_time.format("%H:%M");
iced::widget::text!("{}", formatted_time).into()
Some(iced::widget::text!("{}", formatted_time).into())
}
}

View file

@ -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<Connected<'a>>,
}
struct Connected<'a> {
window: Option<iced::window::Id>,
current_mode: usize,
current_mode: Box<str>,
modes: Box<[Box<str>]>,
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<Connected<'a>> {
let conn = Connection::system().unwrap();
let proxy = PpdProxyBlocking::new(&conn).unwrap();
let proxy = PpdProxyBlocking::new(&conn)?;
let modes: Box<[Box<str>]> = 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();
};
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<crate::widget::Message> {
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<iced::Element<'_, crate::widget::Message>> {
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<iced::Element<'_, crate::widget::Message>> {
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)
}
}

View file

@ -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<Element<'_, Message>> {
if self.window != Some(id) {
return None;
}
fn view(&self, id: iced::window::Id) -> iced::Element<'_, crate::widget::Message> {
match self.window {
Some(child_id) if id == child_id => row![
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(),
.into();
_ => button("")
.on_press(Message::ShutdownEvent(ShutdownEvents::PowerButtonPressed))
.into(),
Some(output)
}
fn view(&self) -> Option<iced::Element<'_, crate::widget::Message>> {
let output = button("")
.on_press(Message::ShutdownEvent(ShutdownEvents::PowerButtonPressed))
.into();
Some(output)
}
}

View file

@ -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<iced::Element<'_, crate::widget::Message>> {
Some(iced::widget::space().width(self.space).into())
}
}