Use ellipsizing and replace chrono with jiff (#1323)
* refactor(time): use `jiff` instead of `chrono` * improv: use text ellipsizing
This commit is contained in:
parent
02b035ce93
commit
7029fcccf6
10 changed files with 708 additions and 530 deletions
1038
Cargo.lock
generated
1038
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -24,7 +24,7 @@ members = [
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1.0.100"
|
anyhow = "1.0.102"
|
||||||
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "d0e95be" }
|
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "d0e95be" }
|
||||||
cosmic-applets-config = { path = "cosmic-applets-config" }
|
cosmic-applets-config = { path = "cosmic-applets-config" }
|
||||||
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
|
||||||
|
|
@ -50,11 +50,11 @@ libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = fa
|
||||||
"desktop-systemd-scope",
|
"desktop-systemd-scope",
|
||||||
"winit",
|
"winit",
|
||||||
] }
|
] }
|
||||||
rust-embed = "8.9.0"
|
rust-embed = "8.11.0"
|
||||||
rust-embed-utils = "8.9.0"
|
rust-embed-utils = "8.11.0"
|
||||||
rustc-hash = "2.1"
|
rustc-hash = "2.1"
|
||||||
rustix = { version = "1.1", features = ["fs", "process"] }
|
rustix = { version = "1.1", features = ["fs", "process"] }
|
||||||
zbus = { version = "5.13.1", default-features = false, features = ["tokio"] }
|
zbus = { version = "5.14.0", default-features = false, features = ["tokio"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
||||||
tracing-log = "0.2.0"
|
tracing-log = "0.2.0"
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ i18n-embed.workspace = true
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
image = { version = "0.25.9", default-features = false }
|
image = { version = "0.25.9", default-features = false }
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
memmap2 = "0.9.9"
|
memmap2 = "0.9.10"
|
||||||
fastrand = "2.3.0"
|
fastrand = "2.3.0"
|
||||||
rust-embed.workspace = true
|
rust-embed.workspace = true
|
||||||
rustix.workspace = true
|
rustix.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,11 @@ use cosmic::{
|
||||||
desktop::IconSourceExt,
|
desktop::IconSourceExt,
|
||||||
iced::{
|
iced::{
|
||||||
self, Alignment, Background, Border, Length, Limits, Padding, Subscription,
|
self, Alignment, Background, Border, Length, Limits, Padding, Subscription,
|
||||||
|
advanced::text::{Ellipsize, EllipsizeHeightLimit},
|
||||||
clipboard::mime::{AllowedMimeTypes, AsMimeTypes},
|
clipboard::mime::{AllowedMimeTypes, AsMimeTypes},
|
||||||
event::listen_with,
|
event::listen_with,
|
||||||
platform_specific::shell::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::commands::popup::{destroy_popup, get_popup},
|
||||||
widget::{
|
widget::{Column, Row, column, mouse_area, row, stack, vertical_rule, vertical_space},
|
||||||
Column, Row, column, mouse_area, row, stack, text::Wrapping, vertical_rule,
|
|
||||||
vertical_space,
|
|
||||||
},
|
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
iced_runtime::{core::event, dnd::peek_dnd},
|
iced_runtime::{core::event, dnd::peek_dnd},
|
||||||
|
|
@ -471,11 +469,6 @@ fn toplevel_button<'a>(
|
||||||
is_focused: bool,
|
is_focused: bool,
|
||||||
is_hovered: bool,
|
is_hovered: bool,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
let title = if title.len() > 22 {
|
|
||||||
format!("{:.20}...", title)
|
|
||||||
} else {
|
|
||||||
title
|
|
||||||
};
|
|
||||||
let border = 1.0;
|
let border = 1.0;
|
||||||
let preview = column![
|
let preview = column![
|
||||||
container(if let Some(img) = img {
|
container(if let Some(img) = img {
|
||||||
|
|
@ -499,7 +492,7 @@ fn toplevel_button<'a>(
|
||||||
.apply(container)
|
.apply(container)
|
||||||
.center(Length::Fill),
|
.center(Length::Fill),
|
||||||
text::body(title)
|
text::body(title)
|
||||||
.wrapping(Wrapping::None)
|
.ellipsize(Ellipsize::End(EllipsizeHeightLimit::Lines(1)))
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.center()
|
.center()
|
||||||
]
|
]
|
||||||
|
|
@ -2073,16 +2066,13 @@ impl cosmic::Application for CosmicAppList {
|
||||||
if !toplevels.is_empty() {
|
if !toplevels.is_empty() {
|
||||||
let mut list_col = column![];
|
let mut list_col = column![];
|
||||||
for (info, _) in toplevels {
|
for (info, _) in toplevels {
|
||||||
let title = if info.title.len() > 34 {
|
list_col = list_col.push(
|
||||||
format!("{:.32}...", &info.title)
|
menu_button(
|
||||||
} else {
|
text::body(&info.title)
|
||||||
info.title.clone()
|
.ellipsize(Ellipsize::End(EllipsizeHeightLimit::Lines(1))),
|
||||||
};
|
)
|
||||||
list_col =
|
.on_press(Message::Activate(info.foreign_toplevel.clone())),
|
||||||
list_col
|
);
|
||||||
.push(menu_button(text::body(title)).on_press(
|
|
||||||
Message::Activate(info.foreign_toplevel.clone()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
content = content.push(list_col);
|
content = content.push(list_col);
|
||||||
content = content.push(divider::horizontal::light());
|
content = content.push(divider::horizontal::light());
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ i18n-embed-fl.workspace = true
|
||||||
i18n-embed.workspace = true
|
i18n-embed.workspace = true
|
||||||
image = { version = "0.25.9", default-features = false }
|
image = { version = "0.25.9", default-features = false }
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
memmap2 = "0.9.9"
|
memmap2 = "0.9.10"
|
||||||
rust-embed.workspace = true
|
rust-embed.workspace = true
|
||||||
rustix.workspace = true
|
rustix.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ zbus.workspace = true
|
||||||
nm-secret-agent-manager = { git = "https://github.com/pop-os/dbus-settings-bindings/" }
|
nm-secret-agent-manager = { git = "https://github.com/pop-os/dbus-settings-bindings/" }
|
||||||
indexmap = "2.13.0"
|
indexmap = "2.13.0"
|
||||||
secure-string = "0.3.0"
|
secure-string = "0.3.0"
|
||||||
uuid = { version = "1.19.0", features = ["v4"] }
|
uuid = { version = "1.21.0", features = ["v4"] }
|
||||||
|
|
||||||
|
|
||||||
[dependencies.cosmic-settings-network-manager-subscription]
|
[dependencies.cosmic-settings-network-manager-subscription]
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use cosmic::{
|
||||||
cosmic_theme::Spacing,
|
cosmic_theme::Spacing,
|
||||||
iced::{
|
iced::{
|
||||||
Alignment, Length, Subscription,
|
Alignment, Length, Subscription,
|
||||||
|
advanced::text::{Ellipsize, EllipsizeHeightLimit},
|
||||||
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
||||||
widget::{column, row},
|
widget::{column, row},
|
||||||
window,
|
window,
|
||||||
|
|
@ -457,15 +458,9 @@ impl cosmic::Application for Notifications {
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.map(|n| {
|
.map(|n| {
|
||||||
let app_name = text::caption(if n.app_name.len() > 24 {
|
let app_name = text::caption(Cow::from(&n.app_name))
|
||||||
Cow::from(format!(
|
.ellipsize(Ellipsize::End(EllipsizeHeightLimit::Lines(1)))
|
||||||
"{:.26}...",
|
.width(Length::Fill);
|
||||||
n.app_name.lines().next().unwrap_or_default()
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Cow::from(&n.app_name)
|
|
||||||
})
|
|
||||||
.width(Length::Fill);
|
|
||||||
|
|
||||||
let duration_since = text::caption(duration_ago_msg(n));
|
let duration_since = text::caption(duration_ago_msg(n));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmic-applets-config.workspace = true
|
cosmic-applets-config.workspace = true
|
||||||
chrono = { version = "0.4.42", features = ["clock"] }
|
jiff = "0.2"
|
||||||
chrono-tz = "0.10"
|
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
i18n-embed.workspace = true
|
i18n-embed.workspace = true
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use chrono::{Datelike, Days, NaiveDate, Weekday};
|
use jiff::{
|
||||||
|
ToSpan,
|
||||||
|
civil::{Date, Weekday},
|
||||||
|
};
|
||||||
|
|
||||||
/// Gets the first date that will be visible on the calendar
|
/// Gets the first date that will be visible on the calendar
|
||||||
pub fn get_calendar_first(year: i32, month: u32, from_weekday: Weekday) -> NaiveDate {
|
pub fn get_calendar_first(year: i16, month: i8, from_weekday: Weekday) -> Date {
|
||||||
let date = NaiveDate::from_ymd_opt(year, month, 1).unwrap();
|
let date = Date::new(year, month, 1).expect("valid date");
|
||||||
let num_days = (date.weekday() as u32 + 7 - from_weekday as u32) % 7; // chrono::Weekday.num_days_from
|
let num_days = date.weekday().since(from_weekday);
|
||||||
date.checked_sub_days(Days::new(num_days as u64)).unwrap()
|
date.checked_sub(num_days.days()).expect("valid date")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use chrono::{Datelike, Timelike};
|
|
||||||
use cosmic::iced_futures::stream;
|
|
||||||
use cosmic::widget::Id;
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
Apply, Element, Task, app,
|
Apply, Element, Task, app,
|
||||||
applet::{cosmic_panel_config::PanelAnchor, menu_button, padded_control},
|
applet::{cosmic_panel_config::PanelAnchor, menu_button, padded_control},
|
||||||
|
|
@ -16,13 +13,20 @@ use cosmic::{
|
||||||
widget::{column, row, vertical_space},
|
widget::{column, row, vertical_space},
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
|
iced_futures::stream,
|
||||||
iced_widget::{Column, horizontal_rule},
|
iced_widget::{Column, horizontal_rule},
|
||||||
surface, theme,
|
surface, theme,
|
||||||
widget::{
|
widget::{
|
||||||
Button, Grid, Space, autosize, button, container, divider, grid, horizontal_space, icon,
|
Button, Grid, Id, Space, autosize, button, container, divider, grid, horizontal_space,
|
||||||
rectangle_tracker::*, text,
|
icon, rectangle_tracker::*, text,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use jiff::{
|
||||||
|
Timestamp, ToSpan, Zoned,
|
||||||
|
civil::{Date, Weekday},
|
||||||
|
fmt::strtime,
|
||||||
|
tz::TimeZone,
|
||||||
|
};
|
||||||
use logind_zbus::manager::ManagerProxy;
|
use logind_zbus::manager::ManagerProxy;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use timedate_zbus::TimeDateProxy;
|
use timedate_zbus::TimeDateProxy;
|
||||||
|
|
@ -35,7 +39,7 @@ use cosmic::applet::token::subscription::{
|
||||||
use icu::{
|
use icu::{
|
||||||
datetime::{
|
datetime::{
|
||||||
DateTimeFormatter, DateTimeFormatterPreferences, fieldsets,
|
DateTimeFormatter, DateTimeFormatterPreferences, fieldsets,
|
||||||
input::{Date, DateTime, Time},
|
input::{Date as IcuDate, DateTime, Time},
|
||||||
options::TimePrecision,
|
options::TimePrecision,
|
||||||
},
|
},
|
||||||
locale::{Locale, preferences::extensions::unicode::keywords::HourCycle},
|
locale::{Locale, preferences::extensions::unicode::keywords::HourCycle},
|
||||||
|
|
@ -76,10 +80,10 @@ fn get_system_locale() -> Locale {
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
core: cosmic::app::Core,
|
core: cosmic::app::Core,
|
||||||
popup: Option<window::Id>,
|
popup: Option<window::Id>,
|
||||||
now: chrono::DateTime<chrono::FixedOffset>,
|
now: Zoned,
|
||||||
timezone: Option<chrono_tz::Tz>,
|
timezone: Option<TimeZone>,
|
||||||
date_today: chrono::NaiveDate,
|
date_today: Date,
|
||||||
date_selected: chrono::NaiveDate,
|
date_selected: Date,
|
||||||
rectangle_tracker: Option<RectangleTracker<u32>>,
|
rectangle_tracker: Option<RectangleTracker<u32>>,
|
||||||
rectangle: Rectangle,
|
rectangle: Rectangle,
|
||||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||||
|
|
@ -94,7 +98,7 @@ pub enum Message {
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
Tick,
|
Tick,
|
||||||
Rectangle(RectangleUpdate<u32>),
|
Rectangle(RectangleUpdate<u32>),
|
||||||
SelectDay(u32),
|
SelectDay(i8),
|
||||||
PreviousMonth,
|
PreviousMonth,
|
||||||
NextMonth,
|
NextMonth,
|
||||||
OpenDateTimeSettings,
|
OpenDateTimeSettings,
|
||||||
|
|
@ -105,10 +109,14 @@ pub enum Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
fn create_datetime<D: Datelike>(&self, date: &D) -> DateTime<icu::calendar::Gregorian> {
|
fn create_datetime(&self, date: &Date) -> DateTime<icu::calendar::Gregorian> {
|
||||||
DateTime {
|
DateTime {
|
||||||
date: Date::try_new_gregorian(date.year(), date.month() as u8, date.day() as u8)
|
date: IcuDate::try_new_gregorian(
|
||||||
.unwrap(),
|
date.year() as i32,
|
||||||
|
date.month() as u8,
|
||||||
|
date.day() as u8,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
time: Time::try_new(
|
time: Time::try_new(
|
||||||
self.now.hour() as u8,
|
self.now.hour() as u8,
|
||||||
self.now.minute() as u8,
|
self.now.minute() as u8,
|
||||||
|
|
@ -120,9 +128,16 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calendar_grid(&self) -> Grid<'_, Message> {
|
fn calendar_grid(&self) -> Grid<'_, Message> {
|
||||||
let mut calendar: Grid<'_, Message> = grid().width(Length::Fill);
|
let mut calendar = grid().width(Length::Fill);
|
||||||
let mut first_day_of_week = chrono::Weekday::try_from(self.config.first_day_of_week)
|
let first_day_of_week = match self.config.first_day_of_week {
|
||||||
.unwrap_or(chrono::Weekday::Sun);
|
0 => Weekday::Monday,
|
||||||
|
1 => Weekday::Tuesday,
|
||||||
|
2 => Weekday::Wednesday,
|
||||||
|
3 => Weekday::Thursday,
|
||||||
|
4 => Weekday::Friday,
|
||||||
|
5 => Weekday::Saturday,
|
||||||
|
_ => Weekday::Sunday,
|
||||||
|
};
|
||||||
|
|
||||||
let first_day = get_calendar_first(
|
let first_day = get_calendar_first(
|
||||||
self.date_selected.year(),
|
self.date_selected.year(),
|
||||||
|
|
@ -130,31 +145,30 @@ impl Window {
|
||||||
first_day_of_week,
|
first_day_of_week,
|
||||||
);
|
);
|
||||||
|
|
||||||
let day_iter = first_day.iter_days();
|
|
||||||
let prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
let prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
||||||
let weekday = DateTimeFormatter::try_new(prefs, fieldsets::E::short()).unwrap();
|
let weekday = DateTimeFormatter::try_new(prefs, fieldsets::E::short()).unwrap();
|
||||||
|
|
||||||
for date in day_iter.take(7) {
|
for i in 0..7 {
|
||||||
|
let date = first_day.checked_add(i.days()).unwrap();
|
||||||
let datetime = self.create_datetime(&date);
|
let datetime = self.create_datetime(&date);
|
||||||
calendar = calendar.push(
|
calendar = calendar.push(
|
||||||
text::caption(weekday.format(&datetime).to_string())
|
text::caption(weekday.format(&datetime).to_string())
|
||||||
.apply(container)
|
.apply(container)
|
||||||
.center_x(Length::Fixed(44.0)),
|
.center_x(Length::Fixed(44.0)),
|
||||||
);
|
);
|
||||||
first_day_of_week = first_day_of_week.succ();
|
|
||||||
}
|
}
|
||||||
calendar = calendar.insert_row();
|
calendar = calendar.insert_row();
|
||||||
|
|
||||||
let mut day_iter = first_day.iter_days();
|
|
||||||
for i in 0..42 {
|
for i in 0..42 {
|
||||||
if i > 0 && i % 7 == 0 {
|
if i > 0 && i % 7 == 0 {
|
||||||
calendar = calendar.insert_row();
|
calendar = calendar.insert_row();
|
||||||
}
|
}
|
||||||
|
|
||||||
let date = day_iter.next().unwrap();
|
let date = first_day
|
||||||
let is_month = date.month() == self.date_selected.month()
|
.checked_add(i.days())
|
||||||
&& date.year_ce() == self.date_selected.year_ce();
|
.expect("valid date in calendar range");
|
||||||
let is_day = date.day() == self.date_selected.day() && is_month;
|
let is_month = date.first_of_month() == self.date_selected.first_of_month();
|
||||||
|
let is_day = date == self.date_selected;
|
||||||
let is_today = date == self.date_today;
|
let is_today = date == self.date_today;
|
||||||
|
|
||||||
calendar = calendar.push(date_button(date.day(), is_month, is_day, is_today));
|
calendar = calendar.push(date_button(date.day(), is_month, is_day, is_today));
|
||||||
|
|
@ -170,14 +184,7 @@ impl Window {
|
||||||
// strftime may override locale specific elements so it stands alone rather
|
// strftime may override locale specific elements so it stands alone rather
|
||||||
// than using ICU.
|
// than using ICU.
|
||||||
(!self.config.format_strftime.is_empty())
|
(!self.config.format_strftime.is_empty())
|
||||||
.then(|| {
|
.then(|| strtime::format(&self.config.format_strftime, &self.now).ok())
|
||||||
let mut s = String::new();
|
|
||||||
self.now
|
|
||||||
.format(&self.config.format_strftime)
|
|
||||||
.write_to(&mut s)
|
|
||||||
.map(|_| s)
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +196,7 @@ impl Window {
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
let date = self.now.naive_local();
|
let date = self.now.date();
|
||||||
let datetime = self.create_datetime(&date);
|
let datetime = self.create_datetime(&date);
|
||||||
let mut prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
let mut prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
||||||
prefs.hour_cycle = Some(if self.config.military_time {
|
prefs.hour_cycle = Some(if self.config.military_time {
|
||||||
|
|
@ -252,7 +259,7 @@ impl Window {
|
||||||
let formatted_date = if let Some(strftime) = self.maybe_strftime() {
|
let formatted_date = if let Some(strftime) = self.maybe_strftime() {
|
||||||
strftime
|
strftime
|
||||||
} else {
|
} else {
|
||||||
let datetime = self.create_datetime(&self.now);
|
let datetime = self.create_datetime(&self.now.date());
|
||||||
let mut prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
let mut prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
||||||
prefs.hour_cycle = Some(if self.config.military_time {
|
prefs.hour_cycle = Some(if self.config.military_time {
|
||||||
HourCycle::H23
|
HourCycle::H23
|
||||||
|
|
@ -310,19 +317,13 @@ impl cosmic::Application for Window {
|
||||||
type Message = Message;
|
type Message = Message;
|
||||||
type Executor = cosmic::SingleThreadExecutor;
|
type Executor = cosmic::SingleThreadExecutor;
|
||||||
type Flags = ();
|
type Flags = ();
|
||||||
const APP_ID: &'static str = "com.system76.CosmicAppletTime";
|
const APP_ID: &str = "com.system76.CosmicAppletTime";
|
||||||
|
|
||||||
fn init(core: app::Core, _flags: Self::Flags) -> (Self, app::Task<Self::Message>) {
|
fn init(core: app::Core, _flags: Self::Flags) -> (Self, app::Task<Self::Message>) {
|
||||||
let locale = get_system_locale();
|
let locale = get_system_locale();
|
||||||
|
let now = Zoned::now();
|
||||||
// Chrono evaluates the local timezone once whereby it's stored in a thread local
|
|
||||||
// variable but never updated
|
|
||||||
// Instead of using the local timezone, we will store an offset that is updated if the
|
|
||||||
// timezone is ever externally changed
|
|
||||||
let now = chrono::Local::now().fixed_offset();
|
|
||||||
|
|
||||||
// get today's date for highlighting purposes
|
// get today's date for highlighting purposes
|
||||||
let today = chrono::NaiveDate::from(now.naive_local());
|
let today = now.date();
|
||||||
|
|
||||||
// Synch `show_seconds` from the config within the time subscription
|
// Synch `show_seconds` from the config within the time subscription
|
||||||
let (show_seconds_tx, _) = watch::channel(true);
|
let (show_seconds_tx, _) = watch::channel(true);
|
||||||
|
|
@ -383,7 +384,7 @@ impl cosmic::Application for Window {
|
||||||
|
|
||||||
// Calculate a delta if we're ticking per minute to keep ticks stable
|
// Calculate a delta if we're ticking per minute to keep ticks stable
|
||||||
// Based on i3status-rust
|
// Based on i3status-rust
|
||||||
let current = chrono::Local::now().second() as u64 % period;
|
let current = Timestamp::now().as_second() as u64 % period;
|
||||||
if current != 0 {
|
if current != 0 {
|
||||||
timer.reset_after(time::Duration::from_secs(period - current));
|
timer.reset_after(time::Duration::from_secs(period - current));
|
||||||
}
|
}
|
||||||
|
|
@ -399,7 +400,7 @@ impl cosmic::Application for Window {
|
||||||
timer = time::interval_at(start, period);
|
timer = time::interval_at(start, period);
|
||||||
} else {
|
} else {
|
||||||
period = 60;
|
period = 60;
|
||||||
let delta = time::Duration::from_secs(period - chrono::Utc::now().second() as u64 % period);
|
let delta = time::Duration::from_secs(period - Timestamp::now().as_second() as u64 % period);
|
||||||
let now = time::Instant::now();
|
let now = time::Instant::now();
|
||||||
// Start ticking from the next minute to update the time properly
|
// Start ticking from the next minute to update the time properly
|
||||||
let start = now + delta;
|
let start = now + delta;
|
||||||
|
|
@ -505,7 +506,7 @@ impl cosmic::Application for Window {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
destroy_popup(p)
|
destroy_popup(p)
|
||||||
} else {
|
} else {
|
||||||
self.date_today = chrono::NaiveDate::from(self.now.naive_local());
|
self.date_today = self.now.date();
|
||||||
self.date_selected = self.date_today;
|
self.date_selected = self.date_today;
|
||||||
|
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
|
|
@ -537,9 +538,9 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Tick => {
|
Message::Tick => {
|
||||||
self.now = self.timezone.map_or_else(
|
self.now = self.timezone.as_ref().map_or_else(
|
||||||
|| chrono::Local::now().into(),
|
|| Zoned::now(),
|
||||||
|tz| chrono::Local::now().with_timezone(&tz).fixed_offset(),
|
|tz| Zoned::now().with_time_zone(tz.clone()),
|
||||||
);
|
);
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -561,32 +562,26 @@ impl cosmic::Application for Window {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::SelectDay(day) => {
|
Message::SelectDay(day) => {
|
||||||
if let Some(date) = self.date_selected.with_day(day) {
|
if let Ok(date) = self.date_selected.with().day(day).build() {
|
||||||
self.date_selected = date;
|
self.date_selected = date;
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("invalid naivedate");
|
tracing::error!("invalid date");
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::PreviousMonth => {
|
Message::PreviousMonth => {
|
||||||
if let Some(date) = self
|
if let Ok(date) = self.date_selected.checked_sub(1.month()) {
|
||||||
.date_selected
|
|
||||||
.checked_sub_months(chrono::Months::new(1))
|
|
||||||
{
|
|
||||||
self.date_selected = date;
|
self.date_selected = date;
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("invalid naivedate");
|
tracing::error!("invalid date");
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::NextMonth => {
|
Message::NextMonth => {
|
||||||
if let Some(date) = self
|
if let Ok(date) = self.date_selected.checked_add(1.month()) {
|
||||||
.date_selected
|
|
||||||
.checked_add_months(chrono::Months::new(1))
|
|
||||||
{
|
|
||||||
self.date_selected = date;
|
self.date_selected = date;
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("invalid naivedate");
|
tracing::error!("invalid date");
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -649,9 +644,9 @@ impl cosmic::Application for Window {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::TimezoneUpdate(timezone) => {
|
Message::TimezoneUpdate(timezone) => {
|
||||||
if let Ok(timezone) = timezone.parse::<chrono_tz::Tz>() {
|
if let Ok(timezone) = TimeZone::get(&timezone) {
|
||||||
self.now = chrono::Local::now().with_timezone(&timezone).fixed_offset();
|
self.now = Zoned::now().with_time_zone(timezone.clone());
|
||||||
self.date_today = chrono::NaiveDate::from(self.now.naive_local());
|
self.date_today = self.now.date();
|
||||||
self.date_selected = self.date_today;
|
self.date_selected = self.date_today;
|
||||||
self.timezone = Some(timezone);
|
self.timezone = Some(timezone);
|
||||||
}
|
}
|
||||||
|
|
@ -756,7 +751,7 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn date_button(day: u32, is_month: bool, is_day: bool, is_today: bool) -> Button<'static, Message> {
|
fn date_button(day: i8, is_month: bool, is_day: bool, is_today: bool) -> Button<'static, Message> {
|
||||||
let style = if is_day {
|
let style = if is_day {
|
||||||
button::ButtonClass::Suggested
|
button::ButtonClass::Suggested
|
||||||
} else if is_today {
|
} else if is_today {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue