diff options
author | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2025-09-08 22:34:26 +0530 |
---|---|---|
committer | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2025-09-08 22:34:26 +0530 |
commit | b2882ae0b0e1521edd82bdb74b59dc2733f78a15 (patch) | |
tree | 806a23740dd982d117b269af28ff1490519ac81b /src/daemon/pomo.rs |
first commit
Diffstat (limited to 'src/daemon/pomo.rs')
-rw-r--r-- | src/daemon/pomo.rs | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/daemon/pomo.rs b/src/daemon/pomo.rs new file mode 100644 index 0000000..3129e7d --- /dev/null +++ b/src/daemon/pomo.rs @@ -0,0 +1,160 @@ +/* Polydoro - Pomodoro widget for polybar and friends + * Copyright (C) 2025 Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +use bincode::{Encode, Decode}; + +#[derive(Encode, Decode, PartialEq, Clone, Copy)] +pub enum State { + WorkIdle, + BreakIdle, + LongBreakIdle, + Work, + Break, + LongBreak, + WorkPaused, + BreakPaused, + LongBreakPaused, +} + +#[derive(Encode, Decode)] +pub struct Pomo { + work_duration: u64, + break_duration: u64, + long_break_duration: u64, + long_break_interval: u64, + + // only these are supposed to change + pub secs_elapsed: u64, + pub counter: u64, + pub current_state: State, +} + +impl Pomo { + pub fn new() -> Self { + Pomo { + secs_elapsed: 0, + counter: 1, + current_state: State::WorkIdle, + + // TODO: load from config, probably + work_duration: 25,// * 60, + break_duration: 5,// * 60, + long_break_duration: 20,// * 60, + long_break_interval: 4, + } + } + + pub fn tick(&mut self) { + // only tick on running states + if matches!(self.current_state, State::Work | State::Break | State::LongBreak) { + self.secs_elapsed += 1; + + let duration = match self.current_state { + State::Work => self.work_duration, + State::Break => self.break_duration, + State::LongBreak => self.long_break_duration, + _ => 0, // will never hit this case + }; + + if self.secs_elapsed >= duration { + self.end_cycle(); + } + } + } + + // start/unpause a cycle + pub fn run(&mut self) { + self.current_state = match self.current_state { + State::WorkIdle => State::Work, + State::BreakIdle => State::Break, + State::LongBreakIdle => State::LongBreak, + + State::WorkPaused => State::Work, + State::BreakPaused => State::Break, + State::LongBreakPaused => State::LongBreak, + + _ => return // already running + }; + } + + pub fn pause(&mut self) { + self.current_state = match self.current_state { + State::Work => State::WorkPaused, + State::Break => State::BreakPaused, + State::LongBreak => State::LongBreakPaused, + _ => return, // idle and paused don't have a place here + }; + } + + // conditionally pause/run + pub fn toggle(&mut self) { + match self.current_state { + State::Work | State::Break | State::LongBreak => self.pause(), + _ => self.run(), + } + } + + // also used in the skip command + pub fn end_cycle(&mut self) { + match self.current_state { + State::Work => { + self.secs_elapsed = 0; + + self.current_state = if self.counter == self.long_break_interval { + State::LongBreakIdle + } else { + State::BreakIdle + }; + }, + State::Break => { + self.secs_elapsed = 0; + self.current_state = State::WorkIdle; + + // because we move on to the next task after the break + self.counter += 1; + } + State::LongBreak => self.hard_reset(), + _ => return, // paused and idle state can't be ended + } + } + + // reset current cycle + pub fn soft_reset(&mut self) { + self.secs_elapsed = 0; + self.current_state = match self.current_state { + State::Work | State::WorkPaused => State::WorkIdle, + State::Break | State::BreakPaused => State::BreakIdle, + State::LongBreak | State::LongBreakPaused => State::LongBreakIdle, + _ => self.current_state, // if already in an idle state, don't change (probably won't hit anyways) + }; + } + + // reset all cycles + pub fn hard_reset(&mut self) { + self.secs_elapsed = 0; + self.counter = 1; + self.current_state = State::WorkIdle; + } + + // conditionally do a soft or a hard reset + pub fn reset(&mut self) { + match self.current_state { + State::WorkIdle | State::BreakIdle | State::LongBreakIdle => self.hard_reset(), + _ => self.soft_reset(), + } + } +} |