From 51f83e5b064850a94ac2372a6020fb12441ec652 Mon Sep 17 00:00:00 2001 From: Jens Krause <47693+sectore@users.noreply.github.com> Date: Mon, 13 Oct 2025 13:28:51 +0200 Subject: [PATCH] =?UTF-8?q?feat(screens)!=20switch=20by=20using=20`?= =?UTF-8?q?=E2=86=90`=20or=20`=E2=86=92`=20keys=20(#127)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(screens) switch by `←` or `→` keys * test cycling `Content` using `next`/`prev` * update CL --- CHANGELOG.md | 6 ++++ README.md | 4 ++- src/app.rs | 16 +++++++--- src/common.rs | 66 +++++++++++++++++++++++++++++++++++++++++ src/widgets/footer.rs | 16 ++++++++-- src/widgets/pomodoro.rs | 4 +-- 6 files changed, 102 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aa3609..3470b00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,14 @@ ## [unreleased] +### Features + +- (event) New `event` screen to count custom date times in the future or past. [#117](https://github.com/sectore/timr-tui/pull/117), [#120](https://github.com/sectore/timr-tui/pull/120), [#122](https://github.com/sectore/timr-tui/pull/122), [#123](https://github.com/sectore/timr-tui/pull/123), [#124](https://github.com/sectore/timr-tui/pull/124), [#125](https://github.com/sectore/timr-tui/pull/125) +- (screens) switch by `←` or `→` keys [#127](https://github.com/sectore/timr-tui/pull/127) + ### Breaking change +- (pomodoro)! new keybindings `ctrl+←` or `ctrl+→` to switch `work`/`pause` [#127](https://github.com/sectore/timr-tui/pull/127) - (keybindings)! change keys for `screens` [#126](https://github.com/sectore/timr-tui/pull/126) - (cli)! Remove `--countdown-target` argument [#121](https://github.com/sectore/timr-tui/pull/121) diff --git a/README.md b/README.md index 25f1606..1b21be3 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,8 @@ Extra option (if `--features sound` is enabled by local build only): | 3 | Timer | | 4 | Event | | 0 | Local Time | +| | next screen | +| | previous screen | ## Controls @@ -152,7 +154,7 @@ Extra option (if `--features sound` is enabled by local build only): | Key | Description | | --- | --- | -| or | switch work/pause | +| ctrl+← or ctrl+→ | switch work/pause | | ctrl+r | reset round | | ctrl+s | save initial value | diff --git a/src/app.rs b/src/app.rs index aec9400..30f0174 100644 --- a/src/app.rs +++ b/src/app.rs @@ -242,11 +242,19 @@ impl App { debug!("Received key {:?}", key.code); match key.code { KeyCode::Char('q') => app.mode = Mode::Quit, - KeyCode::Char('1') | KeyCode::Char('c') /* TODO: deprecated, remove it in next verson */ => app.content = Content::Countdown, - KeyCode::Char('2') | KeyCode::Char('t') /* TODO: deprecated, remove it in next verson */ => app.content = Content::Timer, - KeyCode::Char('3') | KeyCode::Char('p') /* TODO: deprecated, remove it in next verson */ => app.content = Content::Pomodoro, + KeyCode::Char('1') | KeyCode::Char('c') /* TODO: deprecated, remove it in next version */ => app.content = Content::Countdown, + KeyCode::Char('2') | KeyCode::Char('t') /* TODO: deprecated, remove it in next version */ => app.content = Content::Timer, + KeyCode::Char('3') | KeyCode::Char('p') /* TODO: deprecated, remove it in next version */ => app.content = Content::Pomodoro, KeyCode::Char('4') => app.content = Content::Event, - KeyCode::Char('0') | KeyCode::Char('l') /* TODO: deprecated, remove it in next verson */ => app.content = Content::LocalTime, + // toogle app time format + KeyCode::Char('0') | KeyCode::Char('l') /* TODO: deprecated, remove it in next version */ => app.content = Content::LocalTime, + // switch `screens` + KeyCode::Right => { + app.content = app.content.next(); + } + KeyCode::Left => { + app.content = app.content.prev(); + } // toogle app time format KeyCode::Char(':') => { if app.content == Content::LocalTime { diff --git a/src/common.rs b/src/common.rs index 2090f3e..c1b3ee7 100644 --- a/src/common.rs +++ b/src/common.rs @@ -21,6 +21,28 @@ pub enum Content { LocalTime, } +impl Content { + pub fn next(&self) -> Self { + match self { + Content::Countdown => Content::Timer, + Content::Timer => Content::Pomodoro, + Content::Pomodoro => Content::Event, + Content::Event => Content::LocalTime, + Content::LocalTime => Content::Countdown, + } + } + + pub fn prev(&self) -> Self { + match self { + Content::Countdown => Content::LocalTime, + Content::Timer => Content::Countdown, + Content::Pomodoro => Content::Timer, + Content::Event => Content::Pomodoro, + Content::LocalTime => Content::Event, + } + } +} + #[derive(Clone, Debug)] pub enum ClockTypeId { Countdown, @@ -254,4 +276,48 @@ mod tests { "local" ); } + + #[test] + fn test_content_next() { + let start = Content::Countdown; + let mut current = start; + + // Cycle through: Countdown -> Timer -> Pomodoro -> Event -> LocalTime -> Countdown + current = current.next(); + assert_eq!(current, Content::Timer); + + current = current.next(); + assert_eq!(current, Content::Pomodoro); + + current = current.next(); + assert_eq!(current, Content::Event); + + current = current.next(); + assert_eq!(current, Content::LocalTime); + + current = current.next(); + assert_eq!(current, start, "Should cycle back to start"); + } + + #[test] + fn test_content_prev() { + let start = Content::Countdown; + let mut current = start; + + // Cycle backwards: Countdown -> LocalTime -> Event -> Pomodoro -> Timer -> Countdown + current = current.prev(); + assert_eq!(current, Content::LocalTime); + + current = current.prev(); + assert_eq!(current, Content::Event); + + current = current.prev(); + assert_eq!(current, Content::Pomodoro); + + current = current.prev(); + assert_eq!(current, Content::Timer); + + current = current.prev(); + assert_eq!(current, start, "Should cycle back to start"); + } } diff --git a/src/widgets/footer.rs b/src/widgets/footer.rs index af7adbb..b2b0d8a 100644 --- a/src/widgets/footer.rs +++ b/src/widgets/footer.rs @@ -85,7 +85,7 @@ impl StatefulWidget for Footer { .render(border_area, buf); // show menu if state.show_menu { - let content_labels: Vec = content_labels + let mut content_labels: Vec = content_labels .iter() .enumerate() .map(|(index, (content, label))| { @@ -103,6 +103,13 @@ impl StatefulWidget for Footer { }) .collect(); + content_labels.extend_from_slice(&[ + Span::from(SPACE), + Span::from("[→]next"), + Span::from(SPACE), + Span::from("[←]prev."), + ]); + const SPACE: &str = " "; // 2 empty spaces let widths = [Constraint::Length(12), Constraint::Percentage(100)]; let mut table_rows = vec![ @@ -136,7 +143,10 @@ impl StatefulWidget for Footer { ]), ]; - if self.selected_content != Content::LocalTime { + // Controls (except for `localtime` and `event`) + if self.selected_content != Content::LocalTime + && self.selected_content != Content::Event + { table_rows.extend_from_slice(&[ // controls - 1. row Row::new(vec![ @@ -202,7 +212,7 @@ impl StatefulWidget for Footer { let mut spans = vec![]; if self.selected_content == Content::Pomodoro { spans.extend_from_slice(&[Span::from( - "[← →]switch work/pause", + "[^←] or [^→] switch work/pause", )]); } spans diff --git a/src/widgets/pomodoro.rs b/src/widgets/pomodoro.rs index b7c1843..cb63714 100644 --- a/src/widgets/pomodoro.rs +++ b/src/widgets/pomodoro.rs @@ -198,12 +198,12 @@ impl TuiEventHandler for PomodoroState { self.get_clock_mut().toggle_edit(); } // toggle WORK/PAUSE - KeyCode::Left => { + KeyCode::Left if key.modifiers.contains(KeyModifiers::CONTROL) => { // `next` is acting as same as a "prev" function we don't have self.next(); } // toggle WORK/PAUSE - KeyCode::Right => { + KeyCode::Right if key.modifiers.contains(KeyModifiers::CONTROL) => { self.next(); } // reset rounds AND clocks