feat(screens)! switch by using ← or → keys (#127)
* feat(screens) switch by `←` or `→` keys * test cycling `Content` using `next`/`prev` * update CL
This commit is contained in:
parent
b5f3c709bf
commit
51f83e5b06
@ -2,8 +2,14 @@
|
|||||||
|
|
||||||
## [unreleased]
|
## [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
|
### 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)
|
- (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)
|
- (cli)! Remove `--countdown-target` argument [#121](https://github.com/sectore/timr-tui/pull/121)
|
||||||
|
|
||||||
|
|||||||
@ -126,6 +126,8 @@ Extra option (if `--features sound` is enabled by local build only):
|
|||||||
| <kbd>3</kbd> | Timer |
|
| <kbd>3</kbd> | Timer |
|
||||||
| <kbd>4</kbd> | Event |
|
| <kbd>4</kbd> | Event |
|
||||||
| <kbd>0</kbd> | Local Time |
|
| <kbd>0</kbd> | Local Time |
|
||||||
|
| <kbd>→</kbd> | next screen |
|
||||||
|
| <kbd>←</kbd> | previous screen |
|
||||||
|
|
||||||
## Controls
|
## Controls
|
||||||
|
|
||||||
@ -152,7 +154,7 @@ Extra option (if `--features sound` is enabled by local build only):
|
|||||||
|
|
||||||
| Key | Description |
|
| Key | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| <kbd>←</kbd> or <kbd>→</kbd> | switch work/pause |
|
| <kbd>ctrl+←</kbd> or <kbd>ctrl+→</kbd> | switch work/pause |
|
||||||
| <kbd>ctrl+r</kbd> | reset round |
|
| <kbd>ctrl+r</kbd> | reset round |
|
||||||
| <kbd>ctrl+s</kbd> | save initial value |
|
| <kbd>ctrl+s</kbd> | save initial value |
|
||||||
|
|
||||||
|
|||||||
16
src/app.rs
16
src/app.rs
@ -242,11 +242,19 @@ impl App {
|
|||||||
debug!("Received key {:?}", key.code);
|
debug!("Received key {:?}", key.code);
|
||||||
match key.code {
|
match key.code {
|
||||||
KeyCode::Char('q') => app.mode = Mode::Quit,
|
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('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 verson */ => app.content = Content::Timer,
|
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 verson */ => app.content = Content::Pomodoro,
|
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('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
|
// toogle app time format
|
||||||
KeyCode::Char(':') => {
|
KeyCode::Char(':') => {
|
||||||
if app.content == Content::LocalTime {
|
if app.content == Content::LocalTime {
|
||||||
|
|||||||
@ -21,6 +21,28 @@ pub enum Content {
|
|||||||
LocalTime,
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ClockTypeId {
|
pub enum ClockTypeId {
|
||||||
Countdown,
|
Countdown,
|
||||||
@ -254,4 +276,48 @@ mod tests {
|
|||||||
"local"
|
"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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,7 +85,7 @@ impl StatefulWidget for Footer {
|
|||||||
.render(border_area, buf);
|
.render(border_area, buf);
|
||||||
// show menu
|
// show menu
|
||||||
if state.show_menu {
|
if state.show_menu {
|
||||||
let content_labels: Vec<Span> = content_labels
|
let mut content_labels: Vec<Span> = content_labels
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, (content, label))| {
|
.map(|(index, (content, label))| {
|
||||||
@ -103,6 +103,13 @@ impl StatefulWidget for Footer {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
content_labels.extend_from_slice(&[
|
||||||
|
Span::from(SPACE),
|
||||||
|
Span::from("[→]next"),
|
||||||
|
Span::from(SPACE),
|
||||||
|
Span::from("[←]prev."),
|
||||||
|
]);
|
||||||
|
|
||||||
const SPACE: &str = " "; // 2 empty spaces
|
const SPACE: &str = " "; // 2 empty spaces
|
||||||
let widths = [Constraint::Length(12), Constraint::Percentage(100)];
|
let widths = [Constraint::Length(12), Constraint::Percentage(100)];
|
||||||
let mut table_rows = vec![
|
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(&[
|
table_rows.extend_from_slice(&[
|
||||||
// controls - 1. row
|
// controls - 1. row
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
@ -202,7 +212,7 @@ impl StatefulWidget for Footer {
|
|||||||
let mut spans = vec![];
|
let mut spans = vec![];
|
||||||
if self.selected_content == Content::Pomodoro {
|
if self.selected_content == Content::Pomodoro {
|
||||||
spans.extend_from_slice(&[Span::from(
|
spans.extend_from_slice(&[Span::from(
|
||||||
"[← →]switch work/pause",
|
"[^←] or [^→] switch work/pause",
|
||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
spans
|
spans
|
||||||
|
|||||||
@ -198,12 +198,12 @@ impl TuiEventHandler for PomodoroState {
|
|||||||
self.get_clock_mut().toggle_edit();
|
self.get_clock_mut().toggle_edit();
|
||||||
}
|
}
|
||||||
// toggle WORK/PAUSE
|
// 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
|
// `next` is acting as same as a "prev" function we don't have
|
||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
// toggle WORK/PAUSE
|
// toggle WORK/PAUSE
|
||||||
KeyCode::Right => {
|
KeyCode::Right if key.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
// reset rounds AND clocks
|
// reset rounds AND clocks
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user