Use cosmic::Application/cosmic::app::applet

This saves a bit of duplicated boilerplate.

Applets seem to work fairly well with this. Though we should see if any
other changes to initial window settings are needed in certain applets
for the exact behavior we want.
This commit is contained in:
Ian Douglas Scott 2023-08-03 13:22:17 -07:00
parent 3ad64df5f3
commit a23f181b7f
28 changed files with 2029 additions and 2597 deletions

View file

@ -10,19 +10,18 @@ use crate::upower_device::{device_subscription, DeviceDbusEvent};
use crate::upower_kbdbacklight::{
kbd_backlight_subscription, KeyboardBacklightRequest, KeyboardBacklightUpdate,
};
use cosmic::app::{applet::applet_button_theme, Command};
use cosmic::iced::alignment::Horizontal;
use cosmic::iced::wayland::popup::{destroy_popup, get_popup};
use cosmic::iced::Color;
use cosmic::iced::{
widget::{column, container, row, slider, text},
window, Alignment, Application, Command, Length, Subscription,
window, Alignment, Length, Subscription,
};
use cosmic::iced_runtime::core::layout::Limits;
use cosmic::iced_style::application::{self, Appearance};
use cosmic::iced_style::application;
use cosmic::theme::Svg;
use cosmic::widget::{button, divider, icon};
use cosmic::{Element, Theme};
use cosmic_applet::{applet_button_theme, CosmicAppletHelper};
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
use log::error;
@ -46,17 +45,16 @@ fn format_duration(duration: Duration) -> String {
}
pub fn run() -> cosmic::iced::Result {
let helper = CosmicAppletHelper::default();
CosmicBatteryApplet::run(helper.window_settings())
cosmic::app::applet::run::<CosmicBatteryApplet>(false, ())
}
static MAX_CHARGE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
#[derive(Clone, Default)]
struct CosmicBatteryApplet {
core: cosmic::app::Core,
icon_name: String,
display_icon_name: String,
theme: Theme,
charging_limit: bool,
battery_percent: f64,
on_battery: bool,
@ -67,7 +65,6 @@ struct CosmicBatteryApplet {
id_ctr: u128,
screen_sender: Option<UnboundedSender<ScreenBacklightRequest>>,
kbd_sender: Option<UnboundedSender<KeyboardBacklightRequest>>,
applet_helper: CosmicAppletHelper,
power_profile: Power,
power_profile_sender: Option<UnboundedSender<PowerProfileRequest>>,
timeline: Timeline,
@ -144,37 +141,36 @@ enum Message {
InitKbdBacklight(UnboundedSender<KeyboardBacklightRequest>, f64),
InitScreenBacklight(UnboundedSender<ScreenBacklightRequest>, f64),
Errored(String),
Ignore,
InitProfile(UnboundedSender<PowerProfileRequest>, Power),
Profile(Power),
SelectProfile(Power),
Frame(Instant),
Theme(Theme),
}
impl Application for CosmicBatteryApplet {
impl cosmic::Application for CosmicBatteryApplet {
type Message = Message;
type Theme = Theme;
type Executor = cosmic::SingleThreadExecutor;
type Flags = ();
const APP_ID: &'static str = config::APP_ID;
fn new(_flags: ()) -> (Self, Command<Message>) {
let applet_helper = CosmicAppletHelper::default();
let theme = applet_helper.theme();
fn init(core: cosmic::app::Core, _flags: ()) -> (Self, Command<Message>) {
(
CosmicBatteryApplet {
core,
icon_name: "battery-symbolic".to_string(),
display_icon_name: "display-brightness-symbolic".to_string(),
applet_helper,
theme,
..Default::default()
},
Command::none(),
)
}
fn title(&self) -> String {
config::APP_ID.to_string()
fn core(&self) -> &cosmic::app::Core {
&self.core
}
fn core_mut(&mut self) -> &mut cosmic::app::Core {
&mut self.core
}
fn update(&mut self, message: Message) -> Command<Message> {
@ -217,7 +213,7 @@ impl Application for CosmicBatteryApplet {
let new_id = window::Id(self.id_ctr);
self.popup.replace(new_id);
let mut popup_settings = self.applet_helper.get_popup_settings(
let mut popup_settings = self.core.applet_helper.get_popup_settings(
window::Id(0),
new_id,
None,
@ -246,7 +242,6 @@ impl Application for CosmicBatteryApplet {
Message::UpdateKbdBrightness(b) => {
self.kbd_brightness = b;
}
Message::Ignore => {}
Message::InitKbdBacklight(tx, brightness) => {
let _ = tx.send(KeyboardBacklightRequest::Get);
self.kbd_sender = Some(tx);
@ -278,171 +273,170 @@ impl Application for CosmicBatteryApplet {
let _ = tx.send(PowerProfileRequest::Set(profile));
}
}
Message::Theme(t) => {
self.theme = t;
}
}
Command::none()
}
fn view(&self, id: window::Id) -> Element<Message> {
if id == window::Id(0) {
self.applet_helper
.icon_button(&self.icon_name)
.on_press(Message::TogglePopup)
.into()
fn view(&self) -> Element<Message> {
self.core
.applet_helper
.icon_button(&self.icon_name)
.on_press(Message::TogglePopup)
.into()
}
fn view_window(&self, _id: window::Id) -> Element<Message> {
let name = text(fl!("battery")).size(14);
let description = text(if !self.on_battery {
format!("{}%", self.battery_percent)
} else {
let name = text(fl!("battery")).size(14);
let description = text(if !self.on_battery {
format!("{}%", self.battery_percent)
} else {
format!(
"{} {} ({:.0}%)",
format_duration(self.time_remaining),
fl!("until-empty"),
self.battery_percent
)
})
.size(10);
self.applet_helper
.popup_container(
column![
row![
icon(&*self.icon_name, 24).style(Svg::Symbolic),
column![name, description]
]
.padding([0, 24])
.spacing(8)
.align_items(Alignment::Center),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
button(applet_button_theme())
.custom(vec![row![
column![
text(fl!("battery")).size(14),
text(fl!("battery-desc")).size(10)
]
.width(Length::Fill),
icon("emblem-ok-symbolic", 12).size(12).style(
match self.power_profile {
Power::Battery => Svg::SymbolicActive,
_ => Svg::Default,
}
),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectProfile(Power::Battery))
.width(Length::Fill),
button(applet_button_theme())
.custom(vec![row![
column![
text(fl!("balanced")).size(14),
text(fl!("balanced-desc")).size(10)
]
.width(Length::Fill),
icon("emblem-ok-symbolic", 12).size(12).style(
match self.power_profile {
Power::Balanced => Svg::SymbolicActive,
_ => Svg::Default,
}
),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectProfile(Power::Balanced))
.width(Length::Fill),
button(applet_button_theme())
.custom(vec![row![
column![
text(fl!("performance")).size(14),
text(fl!("performance-desc")).size(10)
]
.width(Length::Fill),
icon("emblem-ok-symbolic", 12).size(12).style(
match self.power_profile {
Power::Performance => Svg::SymbolicActive,
_ => Svg::Default,
}
),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectProfile(Power::Performance))
.width(Length::Fill),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
container(
anim!(
//toggler
MAX_CHARGE,
&self.timeline,
fl!("max-charge"),
self.charging_limit,
Message::SetChargingLimit,
)
.text_size(14)
.width(Length::Fill)
)
.padding([0, 24])
.width(Length::Fill),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
row![
icon(self.display_icon_name.as_str(), 24).style(Svg::Symbolic),
slider(
1..=100,
(self.screen_brightness * 100.0) as i32,
Message::SetScreenBrightness
),
text(format!("{:.0}%", self.screen_brightness * 100.0))
.size(16)
.width(Length::Fixed(40.0))
.horizontal_alignment(Horizontal::Right)
]
.padding([0, 24])
.spacing(12),
row![
icon("keyboard-brightness-symbolic", 24).style(Svg::Symbolic),
slider(
0..=100,
(self.kbd_brightness * 100.0) as i32,
Message::SetKbdBrightness
),
text(format!("{:.0}%", self.kbd_brightness * 100.0))
.size(16)
.width(Length::Fixed(40.0))
.horizontal_alignment(Horizontal::Right)
]
.padding([0, 24])
.spacing(12),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
button(applet_button_theme())
.custom(vec![text(fl!("power-settings"))
.size(14)
.width(Length::Fill)
.into()])
.on_press(Message::OpenBatterySettings)
.width(Length::Fill)
.padding([8, 24])
format!(
"{} {} ({:.0}%)",
format_duration(self.time_remaining),
fl!("until-empty"),
self.battery_percent
)
})
.size(10);
self.core
.applet_helper
.popup_container(
column![
row![
icon(&*self.icon_name, 24).style(Svg::Symbolic),
column![name, description]
]
.padding([0, 24])
.spacing(8)
.padding([8, 0]),
)
.into()
}
.align_items(Alignment::Center),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
button(applet_button_theme())
.custom(vec![row![
column![
text(fl!("battery")).size(14),
text(fl!("battery-desc")).size(10)
]
.width(Length::Fill),
icon("emblem-ok-symbolic", 12).size(12).style(
match self.power_profile {
Power::Battery => Svg::SymbolicActive,
_ => Svg::Default,
}
),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectProfile(Power::Battery))
.width(Length::Fill),
button(applet_button_theme())
.custom(vec![row![
column![
text(fl!("balanced")).size(14),
text(fl!("balanced-desc")).size(10)
]
.width(Length::Fill),
icon("emblem-ok-symbolic", 12).size(12).style(
match self.power_profile {
Power::Balanced => Svg::SymbolicActive,
_ => Svg::Default,
}
),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectProfile(Power::Balanced))
.width(Length::Fill),
button(applet_button_theme())
.custom(vec![row![
column![
text(fl!("performance")).size(14),
text(fl!("performance-desc")).size(10)
]
.width(Length::Fill),
icon("emblem-ok-symbolic", 12).size(12).style(
match self.power_profile {
Power::Performance => Svg::SymbolicActive,
_ => Svg::Default,
}
),
]
.align_items(Alignment::Center)
.into()])
.padding([8, 24])
.on_press(Message::SelectProfile(Power::Performance))
.width(Length::Fill),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
container(
anim!(
//toggler
MAX_CHARGE,
&self.timeline,
fl!("max-charge"),
self.charging_limit,
Message::SetChargingLimit,
)
.text_size(14)
.width(Length::Fill)
)
.padding([0, 24])
.width(Length::Fill),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
row![
icon(self.display_icon_name.as_str(), 24).style(Svg::Symbolic),
slider(
1..=100,
(self.screen_brightness * 100.0) as i32,
Message::SetScreenBrightness
),
text(format!("{:.0}%", self.screen_brightness * 100.0))
.size(16)
.width(Length::Fixed(40.0))
.horizontal_alignment(Horizontal::Right)
]
.padding([0, 24])
.spacing(12),
row![
icon("keyboard-brightness-symbolic", 24).style(Svg::Symbolic),
slider(
0..=100,
(self.kbd_brightness * 100.0) as i32,
Message::SetKbdBrightness
),
text(format!("{:.0}%", self.kbd_brightness * 100.0))
.size(16)
.width(Length::Fixed(40.0))
.horizontal_alignment(Horizontal::Right)
]
.padding([0, 24])
.spacing(12),
container(divider::horizontal::light())
.width(Length::Fill)
.padding([0, 12]),
button(applet_button_theme())
.custom(vec![text(fl!("power-settings"))
.size(14)
.width(Length::Fill)
.into()])
.on_press(Message::OpenBatterySettings)
.width(Length::Fill)
.padding([8, 24])
]
.spacing(8)
.padding([8, 0]),
)
.into()
}
fn subscription(&self) -> Subscription<Message> {
Subscription::batch(vec![
self.applet_helper.theme_subscription(0).map(Message::Theme),
device_subscription(0).map(
|DeviceDbusEvent::Update {
on_battery,
@ -473,18 +467,7 @@ impl Application for CosmicBatteryApplet {
])
}
fn theme(&self) -> Theme {
self.theme.clone()
}
fn close_requested(&self, _id: window::Id) -> Message {
Message::Ignore
}
fn style(&self) -> <Self::Theme as application::StyleSheet>::Style {
<Self::Theme as application::StyleSheet>::Style::Custom(Box::new(|theme| Appearance {
background_color: Color::from_rgba(0.0, 0.0, 0.0, 0.0),
text_color: theme.cosmic().on_bg_color().into(),
}))
fn style(&self) -> Option<<Theme as application::StyleSheet>::Style> {
Some(cosmic::app::applet::style())
}
}