diff --git a/src/app.rs b/src/app.rs index cb44099..2819aa9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -7,7 +7,7 @@ use crate::{ widgets::{ clock::{self, Clock, ClockArgs, Style}, countdown::{Countdown, CountdownWidget}, - footer::Footer, + footer::{Footer, FooterArgs}, header::Header, pomodoro::{Mode as PomodoroMode, Pomodoro, PomodoroArgs, PomodoroWidget}, timer::{Timer, TimerWidget}, @@ -59,6 +59,7 @@ pub struct App { pub struct AppArgs { pub style: Style, pub with_decis: bool, + pub show_menu: bool, pub content: Content, pub pomodoro_mode: PomodoroMode, pub initial_value_work: Duration, @@ -76,6 +77,7 @@ impl From<(Args, AppStorage)> for AppArgs { fn from((args, stg): (Args, AppStorage)) -> Self { AppArgs { with_decis: args.decis || stg.with_decis, + show_menu: stg.show_menu, content: args.mode.unwrap_or(stg.content), style: args.style.unwrap_or(stg.style), pomodoro_mode: stg.pomodoro_mode, @@ -94,6 +96,7 @@ impl App { pub fn new(args: AppArgs) -> Self { let AppArgs { style, + show_menu, initial_value_work, initial_value_pause, initial_value_countdown, @@ -108,7 +111,7 @@ impl App { Self { mode: Mode::Running, content, - show_menu: false, + show_menu, style, with_decis, countdown: Countdown::new(Clock::::new(ClockArgs { @@ -163,6 +166,22 @@ impl App { self.mode != Mode::Quit } + fn is_edit_mode(&mut self) -> bool { + match self.content { + Content::Countdown => self.countdown.get_clock().clone().is_edit_mode(), + Content::Timer => self.timer.get_clock().clone().is_edit_mode(), + Content::Pomodoro => self.pomodoro.get_clock().is_edit_mode(), + } + } + + fn clock_is_running(&mut self) -> bool { + match self.content { + Content::Countdown => self.countdown.get_clock().clone().is_running(), + Content::Timer => self.timer.get_clock().clone().is_running(), + Content::Pomodoro => self.pomodoro.get_clock().is_running(), + } + } + fn handle_key_event(&mut self, key: KeyEvent) { debug!("Received key {:?}", key.code); match key.code { @@ -234,12 +253,21 @@ impl StatefulWidget for AppWidget { let vertical = Layout::vertical([ Constraint::Length(1), Constraint::Percentage(100), - Constraint::Length(if state.show_menu { 2 } else { 1 }), + Constraint::Length(if state.show_menu { 5 } else { 1 }), ]); let [v0, v1, v2] = vertical.areas(area); + // header Header::new(true).render(v0, buf); + // content self.render_content(v1, buf, state); - Footer::new(state.show_menu, state.content).render(v2, buf); + // footer + Footer::new(FooterArgs { + show_menu: state.show_menu, + running_clock: state.clock_is_running(), + selected_content: state.content, + edit_mode: state.is_edit_mode(), + }) + .render(v2, buf); } } diff --git a/src/widgets/clock.rs b/src/widgets/clock.rs index 20d676b..8562d9c 100644 --- a/src/widgets/clock.rs +++ b/src/widgets/clock.rs @@ -211,6 +211,10 @@ impl Clock { &self.mode } + pub fn is_running(&self) -> bool { + self.mode == Mode::Tick + } + pub fn is_edit_mode(&mut self) -> bool { matches!(self.mode, Mode::Editable(_, _)) } diff --git a/src/widgets/footer.rs b/src/widgets/footer.rs index 7a48ccc..0064587 100644 --- a/src/widgets/footer.rs +++ b/src/widgets/footer.rs @@ -7,21 +7,38 @@ use ratatui::{ style::{Modifier, Style}, symbols, text::{Line, Span}, - widgets::{Block, Borders, Widget}, + widgets::{Block, Borders, Cell, Row, Table, Widget}, }; #[derive(Debug, Clone)] pub struct Footer { show_menu: bool, + running_clock: bool, selected_content: Content, content_labels: BTreeMap, + edit_mode: bool, +} + +pub struct FooterArgs { + pub show_menu: bool, + pub running_clock: bool, + pub selected_content: Content, + pub edit_mode: bool, } impl Footer { - pub fn new(show_menu: bool, selected_content: Content) -> Self { + pub fn new(args: FooterArgs) -> Self { + let FooterArgs { + show_menu, + running_clock, + selected_content, + edit_mode, + } = args; Self { show_menu, + running_clock, selected_content, + edit_mode, content_labels: BTreeMap::from([ (Content::Countdown, "[c]ountdown".into()), (Content::Timer, "[t]imer".into()), @@ -34,7 +51,7 @@ impl Footer { impl Widget for Footer { fn render(self, area: Rect, buf: &mut Buffer) { let [border_area, menu_area] = - Layout::vertical([Constraint::Length(1), Constraint::Fill(0)]).areas(area); + Layout::vertical([Constraint::Length(2), Constraint::Percentage(100)]).areas(area); Block::new() .borders(Borders::TOP) .title(format! {"[m]enu {:} ", if self.show_menu {"↓"} else {"↑"}}) @@ -42,12 +59,7 @@ impl Widget for Footer { .render(border_area, buf); // show menu if self.show_menu { - let [title_area, labels_area] = - Layout::horizontal([Constraint::Length(12), Constraint::Fill(0)]).areas(menu_area); - - Span::styled("screens", Style::default().add_modifier(Modifier::BOLD)) - .render(title_area, buf); - let spans: Vec = self + let content_labels: Vec = self .content_labels .iter() .enumerate() @@ -65,7 +77,74 @@ impl Widget for Footer { Span::styled(label, style) }) .collect(); - Line::from(spans).render(labels_area, buf); + + const SPACE: &str = " "; + let widths = [Constraint::Length(12), Constraint::Percentage(100)]; + Table::new( + [ + // content + Row::new(vec![ + Cell::from(Span::styled( + "screens", + Style::default().add_modifier(Modifier::BOLD), + )), + Cell::from(Line::from(content_labels)), + ]), + // format + 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"), + ])), + ]), + // edit + Row::new(vec![ + Cell::from(Span::styled( + "controls", + Style::default().add_modifier(Modifier::BOLD), + )), + Cell::from(Line::from({ + if self.edit_mode { + vec![ + Span::from("[e]dit done"), + Span::from(SPACE), + Span::from("[← →]edit selection"), + Span::from(SPACE), + Span::from("[↑]edit up"), + Span::from(SPACE), + Span::from("[↓]edit down"), + ] + } else { + let mut spans = vec![ + Span::from(if self.running_clock { + "[s]top" + } else { + "[s]tart" + }), + Span::from(SPACE), + Span::from("[r]eset"), + Span::from(SPACE), + Span::from("[e]dit"), + ]; + if self.selected_content == Content::Pomodoro { + spans.extend_from_slice(&[ + Span::from(SPACE), + Span::from("[← →]switch work/pause"), + ]); + } + spans + } + })), + ]), + ], + widths, + ) + .render(menu_area, buf); } } }