fix(time): Timezone stream spams updates
This commit is contained in:
parent
323e8a55b2
commit
0d0a13a062
1 changed files with 40 additions and 58 deletions
|
|
@ -9,14 +9,13 @@ use cosmic::{
|
||||||
applet::{cosmic_panel_config::PanelAnchor, menu_button, padded_control},
|
applet::{cosmic_panel_config::PanelAnchor, menu_button, padded_control},
|
||||||
cctk::sctk::reexports::calloop,
|
cctk::sctk::reexports::calloop,
|
||||||
iced::{
|
iced::{
|
||||||
futures::{FutureExt, TryFutureExt},
|
futures::{channel::mpsc, SinkExt, StreamExt, TryFutureExt},
|
||||||
subscription,
|
subscription,
|
||||||
wayland::popup::{destroy_popup, get_popup},
|
wayland::popup::{destroy_popup, get_popup},
|
||||||
widget::{column, row, text, vertical_space},
|
widget::{column, row, text, vertical_space},
|
||||||
window, Alignment, Length, Rectangle, Subscription,
|
window, Alignment, Length, Rectangle, Subscription,
|
||||||
},
|
},
|
||||||
iced_core::alignment::{Horizontal, Vertical},
|
iced_core::alignment::{Horizontal, Vertical},
|
||||||
iced_runtime::command,
|
|
||||||
iced_style::application,
|
iced_style::application,
|
||||||
iced_widget::{horizontal_rule, Column},
|
iced_widget::{horizontal_rule, Column},
|
||||||
widget::{
|
widget::{
|
||||||
|
|
@ -26,7 +25,6 @@ use cosmic::{
|
||||||
Command, Element, Theme,
|
Command, Element, Theme,
|
||||||
};
|
};
|
||||||
use timedate_zbus::TimeDateProxy;
|
use timedate_zbus::TimeDateProxy;
|
||||||
use zbus::Connection;
|
|
||||||
|
|
||||||
use icu::{
|
use icu::{
|
||||||
calendar::DateTime,
|
calendar::DateTime,
|
||||||
|
|
@ -59,12 +57,10 @@ pub struct Window {
|
||||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||||
config: TimeAppletConfig,
|
config: TimeAppletConfig,
|
||||||
locale: Locale,
|
locale: Locale,
|
||||||
conn: Option<Connection>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
Init(Option<Connection>),
|
|
||||||
TogglePopup,
|
TogglePopup,
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
Tick,
|
Tick,
|
||||||
|
|
@ -75,7 +71,7 @@ pub enum Message {
|
||||||
OpenDateTimeSettings,
|
OpenDateTimeSettings,
|
||||||
Token(TokenUpdate),
|
Token(TokenUpdate),
|
||||||
ConfigChanged(TimeAppletConfig),
|
ConfigChanged(TimeAppletConfig),
|
||||||
TimezoneUpdate(Option<String>),
|
TimezoneUpdate(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
|
@ -152,10 +148,8 @@ impl cosmic::Application for Window {
|
||||||
token_tx: None,
|
token_tx: None,
|
||||||
config: TimeAppletConfig::default(),
|
config: TimeAppletConfig::default(),
|
||||||
locale,
|
locale,
|
||||||
conn: None,
|
|
||||||
},
|
},
|
||||||
Command::single(command::Action::Future(Box::pin(Connection::system())))
|
Command::none(),
|
||||||
.map(|res| Message::Init(res.ok()).into()),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,49 +179,43 @@ impl cosmic::Application for Window {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let conn = self.conn.clone();
|
// Update applet's timezone if the system's timezone changes
|
||||||
fn timezone_subscription(conn: Option<Connection>) -> Subscription<Message> {
|
async fn timezone_update(output: &mut mpsc::Sender<Message>) -> zbus::Result<()> {
|
||||||
use cosmic::iced_futures::futures::StreamExt;
|
let conn = zbus::Connection::system().await?;
|
||||||
let Some(conn) = conn else {
|
let proxy = TimeDateProxy::new(&conn).await?;
|
||||||
return Subscription::none();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update applet's timezone if the system's timezone changes
|
// The stream always returns the current timezone as its first item even if it wasn't
|
||||||
subscription::unfold("timezone-sub", (), move |_| {
|
// updated. If the proxy is recreated in a loop somehow, the resulting stream will
|
||||||
let conn = conn.clone();
|
// always yield an update immediately which could lead to spammed false updates.
|
||||||
async move {
|
while let Some(property) = proxy.receive_timezone_changed().await.next().await {
|
||||||
TimeDateProxy::new(&conn)
|
let tz = property.get().await?;
|
||||||
.inspect_err(|e| {
|
output
|
||||||
tracing::error!("Failed to connect to timedate endpoint: {e:?}")
|
.send(Message::TimezoneUpdate(tz))
|
||||||
})
|
.map_err(|e| {
|
||||||
.then(|proxy| async move {
|
zbus::Error::InputOutput(std::sync::Arc::new(std::io::Error::other(e)))
|
||||||
let Ok(proxy) = proxy else {
|
})
|
||||||
return (Message::TimezoneUpdate(None), ());
|
.await?;
|
||||||
};
|
}
|
||||||
proxy
|
|
||||||
.receive_timezone_changed()
|
Ok(())
|
||||||
.then(|stream| stream.into_future())
|
}
|
||||||
.then(|(prop_opt, _)| async move {
|
|
||||||
if let Some(property) = prop_opt {
|
fn timezone_subscription() -> Subscription<Message> {
|
||||||
property
|
subscription::channel("timezone-sub", 1, |mut output| async move {
|
||||||
.get()
|
'retry: loop {
|
||||||
.await
|
match timezone_update(&mut output).await {
|
||||||
.inspect_err(|e| {
|
Ok(()) => break 'retry,
|
||||||
tracing::error!(
|
Err(err) => {
|
||||||
"Failed to receive time zone update: {e:?}"
|
tracing::error!(
|
||||||
)
|
?err,
|
||||||
})
|
"Automatic timezone updater failed; retrying in one minute"
|
||||||
.ok()
|
);
|
||||||
.map(|tz| (Message::TimezoneUpdate(Some(tz)), ()))
|
tokio::time::sleep(std::time::Duration::from_secs(60)).await;
|
||||||
.unwrap_or((Message::TimezoneUpdate(None), ()))
|
}
|
||||||
} else {
|
}
|
||||||
(Message::TimezoneUpdate(None), ())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::future::pending().await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,7 +223,7 @@ impl cosmic::Application for Window {
|
||||||
rectangle_tracker_subscription(0).map(|e| Message::Rectangle(e.1)),
|
rectangle_tracker_subscription(0).map(|e| Message::Rectangle(e.1)),
|
||||||
time_subscription().map(|_| Message::Tick),
|
time_subscription().map(|_| Message::Tick),
|
||||||
activation_token_subscription(0).map(Message::Token),
|
activation_token_subscription(0).map(Message::Token),
|
||||||
timezone_subscription(conn),
|
timezone_subscription(),
|
||||||
self.core.watch_config(Self::APP_ID).map(|u| {
|
self.core.watch_config(Self::APP_ID).map(|u| {
|
||||||
for err in u.errors {
|
for err in u.errors {
|
||||||
tracing::error!(?err, "Error watching config");
|
tracing::error!(?err, "Error watching config");
|
||||||
|
|
@ -250,10 +238,6 @@ impl cosmic::Application for Window {
|
||||||
message: Self::Message,
|
message: Self::Message,
|
||||||
) -> cosmic::iced::Command<app::Message<Self::Message>> {
|
) -> cosmic::iced::Command<app::Message<Self::Message>> {
|
||||||
match message {
|
match message {
|
||||||
Message::Init(conn) => {
|
|
||||||
self.conn = conn;
|
|
||||||
Command::none()
|
|
||||||
}
|
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
destroy_popup(p)
|
destroy_popup(p)
|
||||||
|
|
@ -376,9 +360,7 @@ impl cosmic::Application for Window {
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
Message::TimezoneUpdate(timezone) => {
|
Message::TimezoneUpdate(timezone) => {
|
||||||
if let Some(timezone) =
|
if let Ok(timezone) = timezone.parse::<chrono_tz::Tz>() {
|
||||||
timezone.and_then(|timezone| timezone.parse::<chrono_tz::Tz>().ok())
|
|
||||||
{
|
|
||||||
self.now = chrono::Local::now().with_timezone(&timezone).fixed_offset();
|
self.now = chrono::Local::now().with_timezone(&timezone).fixed_offset();
|
||||||
self.timezone = Some(timezone);
|
self.timezone = Some(timezone);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue