pomo_cli/
timer.rs

1use std::collections::HashMap;
2use std::fmt;
3use std::sync::Arc;
4use std::sync::Mutex;
5use tokio::task;
6use tokio::time::{Duration, Instant};
7
8#[derive(Copy, Clone)]
9pub enum TimerType {
10    Work,
11    Break,
12}
13
14impl fmt::Display for TimerType {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        let string = match self {
17            TimerType::Work => "work",
18            TimerType::Break => "break",
19        };
20
21        write!(f, "{}", string)
22    }
23}
24
25#[derive(Copy, Clone, Eq, PartialEq, Hash)]
26pub enum TimerEvent {
27    Finish,
28    Start,
29    Pause,
30    Stop,
31}
32
33#[derive(Copy, Clone)]
34pub enum TimerState {
35    Running,
36    Paused,
37    Stopped,
38}
39
40pub struct Timer {
41    remaining: Duration,
42    handle: Option<tokio::task::JoinHandle<()>>,
43    state: TimerState,
44    last_started_at: Option<Instant>,
45    timer_type: TimerType,
46    event_handlers: HashMap<TimerEvent, Vec<Arc<dyn Fn(&Timer) + Send + Sync>>>,
47}
48
49impl Timer {
50    pub fn new(timer_type: TimerType, duration: &Duration) -> Arc<Mutex<Timer>> {
51        Arc::new(Mutex::new(Timer {
52            event_handlers: HashMap::new(),
53            handle: None,
54            last_started_at: None,
55            remaining: duration.clone(),
56            state: TimerState::Stopped,
57            timer_type,
58        }))
59    }
60
61    pub fn start(timer: &Arc<Mutex<Timer>>) {
62        let timer = Arc::clone(timer);
63
64        let mut timer_guard = timer.lock().expect("Failed to lock timer");
65
66        if let TimerState::Running = timer_guard.state {
67            return;
68        }
69
70        let duration = timer_guard.time_left();
71
72        let timer2 = Arc::clone(&timer);
73
74        let handle = task::spawn(async move {
75            tokio::time::sleep(duration).await;
76
77            let mut timer_guard = timer2.lock().expect("Failed to lock timer");
78            timer_guard.finished();
79        });
80
81        timer_guard.handle = Some(handle);
82        timer_guard.last_started_at = Some(Instant::now());
83        timer_guard.state = TimerState::Running;
84
85        timer_guard.event(TimerEvent::Start);
86    }
87
88    pub fn stop(&mut self) {
89        self.state = TimerState::Stopped;
90
91        // abort current sleep task
92        self.abort_current_task();
93
94        self.event(TimerEvent::Stop);
95    }
96
97    pub fn pause(&mut self) {
98        // it's only possible to pause a timer that's running
99        if let TimerState::Running = self.state {
100            self.remaining = self.time_left();
101
102            // abort current sleep task
103            self.abort_current_task();
104
105            self.state = TimerState::Paused;
106
107            self.event(TimerEvent::Pause);
108        }
109    }
110
111    pub fn time_left(&self) -> Duration {
112        let elapsed = match &self.state {
113            TimerState::Running => match self.last_started_at {
114                Some(last_started_at) => last_started_at.elapsed(),
115                None => Duration::ZERO,
116            },
117            _ => Duration::ZERO,
118        };
119
120        if elapsed <= self.remaining {
121            self.remaining - elapsed
122        } else {
123            Duration::ZERO
124        }
125    }
126
127    pub fn on(&mut self, event: TimerEvent, callback: Arc<dyn Fn(&Timer) + Send + Sync>) {
128        self.event_handlers
129            .entry(event)
130            .or_default()
131            .push(callback.clone());
132    }
133
134    pub fn timer_type(&self) -> TimerType {
135        self.timer_type.clone()
136    }
137
138    pub fn clone(&self) -> Timer {
139        Timer {
140            handle: None,
141            last_started_at: self.last_started_at.clone(),
142            remaining: self.remaining.clone(),
143            state: self.state.clone(),
144            timer_type: self.timer_type.clone(),
145            event_handlers: HashMap::new(),
146        }
147    }
148
149    fn abort_current_task(&self) {
150        if let Some(handle) = &self.handle {
151            handle.abort();
152        }
153    }
154
155    fn finished(&mut self) {
156        self.remaining = Duration::ZERO;
157        self.state = TimerState::Stopped;
158
159        self.event(TimerEvent::Finish);
160    }
161
162    fn event(&self, event: TimerEvent) {
163        if let Some(handlers) = self.event_handlers.get(&event) {
164            for callback in handlers {
165                callback(&*self);
166            }
167        }
168    }
169}
170
171// impl Drop for Timer {
172//     fn drop(&mut self) {
173//         println!("Timer dropped");
174//     }
175// }