i3status_rs/blocks/tea_timer.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! Timer
//!
//! # Configuration
//!
//! Key | Values | Default
//! ----|--------|--------
//! `format` | A string to customise the output of this block. See below for available placeholders. | <code>\" $icon {$time.duration(hms:true) \|}\"</code>
//! `increment` | The numbers of seconds to add each time the block is clicked. | 30
//! `done_cmd` | A command to run in `sh` when timer finishes. | None
//!
//! Placeholder | Value | Type | Unit
//! -----------------------|----------------------------------------------------------------|----------|---------------
//! `icon` | A static icon | Icon | -
//! `time` | The time remaining on the timer | Duration | -
//! `hours` *DEPRECATED* | The hours remaining on the timer | Text | h
//! `minutes` *DEPRECATED* | The minutes remaining on the timer | Text | mn
//! `seconds` *DEPRECATED* | The seconds remaining on the timer | Text | s
//!
//! `time`, `hours`, `minutes`, and `seconds` are unset when the timer is inactive.
//!
//! `hours`, `minutes`, and `seconds` have been deprecated in favor of `time`.
//!
//! Action | Default button
//! ------------|---------------
//! `increment` | Left / Wheel Up
//! `decrement` | Wheel Down
//! `reset` | Right
//!
//! # Example
//!
//! ```toml
//! [[block]]
//! block = "tea_timer"
//! format = " $icon {$minutes:$seconds |}"
//! done_cmd = "notify-send 'Timer Finished'"
//! ```
//!
//! # Icons Used
//! - `tea`
use super::prelude::*;
use crate::subprocess::spawn_shell;
use std::time::{Duration, Instant};
#[derive(Deserialize, Debug, SmartDefault)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
pub format: FormatConfig,
pub increment: Option<u64>,
pub done_cmd: Option<String>,
}
pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
let mut actions = api.get_actions()?;
api.set_default_actions(&[
(MouseButton::Left, None, "increment"),
(MouseButton::WheelUp, None, "increment"),
(MouseButton::WheelDown, None, "decrement"),
(MouseButton::Right, None, "reset"),
])?;
let interval: Seconds = 1.into();
let mut timer = interval.timer();
let format = config
.format
.with_default(" $icon {$time.duration(hms:true) |}")?;
let increment = Duration::from_secs(config.increment.unwrap_or(30));
let mut timer_end = Instant::now();
let mut timer_was_active = false;
loop {
let mut widget = Widget::new().with_format(format.clone());
let remaining_time = timer_end - Instant::now();
let is_timer_active = !remaining_time.is_zero();
if !is_timer_active && timer_was_active {
if let Some(cmd) = &config.done_cmd {
spawn_shell(cmd).error("done_cmd error")?;
}
}
timer_was_active = is_timer_active;
let mut values = map!(
"icon" => Value::icon("tea"),
);
if is_timer_active {
values.insert("time".into(), Value::duration(remaining_time));
let mut seconds = remaining_time.as_secs();
if format.contains_key("hours") {
let hours = seconds / 3_600;
values.insert("hours".into(), Value::text(format!("{hours:02}")));
seconds %= 3_600;
}
if format.contains_key("minutes") {
let minutes = seconds / 60;
values.insert("minutes".into(), Value::text(format!("{minutes:02}")));
seconds %= 60;
}
values.insert("seconds".into(), Value::text(format!("{seconds:02}")));
}
widget.set_values(values);
api.set_widget(widget)?;
select! {
_ = timer.tick(), if is_timer_active => (),
_ = api.wait_for_update_request() => (),
Some(action) = actions.recv() => {
let now = Instant::now();
match action.as_ref() {
"increment" if is_timer_active => timer_end += increment,
"increment" => timer_end = now + increment,
"decrement" if is_timer_active => timer_end -= increment,
"reset" => timer_end = now,
_ => (),
}
}
}
}
}