use chrono::{Timelike as _, Utc};
use chrono_tz::Tz;
use super::prelude::*;
#[derive(Deserialize, Debug, SmartDefault)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
pub format: FormatConfig,
#[default(10.into())]
pub interval: Seconds,
pub timezone: Option<Timezone>,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum Timezone {
Timezone(Tz),
Timezones(Vec<Tz>),
}
pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
let mut actions = api.get_actions()?;
api.set_default_actions(&[
(MouseButton::Left, None, "next_timezone"),
(MouseButton::Right, None, "prev_timezone"),
])?;
let format = config
.format
.with_default(" $icon $timestamp.datetime() ")?;
let timezones = match config.timezone.clone() {
Some(tzs) => match tzs {
Timezone::Timezone(tz) => vec![tz],
Timezone::Timezones(tzs) => tzs,
},
None => Vec::new(),
};
let prev_step_length = timezones.len().saturating_sub(2);
let mut timezone_iter = timezones.iter().cycle();
let mut timezone = timezone_iter.next();
let interval_seconds = config.interval.seconds().max(1);
let mut timer = tokio::time::interval_at(
tokio::time::Instant::now() + Duration::from_secs(interval_seconds),
Duration::from_secs(interval_seconds),
);
timer.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
let mut widget = Widget::new().with_format(format.clone());
let now = Utc::now();
widget.set_values(map! {
"icon" => Value::icon("time"),
"timestamp" => Value::datetime(now, timezone.copied())
});
api.set_widget(widget)?;
let phase = now.second() as u64 % interval_seconds;
if phase != 0 {
timer.reset_after(Duration::from_secs(interval_seconds - phase));
}
tokio::select! {
_ = timer.tick() => (),
_ = api.wait_for_update_request() => (),
Some(action) = actions.recv() => match action.as_ref() {
"next_timezone" => {
timezone = timezone_iter.next();
},
"prev_timezone" => {
timezone = timezone_iter.nth(prev_step_length);
},
_ => (),
}
}
}
}