Update keybindings (#76)
* (pomodoro) reset both clocks at once * quit app by pressing `q` only * (countdown) enter/esc keybindings * (timer) enter/esc keybindings * (pomodoro) enter/esc keybindings * update footer label * fix(coundown): don't reset elapsed clock while skipping editing changes * fix(clock): order of actions matters for ESC handling. Set `pause` instead of `initial` mode while toggeling back. * fix(timer): order of actions matters (ESC key) * (footer) update order, lowercase standard keys
This commit is contained in:
parent
90d9988e7a
commit
e6291a3131
@ -202,7 +202,7 @@ impl App {
|
|||||||
let handle_key_event = |app: &mut Self, key: KeyEvent| {
|
let handle_key_event = |app: &mut Self, key: KeyEvent| {
|
||||||
debug!("Received key {:?}", key.code);
|
debug!("Received key {:?}", key.code);
|
||||||
match key.code {
|
match key.code {
|
||||||
KeyCode::Char('q') | KeyCode::Esc => app.mode = Mode::Quit,
|
KeyCode::Char('q') => app.mode = Mode::Quit,
|
||||||
KeyCode::Char('c') => app.content = Content::Countdown,
|
KeyCode::Char('c') => app.content = Content::Countdown,
|
||||||
KeyCode::Char('t') => app.content = Content::Timer,
|
KeyCode::Char('t') => app.content = Content::Timer,
|
||||||
KeyCode::Char('p') => app.content = Content::Pomodoro,
|
KeyCode::Char('p') => app.content = Content::Pomodoro,
|
||||||
|
|||||||
@ -74,6 +74,7 @@ pub struct ClockState<T> {
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
initial_value: DurationEx,
|
initial_value: DurationEx,
|
||||||
current_value: DurationEx,
|
current_value: DurationEx,
|
||||||
|
prev_value: DurationEx,
|
||||||
tick_value: DurationEx,
|
tick_value: DurationEx,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
format: Format,
|
format: Format,
|
||||||
@ -151,14 +152,18 @@ impl<T> ClockState<T> {
|
|||||||
self.update_format();
|
self.update_format();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_prev_value(&self) -> &DurationEx {
|
||||||
|
&self.prev_value
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toggle_edit(&mut self) {
|
pub fn toggle_edit(&mut self) {
|
||||||
self.mode = match self.mode.clone() {
|
self.mode = match self.mode.clone() {
|
||||||
Mode::Editable(_, prev) => {
|
Mode::Editable(_, prev) => {
|
||||||
let p = *prev;
|
let p = *prev;
|
||||||
// special cases: Should `Mode` be updated?
|
// Update `Mode`
|
||||||
// 1. `Done` -> `Initial` ?
|
// 1. `Done` -> `Pause`
|
||||||
if p == Mode::Done && self.current_value.gt(&Duration::ZERO.into()) {
|
if p == Mode::Done && self.current_value.gt(&Duration::ZERO.into()) {
|
||||||
Mode::Initial
|
Mode::Pause
|
||||||
}
|
}
|
||||||
// 2. `_` -> `Done` ?
|
// 2. `_` -> `Done` ?
|
||||||
else if p != Mode::Done && self.current_value.eq(&Duration::ZERO.into()) {
|
else if p != Mode::Done && self.current_value.eq(&Duration::ZERO.into()) {
|
||||||
@ -170,6 +175,8 @@ impl<T> ClockState<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mode => {
|
mode => {
|
||||||
|
// store prev. value
|
||||||
|
self.prev_value = self.current_value;
|
||||||
if self.format <= Format::Ss {
|
if self.format <= Format::Ss {
|
||||||
Mode::Editable(Time::Seconds, Box::new(mode))
|
Mode::Editable(Time::Seconds, Box::new(mode))
|
||||||
} else {
|
} else {
|
||||||
@ -402,6 +409,7 @@ impl ClockState<Countdown> {
|
|||||||
name: None,
|
name: None,
|
||||||
initial_value: initial_value.into(),
|
initial_value: initial_value.into(),
|
||||||
current_value: current_value.into(),
|
current_value: current_value.into(),
|
||||||
|
prev_value: current_value.into(),
|
||||||
tick_value: tick_value.into(),
|
tick_value: tick_value.into(),
|
||||||
mode: if current_value == Duration::ZERO {
|
mode: if current_value == Duration::ZERO {
|
||||||
Mode::Done
|
Mode::Done
|
||||||
@ -475,6 +483,7 @@ impl ClockState<Timer> {
|
|||||||
name: None,
|
name: None,
|
||||||
initial_value: initial_value.into(),
|
initial_value: initial_value.into(),
|
||||||
current_value: current_value.into(),
|
current_value: current_value.into(),
|
||||||
|
prev_value: current_value.into(),
|
||||||
tick_value: tick_value.into(),
|
tick_value: tick_value.into(),
|
||||||
mode: if current_value == initial_value {
|
mode: if current_value == initial_value {
|
||||||
Mode::Initial
|
Mode::Initial
|
||||||
|
|||||||
@ -187,33 +187,65 @@ impl TuiEventHandler for CountdownState {
|
|||||||
self.edit_time_done(edit_time);
|
self.edit_time_done(edit_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// STRG + e => toggle edit time
|
// skip editing clock
|
||||||
KeyCode::Char('e') if key.modifiers.contains(KeyModifiers::CONTROL) => {
|
KeyCode::Esc if self.is_clock_edit_mode() => {
|
||||||
// reset both clocks
|
// Important: set current value first
|
||||||
self.clock.reset();
|
self.clock.set_current_value(*self.clock.get_prev_value());
|
||||||
self.elapsed_clock.reset();
|
// before toggling back to non-edit mode
|
||||||
|
|
||||||
if let Some(edit_time) = &mut self.edit_time.clone() {
|
|
||||||
self.edit_time_done(edit_time)
|
|
||||||
} else {
|
|
||||||
// update `edit_time`
|
|
||||||
self.edit_time = Some(EditTimeState::new(EditTimeStateArgs {
|
|
||||||
time: self.time_to_edit(),
|
|
||||||
min: self.min_time_to_edit(),
|
|
||||||
max: self.max_time_to_edit(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// e => toggle edit clock
|
|
||||||
KeyCode::Char('e') => {
|
|
||||||
// toggle edit mode
|
|
||||||
self.clock.toggle_edit();
|
self.clock.toggle_edit();
|
||||||
|
}
|
||||||
|
// skip editing by local time
|
||||||
|
KeyCode::Esc if self.is_time_edit_mode() => {
|
||||||
|
self.edit_time = None;
|
||||||
|
}
|
||||||
|
|
||||||
// stop `elapsed_clock`
|
// Enter edit by local time mode
|
||||||
|
KeyCode::Char('e')
|
||||||
|
if key.modifiers.contains(KeyModifiers::CONTROL)
|
||||||
|
&& !self.is_time_edit_mode() =>
|
||||||
|
{
|
||||||
|
// set `edit_time`
|
||||||
|
self.edit_time = Some(EditTimeState::new(EditTimeStateArgs {
|
||||||
|
time: self.time_to_edit(),
|
||||||
|
min: self.min_time_to_edit(),
|
||||||
|
max: self.max_time_to_edit(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// pause `elapsed_clock`
|
||||||
if self.elapsed_clock.is_running() {
|
if self.elapsed_clock.is_running() {
|
||||||
self.elapsed_clock.toggle_pause();
|
self.elapsed_clock.toggle_pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enter edit clock
|
||||||
|
KeyCode::Char('e') if !self.is_clock_edit_mode() => {
|
||||||
|
// toggle edit mode
|
||||||
|
self.clock.toggle_edit();
|
||||||
|
|
||||||
|
// pause `elapsed_clock`
|
||||||
|
if self.elapsed_clock.is_running() {
|
||||||
|
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() => {
|
KeyCode::Left if self.is_clock_edit_mode() => {
|
||||||
self.clock.edit_next();
|
self.clock.edit_next();
|
||||||
}
|
}
|
||||||
@ -230,8 +262,6 @@ impl TuiEventHandler for CountdownState {
|
|||||||
}
|
}
|
||||||
KeyCode::Up if self.is_clock_edit_mode() => {
|
KeyCode::Up if self.is_clock_edit_mode() => {
|
||||||
self.clock.edit_up();
|
self.clock.edit_up();
|
||||||
// whenever `clock`'s value is changed, reset `elapsed_clock`
|
|
||||||
self.elapsed_clock.reset();
|
|
||||||
}
|
}
|
||||||
KeyCode::Up if self.is_time_edit_mode() => {
|
KeyCode::Up if self.is_time_edit_mode() => {
|
||||||
// safe unwrap because of previous check in `is_time_edit_mode`
|
// safe unwrap because of previous check in `is_time_edit_mode`
|
||||||
@ -239,8 +269,6 @@ impl TuiEventHandler for CountdownState {
|
|||||||
}
|
}
|
||||||
KeyCode::Down if self.is_clock_edit_mode() => {
|
KeyCode::Down if self.is_clock_edit_mode() => {
|
||||||
self.clock.edit_down();
|
self.clock.edit_down();
|
||||||
// whenever clock value is changed, reset timer
|
|
||||||
self.elapsed_clock.reset();
|
|
||||||
}
|
}
|
||||||
KeyCode::Down if self.is_time_edit_mode() => {
|
KeyCode::Down if self.is_time_edit_mode() => {
|
||||||
// safe unwrap because of previous check in `is_time_edit_mode`
|
// safe unwrap because of previous check in `is_time_edit_mode`
|
||||||
|
|||||||
@ -104,7 +104,7 @@ impl StatefulWidget for Footer {
|
|||||||
let widths = [Constraint::Length(12), Constraint::Percentage(100)];
|
let widths = [Constraint::Length(12), Constraint::Percentage(100)];
|
||||||
let table = Table::new(
|
let table = Table::new(
|
||||||
[
|
[
|
||||||
// content
|
// screens
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
Cell::from(Span::styled(
|
Cell::from(Span::styled(
|
||||||
"screens",
|
"screens",
|
||||||
@ -112,27 +112,7 @@ impl StatefulWidget for Footer {
|
|||||||
)),
|
)),
|
||||||
Cell::from(Line::from(content_labels)),
|
Cell::from(Line::from(content_labels)),
|
||||||
]),
|
]),
|
||||||
// format
|
// controls
|
||||||
Row::new(vec![
|
|
||||||
Cell::from(Span::styled(
|
|
||||||
"appearance",
|
|
||||||
Style::default().add_modifier(Modifier::BOLD),
|
|
||||||
)),
|
|
||||||
Cell::from(Line::from(vec![
|
|
||||||
Span::from("[,]change style"),
|
|
||||||
Span::from(SPACE),
|
|
||||||
Span::from("[.]toggle deciseconds"),
|
|
||||||
Span::from(SPACE),
|
|
||||||
Span::from(format!(
|
|
||||||
"[:]toggle {} time",
|
|
||||||
match self.app_time {
|
|
||||||
AppTime::Local(_) => "local",
|
|
||||||
AppTime::Utc(_) => "utc",
|
|
||||||
}
|
|
||||||
)),
|
|
||||||
])),
|
|
||||||
]),
|
|
||||||
// edit
|
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
Cell::from(Span::styled(
|
Cell::from(Span::styled(
|
||||||
"controls",
|
"controls",
|
||||||
@ -170,12 +150,10 @@ impl StatefulWidget for Footer {
|
|||||||
}
|
}
|
||||||
spans
|
spans
|
||||||
}
|
}
|
||||||
others => vec![
|
_ => vec![
|
||||||
Span::from(match others {
|
Span::from("[enter]apply changes"),
|
||||||
AppEditMode::Clock => "[e]dit done",
|
Span::from(SPACE),
|
||||||
AppEditMode::Time => "[^e]dit done",
|
Span::from("[esc]skip changes"),
|
||||||
_ => "",
|
|
||||||
}),
|
|
||||||
Span::from(SPACE),
|
Span::from(SPACE),
|
||||||
Span::from(format!(
|
Span::from(format!(
|
||||||
"[{} {}]edit selection",
|
"[{} {}]edit selection",
|
||||||
@ -190,6 +168,26 @@ impl StatefulWidget for Footer {
|
|||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
]),
|
]),
|
||||||
|
// appearance
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(Span::styled(
|
||||||
|
"appearance",
|
||||||
|
Style::default().add_modifier(Modifier::BOLD),
|
||||||
|
)),
|
||||||
|
Cell::from(Line::from(vec![
|
||||||
|
Span::from("[,]change style"),
|
||||||
|
Span::from(SPACE),
|
||||||
|
Span::from("[.]toggle deciseconds"),
|
||||||
|
Span::from(SPACE),
|
||||||
|
Span::from(format!(
|
||||||
|
"[:]toggle {} time",
|
||||||
|
match self.app_time {
|
||||||
|
AppTime::Local(_) => "local",
|
||||||
|
AppTime::Utc(_) => "utc",
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
])),
|
||||||
|
]),
|
||||||
],
|
],
|
||||||
widths,
|
widths,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -145,7 +145,18 @@ impl TuiEventHandler for PomodoroState {
|
|||||||
KeyCode::Char('s') => {
|
KeyCode::Char('s') => {
|
||||||
self.get_clock_mut().toggle_pause();
|
self.get_clock_mut().toggle_pause();
|
||||||
}
|
}
|
||||||
KeyCode::Char('e') => {
|
// 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 => {
|
||||||
self.get_clock_mut().toggle_edit();
|
self.get_clock_mut().toggle_edit();
|
||||||
}
|
}
|
||||||
KeyCode::Left if edit_mode => {
|
KeyCode::Left if edit_mode => {
|
||||||
@ -175,7 +186,9 @@ impl TuiEventHandler for PomodoroState {
|
|||||||
if self.get_mode() == &Mode::Work && self.get_clock().is_done() {
|
if self.get_mode() == &Mode::Work && self.get_clock().is_done() {
|
||||||
self.round += 1;
|
self.round += 1;
|
||||||
}
|
}
|
||||||
self.get_clock_mut().reset();
|
// reset both clocks
|
||||||
|
self.clock_map.pause.reset();
|
||||||
|
self.clock_map.work.reset();
|
||||||
}
|
}
|
||||||
_ => return Some(event),
|
_ => return Some(event),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -46,7 +46,16 @@ impl TuiEventHandler for TimerState {
|
|||||||
KeyCode::Char('r') => {
|
KeyCode::Char('r') => {
|
||||||
self.clock.reset();
|
self.clock.reset();
|
||||||
}
|
}
|
||||||
KeyCode::Char('e') => {
|
KeyCode::Esc if 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();
|
||||||
|
}
|
||||||
|
KeyCode::Enter if edit_mode => {
|
||||||
|
self.clock.toggle_edit();
|
||||||
|
}
|
||||||
|
KeyCode::Char('e') if !edit_mode => {
|
||||||
self.clock.toggle_edit();
|
self.clock.toggle_edit();
|
||||||
}
|
}
|
||||||
KeyCode::Left if edit_mode => {
|
KeyCode::Left if edit_mode => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user