Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- (pomodoro) auto-detect `Tabata` [#207](https://github.com/sectore/timr-tui/pull/207)
- (pomodoro) introduce `max rounds` to limit sessions [#205](https://github.com/sectore/timr-tui/pull/205), [#206](https://github.com/sectore/timr-tui/pull/206)
- (notification) detailed pomodoro status in system notification [#204](https://github.com/sectore/timr-tui/pull/204)
- (cli) Add `--auto-switch` argument [#203](https://github.com/sectore/timr-tui/pull/203)
Expand Down
9 changes: 9 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,14 @@ impl App {
ClockTypeId::Timer => {
format!("{name} stopped by reaching its maximum value.")
}
ClockTypeId::Countdown if app.content == Content::Pomodoro => {
let prefix = if app.pomodoro.is_tabata() {
"Tabata"
} else {
"Pomodoro"
};
format!("{prefix} {name} done!")
}
_ => format!("{type_id:?} {name} done!"),
};
// notification
Expand Down Expand Up @@ -618,6 +626,7 @@ impl StatefulWidget for AppWidget {
app_edit_mode: state.get_edit_mode(),
app_time: state.app_time,
pomodoro_auto_switch: state.pomodoro.get_auto_switch(),
is_tabata: state.pomodoro.is_tabata(),
}
.render(v2, buf, &mut state.footer);
}
Expand Down
6 changes: 6 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
use std::time::Duration;

pub static APP_NAME: &str = env!("CARGO_PKG_NAME");

pub static TICK_VALUE_MS: u64 = 1000 / 10; // 0.1 sec in milliseconds

pub static TABATA_WORK: Duration = Duration::from_secs(20);
pub static TABATA_PAUSE: Duration = Duration::from_secs(10);
pub static TABATA_MAX_ROUNDS: u64 = 8;
6 changes: 5 additions & 1 deletion src/widgets/footer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub struct Footer {
pub app_edit_mode: AppEditMode,
pub app_time: AppTime,
pub pomodoro_auto_switch: bool,
pub is_tabata: bool,
}

const SPACE: &str = " "; // single (empty) SPACE
Expand Down Expand Up @@ -106,7 +107,10 @@ impl StatefulWidget for Footer {
let content_labels: BTreeMap<Content, &str> = BTreeMap::from([
(Content::Countdown, "countdown"),
(Content::Timer, "timer"),
(Content::Pomodoro, "pomodoro"),
(
Content::Pomodoro,
if self.is_tabata { "tabata" } else { "pomodoro" },
),
(Content::Event, "event"),
(Content::LocalTime, "local time"),
]);
Expand Down
14 changes: 14 additions & 0 deletions src/widgets/footer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn w() -> Footer {
app_edit_mode: AppEditMode::None,
app_time: AppTime::Local(FIXED_TIME),
pomodoro_auto_switch: false,
is_tabata: false,
}
}

Expand Down Expand Up @@ -197,6 +198,19 @@ fn test_menu_countdown_edit_mode_vim() {
assert_snapshot!("menu_countdown_edit_mode_vim", t.backend());
}

// tabata

#[test]
fn test_menu_tabata() {
let w = Footer {
selected_content: Content::Pomodoro,
is_tabata: true,
..w()
};
let t = terminal(w, st());
assert_snapshot!("menu_tabata", t.backend());
}

// time formats

#[test]
Expand Down
15 changes: 13 additions & 2 deletions src/widgets/pomodoro.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
common::Style,
constants::TICK_VALUE_MS,
constants::{TABATA_MAX_ROUNDS, TABATA_PAUSE, TABATA_WORK, TICK_VALUE_MS},
events::{AppEventTx, TuiEvent, TuiEventHandler},
widgets::clock::{ClockState, ClockStateArgs, ClockWidget, Countdown},
};
Expand Down Expand Up @@ -195,6 +195,12 @@ impl PomodoroState {
self.is_last_round() && self.get_clock_work().is_done()
}

pub fn is_tabata(&self) -> bool {
*self.get_clock_work().get_initial_value() == TABATA_WORK.into()
&& self.pause_duration == PauseDuration::Fixed(TABATA_PAUSE)
&& self.max_rounds == Some(TABATA_MAX_ROUNDS)
}

fn round_label(&self) -> String {
match self.max_rounds {
Some(max) => format!("round {} of {}", self.round, max),
Expand Down Expand Up @@ -476,7 +482,12 @@ impl StatefulWidget for PomodoroWidget {
.is_special_round(state.get_round());
let label = Line::raw(
(format!(
"Pomodoro {} {}{}",
"{} {} {}{}",
if state.is_tabata() {
"Tabata"
} else {
"Pomodoro"
},
state.mode.clone(),
if is_special_pause { "Special " } else { "" },
state.get_clock_mut().get_mode()
Expand Down
34 changes: 34 additions & 0 deletions src/widgets/pomodoro_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
common::Style,
constants::{TABATA_MAX_ROUNDS, TABATA_PAUSE, TABATA_WORK},
duration::{ONE_MINUTE, ONE_SECOND},
events::{TuiEvent, TuiEventHandler},
widgets::{
Expand Down Expand Up @@ -151,3 +152,36 @@ fn test_work_edit_seconds() {
let t = terminal(w(), st);
assert_snapshot!("work_edit_seconds", t.backend());
}

// tabata

#[test]
fn test_tabata_work() {
let st = st_with_args(PomodoroStateArgs {
initial_value_work: TABATA_WORK,
current_value_work: TABATA_WORK,
pause_duration: PauseDuration::Fixed(TABATA_PAUSE),
current_value_pause: TABATA_PAUSE,
max_rounds: Some(TABATA_MAX_ROUNDS),
..args()
});
assert!(st.is_tabata());
let t = terminal(w(), st);
assert_snapshot!("tabata_work", t.backend());
}

#[test]
fn test_tabata_pause() {
let st = st_with_args(PomodoroStateArgs {
initial_value_work: TABATA_WORK,
current_value_work: TABATA_WORK,
pause_duration: PauseDuration::Fixed(TABATA_PAUSE),
current_value_pause: TABATA_PAUSE,
max_rounds: Some(TABATA_MAX_ROUNDS),
mode: Mode::Pause,
..args()
});
assert!(st.is_tabata());
let t = terminal(w(), st);
assert_snapshot!("tabata_pause", t.backend());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: src/widgets/footer_test.rs
expression: t.backend()
---
" m hide menu ───────────────────────────────────────────────────────────────────────────────────────────────────────────"
" screens 1 countdown 2 timer 3 tabata 4 event 5 local time ← or → switch screens "
" appearance , change style . toggle deciseconds : toggle local time "
" controls space start e edit r reset clock ^r reset clocks/rounds a enable auto switch "
" ^← or ^→ switch work/pause ↑ next round ↓ previous round ^↑ max rounds up ^↓ max rounds down "
" "
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
source: src/widgets/pomodoro_test.rs
expression: t.backend()
---
" "
" "
" "
" "
" "
" ██ █████ "
" ██ ██ ██ "
" ██ ██ ██ "
" ██ ██ ██ "
" ██ █████ "
" "
" TABATA PAUSE [] "
" ROUND 1 OF 8 "
" "
" "
" "
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
source: src/widgets/pomodoro_test.rs
expression: t.backend()
---
" "
" "
" "
" "
" "
" █████ █████ "
" ██ ██ ██ "
" █████ ██ ██ "
" ██ ██ ██ "
" █████ █████ "
" "
" TABATA WORK [] "
" ROUND 1 OF 8 "
" "
" "
" "
Loading