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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### Features

- (pomodoro) `--max-rounds` arg to limit sessions [#205](https://github.com/sectore/timr-tui/pull/205)
- (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
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Options:
-w, --work <WORK> Work time to count down from. Formats: 'ss', 'mm:ss', 'hh:mm:ss'
-p, --pause <PAUSE> Pause duration. Single value (every round): '5:00'. Variable: 'regular,special[,every_n_rounds]' - special pause every N rounds, default every 4. Examples: '5:00,25:00' or '5:00,30:00,5'. Duration formats: 'ss', 'mm:ss', 'hh:mm:ss'.
--auto-switch Enable auto-switch between `work` and `pause` screens.
--max-rounds <MAX_ROUNDS> Maximum number of pomodoro rounds. 0 = unlimited.
-e, --event <EVENT> Event date time and title (optional). Format: 'YYYY-MM-DD HH:MM:SS' or 'time=YYYY-MM-DD HH:MM:SS[,title=...]'. Examples: '2025-10-10 14:30:00' or 'time=2025-10-10 14:30:00,title=My Event'.
-d, --decis Show deciseconds.
-m, --mode <MODE> Mode to start with. [possible values: countdown, timer, pomodoro, event, localtime]
Expand Down Expand Up @@ -176,17 +177,21 @@ Note: To enable Vim motions key binding, run with `--vim=on` once. It will be st

**In `Pomodoro` screen only:**

| Key | Description |
| -------------------------------------- | --------------------------------- |
| <kbd>ctrl+←</kbd> or <kbd>ctrl+→</kbd> | switch work/pause |
| <kbd>ctrl+h</kbd> or <kbd>ctrl+l</kbd> | switch work/pause _(Vim motions)_ |
| <kbd>a</kbd> | toggle auto switch work/pause |
| <kbd>↑</kbd> | next round |
| <kbd>k</kbd> | next round _(Vim motions)_ |
| <kbd>↓</kbd> | previous round |
| <kbd>j</kbd> | previous round _(Vim motions)_ |
| <kbd>ctrl+r</kbd> | reset rounds |
| <kbd>ctrl+s</kbd> | save initial value |
| Key | Description |
| -------------------------------------- | ----------------------------------- |
| <kbd>ctrl+←</kbd> or <kbd>ctrl+→</kbd> | switch work/pause |
| <kbd>ctrl+h</kbd> or <kbd>ctrl+l</kbd> | switch work/pause _(Vim motions)_ |
| <kbd>a</kbd> | toggle auto switch work/pause |
| <kbd>↑</kbd> | next round |
| <kbd>k</kbd> | next round _(Vim motions)_ |
| <kbd>↓</kbd> | previous round |
| <kbd>j</kbd> | previous round _(Vim motions)_ |
| <kbd>ctrl+↑</kbd> | increase max rounds |
| <kbd>ctrl+k</kbd> | increase max rounds _(Vim motions)_ |
| <kbd>ctrl+↓</kbd> | decrease max rounds |
| <kbd>ctrl+j</kbd> | decrease max rounds _(Vim motions)_ |
| <kbd>ctrl+r</kbd> | reset rounds |
| <kbd>ctrl+s</kbd> | save initial value |

**In `Countdown` screen only:**

Expand Down
8 changes: 8 additions & 0 deletions src/widgets/footer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,14 @@ impl StatefulWidget for Footer {
Span::styled(symbol_down, BOLD),
Span::from(SPACE),
Span::styled("previous round", ITALIC),
Span::from(WIDE_SPACE),
Span::styled(format!("^{}", symbol_up), BOLD),
Span::from(SPACE),
Span::styled("max rounds up", ITALIC),
Span::from(WIDE_SPACE),
Span::styled(format!("^{}", symbol_down), BOLD),
Span::from(SPACE),
Span::styled("max rounds down", ITALIC),
]);
}
spans
Expand Down
73 changes: 48 additions & 25 deletions src/widgets/pomodoro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,28 +203,20 @@ impl PomodoroState {
}

fn update_work_name(&mut self) {
let name = if self.is_last_round() {
"work (last round)".to_owned()
} else {
format!("work ({})", self.round_label())
};
let name = format!("work ({})", self.round_label());
self.get_clock_work_mut().set_name(name);
}

fn update_pause_name(&mut self) {
let name = if self.is_last_round() {
"pause (last round)".to_owned()
} else {
format!(
"{} ({})",
if self.pause_duration.is_special_round(self.round) {
"pause special"
} else {
"pause"
},
self.round_label()
)
};
let name = format!(
"{} ({})",
if self.pause_duration.is_special_round(self.round) {
"pause special"
} else {
"pause"
},
self.round_label()
);
self.get_clock_pause_mut().set_name(name);
}

Expand All @@ -243,6 +235,23 @@ impl PomodoroState {
self.clock_map.pause.with_decis = with_decis;
}

pub fn increase_max_rounds(&mut self) {
self.max_rounds = Some(self.max_rounds.map_or(1, |n| n + 1));
self.clamp_round();
}

pub fn decrease_max_rounds(&mut self) {
self.max_rounds = self.max_rounds.and_then(|n| (n > 1).then_some(n - 1));
self.clamp_round();
}

fn clamp_round(&mut self) {
if let Some(max) = self.max_rounds {
self.round = self.round.min(max);
}
self.update_clock_names();
}

fn next_round(&mut self) {
if !self.is_last_round() {
// increase round before (!!) updating the clock
Expand Down Expand Up @@ -402,6 +411,23 @@ impl TuiEventHandler for PomodoroState {
{
self.switch_mode();
}
// increase/decrease max rounds
KeyCode::Up if key.modifiers.contains(KeyModifiers::CONTROL) => {
self.increase_max_rounds();
}
KeyCode::Char('k')
if key.modifiers.contains(KeyModifiers::CONTROL) && self.vim_motions =>
{
self.increase_max_rounds();
}
KeyCode::Down if key.modifiers.contains(KeyModifiers::CONTROL) => {
self.decrease_max_rounds();
}
KeyCode::Char('j')
if key.modifiers.contains(KeyModifiers::CONTROL) && self.vim_motions =>
{
self.decrease_max_rounds();
}
// next round
KeyCode::Up => self.next_round(),
KeyCode::Char('k') if self.vim_motions => {
Expand Down Expand Up @@ -457,19 +483,16 @@ impl StatefulWidget for PomodoroWidget {
))
.to_uppercase(),
);
let label_round = Line::raw(if state.is_last_round() {
"LAST ROUND".to_owned()
} else if let Some(max) = state.get_max_rounds() {
format!("ROUND {} OF {}", state.get_round(), max)
} else {
format!("ROUND {}", state.get_round())
let label_round = Line::raw(match state.get_max_rounds() {
Some(max) => format!("ROUND {} OF {}", state.get_round(), max),
None => format!("ROUND {}", state.get_round()),
});

let area = area.centered(
Constraint::Length(max(
clock_widget
.get_width(state.get_clock().get_format(), state.get_clock().with_decis),
label.width() as u16,
max(label.width() as u16, label_round.width() as u16),
)),
Constraint::Length(
// empty label + height of `label` + `label_round`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ expression: t.backend()
" screens 1 countdown 2 timer 3 pomodoro 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 "
" ^← or ^→ switch work/pause ↑ next round ↓ previous round ^↑ max rounds up ^↓ max rounds down "
" "
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ expression: t.backend()
" screens 1 countdown 2 timer 3 pomodoro 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 disable auto switch "
" ^← or ^→ switch work/pause ↑ next round ↓ previous round "
" ^← or ^→ switch work/pause ↑ next round ↓ previous round ^↑ max rounds up ^↓ max rounds down "
" "
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ expression: t.backend()
" █████ █████ █████ █████ "
" "
" POMODORO WORK [] "
" LAST ROUND "
" ROUND 3 OF 3 "
" "
" "
" "
Loading