diff --git a/Cargo.lock b/Cargo.lock index b5b44c3..e0d61f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1482,7 +1482,7 @@ dependencies = [ [[package]] name = "cosmic-comp-config" version = "1.0.0" -source = "git+https://github.com/pop-os/cosmic-comp?branch=action-on-typing#df7819b2b24bb6b66ca97a2456572410f3e05521" +source = "git+https://github.com/pop-os/cosmic-comp#ef14b7e29469c4dc066e1c8cf096868d08213caf" dependencies = [ "cosmic-config", "input", @@ -1703,6 +1703,7 @@ dependencies = [ "indexmap 2.13.0", "itertools 0.14.0", "itoa", + "jiff", "libcosmic", "locale1", "locales-rs", @@ -4268,6 +4269,47 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84de9d95a6d2547d9b77ee3f25fa0ee32e3c3a6484d47a55adebc0439c077992" +[[package]] +name = "jiff" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c867c356cc096b33f4981825ab281ecba3db0acefe60329f044c1789d94c6543" +dependencies = [ + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-sys 0.61.2", +] + +[[package]] +name = "jiff-static" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7946b4325269738f270bb55b3c19ab5c5040525f83fd625259422a9d25d9be5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68971ebff725b9e2ca27a601c5eb38a4c5d64422c4cbab0c535f248087eda5c2" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "jni" version = "0.21.1" @@ -6053,6 +6095,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -7261,9 +7318,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "sunrise" -version = "2.1.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0733c9f1eaa06ed6d103d88e21f784449d08a6733c2ca2b39381cbcbcfe89272" +checksum = "15eecb5ec59a060dd9fe8f88c48b701abecd6be9d9c28d55081b80bdda73981c" dependencies = [ "chrono", ] diff --git a/Cargo.toml b/Cargo.toml index ec53772..e370ef2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ default-members = ["cosmic-settings"] resolver = "3" [workspace.package] -rust-version = "1.85" +rust-version = "1.90" [workspace.dependencies] cosmic-randr = { git = "https://github.com/pop-os/cosmic-randr" } @@ -22,7 +22,6 @@ git = "https://github.com/pop-os/cosmic-bg" [workspace.dependencies.cosmic-comp-config] git = "https://github.com/pop-os/cosmic-comp" -branch = "action-on-typing" features = ["output"] [workspace.dependencies.cosmic-idle-config] diff --git a/cosmic-settings/Cargo.toml b/cosmic-settings/Cargo.toml index e901b68..2b37c25 100644 --- a/cosmic-settings/Cargo.toml +++ b/cosmic-settings/Cargo.toml @@ -11,7 +11,8 @@ anyhow = "1.0" ashpd = { version = "0.12", default-features = false, features = [ "tokio", ], optional = true } -chrono = "0.4.42" +chrono = "0.4" +jiff = "0.2" clap = { version = "4.5.54", features = ["derive"] } color-eyre = "0.6.5" cosmic-bg-config.workspace = true @@ -69,7 +70,7 @@ serde = { version = "1.0.228", features = ["derive"] } slab = "0.4.11" slotmap = "1.1.1" static_init = "1.0.4" -sunrise = "2.1.0" +sunrise = "3.0.0" timedate-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true } tokio = { workspace = true, features = ["fs", "io-util", "process", "sync"] } tracing = "0.1.44" diff --git a/cosmic-settings/src/pages/power/backend/mod.rs b/cosmic-settings/src/pages/power/backend/mod.rs index 02b843d..fd9ca73 100644 --- a/cosmic-settings/src/pages/power/backend/mod.rs +++ b/cosmic-settings/src/pages/power/backend/mod.rs @@ -1,5 +1,5 @@ -use chrono::{Duration, TimeDelta}; use futures::{FutureExt, Stream, StreamExt, future::join_all}; +use jiff::{Span, SpanRelativeTo, SpanRound, ToSpan, Unit}; use upower_dbus::{BatteryState, BatteryType, DeviceProxy}; use zbus::{Connection, zvariant::ObjectPath}; @@ -233,7 +233,7 @@ pub struct Battery { pub is_present: bool, pub percent: f64, pub is_charging: bool, - pub remaining_duration: Duration, + pub remaining_duration: Span, } #[derive(Default, Debug, Clone)] @@ -302,7 +302,7 @@ async fn enumerate_devices<'a>() -> Result>, zb impl Battery { pub async fn from_device(proxy: &DeviceProxy<'_>) -> Self { - let mut remaining_duration: Duration = Duration::default(); + let mut remaining_duration = Span::default(); let (is_present, percentage, battery_state) = futures::join!( proxy.is_present().map(Result::unwrap_or_default), @@ -319,15 +319,11 @@ impl Battery { && (percent - 100.0_f64).abs() < f64::EPSILON; if !is_charging { - if let Ok(time) = proxy.time_to_empty().await - && let Ok(dur) = Duration::from_std(std::time::Duration::from_secs(time as u64)) - { - remaining_duration = dur; + if let Ok(time) = proxy.time_to_empty().await { + remaining_duration = time.seconds(); } - } else if let Ok(time) = proxy.time_to_full().await - && let Ok(dur) = Duration::from_std(std::time::Duration::from_secs(time as u64)) - { - remaining_duration = dur; + } else if let Ok(time) = proxy.time_to_full().await { + remaining_duration = time.seconds(); } let battery_percent = if percent > 95.0 { @@ -378,15 +374,22 @@ impl Battery { Battery::default() } pub fn remaining_time(&self) -> String { - if self.remaining_duration <= TimeDelta::zero() { + if !self.remaining_duration.is_positive() { return String::new(); } - let total_seconds = self.remaining_duration.num_seconds(); + let balanced = self + .remaining_duration + .round( + SpanRound::new() + .largest(Unit::Day) + .relative(SpanRelativeTo::days_are_24_hours()), + ) + .unwrap(); - let days = total_seconds / 86400; - let hours = total_seconds % 86400 / 3600; - let minutes = (total_seconds % 3600) / 60; + let days = balanced.get_days(); + let hours = balanced.get_hours(); + let minutes = balanced.get_minutes(); let mut time: Vec = Vec::new(); if days > 0 { @@ -546,7 +549,7 @@ mod tests { for case in cases { let (actual, expected) = case; let battery = Battery { - remaining_duration: Duration::new(actual, 0).unwrap(), + remaining_duration: actual.seconds(), is_charging: false, ..Default::default() }; diff --git a/cosmic-settings/src/pages/power/mod.rs b/cosmic-settings/src/pages/power/mod.rs index a4e5965..f419840 100644 --- a/cosmic-settings/src/pages/power/mod.rs +++ b/cosmic-settings/src/pages/power/mod.rs @@ -3,7 +3,6 @@ mod backend; use self::backend::{GetCurrentPowerProfile, SetPowerProfile}; use backend::{Battery, ConnectedDevice, PowerProfile}; -use chrono::TimeDelta; use cosmic::iced::{self, Alignment, Length}; use cosmic::iced_widget::{column, row}; use cosmic::widget::{self, radio, settings, text}; @@ -423,7 +422,7 @@ fn connected_devices() -> Section { widget::icon::from_name(connected_device.battery.icon_name.clone()); let battery_percent_and_time = widget::text( - if connected_device.battery.remaining_duration > TimeDelta::zero() { + if connected_device.battery.remaining_duration.is_positive() { format!( "{}% - {}", connected_device.battery.percent, diff --git a/cosmic-settings/src/pages/time/date.rs b/cosmic-settings/src/pages/time/date.rs index 62bc470..09ab475 100644 --- a/cosmic-settings/src/pages/time/date.rs +++ b/cosmic-settings/src/pages/time/date.rs @@ -1,7 +1,6 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use chrono::{Datelike, Timelike}; use cosmic::{ Apply, Element, Task, app::ContextDrawer, @@ -564,10 +563,11 @@ fn format_date(date: &DateTime, military: bool, show_seconds: bool) - } fn update_local_time() -> DateTime { - let now = chrono::Local::now(); + let now = jiff::Zoned::now(); DateTime { - date: Date::try_new_gregorian(now.year(), now.month() as u8, now.day() as u8).unwrap(), + date: Date::try_new_gregorian(now.year() as i32, now.month() as u8, now.day() as u8) + .unwrap(), time: Time::try_new(now.hour() as u8, now.minute() as u8, now.second() as u8, 0).unwrap(), } } diff --git a/cosmic-settings/src/subscription/daytime.rs b/cosmic-settings/src/subscription/daytime.rs index 2fd90ff..0376f5f 100644 --- a/cosmic-settings/src/subscription/daytime.rs +++ b/cosmic-settings/src/subscription/daytime.rs @@ -1,6 +1,7 @@ use std::any::TypeId; use ashpd::desktop::location::{Location, LocationProxy}; +use chrono::NaiveDate; use cosmic::iced::{ Subscription, futures::{SinkExt, StreamExt, channel::mpsc::Sender, future}, @@ -46,28 +47,49 @@ async fn inner(mut tx: Sender) -> anyhow::Result<()> { }; let coord = Coordinates::new(loc.latitude(), loc.longitude()).unwrap(); - let now = chrono::Local::now(); - let date = now.date_naive(); - let now_in_seconds = now.timestamp(); + let now = jiff::Zoned::now(); + let now_in_seconds = now.timestamp().as_second(); + let northern_tilt = now.month() >= 3 && now.month() <= 9; + // TODO: remove chrono if sunrise adds support for jiff - https://github.com/nathan-osman/rust-sunrise/pull/20 + let date = NaiveDate::from_ymd_opt(now.year() as i32, now.month() as u32, now.day() as u32) + .expect("jiff date is valid"); let current_solar_day = SolarDay::new(coord, date); let sunrise = current_solar_day .event_time(SolarEvent::Sunrise) - .timestamp(); - let sunset = current_solar_day.event_time(SolarEvent::Sunset).timestamp(); - let daytime = now_in_seconds >= sunrise && now_in_seconds <= sunset; + .map(|s| s.timestamp()); + let sunset = current_solar_day + .event_time(SolarEvent::Sunset) + .map(|s| s.timestamp()); + let daytime = match (sunrise, sunset) { + (Some(sunrise), Some(sunset)) => now_in_seconds >= sunrise && now_in_seconds <= sunset, + // transition into polar day + (Some(sunrise), None) => now_in_seconds >= sunrise, + // transition out of polar day + (None, Some(sunset)) => now_in_seconds <= sunset, + // polar day + (None, None) => { + (coord.lat() > 0.0 && northern_tilt) || (coord.lat() < 0.0 && !northern_tilt) + } + }; tx.send(daytime).await?; - let sleep = if daytime { - sunset - now_in_seconds - } else if now_in_seconds < sunset { - sunrise - now_in_seconds + let next_event = if daytime { + sunset + } else if now_in_seconds < sunrise.unwrap_or(0) { + sunrise } else { - let tmrw = now + chrono::Duration::days(1); - let tmrw_sunrise = SolarDay::new(coord, tmrw.date_naive()) + let tmrw = now.checked_add(jiff::Span::new().days(1))?; + let tmrw_sunrise = + NaiveDate::from_ymd_opt(tmrw.year() as i32, tmrw.month() as u32, tmrw.day() as u32) + .expect("jiff date is valid"); + + SolarDay::new(coord, tmrw_sunrise) .event_time(SolarEvent::Sunrise) - .timestamp(); - tmrw_sunrise - now_in_seconds + .map(|s| s.timestamp()) }; + let sleep = next_event + .map(|ts| (ts - now_in_seconds).max(60)) + .unwrap_or(3600); next = select! { () = tokio::time::sleep(tokio::time::Duration::from_secs(sleep as u64)) => { Some(Event::Daytime)