From 0a533b1757dcbdf9e65bdfa0e5f2ccd6b39150af Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:46:14 -0500 Subject: [PATCH] refactor: simplify state machine. --- src/main.rs | 106 +++++++++++++++++++++------------------------------- 1 file changed, 42 insertions(+), 64 deletions(-) diff --git a/src/main.rs b/src/main.rs index d107922..0056201 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,13 +21,12 @@ use ratatui::{ widgets::{Block, Borders, Clear, Paragraph}, }; -const SECONDS_PER_MIN: i64 = 60; +const SECONDS_PER_MIN: u32 = 60; -#[derive(Debug, PartialEq, Clone)] -enum TimerState { +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum TimerMode { Work, Break, - Paused, } fn send_desktop_notification(title: &str, body: &str) { @@ -44,23 +43,21 @@ fn send_desktop_notification(title: &str, body: &str) { } struct Termato { - work_mins: i64, - break_mins: i64, - state: TimerState, - prior_state: TimerState, + work_mins: u32, + break_mins: u32, + mode: TimerMode, is_running: bool, - duration_in_secs: i64, - time_remaining_in_sec: i64, + duration_in_secs: u32, + time_remaining_in_sec: u32, show_help: bool, } impl Termato { - fn new(work_mins: i64, break_mins: i64) -> Self { + fn new(work_mins: u32, break_mins: u32) -> Self { Termato { work_mins, break_mins, - state: TimerState::Work, - prior_state: TimerState::Work, + mode: TimerMode::Work, is_running: false, duration_in_secs: work_mins * SECONDS_PER_MIN, time_remaining_in_sec: work_mins * SECONDS_PER_MIN, @@ -69,30 +66,18 @@ impl Termato { } fn toggle_running(&mut self) { - if self.is_running { - self.prior_state = self.state.clone(); - self.state = TimerState::Paused; - self.is_running = false; - } else { - self.state = self.prior_state.clone(); - self.is_running = true; - } + self.is_running = !self.is_running; } fn toggle_mode(&mut self) { - let is_on_break = self.state == TimerState::Break - || (self.state == TimerState::Paused && self.prior_state == TimerState::Break); - - if is_on_break { - self.state = TimerState::Work; - self.prior_state = TimerState::Work; - self.duration_in_secs = self.work_mins * SECONDS_PER_MIN; - } else { - self.state = TimerState::Break; - self.prior_state = TimerState::Break; - self.duration_in_secs = self.break_mins * SECONDS_PER_MIN; - } - + self.mode = match self.mode { + TimerMode::Work => TimerMode::Break, + TimerMode::Break => TimerMode::Work, + }; + self.duration_in_secs = match self.mode { + TimerMode::Work => self.work_mins * SECONDS_PER_MIN, + TimerMode::Break => self.break_mins * SECONDS_PER_MIN, + }; self.time_remaining_in_sec = self.duration_in_secs; } @@ -101,10 +86,9 @@ impl Termato { self.time_remaining_in_sec -= 1; if self.time_remaining_in_sec == 0 { - if self.state == TimerState::Work { - send_desktop_notification("Work Done", "Time to take a break."); - } else { - send_desktop_notification("Break Over", "Time to focus."); + match self.mode { + TimerMode::Work => send_desktop_notification("Work Done", "Time to take a break."), + TimerMode::Break => send_desktop_notification("Break Over", "Time to focus."), } self.toggle_mode(); @@ -114,8 +98,7 @@ impl Termato { fn reset(&mut self) { self.is_running = false; - self.state = TimerState::Work; - self.prior_state = TimerState::Work; + self.mode = TimerMode::Work; self.duration_in_secs = self.work_mins * SECONDS_PER_MIN; self.time_remaining_in_sec = self.duration_in_secs; } @@ -169,10 +152,13 @@ fn main() -> Result<(), io::Error> { let seconds = termato.time_remaining_in_sec % SECONDS_PER_MIN; let time_str = format!("{:02}:{:02}", minutes, seconds); - let time_color = match termato.state { - TimerState::Work => Color::Red, - TimerState::Break => Color::Green, - TimerState::Paused => Color::Yellow, + let time_color = if !termato.is_running { + Color::Yellow + } else { + match termato.mode { + TimerMode::Work => Color::Red, + TimerMode::Break => Color::Green, + } }; let big_time_text = if let Some(fig) = font.convert(&time_str) { @@ -278,8 +264,7 @@ mod tests { assert_eq!(result.work_mins, 25); assert_eq!(result.break_mins, 5); - assert_eq!(result.state, TimerState::Work); - assert_eq!(result.prior_state, TimerState::Work); + assert_eq!(result.mode, TimerMode::Work); assert!(!result.is_running); assert_eq!(result.duration_in_secs, 1500); assert_eq!(result.time_remaining_in_sec, 1500); @@ -323,8 +308,7 @@ mod tests { termato.tick(); - assert_eq!(termato.state, TimerState::Break); - assert_eq!(termato.prior_state, TimerState::Break); + assert_eq!(termato.mode, TimerMode::Break); assert_eq!(termato.duration_in_secs, 120); assert_eq!(termato.time_remaining_in_sec, 120); } @@ -332,28 +316,28 @@ mod tests { #[test] fn termato_tick_when_running_on_break_and_time_remaining_reaches_zero_it_should_toggle_to_work() { let mut termato = Termato::new(2, 1); - termato.state = TimerState::Break; + termato.mode = TimerMode::Break; termato.is_running = true; termato.time_remaining_in_sec = 1; termato.tick(); - assert_eq!(termato.state, TimerState::Work); - assert_eq!(termato.prior_state, TimerState::Work); + assert_eq!(termato.mode, TimerMode::Work); assert_eq!(termato.duration_in_secs, 120); assert_eq!(termato.time_remaining_in_sec, 120); } #[test] - fn termato_toggle_mode_when_paused_and_previous_state_is_break_it_should_toggle_to_work() { + fn termato_toggle_mode_when_called_it_should_toggle_the_mode() { let mut termato = Termato::new(2, 1); - termato.state = TimerState::Paused; - termato.prior_state = TimerState::Break; termato.toggle_mode(); + assert_eq!(termato.mode, TimerMode::Break); + assert_eq!(termato.duration_in_secs, 60); + assert_eq!(termato.time_remaining_in_sec, 60); - assert_eq!(termato.state, TimerState::Work); - assert_eq!(termato.prior_state, TimerState::Work); + termato.toggle_mode(); + assert_eq!(termato.mode, TimerMode::Work); assert_eq!(termato.duration_in_secs, 120); assert_eq!(termato.time_remaining_in_sec, 120); } @@ -365,8 +349,6 @@ mod tests { termato.toggle_running(); - assert_eq!(termato.state, TimerState::Paused); - assert_eq!(termato.prior_state, TimerState::Work); assert!(!termato.is_running) } @@ -376,8 +358,6 @@ mod tests { termato.toggle_running(); - assert_eq!(termato.state, TimerState::Work); - assert_eq!(termato.prior_state, TimerState::Work); assert!(termato.is_running) } @@ -385,16 +365,14 @@ mod tests { fn termato_rest_when_called_it_should_reset_the_apps_state() { let mut termato = Termato::new(1, 1); termato.is_running = true; - termato.state = TimerState::Break; - termato.prior_state = TimerState::Break; + termato.mode = TimerMode::Break; termato.duration_in_secs = 1; termato.time_remaining_in_sec = 1; termato.reset(); assert!(!termato.is_running); - assert_eq!(termato.state, TimerState::Work); - assert_eq!(termato.prior_state, TimerState::Work); + assert_eq!(termato.mode, TimerMode::Work); assert_eq!(termato.duration_in_secs, 60); assert_eq!(termato.time_remaining_in_sec, 60); }