use std::time::{Duration, Instant};
pub struct Countdown {
active: bool,
current_number: Option<u8>,
start_time: Option<Instant>,
pause_time: Option<Instant>,
total_paused: Duration,
}
impl Countdown {
pub fn new() -> Self {
Self {
active: false,
current_number: None,
start_time: None,
pause_time: None,
total_paused: Duration::ZERO,
}
}
pub fn start_countdown(&mut self) {
self.active = true;
self.current_number = Some(3);
self.start_time = Some(Instant::now());
self.pause_time = None;
self.total_paused = Duration::ZERO;
}
pub fn update_state(&mut self) -> Option<Instant> {
if !self.active {
return None;
}
if let Some(current_num) = self.current_number {
if let Some(start_time) = self.start_time {
let total_elapsed = start_time.elapsed();
let current_paused = if let Some(pause_time) = self.pause_time {
self.total_paused + pause_time.elapsed()
} else {
self.total_paused
};
let elapsed = total_elapsed.saturating_sub(current_paused);
let required_duration = if current_num == 0 {
Duration::from_millis(400)
} else {
Duration::from_millis(600)
};
if elapsed >= required_duration {
if current_num > 1 {
self.current_number = Some(current_num - 1);
self.start_time = Some(Instant::now());
self.pause_time = None;
self.total_paused = Duration::ZERO;
} else if current_num == 1 {
self.current_number = Some(0); self.start_time = Some(Instant::now());
self.pause_time = None;
self.total_paused = Duration::ZERO;
} else {
self.active = false;
self.current_number = None;
self.start_time = None;
self.pause_time = None;
self.total_paused = Duration::ZERO;
return Some(Instant::now());
}
}
}
}
None
}
pub fn get_current_count(&self) -> Option<u8> {
if self.active {
self.current_number
} else {
None
}
}
pub fn is_active(&self) -> bool {
self.active
}
pub fn pause(&mut self) {
if self.active && self.pause_time.is_none() {
self.pause_time = Some(Instant::now());
}
}
pub fn resume(&mut self) {
if let Some(pause_time) = self.pause_time.take() {
self.total_paused += pause_time.elapsed();
}
}
#[cfg_attr(not(test), allow(dead_code))]
pub fn fast_forward_for_test(&mut self, duration: Duration) {
if let Some(start_time) = self.start_time {
self.start_time = start_time.checked_sub(duration).or(Some(start_time));
}
if let Some(pause_time) = self.pause_time {
self.pause_time = pause_time.checked_sub(duration).or(Some(pause_time));
}
}
}
impl Default for Countdown {
fn default() -> Self {
Self::new()
}
}