feat: add help menu
This commit is contained in:
+72
-10
@@ -6,18 +6,12 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
ExecutableCommand,
|
ExecutableCommand, event::{self, Event, KeyCode, KeyModifiers}, terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
|
||||||
event::{self, Event, KeyCode, KeyModifiers},
|
|
||||||
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use figlet_rs::Toilet;
|
use figlet_rs::Toilet;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
Terminal,
|
Terminal, backend::CrosstermBackend, layout::{Alignment, Constraint, Direction, Layout}, style::{Color, Style}, widgets::{Block, Borders, Clear, Paragraph},
|
||||||
backend::CrosstermBackend,
|
|
||||||
layout::{Alignment, Constraint, Direction, Layout},
|
|
||||||
style::{Color, Style},
|
|
||||||
widgets::Paragraph,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const SECONDS_PER_MIN: i64 = 60;
|
const SECONDS_PER_MIN: i64 = 60;
|
||||||
@@ -37,6 +31,7 @@ struct Termato {
|
|||||||
is_running: bool,
|
is_running: bool,
|
||||||
duration_in_secs: i64,
|
duration_in_secs: i64,
|
||||||
time_remaining_in_sec: i64,
|
time_remaining_in_sec: i64,
|
||||||
|
show_help: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Termato {
|
impl Termato {
|
||||||
@@ -49,6 +44,7 @@ impl Termato {
|
|||||||
is_running: false,
|
is_running: false,
|
||||||
duration_in_secs: work_mins * SECONDS_PER_MIN,
|
duration_in_secs: work_mins * SECONDS_PER_MIN,
|
||||||
time_remaining_in_sec: break_mins * SECONDS_PER_MIN,
|
time_remaining_in_sec: break_mins * SECONDS_PER_MIN,
|
||||||
|
show_help: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +93,14 @@ impl Termato {
|
|||||||
self.duration_in_secs = self.work_mins * SECONDS_PER_MIN;
|
self.duration_in_secs = self.work_mins * SECONDS_PER_MIN;
|
||||||
self.time_remaining_in_sec = self.duration_in_secs;
|
self.time_remaining_in_sec = self.duration_in_secs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn toggle_help(&mut self) {
|
||||||
|
self.show_help = !self.show_help;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: I think we can refactor this to be more like iced.rs
|
||||||
|
// basically implement an elem like approach.
|
||||||
fn main() -> Result<(), io::Error> {
|
fn main() -> Result<(), io::Error> {
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
stdout().execute(EnterAlternateScreen)?;
|
stdout().execute(EnterAlternateScreen)?;
|
||||||
@@ -122,11 +124,11 @@ fn main() -> Result<(), io::Error> {
|
|||||||
loop {
|
loop {
|
||||||
terminal.draw(|f| {
|
terminal.draw(|f| {
|
||||||
let size = f.area();
|
let size = f.area();
|
||||||
|
|
||||||
let minutes = termato.time_remaining_in_sec / SECONDS_PER_MIN;
|
let minutes = termato.time_remaining_in_sec / SECONDS_PER_MIN;
|
||||||
let seconds = termato.time_remaining_in_sec % SECONDS_PER_MIN;
|
let seconds = termato.time_remaining_in_sec % SECONDS_PER_MIN;
|
||||||
let time_str = format!("{:02}:{:02}", minutes, seconds);
|
let time_str = format!("{:02}:{:02}", minutes, seconds);
|
||||||
|
|
||||||
let time_color = match termato.state {
|
let time_color = match termato.state {
|
||||||
TimerState::Work => Color::Red,
|
TimerState::Work => Color::Red,
|
||||||
TimerState::Break => Color::Green,
|
TimerState::Break => Color::Green,
|
||||||
@@ -155,6 +157,52 @@ fn main() -> Result<(), io::Error> {
|
|||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
|
|
||||||
f.render_widget(timer_paragraph, vertical_layout[1]);
|
f.render_widget(timer_paragraph, vertical_layout[1]);
|
||||||
|
|
||||||
|
if termato.show_help {
|
||||||
|
let popup_width = 44;
|
||||||
|
let popup_height = 7;
|
||||||
|
|
||||||
|
if size.width >= popup_width && size.height >= popup_height {
|
||||||
|
let popup_vertical = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.constraints([
|
||||||
|
Constraint::Length((size.height.saturating_sub(popup_height)) / 2),
|
||||||
|
Constraint::Length(popup_height),
|
||||||
|
Constraint::Min(1),
|
||||||
|
])
|
||||||
|
.split(size);
|
||||||
|
|
||||||
|
let popup_horizontal = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints([
|
||||||
|
Constraint::Length((size.width.saturating_sub(popup_width)) / 2),
|
||||||
|
Constraint::Length(popup_width),
|
||||||
|
Constraint::Min(1),
|
||||||
|
])
|
||||||
|
.split(popup_vertical[1]);
|
||||||
|
|
||||||
|
let popup_area = popup_horizontal[1];
|
||||||
|
|
||||||
|
let help_block = Block::default()
|
||||||
|
.title(" Controls ")
|
||||||
|
.borders(Borders::ALL)
|
||||||
|
.border_style(Style::default().fg(Color::DarkGray));
|
||||||
|
|
||||||
|
let help_content = Paragraph::new(
|
||||||
|
"[Space] Pause / Resume\n\
|
||||||
|
[S] Switch Mode\n\
|
||||||
|
[R] Reset Timer\n\
|
||||||
|
[?] Toggle Help\n\
|
||||||
|
[Q] Quit",
|
||||||
|
)
|
||||||
|
.block(help_block)
|
||||||
|
.style(Style::default().fg(Color::DarkGray))
|
||||||
|
.alignment(Alignment::Left);
|
||||||
|
|
||||||
|
f.render_widget(Clear, popup_area);
|
||||||
|
f.render_widget(help_content, popup_area);
|
||||||
|
}
|
||||||
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if event::poll(Duration::from_millis(100))?
|
if event::poll(Duration::from_millis(100))?
|
||||||
@@ -167,6 +215,7 @@ fn main() -> Result<(), io::Error> {
|
|||||||
KeyCode::Char(' ') => termato.toggle_running(),
|
KeyCode::Char(' ') => termato.toggle_running(),
|
||||||
KeyCode::Char('s') | KeyCode::Char('S') => termato.toggle_mode(),
|
KeyCode::Char('s') | KeyCode::Char('S') => termato.toggle_mode(),
|
||||||
KeyCode::Char('r') | KeyCode::Char('R') => termato.reset(),
|
KeyCode::Char('r') | KeyCode::Char('R') => termato.reset(),
|
||||||
|
KeyCode::Char('?') => termato.toggle_help(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,4 +360,17 @@ mod tests {
|
|||||||
assert_eq!(termato.duration_in_secs, 60);
|
assert_eq!(termato.duration_in_secs, 60);
|
||||||
assert_eq!(termato.time_remaining_in_sec, 60);
|
assert_eq!(termato.time_remaining_in_sec, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn termato_toggle_help_when_called_it_should_toggle_help() {
|
||||||
|
let mut termato = Termato::new(1, 1);
|
||||||
|
|
||||||
|
termato.toggle_help();
|
||||||
|
|
||||||
|
assert!(termato.show_help);
|
||||||
|
|
||||||
|
termato.toggle_help();
|
||||||
|
|
||||||
|
assert!(!termato.show_help);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user