diff --git a/README.md b/README.md index 14c72e9..0e255ff 100644 --- a/README.md +++ b/README.md @@ -129,10 +129,12 @@ Extra option (if `--features sound` is enabled by local build only): | Key | Description | | --- | --- | -| Enter | apply changes | +| s | save changes | +| ^s | save initial value | | Esc | skip changes | | or | change selection | -| or | change values to go up or down | +| | edit to go up | +| | edit to go down | **In `Pomodoro` screen only** diff --git a/src/app.rs b/src/app.rs index 4d4a416..ee6472a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -414,7 +414,7 @@ impl StatefulWidget for AppWidget { let [v0, v1, v2] = Layout::vertical([ Constraint::Length(1), Constraint::Percentage(100), - Constraint::Length(if state.footer.get_show_menu() { 4 } else { 1 }), + Constraint::Length(if state.footer.get_show_menu() { 5 } else { 1 }), ]) .areas(area); diff --git a/src/widgets/clock.rs b/src/widgets/clock.rs index d1449e6..07d4dbf 100644 --- a/src/widgets/clock.rs +++ b/src/widgets/clock.rs @@ -143,6 +143,10 @@ impl ClockState { &self.initial_value } + pub fn set_initial_value(&mut self, duration: DurationEx) { + self.initial_value = duration; + } + pub fn get_current_value(&self) -> &DurationEx { &self.current_value } diff --git a/src/widgets/countdown.rs b/src/widgets/countdown.rs index 83ac8d9..181dca7 100644 --- a/src/widgets/countdown.rs +++ b/src/widgets/countdown.rs @@ -162,6 +162,96 @@ impl TuiEventHandler for CountdownState { edit_time.set_max_time(max_time); } } + // EDIT CLOCK mode + TuiEvent::Key(key) if self.is_clock_edit_mode() => match key.code { + // skip editing + KeyCode::Esc => { + // Important: set current value first + self.clock.set_current_value(*self.clock.get_prev_value()); + // before toggling back to non-edit mode + self.clock.toggle_edit(); + } + // Apply changes and set new initial value + KeyCode::Char('s') if key.modifiers.contains(KeyModifiers::CONTROL) => { + // toggle edit mode + self.clock.toggle_edit(); + // set initial value + self.clock + .set_initial_value(*self.clock.get_current_value()); + // always reset `elapsed_clock` + self.elapsed_clock.reset(); + } + // Apply changes + KeyCode::Char('s') => { + // toggle edit mode + self.clock.toggle_edit(); + // always reset `elapsed_clock` + self.elapsed_clock.reset(); + } + KeyCode::Right => { + self.clock.edit_prev(); + } + KeyCode::Left => { + self.clock.edit_next(); + } + KeyCode::Up => { + self.clock.edit_up(); + } + KeyCode::Down => { + self.clock.edit_down(); + } + _ => return Some(event), + }, + // EDIT LOCAL TIME mode + TuiEvent::Key(key) if self.is_time_edit_mode() => match key.code { + // skip editing + KeyCode::Esc => { + self.edit_time = None; + } + // Apply changes and set new initial value + KeyCode::Char('s') if key.modifiers.contains(KeyModifiers::CONTROL) => { + if let Some(edit_time) = &mut self.edit_time.clone() { + // Order matters: + // 1. update current value + self.edit_time_done(edit_time); + // 2. set initial value + self.clock + .set_initial_value(*self.clock.get_current_value()); + } + // always reset `elapsed_clock` + self.elapsed_clock.reset(); + } + // Apply changes of editing by local time + KeyCode::Char('s') => { + if let Some(edit_time) = &mut self.edit_time.clone() { + self.edit_time_done(edit_time) + } + // always reset `elapsed_clock` + self.elapsed_clock.reset(); + } + // move edit position to the left + KeyCode::Left => { + // safe unwrap because we are in `is_time_edit_mode` + self.edit_time.as_mut().unwrap().next(); + } + // move edit position to the right + KeyCode::Right => { + // safe unwrap because we are in `is_time_edit_mode` + self.edit_time.as_mut().unwrap().prev(); + } + // Value up + KeyCode::Up => { + // safe unwrap because of previous check in `is_time_edit_mode` + self.edit_time.as_mut().unwrap().up(); + } + // Value down + KeyCode::Down => { + // safe unwrap because of previous check in `is_time_edit_mode` + self.edit_time.as_mut().unwrap().down(); + } + _ => return Some(event), + }, + // default mode TuiEvent::Key(key) => match key.code { KeyCode::Char('r') => { // reset both clocks to use intial values @@ -187,23 +277,8 @@ impl TuiEventHandler for CountdownState { self.edit_time_done(edit_time); } } - // skip editing clock - KeyCode::Esc if self.is_clock_edit_mode() => { - // Important: set current value first - self.clock.set_current_value(*self.clock.get_prev_value()); - // before toggling back to non-edit mode - self.clock.toggle_edit(); - } - // skip editing by local time - KeyCode::Esc if self.is_time_edit_mode() => { - self.edit_time = None; - } - // Enter edit by local time mode - KeyCode::Char('e') - if key.modifiers.contains(KeyModifiers::CONTROL) - && !self.is_time_edit_mode() => - { + KeyCode::Char('e') if key.modifiers.contains(KeyModifiers::CONTROL) => { // set `edit_time` self.edit_time = Some(EditTimeState::new(EditTimeStateArgs { time: self.time_to_edit(), @@ -216,9 +291,8 @@ impl TuiEventHandler for CountdownState { self.elapsed_clock.toggle_pause(); } } - - // Enter edit clock - KeyCode::Char('e') if !self.is_clock_edit_mode() => { + // Enter edit clock mode + KeyCode::Char('e') => { // toggle edit mode self.clock.toggle_edit(); @@ -227,53 +301,6 @@ impl TuiEventHandler for CountdownState { self.elapsed_clock.toggle_pause(); } } - - // Apply changes of editing by local time - KeyCode::Enter if self.is_time_edit_mode() => { - if let Some(edit_time) = &mut self.edit_time.clone() { - self.edit_time_done(edit_time) - } - // always reset `elapsed_clock` - self.elapsed_clock.reset(); - } - - // Apply changes of editing clock - // Note: Using Ctrl+e is deprecated, use Enter instead - KeyCode::Enter if self.is_clock_edit_mode() => { - // toggle edit mode - self.clock.toggle_edit(); - // always reset `elapsed_clock` - self.elapsed_clock.reset(); - } - - KeyCode::Left if self.is_clock_edit_mode() => { - self.clock.edit_next(); - } - KeyCode::Left if self.is_time_edit_mode() => { - // safe unwrap because of previous check in `is_time_edit_mode` - self.edit_time.as_mut().unwrap().next(); - } - KeyCode::Right if self.is_clock_edit_mode() => { - self.clock.edit_prev(); - } - KeyCode::Right if self.is_time_edit_mode() => { - // safe unwrap because of previous check in `is_time_edit_mode` - self.edit_time.as_mut().unwrap().prev(); - } - KeyCode::Up if self.is_clock_edit_mode() => { - self.clock.edit_up(); - } - KeyCode::Up if self.is_time_edit_mode() => { - // safe unwrap because of previous check in `is_time_edit_mode` - self.edit_time.as_mut().unwrap().up(); - } - KeyCode::Down if self.is_clock_edit_mode() => { - self.clock.edit_down(); - } - KeyCode::Down if self.is_time_edit_mode() => { - // safe unwrap because of previous check in `is_time_edit_mode` - self.edit_time.as_mut().unwrap().down(); - } _ => return Some(event), }, _ => return Some(event), diff --git a/src/widgets/footer.rs b/src/widgets/footer.rs index b67ef12..de97cc8 100644 --- a/src/widgets/footer.rs +++ b/src/widgets/footer.rs @@ -112,62 +112,6 @@ impl StatefulWidget for Footer { )), Cell::from(Line::from(content_labels)), ]), - // controls - Row::new(vec![ - Cell::from(Span::styled( - "controls", - Style::default().add_modifier(Modifier::BOLD), - )), - Cell::from(Line::from({ - match self.app_edit_mode { - AppEditMode::None => { - let mut spans = vec![ - Span::from(if self.running_clock { - "[s]top" - } else { - "[s]tart" - }), - Span::from(SPACE), - Span::from("[r]eset"), - ]; - if self.selected_content == Content::Pomodoro { - spans.extend_from_slice(&[ - Span::from(SPACE), - Span::from("[^r]eset round"), - Span::from(SPACE), - Span::from("[← →]switch work/pause"), - ]); - } - spans.extend_from_slice(&[ - Span::from(SPACE), - Span::from("[e]dit"), - ]); - if self.selected_content == Content::Countdown { - spans.extend_from_slice(&[ - Span::from(SPACE), - Span::from("[^e]dit by local time"), - ]); - } - spans - } - _ => vec![ - Span::from("[enter]apply changes"), - Span::from(SPACE), - Span::from("[esc]skip changes"), - Span::from(SPACE), - Span::from(format!( - "[{} {}]edit selection", - scrollbar::HORIZONTAL.begin, - scrollbar::HORIZONTAL.end - )), // ← →, - Span::from(SPACE), - Span::from(format!("[{}]edit up", scrollbar::VERTICAL.begin)), // ↑ - Span::from(SPACE), - Span::from(format!("[{}]edit up", scrollbar::VERTICAL.end)), // ↓, - ], - } - })), - ]), // appearance Row::new(vec![ Cell::from(Span::styled( @@ -188,6 +132,89 @@ impl StatefulWidget for Footer { )), ])), ]), + // controls - 1. row + Row::new(vec![ + Cell::from(Span::styled( + "controls", + Style::default().add_modifier(Modifier::BOLD), + )), + Cell::from(Line::from({ + match self.app_edit_mode { + AppEditMode::None => { + let mut spans = vec![Span::from(if self.running_clock { + "[s]top" + } else { + "[s]tart" + })]; + spans.extend_from_slice(&[ + Span::from(SPACE), + Span::from("[e]dit"), + ]); + if self.selected_content == Content::Countdown { + spans.extend_from_slice(&[ + Span::from(SPACE), + Span::from("[^e]dit by local time"), + ]); + } + spans.extend_from_slice(&[ + Span::from(SPACE), + Span::from("[r]eset"), + ]); + if self.selected_content == Content::Pomodoro { + spans.extend_from_slice(&[ + Span::from(SPACE), + Span::from("[^r]eset round"), + ]); + } + spans + } + _ => vec![ + Span::from("[s]ave changes"), + Span::from(SPACE), + Span::from("[^s]ave initial value"), + Span::from(SPACE), + Span::from("[esc]skip changes"), + ], + } + })), + ]), + // controls - 2. row + Row::new(vec![ + Cell::from(Line::from("")), + Cell::from(Line::from({ + match self.app_edit_mode { + AppEditMode::None => { + let mut spans = vec![]; + if self.selected_content == Content::Pomodoro { + spans.extend_from_slice(&[Span::from( + "[← →]switch work/pause", + )]); + } + spans + } + _ => vec![ + Span::from(format!( + // ← →, + "[{} {}]change selection", + scrollbar::HORIZONTAL.begin, + scrollbar::HORIZONTAL.end + )), + Span::from(SPACE), + Span::from(format!( + // ↑ + "[{}]edit up", + scrollbar::VERTICAL.begin + )), + Span::from(SPACE), + Span::from(format!( + // ↓ + "[{}]edit up", + scrollbar::VERTICAL.end + )), + ], + } + })), + ]), ], widths, ) diff --git a/src/widgets/pomodoro.rs b/src/widgets/pomodoro.rs index d5b0e8a..cc4fcc4 100644 --- a/src/widgets/pomodoro.rs +++ b/src/widgets/pomodoro.rs @@ -5,10 +5,9 @@ use crate::{ utils::center, widgets::clock::{ClockState, ClockStateArgs, ClockWidget, Countdown}, }; -use crossterm::event::KeyModifiers; +use crossterm::event::{KeyCode, KeyModifiers}; use ratatui::{ buffer::Buffer, - crossterm::event::KeyCode, layout::{Constraint, Layout, Rect}, text::Line, widgets::{StatefulWidget, Widget}, @@ -141,46 +140,69 @@ impl TuiEventHandler for PomodoroState { self.get_clock_mut().tick(); self.get_clock_mut().update_done_count(); } + // EDIT mode + TuiEvent::Key(key) if edit_mode => match key.code { + // Skip changes + KeyCode::Esc => { + let clock = self.get_clock_mut(); + // Important: set current value first + clock.set_current_value(*clock.get_prev_value()); + // before toggling back to non-edit mode + clock.toggle_edit(); + } + // Apply changes and update initial value + KeyCode::Char('s') if key.modifiers.contains(KeyModifiers::CONTROL) => { + self.get_clock_mut().toggle_edit(); + // update initial value + let c = *self.get_clock().get_current_value(); + self.get_clock_mut().set_initial_value(c); + } + // Apply changes + KeyCode::Char('s') => { + self.get_clock_mut().toggle_edit(); + } + // Value up + KeyCode::Up => { + self.get_clock_mut().edit_up(); + } + // Value down + KeyCode::Down => { + self.get_clock_mut().edit_down(); + } + // move edit position to the left + KeyCode::Left => { + self.get_clock_mut().edit_next(); + } + // move edit position to the right + KeyCode::Right => { + self.get_clock_mut().edit_prev(); + } + _ => return Some(event), + }, + // default mode TuiEvent::Key(key) => match key.code { + // Toggle run/pause KeyCode::Char('s') => { self.get_clock_mut().toggle_pause(); } - // Skip changes - KeyCode::Esc if edit_mode => { - let clock = self.get_clock_mut(); - clock.toggle_edit(); - clock.set_current_value(*clock.get_prev_value()); - } - // Apply changes - KeyCode::Enter if edit_mode => { - self.get_clock_mut().toggle_edit(); - } // Enter edit mode - KeyCode::Char('e') if !edit_mode => { + KeyCode::Char('e') => { self.get_clock_mut().toggle_edit(); } - KeyCode::Left if edit_mode => { - self.get_clock_mut().edit_next(); - } + // toggle WORK/PAUSE KeyCode::Left => { - // `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(); } - KeyCode::Right if edit_mode => { - self.get_clock_mut().edit_prev(); - } + // toggle WORK/PAUSE KeyCode::Right => { self.next(); } - KeyCode::Up if edit_mode => { - self.get_clock_mut().edit_up(); - } - KeyCode::Down if edit_mode => { - self.get_clock_mut().edit_down(); - } + // reset round KeyCode::Char('r') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.round = 1; } + // reset values KeyCode::Char('r') => { // count number of finished rounds of WORK before resetting the clock if self.get_mode() == &Mode::Work && self.get_clock().is_done() { diff --git a/src/widgets/timer.rs b/src/widgets/timer.rs index ac46bde..3d1ccdf 100644 --- a/src/widgets/timer.rs +++ b/src/widgets/timer.rs @@ -39,39 +39,53 @@ impl TuiEventHandler for TimerState { self.clock.tick(); self.clock.update_done_count(); } - TuiEvent::Key(key) => match key.code { - KeyCode::Char('s') => { - self.clock.toggle_pause(); - } - KeyCode::Char('r') => { - self.clock.reset(); - } - KeyCode::Esc if edit_mode => { + // EDIT mode + TuiEvent::Key(key) if edit_mode => match key.code { + // Skip changes + KeyCode::Esc => { // Important: set current value first self.clock.set_current_value(*self.clock.get_prev_value()); // before toggling back to non-edit mode self.clock.toggle_edit(); } - KeyCode::Enter if edit_mode => { + // Apply changes + KeyCode::Char('s') => { self.clock.toggle_edit(); } - KeyCode::Char('e') if !edit_mode => { - self.clock.toggle_edit(); - } - KeyCode::Left if edit_mode => { + // move change position to the left + KeyCode::Left => { self.clock.edit_next(); } - KeyCode::Right if edit_mode => { + // move change position to the right + KeyCode::Right => { self.clock.edit_prev(); } - KeyCode::Up if edit_mode => { + // change value up + KeyCode::Up => { self.clock.edit_up(); } - KeyCode::Down if edit_mode => { + // change value down + KeyCode::Down => { self.clock.edit_down(); } _ => return Some(event), }, + // default mode + TuiEvent::Key(key) => match key.code { + // Toggle run/pause + KeyCode::Char('s') => { + self.clock.toggle_pause(); + } + // reset clock + KeyCode::Char('r') => { + self.clock.reset(); + } + // enter edit mode + KeyCode::Char('e') => { + self.clock.toggle_edit(); + } + _ => return Some(event), + }, _ => return Some(event), } None