From 97bcbc64ec32cb31f5f2fe54480c4226dda42250 Mon Sep 17 00:00:00 2001 From: Antoine Colombier <7086688+acolombier@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:24:02 +0100 Subject: [PATCH] fix(power): alignment of remaining battery --- cosmic-settings/src/localize.rs | 4 + .../src/pages/desktop/panel/inner.rs | 2 +- .../src/pages/power/backend/mod.rs | 82 +++++++++++++++---- cosmic-settings/src/pages/power/mod.rs | 22 ++--- i18n/en/cosmic_settings.ftl | 23 +++++- i18n/fr/cosmic_settings.ftl | 23 +++++- 6 files changed, 121 insertions(+), 35 deletions(-) diff --git a/cosmic-settings/src/localize.rs b/cosmic-settings/src/localize.rs index cd2c281..316fe35 100644 --- a/cosmic-settings/src/localize.rs +++ b/cosmic-settings/src/localize.rs @@ -19,6 +19,10 @@ pub static LANGUAGE_LOADER: Lazy = Lazy::new(|| { .load_fallback_language(&Localizations) .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 }); diff --git a/cosmic-settings/src/pages/desktop/panel/inner.rs b/cosmic-settings/src/pages/desktop/panel/inner.rs index 867713d..a2a4fb6 100644 --- a/cosmic-settings/src/pages/desktop/panel/inner.rs +++ b/cosmic-settings/src/pages/desktop/panel/inner.rs @@ -36,7 +36,7 @@ impl Default for PageInner { Self { config_helper: Option::default(), panel_config: Option::default(), - outputs: vec![fl!("all")], + outputs: vec![fl!("all-displays")], anchors: vec![ Anchor(PanelAnchor::Left).to_string(), Anchor(PanelAnchor::Right).to_string(), diff --git a/cosmic-settings/src/pages/power/backend/mod.rs b/cosmic-settings/src/pages/power/backend/mod.rs index dbbea6c..8278f13 100644 --- a/cosmic-settings/src/pages/power/backend/mod.rs +++ b/cosmic-settings/src/pages/power/backend/mod.rs @@ -1,4 +1,4 @@ -use chrono::Duration; +use chrono::{Duration, TimeDelta}; use futures::FutureExt; use zbus::Connection; @@ -236,7 +236,6 @@ pub struct Battery { pub percent: f64, pub on_battery: bool, pub remaining_duration: Duration, - pub remaining_time: String, } async fn get_device_proxy<'a>() -> Result, zbus::Error> { @@ -321,30 +320,79 @@ impl Battery { let icon_name = 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 { icon_name, is_present, percent, on_battery, remaining_duration, - remaining_time: remaining_time(remaining_duration), }; } 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 = 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); + } + } } diff --git a/cosmic-settings/src/pages/power/mod.rs b/cosmic-settings/src/pages/power/mod.rs index 856309c..249e0a2 100644 --- a/cosmic-settings/src/pages/power/mod.rs +++ b/cosmic-settings/src/pages/power/mod.rs @@ -3,8 +3,7 @@ mod backend; use self::backend::{GetCurrentPowerProfile, SetPowerProfile}; use backend::{Battery, PowerProfile}; -use chrono::TimeDelta; -use cosmic::iced::Length; +use cosmic::iced::{Alignment, Length}; use cosmic::iced_widget::row; use cosmic::widget::{self, column, radio, settings, text}; use cosmic::Apply; @@ -79,18 +78,19 @@ fn battery_info() -> Section { .show_while::(|page| page.battery.is_present) .view::(move |_binder, page, section| { let battery_icon = widget::icon::from_name(page.battery.icon_name.clone()); - let battery_percent = text::body(format!("{}%", page.battery.percent)); - - let battery_time = text::body(if page.battery.remaining_duration > TimeDelta::zero() { - &page.battery.remaining_time - } else { - "" - }); + let battery_label = text::body(format!( + "{}% {}", + page.battery.percent, + page.battery.remaining_time() + )); column::with_capacity(2) - .spacing(8) .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() }) } diff --git a/i18n/en/cosmic_settings.ftl b/i18n/en/cosmic_settings.ftl index b076311..965d966 100644 --- a/i18n/en/cosmic_settings.ftl +++ b/i18n/en/cosmic_settings.ftl @@ -156,8 +156,8 @@ panel-style = Style .background-opacity = Background opacity panel-applets = Configuration - .dock-desc = Configure dock applets. - .desc = Configure panel applets. + .dock-desc = Configure dock applets + .desc = Configure panel applets panel-missing = Panel Configuration is Missing .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 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 .battery = Extended battery life diff --git a/i18n/fr/cosmic_settings.ftl b/i18n/fr/cosmic_settings.ftl index c13f96f..b12e190 100644 --- a/i18n/fr/cosmic_settings.ftl +++ b/i18n/fr/cosmic_settings.ftl @@ -156,8 +156,8 @@ panel-style = Style .background-opacity = Opacité de l'arrière-plan panel-applets = Configuration - .dock-desc = Configuration des applets du dock. - .desc = Configuration des applets du panneau. + .dock-desc = Configuration des applets du dock + .desc = Configuration des applets du panneau 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. @@ -294,7 +294,24 @@ power = Énergie .desc = Gérer les paramètres d'alimentation 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 .battery = Économie d'énergie