i3status_rs/blocks/
time.rs1use chrono::{Timelike as _, Utc};
53use chrono_tz::Tz;
54
55use super::prelude::*;
56
57#[derive(Deserialize, Debug, SmartDefault)]
58#[serde(deny_unknown_fields, default)]
59pub struct Config {
60 pub format: FormatConfig,
61 #[default(10.into())]
62 pub interval: Seconds,
63 pub timezone: Option<Timezone>,
64}
65
66#[derive(Deserialize, Debug, Clone)]
67#[serde(untagged)]
68pub enum Timezone {
69 Timezone(Tz),
70 Timezones(Vec<Tz>),
71}
72
73pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
74 let mut actions = api.get_actions()?;
75 api.set_default_actions(&[
76 (MouseButton::Left, None, "next_timezone"),
77 (MouseButton::Right, None, "prev_timezone"),
78 ])?;
79
80 let format = config
81 .format
82 .with_default(" $icon $timestamp.datetime() ")?;
83
84 let timezones = match config.timezone.clone() {
85 Some(tzs) => match tzs {
86 Timezone::Timezone(tz) => vec![tz],
87 Timezone::Timezones(tzs) => tzs,
88 },
89 None => Vec::new(),
90 };
91
92 let prev_step_length = timezones.len().saturating_sub(2);
93
94 let mut timezone_iter = timezones.iter().cycle();
95
96 let mut timezone = timezone_iter.next();
97
98 let interval_seconds = config.interval.seconds().max(1);
99
100 let mut timer = tokio::time::interval_at(
101 tokio::time::Instant::now() + Duration::from_secs(interval_seconds),
102 Duration::from_secs(interval_seconds),
103 );
104 timer.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
105
106 loop {
107 let mut widget = Widget::new().with_format(format.clone());
108 let now = Utc::now();
109
110 widget.set_values(map! {
111 "icon" => Value::icon("time"),
112 "timestamp" => Value::datetime(now, timezone.copied())
113 });
114
115 api.set_widget(widget)?;
116
117 let phase = now.second() as u64 % interval_seconds;
118 if phase != 0 {
119 timer.reset_after(Duration::from_secs(interval_seconds - phase));
120 }
121
122 tokio::select! {
123 _ = timer.tick() => (),
124 _ = api.wait_for_update_request() => (),
125 Some(action) = actions.recv() => match action.as_ref() {
126 "next_timezone" => {
127 timezone = timezone_iter.next();
128 },
129 "prev_timezone" => {
130 timezone = timezone_iter.nth(prev_step_length);
131 },
132 _ => (),
133 }
134 }
135 }
136}