fix(power): alignment of remaining battery
This commit is contained in:
parent
090efbfad7
commit
97bcbc64ec
6 changed files with 121 additions and 35 deletions
|
|
@ -19,6 +19,10 @@ pub static LANGUAGE_LOADER: Lazy<FluentLanguageLoader> = Lazy::new(|| {
|
||||||
.load_fallback_language(&Localizations)
|
.load_fallback_language(&Localizations)
|
||||||
.expect("Error while loading fallback language");
|
.expect("Error while loading fallback language");
|
||||||
|
|
||||||
|
// In test, disable the isolating markers to help with string assertion
|
||||||
|
#[cfg(test)]
|
||||||
|
loader.set_use_isolating(false);
|
||||||
|
|
||||||
loader
|
loader
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ impl Default for PageInner {
|
||||||
Self {
|
Self {
|
||||||
config_helper: Option::default(),
|
config_helper: Option::default(),
|
||||||
panel_config: Option::default(),
|
panel_config: Option::default(),
|
||||||
outputs: vec![fl!("all")],
|
outputs: vec![fl!("all-displays")],
|
||||||
anchors: vec![
|
anchors: vec![
|
||||||
Anchor(PanelAnchor::Left).to_string(),
|
Anchor(PanelAnchor::Left).to_string(),
|
||||||
Anchor(PanelAnchor::Right).to_string(),
|
Anchor(PanelAnchor::Right).to_string(),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use chrono::Duration;
|
use chrono::{Duration, TimeDelta};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use zbus::Connection;
|
use zbus::Connection;
|
||||||
|
|
||||||
|
|
@ -236,7 +236,6 @@ pub struct Battery {
|
||||||
pub percent: f64,
|
pub percent: f64,
|
||||||
pub on_battery: bool,
|
pub on_battery: bool,
|
||||||
pub remaining_duration: Duration,
|
pub remaining_duration: Duration,
|
||||||
pub remaining_time: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_device_proxy<'a>() -> Result<upower_dbus::DeviceProxy<'a>, zbus::Error> {
|
async fn get_device_proxy<'a>() -> Result<upower_dbus::DeviceProxy<'a>, zbus::Error> {
|
||||||
|
|
@ -321,30 +320,79 @@ impl Battery {
|
||||||
let icon_name =
|
let icon_name =
|
||||||
format!("cosmic-applet-battery-level-{battery_percent}-{charging}symbolic",);
|
format!("cosmic-applet-battery-level-{battery_percent}-{charging}symbolic",);
|
||||||
|
|
||||||
let remaining_time = |duration: Duration| {
|
|
||||||
let total_seconds = duration.num_seconds();
|
|
||||||
|
|
||||||
let hours = total_seconds / 3600;
|
|
||||||
let minutes = (total_seconds % 3600) / 60;
|
|
||||||
let seconds = total_seconds % 60;
|
|
||||||
|
|
||||||
fl!(
|
|
||||||
"battery",
|
|
||||||
"remaining-time",
|
|
||||||
time = format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
return Battery {
|
return Battery {
|
||||||
icon_name,
|
icon_name,
|
||||||
is_present,
|
is_present,
|
||||||
percent,
|
percent,
|
||||||
on_battery,
|
on_battery,
|
||||||
remaining_duration,
|
remaining_duration,
|
||||||
remaining_time: remaining_time(remaining_duration),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Battery::default()
|
Battery::default()
|
||||||
}
|
}
|
||||||
|
pub fn remaining_time(&self) -> String {
|
||||||
|
if self.remaining_duration <= TimeDelta::zero() {
|
||||||
|
return String::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
let total_seconds = self.remaining_duration.num_seconds();
|
||||||
|
|
||||||
|
let days = total_seconds / 86400;
|
||||||
|
let hours = total_seconds % 86400 / 3600;
|
||||||
|
let minutes = (total_seconds % 3600) / 60;
|
||||||
|
|
||||||
|
let mut time: Vec<String> = Vec::new();
|
||||||
|
if days > 0 {
|
||||||
|
time.push(fl!("battery", "day", value = days));
|
||||||
|
}
|
||||||
|
if hours > 0 {
|
||||||
|
time.push(fl!("battery", "hour", value = hours));
|
||||||
|
}
|
||||||
|
if minutes > 0 {
|
||||||
|
time.push(fl!("battery", "minute", value = minutes));
|
||||||
|
}
|
||||||
|
|
||||||
|
if time.len() == 3 {
|
||||||
|
let last = time.pop().unwrap();
|
||||||
|
time = vec![time.join(", "), last];
|
||||||
|
}
|
||||||
|
let time = if time.is_empty() { fl!("battery", "less-than-minute")
|
||||||
|
} else {time.join(&format!(" {} ", fl!("battery", "and"))) };
|
||||||
|
|
||||||
|
fl!(
|
||||||
|
"battery",
|
||||||
|
"remaining-time",
|
||||||
|
time = time,
|
||||||
|
action = if self.on_battery { "empty" } else { "full" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_format_battery_remaining() {
|
||||||
|
let cases = [
|
||||||
|
(59, "Less than a minute until empty"),
|
||||||
|
(300, "5 minutes until empty"),
|
||||||
|
(305, "5 minutes until empty"),
|
||||||
|
(330, "5 minutes until empty"),
|
||||||
|
(360, "6 minutes until empty"),
|
||||||
|
(3660, "1 hour and 1 minute until empty"),
|
||||||
|
(10800, "3 hours until empty"),
|
||||||
|
(969400, "11 days, 5 hours and 16 minutes until empty"),
|
||||||
|
];
|
||||||
|
for case in cases {
|
||||||
|
let (actual, expected) = case;
|
||||||
|
let battery = Battery {
|
||||||
|
remaining_duration: Duration::new(actual, 0).unwrap(),
|
||||||
|
on_battery: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
assert_eq!(battery.remaining_time(), expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ mod backend;
|
||||||
use self::backend::{GetCurrentPowerProfile, SetPowerProfile};
|
use self::backend::{GetCurrentPowerProfile, SetPowerProfile};
|
||||||
use backend::{Battery, PowerProfile};
|
use backend::{Battery, PowerProfile};
|
||||||
|
|
||||||
use chrono::TimeDelta;
|
use cosmic::iced::{Alignment, Length};
|
||||||
use cosmic::iced::Length;
|
|
||||||
use cosmic::iced_widget::row;
|
use cosmic::iced_widget::row;
|
||||||
use cosmic::widget::{self, column, radio, settings, text};
|
use cosmic::widget::{self, column, radio, settings, text};
|
||||||
use cosmic::Apply;
|
use cosmic::Apply;
|
||||||
|
|
@ -79,18 +78,19 @@ fn battery_info() -> Section<crate::pages::Message> {
|
||||||
.show_while::<Page>(|page| page.battery.is_present)
|
.show_while::<Page>(|page| page.battery.is_present)
|
||||||
.view::<Page>(move |_binder, page, section| {
|
.view::<Page>(move |_binder, page, section| {
|
||||||
let battery_icon = widget::icon::from_name(page.battery.icon_name.clone());
|
let battery_icon = widget::icon::from_name(page.battery.icon_name.clone());
|
||||||
let battery_percent = text::body(format!("{}%", page.battery.percent));
|
let battery_label = text::body(format!(
|
||||||
|
"{}% {}",
|
||||||
let battery_time = text::body(if page.battery.remaining_duration > TimeDelta::zero() {
|
page.battery.percent,
|
||||||
&page.battery.remaining_time
|
page.battery.remaining_time()
|
||||||
} else {
|
));
|
||||||
""
|
|
||||||
});
|
|
||||||
|
|
||||||
column::with_capacity(2)
|
column::with_capacity(2)
|
||||||
.spacing(8)
|
|
||||||
.push(text::heading(§ion.title))
|
.push(text::heading(§ion.title))
|
||||||
.push(row!(battery_icon, battery_percent, battery_time).spacing(8))
|
.push(
|
||||||
|
row!(battery_icon, battery_label)
|
||||||
|
.align_items(Alignment::Center)
|
||||||
|
.spacing(cosmic::theme::active().cosmic().space_xxxs()),
|
||||||
|
)
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,8 @@ panel-style = Style
|
||||||
.background-opacity = Background opacity
|
.background-opacity = Background opacity
|
||||||
|
|
||||||
panel-applets = Configuration
|
panel-applets = Configuration
|
||||||
.dock-desc = Configure dock applets.
|
.dock-desc = Configure dock applets
|
||||||
.desc = Configure panel applets.
|
.desc = Configure panel applets
|
||||||
|
|
||||||
panel-missing = Panel Configuration is Missing
|
panel-missing = Panel Configuration is Missing
|
||||||
.desc = The panel configuration file is missing due to use of a custom configuration or it is corrupted.
|
.desc = The panel configuration file is missing due to use of a custom configuration or it is corrupted.
|
||||||
|
|
@ -304,7 +304,24 @@ power = Power & Battery
|
||||||
.desc = Manage power settings
|
.desc = Manage power settings
|
||||||
|
|
||||||
battery = Battery
|
battery = Battery
|
||||||
.remaining-time = ({ $time } left)
|
.minute = { $value } { $value ->
|
||||||
|
[one] minute
|
||||||
|
*[other] minutes
|
||||||
|
}
|
||||||
|
.hour = { $value } { $value ->
|
||||||
|
[one] hour
|
||||||
|
*[other] hours
|
||||||
|
}
|
||||||
|
.day = { $value } { $value ->
|
||||||
|
[one] day
|
||||||
|
*[other] days
|
||||||
|
}
|
||||||
|
.less-than-minute = Less than a minute
|
||||||
|
.and = and
|
||||||
|
.remaining-time = ({ $time } until { $action ->
|
||||||
|
[full] full
|
||||||
|
*[other] empty
|
||||||
|
})
|
||||||
|
|
||||||
power-mode = Power Mode
|
power-mode = Power Mode
|
||||||
.battery = Extended battery life
|
.battery = Extended battery life
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,8 @@ panel-style = Style
|
||||||
.background-opacity = Opacité de l'arrière-plan
|
.background-opacity = Opacité de l'arrière-plan
|
||||||
|
|
||||||
panel-applets = Configuration
|
panel-applets = Configuration
|
||||||
.dock-desc = Configuration des applets du dock.
|
.dock-desc = Configuration des applets du dock
|
||||||
.desc = Configuration des applets du panneau.
|
.desc = Configuration des applets du panneau
|
||||||
|
|
||||||
panel-missing = La configuration du panneau est manquante
|
panel-missing = La configuration du panneau est manquante
|
||||||
.desc = Le fichier de configuration du panneau est manquant à cause d'une configuration personnalisée ou il est corrompu.
|
.desc = Le fichier de configuration du panneau est manquant à cause d'une configuration personnalisée ou il est corrompu.
|
||||||
|
|
@ -294,7 +294,24 @@ power = Énergie
|
||||||
.desc = Gérer les paramètres d'alimentation
|
.desc = Gérer les paramètres d'alimentation
|
||||||
|
|
||||||
battery = Batterie
|
battery = Batterie
|
||||||
.remaining-time = ({ $time } restant)
|
.minute = { $value } { $value ->
|
||||||
|
[one] minute
|
||||||
|
*[other] minutes
|
||||||
|
}
|
||||||
|
.hour = { $value } { $value ->
|
||||||
|
[one] heure
|
||||||
|
*[other] heures
|
||||||
|
}
|
||||||
|
.day = { $value } { $value ->
|
||||||
|
[one] jour
|
||||||
|
*[other] jours
|
||||||
|
}
|
||||||
|
.less-than-minute = Moins d'une minute
|
||||||
|
.and = et
|
||||||
|
.remaining-time = ({ $time } jusqu'à la { $action ->
|
||||||
|
[full] charge
|
||||||
|
*[other] decharge
|
||||||
|
} complète)
|
||||||
|
|
||||||
power-profiles = Modes d'énergie
|
power-profiles = Modes d'énergie
|
||||||
.battery = Économie d'énergie
|
.battery = Économie d'énergie
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue