use std::time::Instant;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimerState {
Idle,
Running,
Paused,
Finished,
}
pub struct Timer {
pub state: TimerState,
pub total_secs: u64,
remaining_secs_at_pause: u64,
started_at: Option<Instant>,
}
impl Timer {
pub fn new() -> Self {
Self {
state: TimerState::Idle,
total_secs: 0,
remaining_secs_at_pause: 0,
started_at: None,
}
}
pub fn start(&mut self, total_secs: u64) {
self.total_secs = total_secs;
self.remaining_secs_at_pause = total_secs;
self.started_at = Some(Instant::now());
self.state = TimerState::Running;
}
pub fn resume(&mut self) {
if self.state == TimerState::Paused {
self.started_at = Some(Instant::now());
self.state = TimerState::Running;
}
}
pub fn pause(&mut self) {
if self.state == TimerState::Running {
self.remaining_secs_at_pause = self.remaining_secs();
self.started_at = None;
self.state = TimerState::Paused;
}
}
pub fn stop(&mut self) {
self.state = TimerState::Idle;
self.started_at = None;
self.remaining_secs_at_pause = 0;
self.total_secs = 0;
}
pub fn remaining_secs(&self) -> u64 {
match self.state {
TimerState::Idle | TimerState::Finished => 0,
TimerState::Paused => self.remaining_secs_at_pause,
TimerState::Running => {
let elapsed = self.started_at.map_or(0, |s| s.elapsed().as_secs());
self.remaining_secs_at_pause.saturating_sub(elapsed)
}
}
}
pub fn tick(&mut self) -> bool {
if self.state == TimerState::Running && self.remaining_secs() == 0 {
self.state = TimerState::Finished;
return true;
}
false
}
}