feat(countdown): persist elapsed time (#46)

This commit is contained in:
Jens Krause 2025-01-10 16:01:03 +01:00 committed by GitHub
parent c8af76c9e5
commit 9ea9f88266
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 74 additions and 43 deletions

View File

@ -57,6 +57,7 @@ pub struct AppArgs {
pub current_value_pause: Duration,
pub initial_value_countdown: Duration,
pub current_value_countdown: Duration,
pub elapsed_value_countdown: Duration,
pub current_value_timer: Duration,
}
@ -80,6 +81,7 @@ impl From<(Args, AppStorage)> for AppArgs {
initial_value_countdown: args.countdown.unwrap_or(stg.inital_value_countdown),
// invalidate `current_value_countdown` if an initial value is set via args
current_value_countdown: args.countdown.unwrap_or(stg.current_value_countdown),
elapsed_value_countdown: stg.elapsed_value_countdown,
current_value_timer: stg.current_value_timer,
}
}
@ -104,6 +106,7 @@ impl App {
current_value_work,
current_value_pause,
current_value_countdown,
elapsed_value_countdown,
current_value_timer,
content,
with_decis,
@ -115,12 +118,15 @@ impl App {
app_time: get_app_time(),
style,
with_decis,
countdown: CountdownState::new(ClockState::<clock::Countdown>::new(ClockStateArgs {
initial_value: initial_value_countdown,
current_value: current_value_countdown,
tick_value: Duration::from_millis(TICK_VALUE_MS),
with_decis,
})),
countdown: CountdownState::new(
ClockState::<clock::Countdown>::new(ClockStateArgs {
initial_value: initial_value_countdown,
current_value: current_value_countdown,
tick_value: Duration::from_millis(TICK_VALUE_MS),
with_decis,
}),
elapsed_value_countdown,
),
timer: TimerState::new(ClockState::<clock::Timer>::new(ClockStateArgs {
initial_value: Duration::ZERO,
current_value: current_value_timer,
@ -247,6 +253,7 @@ impl App {
current_value_countdown: Duration::from(
*self.countdown.get_clock().get_current_value(),
),
elapsed_value_countdown: Duration::from(*self.countdown.get_elapsed_value()),
current_value_timer: Duration::from(*self.timer.get_clock().get_current_value()),
}
}

View File

@ -25,6 +25,7 @@ pub struct AppStorage {
// countdown
pub inital_value_countdown: Duration,
pub current_value_countdown: Duration,
pub elapsed_value_countdown: Duration,
// timer
pub current_value_timer: Duration,
}
@ -50,6 +51,7 @@ impl Default for AppStorage {
// countdown
inital_value_countdown: DEFAULT_COUNTDOWN,
current_value_countdown: DEFAULT_COUNTDOWN,
elapsed_value_countdown: Duration::ZERO,
// timer
current_value_timer: Duration::ZERO,
}

View File

@ -91,6 +91,27 @@ pub struct ClockStateArgs {
}
impl<T> ClockState<T> {
pub fn with_mode(mut self, mode: Mode) -> Self {
self.mode = mode;
self
}
pub fn get_mode(&self) -> &Mode {
&self.mode
}
pub fn is_initial(&self) -> bool {
self.mode == Mode::Initial
}
pub fn run(&mut self) {
self.mode = Mode::Tick
}
pub fn is_running(&self) -> bool {
self.mode == Mode::Tick
}
pub fn toggle_pause(&mut self) {
self.mode = if self.mode == Mode::Tick {
Mode::Pause
@ -185,6 +206,7 @@ impl<T> ClockState<T> {
};
self.update_format();
}
pub fn edit_current_down(&mut self) {
self.current_value = match self.mode {
Mode::Editable(Time::Decis, _) => {
@ -203,22 +225,6 @@ impl<T> ClockState<T> {
self.update_mode();
}
pub fn get_mode(&self) -> &Mode {
&self.mode
}
pub fn run(&mut self) {
self.mode = Mode::Tick
}
pub fn is_running(&self) -> bool {
self.mode == Mode::Tick
}
pub fn is_initial(&self) -> bool {
self.mode == Mode::Initial
}
pub fn is_edit_mode(&self) -> bool {
matches!(self.mode, Mode::Editable(_, _))
}

View File

@ -10,9 +10,10 @@ use std::{cmp::max, time::Duration};
use crate::{
common::Style,
constants::TICK_VALUE_MS,
duration::DurationEx,
events::{Event, EventHandler},
utils::center,
widgets::clock::{self, ClockState, ClockStateArgs, ClockWidget},
widgets::clock::{self, ClockState, ClockStateArgs, ClockWidget, Mode as ClockMode},
};
/// State for Countdown Widget
@ -20,26 +21,34 @@ use crate::{
pub struct CountdownState {
/// clock to count down
clock: ClockState<clock::Countdown>,
/// clock to count up afterwards
timer: ClockState<clock::Timer>,
/// clock to count time after `DONE` - similar to Mission Elapsed Time (MET)
elapsed_clock: ClockState<clock::Timer>,
}
impl CountdownState {
pub fn new(clock: ClockState<clock::Countdown>) -> Self {
pub fn new(clock: ClockState<clock::Countdown>, elapsed_value: Duration) -> Self {
Self {
clock,
timer: ClockState::<clock::Timer>::new(ClockStateArgs {
elapsed_clock: ClockState::<clock::Timer>::new(ClockStateArgs {
initial_value: Duration::ZERO,
current_value: Duration::ZERO,
current_value: elapsed_value,
tick_value: Duration::from_millis(TICK_VALUE_MS),
with_decis: false,
})
// A previous `elapsed_value > 0` means the `Clock` was running before,
// but not in `Initial` state anymore. Updating `Mode` here
// is needed to handle `Event::Tick` in `EventHandler::update` properly
.with_mode(if elapsed_value.gt(&Duration::ZERO) {
ClockMode::Pause
} else {
ClockMode::Initial
}),
}
}
pub fn set_with_decis(&mut self, with_decis: bool) {
self.clock.with_decis = with_decis;
self.timer.with_decis = with_decis;
self.elapsed_clock.with_decis = with_decis;
}
pub fn get_clock(&self) -> &ClockState<clock::Countdown> {
@ -47,7 +56,11 @@ impl CountdownState {
}
pub fn is_running(&self) -> bool {
self.clock.is_running() || self.timer.is_running()
self.clock.is_running() || self.elapsed_clock.is_running()
}
pub fn get_elapsed_value(&self) -> &DurationEx {
self.elapsed_clock.get_current_value()
}
}
@ -59,9 +72,9 @@ impl EventHandler for CountdownState {
if !self.clock.is_done() {
self.clock.tick();
} else {
self.timer.tick();
if self.timer.is_initial() {
self.timer.run();
self.elapsed_clock.tick();
if self.elapsed_clock.is_initial() {
self.elapsed_clock.run();
}
}
}
@ -69,21 +82,21 @@ impl EventHandler for CountdownState {
KeyCode::Char('r') => {
// reset both clocks
self.clock.reset();
self.timer.reset();
self.elapsed_clock.reset();
}
KeyCode::Char('s') => {
// toggle pause status depending on who is running
// toggle pause status depending on which clock is running
if !self.clock.is_done() {
self.clock.toggle_pause();
} else {
self.timer.toggle_pause();
self.elapsed_clock.toggle_pause();
}
}
KeyCode::Char('e') => {
self.clock.toggle_edit();
// stop + reset timer entering `edit` mode
if self.timer.is_running() {
self.timer.toggle_pause();
if self.elapsed_clock.is_running() {
self.elapsed_clock.toggle_pause();
}
}
KeyCode::Left if edit_mode => {
@ -94,13 +107,13 @@ impl EventHandler for CountdownState {
}
KeyCode::Up if edit_mode => {
self.clock.edit_up();
// whenever clock value is changed, reset timer
self.timer.reset();
// whenever `clock`'s value is changed, reset `elapsed_clock`
self.elapsed_clock.reset();
}
KeyCode::Down if edit_mode => {
self.clock.edit_down();
// whenever clock value is changed, reset timer
self.timer.reset();
self.elapsed_clock.reset();
}
_ => return Some(event),
},
@ -125,13 +138,16 @@ impl StatefulWidget for Countdown {
format!(
"Countdown {} +{}",
state.clock.get_mode(),
state.timer.get_current_value().to_string_with_decis()
state
.elapsed_clock
.get_current_value()
.to_string_with_decis()
)
} else {
format!(
"Countdown {} +{}",
state.clock.get_mode(),
state.timer.get_current_value()
state.elapsed_clock.get_current_value()
)
}
} else {