From 8f50bc5fc6bd89bd7600a1c85b2d5976ccd2fb49 Mon Sep 17 00:00:00 2001 From: Jens Krause <47693+sectore@users.noreply.github.com> Date: Tue, 4 Feb 2025 15:05:02 +0100 Subject: [PATCH] `AppEvent` (#61) Extend `events` to provide a `mpsc` channel to send `AppEvent`'s from anywhere in the app straight to the `App`. --- src/app.rs | 146 ++++++++++++++++++++++++-------------- src/events.rs | 52 ++++++++++---- src/main.rs | 15 ++-- src/sound.rs | 29 ++++++++ src/widgets/clock.rs | 10 +++ src/widgets/clock_test.rs | 34 +++++++-- src/widgets/countdown.rs | 18 ++--- src/widgets/pomodoro.rs | 14 ++-- src/widgets/timer.rs | 10 +-- 9 files changed, 232 insertions(+), 96 deletions(-) create mode 100644 src/sound.rs diff --git a/src/app.rs b/src/app.rs index 9e7bdbb..9093022 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,7 +2,8 @@ use crate::{ args::Args, common::{AppEditMode, AppTime, AppTimeFormat, Content, Notification, Style}, constants::TICK_VALUE_MS, - events::{Event, EventHandler, Events}, + events, + events::TuiEventHandler, storage::AppStorage, terminal::Terminal, widgets::{ @@ -60,13 +61,21 @@ pub struct AppArgs { pub current_value_countdown: Duration, pub elapsed_value_countdown: Duration, pub current_value_timer: Duration, + pub app_tx: events::AppEventTx, } -/// Getting `AppArgs` by merging `Args` and `AppStorage`. -/// `Args` wins btw. -impl From<(Args, AppStorage)> for AppArgs { - fn from((args, stg): (Args, AppStorage)) -> Self { - AppArgs { +pub struct FromAppArgs { + pub args: Args, + pub stg: AppStorage, + pub app_tx: events::AppEventTx, +} + +/// Creates an `App` by merging `Args` and `AppStorage` (`Args` wins) +/// and adding `AppEventTx` +impl From for App { + fn from(args: FromAppArgs) -> Self { + let FromAppArgs { args, stg, app_tx } = args; + App::new(AppArgs { with_decis: args.decis || stg.with_decis, show_menu: args.menu || stg.show_menu, notification: args.notification.unwrap_or(stg.notification), @@ -85,7 +94,8 @@ impl From<(Args, AppStorage)> for AppArgs { current_value_countdown: args.countdown.unwrap_or(stg.current_value_countdown), elapsed_value_countdown: stg.elapsed_value_countdown, current_value_timer: stg.current_value_timer, - } + app_tx, + }) } } @@ -114,8 +124,10 @@ impl App { with_decis, pomodoro_mode, notification, + app_tx, } = args; let app_time = get_app_time(); + Self { mode: Mode::Running, notification, @@ -130,6 +142,7 @@ impl App { app_time, with_decis, with_notification: notification == Notification::On, + app_tx: app_tx.clone(), }), timer: TimerState::new( ClockState::::new(ClockStateArgs { @@ -137,6 +150,7 @@ impl App { current_value: current_value_timer, tick_value: Duration::from_millis(TICK_VALUE_MS), with_decis, + app_tx: None, }) .with_on_done_by_condition( notification == Notification::On, @@ -159,33 +173,84 @@ impl App { current_value_pause, with_decis, with_notification: notification == Notification::On, + app_tx: app_tx.clone(), }), footer: FooterState::new(show_menu, app_time_format), } } - pub async fn run(mut self, mut terminal: Terminal, mut events: Events) -> Result { + pub async fn run( + mut self, + terminal: &mut Terminal, + mut events: events::Events, + ) -> Result { + // Closure to handle `KeyEvent`'s + let handle_key_event = |app: &mut Self, key: KeyEvent| { + debug!("Received key {:?}", key.code); + match key.code { + KeyCode::Char('q') | KeyCode::Esc => app.mode = Mode::Quit, + KeyCode::Char('c') => app.content = Content::Countdown, + KeyCode::Char('t') => app.content = Content::Timer, + KeyCode::Char('p') => app.content = Content::Pomodoro, + // toogle app time format + KeyCode::Char(':') => app.footer.toggle_app_time_format(), + // toogle menu + KeyCode::Char('m') => app.footer.set_show_menu(!app.footer.get_show_menu()), + KeyCode::Char(',') => { + app.style = app.style.next(); + } + KeyCode::Char('.') => { + app.with_decis = !app.with_decis; + // update clocks + app.timer.set_with_decis(app.with_decis); + app.countdown.set_with_decis(app.with_decis); + app.pomodoro.set_with_decis(app.with_decis); + } + KeyCode::Up => app.footer.set_show_menu(true), + KeyCode::Down => app.footer.set_show_menu(false), + _ => {} + }; + }; + // Closure to handle `TuiEvent`'s + let mut handle_tui_events = |app: &mut Self, event: events::TuiEvent| -> Result<()> { + if matches!(event, events::TuiEvent::Tick) { + app.app_time = get_app_time(); + app.countdown.set_app_time(app.app_time); + } + + // Pipe events into subviews and handle only 'unhandled' events afterwards + if let Some(unhandled) = match app.content { + Content::Countdown => app.countdown.update(event.clone()), + Content::Timer => app.timer.update(event.clone()), + Content::Pomodoro => app.pomodoro.update(event.clone()), + } { + match unhandled { + events::TuiEvent::Render | events::TuiEvent::Resize => { + app.draw(terminal)?; + } + events::TuiEvent::Key(key) => handle_key_event(app, key), + _ => {} + } + } + Ok(()) + }; + + // Closure to handle `AppEvent`'s + let handle_app_events = |_: &mut Self, event: events::AppEvent| -> Result<()> { + match event { + events::AppEvent::ClockDone => { + debug!("AppEvent::ClockDone"); + } + } + Ok(()) + }; + while self.is_running() { if let Some(event) = events.next().await { - if matches!(event, Event::Tick) { - self.app_time = get_app_time(); - self.countdown.set_app_time(self.app_time); - } - - // Pipe events into subviews and handle only 'unhandled' events afterwards - if let Some(unhandled) = match self.content { - Content::Countdown => self.countdown.update(event.clone()), - Content::Timer => self.timer.update(event.clone()), - Content::Pomodoro => self.pomodoro.update(event.clone()), - } { - match unhandled { - Event::Render | Event::Resize => { - self.draw(&mut terminal)?; - } - Event::Key(key) => self.handle_key_event(key), - _ => {} - } - } + let _ = match event { + events::Event::Terminal(e) => handle_tui_events(&mut self, e), + events::Event::App(e) => handle_app_events(&mut self, e), + }; } } Ok(self) @@ -240,33 +305,6 @@ impl App { } } - fn handle_key_event(&mut self, key: KeyEvent) { - debug!("Received key {:?}", key.code); - match key.code { - KeyCode::Char('q') | KeyCode::Esc => self.mode = Mode::Quit, - KeyCode::Char('c') => self.content = Content::Countdown, - KeyCode::Char('t') => self.content = Content::Timer, - KeyCode::Char('p') => self.content = Content::Pomodoro, - // toogle app time format - KeyCode::Char(':') => self.footer.toggle_app_time_format(), - // toogle menu - KeyCode::Char('m') => self.footer.set_show_menu(!self.footer.get_show_menu()), - KeyCode::Char(',') => { - self.style = self.style.next(); - } - KeyCode::Char('.') => { - self.with_decis = !self.with_decis; - // update clocks - self.timer.set_with_decis(self.with_decis); - self.countdown.set_with_decis(self.with_decis); - self.pomodoro.set_with_decis(self.with_decis); - } - KeyCode::Up => self.footer.set_show_menu(true), - KeyCode::Down => self.footer.set_show_menu(false), - _ => {} - }; - } - fn draw(&mut self, terminal: &mut Terminal) -> Result<()> { terminal.draw(|frame| { frame.render_stateful_widget(AppWidget, frame.area(), self); diff --git a/src/events.rs b/src/events.rs index 7aedea0..bca3581 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,6 +1,7 @@ use crossterm::event::{Event as CrosstermEvent, EventStream, KeyEvent, KeyEventKind}; use futures::{Stream, StreamExt}; use std::{pin::Pin, time::Duration}; +use tokio::sync::mpsc; use tokio::time::interval; use tokio_stream::{wrappers::IntervalStream, StreamMap}; @@ -12,8 +13,9 @@ enum StreamKey { Render, Crossterm, } + #[derive(Clone, Debug)] -pub enum Event { +pub enum TuiEvent { Error, Tick, Render, @@ -21,8 +23,17 @@ pub enum Event { Resize, } +#[derive(Clone, Debug)] +pub enum AppEvent { + ClockDone, +} + +pub type AppEventTx = mpsc::UnboundedSender; +pub type AppEventRx = mpsc::UnboundedReceiver; + pub struct Events { - streams: StreamMap>>>, + streams: StreamMap>>>, + app_channel: (AppEventTx, AppEventRx), } impl Default for Events { @@ -33,31 +44,46 @@ impl Default for Events { (StreamKey::Render, render_stream()), (StreamKey::Crossterm, crossterm_stream()), ]), + app_channel: mpsc::unbounded_channel(), } } } +pub enum Event { + Terminal(TuiEvent), + App(AppEvent), +} + impl Events { pub fn new() -> Self { Self::default() } pub async fn next(&mut self) -> Option { - self.streams.next().await.map(|(_, event)| event) + let streams = &mut self.streams; + let app_rx = &mut self.app_channel.1; + tokio::select! { + Some((_, event)) = streams.next() => Some(Event::Terminal(event)), + Some(app_event) = app_rx.recv() => Some(Event::App(app_event)), + } + } + + pub fn get_app_event_tx(&self) -> AppEventTx { + self.app_channel.0.clone() } } -fn tick_stream() -> Pin>> { +fn tick_stream() -> Pin>> { let tick_interval = interval(Duration::from_millis(TICK_VALUE_MS)); - Box::pin(IntervalStream::new(tick_interval).map(|_| Event::Tick)) + Box::pin(IntervalStream::new(tick_interval).map(|_| TuiEvent::Tick)) } -fn render_stream() -> Pin>> { +fn render_stream() -> Pin>> { let render_interval = interval(Duration::from_millis(FPS_VALUE_MS)); - Box::pin(IntervalStream::new(render_interval).map(|_| Event::Render)) + Box::pin(IntervalStream::new(render_interval).map(|_| TuiEvent::Render)) } -fn crossterm_stream() -> Pin>> { +fn crossterm_stream() -> Pin>> { Box::pin( EventStream::new() .fuse() @@ -65,16 +91,16 @@ fn crossterm_stream() -> Pin>> { .filter_map(|event| async move { match event { Ok(CrosstermEvent::Key(key)) if key.kind == KeyEventKind::Press => { - Some(Event::Key(key)) + Some(TuiEvent::Key(key)) } - Ok(CrosstermEvent::Resize(_, _)) => Some(Event::Resize), - Err(_) => Some(Event::Error), + Ok(CrosstermEvent::Resize(_, _)) => Some(TuiEvent::Resize), + Err(_) => Some(TuiEvent::Error), _ => None, } }), ) } -pub trait EventHandler { - fn update(&mut self, _: Event) -> Option; +pub trait TuiEventHandler { + fn update(&mut self, _: TuiEvent) -> Option; } diff --git a/src/main.rs b/src/main.rs index dc04cc3..4b48255 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ mod terminal; mod utils; mod widgets; -use app::{App, AppArgs}; +use app::{App, FromAppArgs}; use args::Args; use clap::Parser; use color_eyre::Result; @@ -30,7 +30,7 @@ async fn main() -> Result<()> { // get args given by CLI let args = Args::parse(); - let terminal = terminal::setup()?; + let mut terminal = terminal::setup()?; let events = events::Events::new(); // check persistant storage @@ -42,9 +42,14 @@ async fn main() -> Result<()> { storage.load().unwrap_or_default() }; - // merge `Args` and `AppStorage`. - let app_args = AppArgs::from((args, stg)); - let app_storage = App::new(app_args).run(terminal, events).await?.to_storage(); + let app_storage = App::from(FromAppArgs { + args, + stg, + app_tx: events.get_app_event_tx(), + }) + .run(&mut terminal, events) + .await? + .to_storage(); // store app state persistantly storage.save(app_storage)?; diff --git a/src/sound.rs b/src/sound.rs new file mode 100644 index 0000000..c1afef9 --- /dev/null +++ b/src/sound.rs @@ -0,0 +1,29 @@ +use rodio::{Decoder, OutputStream, Sink}; +use std::fs; + +pub struct Sound { + sound_data: Vec, +} + +impl Sound { + pub fn new(path: &str) -> Result { + let sound_data = fs::read(path).map_err(|e| format!("Failed to read sound file: {}", e))?; + Ok(Self { sound_data }) + } + + pub fn play(&self) -> Result<(), String> { + let (_stream, stream_handle) = OutputStream::try_default() + .map_err(|e| format!("Failed to get audio output: {}", e))?; + + let sink = Sink::try_new(&stream_handle) + .map_err(|e| format!("Failed to create audio sink: {}", e))?; + + let cursor = std::io::Cursor::new(self.sound_data.clone()); + let source = Decoder::new(cursor).map_err(|e| format!("Failed to decode audio: {}", e))?; + + sink.append(source); + sink.sleep_until_end(); + + Ok(()) + } +} diff --git a/src/widgets/clock.rs b/src/widgets/clock.rs index d2e160d..0e12f4c 100644 --- a/src/widgets/clock.rs +++ b/src/widgets/clock.rs @@ -12,6 +12,7 @@ use ratatui::{ use crate::{ common::Style, duration::{DurationEx, MAX_DURATION, ONE_DECI_SECOND, ONE_HOUR, ONE_MINUTE, ONE_SECOND}, + events::{AppEvent, AppEventTx}, utils::center_horizontal, widgets::clock_elements::{ Colon, Digit, Dot, COLON_WIDTH, DIGIT_HEIGHT, DIGIT_SPACE_WIDTH, DIGIT_WIDTH, DOT_WIDTH, @@ -73,6 +74,7 @@ pub struct ClockState { format: Format, pub with_decis: bool, on_done: Option>, + app_tx: Option, phantom: PhantomData, } @@ -81,6 +83,7 @@ pub struct ClockStateArgs { pub current_value: Duration, pub tick_value: Duration, pub with_decis: bool, + pub app_tx: Option, } impl ClockState { @@ -329,6 +332,9 @@ impl ClockState { if let Some(handler) = &mut self.on_done { handler(); }; + if let Some(tx) = &mut self.app_tx { + _ = tx.send(AppEvent::ClockDone); + }; } } @@ -363,6 +369,7 @@ impl ClockState { current_value, tick_value, with_decis, + app_tx, } = args; let mut instance = Self { initial_value: initial_value.into(), @@ -378,6 +385,7 @@ impl ClockState { format: Format::S, with_decis, on_done: None, + app_tx, phantom: PhantomData, }; // update format once @@ -432,6 +440,7 @@ impl ClockState { current_value, tick_value, with_decis, + app_tx, } = args; let mut instance = Self { initial_value: initial_value.into(), @@ -447,6 +456,7 @@ impl ClockState { format: Format::S, with_decis, on_done: None, + app_tx, phantom: PhantomData, }; // update format once diff --git a/src/widgets/clock_test.rs b/src/widgets/clock_test.rs index 3054554..4a0178f 100644 --- a/src/widgets/clock_test.rs +++ b/src/widgets/clock_test.rs @@ -11,6 +11,7 @@ fn test_toggle_edit() { current_value: ONE_HOUR, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // off by default assert!(!c.is_edit_mode()); @@ -29,6 +30,7 @@ fn test_default_edit_mode_hhmmss() { current_value: ONE_HOUR, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on @@ -43,6 +45,7 @@ fn test_default_edit_mode_mmss() { current_value: ONE_MINUTE, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on c.toggle_edit(); @@ -56,6 +59,7 @@ fn test_default_edit_mode_ss() { current_value: ONE_SECOND, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on c.toggle_edit(); @@ -69,6 +73,7 @@ fn test_edit_next_hhmmssd() { current_value: ONE_HOUR, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on @@ -90,6 +95,7 @@ fn test_edit_next_hhmmss() { current_value: ONE_HOUR, tick_value: ONE_DECI_SECOND, with_decis: false, + app_tx: None, }); // toggle on @@ -109,6 +115,7 @@ fn test_edit_next_mmssd() { current_value: ONE_MINUTE, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on @@ -128,6 +135,7 @@ fn test_edit_next_mmss() { current_value: ONE_MINUTE, tick_value: ONE_DECI_SECOND, with_decis: false, + app_tx: None, }); // toggle on @@ -145,6 +153,7 @@ fn test_edit_next_ssd() { current_value: ONE_SECOND * 3, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on @@ -160,6 +169,7 @@ fn test_edit_next_ss() { current_value: ONE_SECOND * 3, tick_value: ONE_DECI_SECOND, with_decis: false, + app_tx: None, }); // toggle on @@ -176,6 +186,7 @@ fn test_edit_prev_hhmmssd() { current_value: ONE_HOUR, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on @@ -196,6 +207,7 @@ fn test_edit_prev_hhmmss() { current_value: ONE_HOUR, tick_value: ONE_DECI_SECOND, with_decis: false, + app_tx: None, }); // toggle on @@ -214,6 +226,7 @@ fn test_edit_prev_mmssd() { current_value: ONE_MINUTE, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on @@ -234,6 +247,7 @@ fn test_edit_prev_mmss() { current_value: ONE_MINUTE, tick_value: ONE_DECI_SECOND, with_decis: false, + app_tx: None, }); // toggle on @@ -252,6 +266,7 @@ fn test_edit_prev_ssd() { current_value: ONE_SECOND, tick_value: ONE_DECI_SECOND, with_decis: true, + app_tx: None, }); // toggle on @@ -270,6 +285,7 @@ fn test_edit_prev_ss() { current_value: ONE_SECOND, tick_value: ONE_DECI_SECOND, with_decis: false, + app_tx: None, }); // toggle on @@ -285,7 +301,8 @@ fn test_edit_up_ss() { initial_value: Duration::ZERO, current_value: Duration::ZERO, tick_value: ONE_DECI_SECOND, - with_decis: false, + with_decis: true, + app_tx: None, }); // toggle on @@ -301,7 +318,8 @@ fn test_edit_up_mmss() { initial_value: Duration::ZERO, current_value: Duration::from_secs(60), tick_value: ONE_DECI_SECOND, - with_decis: false, + with_decis: true, + app_tx: None, }); // toggle on @@ -320,7 +338,8 @@ fn test_edit_up_hhmmss() { initial_value: Duration::ZERO, current_value: Duration::from_secs(3600), tick_value: ONE_DECI_SECOND, - with_decis: false, + with_decis: true, + app_tx: None, }); // toggle on @@ -341,7 +360,8 @@ fn test_edit_down_ss() { initial_value: Duration::ZERO, current_value: ONE_SECOND, tick_value: ONE_DECI_SECOND, - with_decis: false, + with_decis: true, + app_tx: None, }); // toggle on @@ -361,7 +381,8 @@ fn test_edit_down_mmss() { initial_value: Duration::ZERO, current_value: Duration::from_secs(120), tick_value: ONE_DECI_SECOND, - with_decis: false, + with_decis: true, + app_tx: None, }); // toggle on @@ -383,7 +404,8 @@ fn test_edit_down_hhmmss() { initial_value: Duration::ZERO, current_value: Duration::from_secs(3600), tick_value: ONE_DECI_SECOND, - with_decis: false, + with_decis: true, + app_tx: None, }); // toggle on diff --git a/src/widgets/countdown.rs b/src/widgets/countdown.rs index f341746..e560c11 100644 --- a/src/widgets/countdown.rs +++ b/src/widgets/countdown.rs @@ -2,11 +2,11 @@ use crate::{ common::{AppTime, Style}, constants::TICK_VALUE_MS, duration::{DurationEx, MAX_DURATION}, - events::{Event, EventHandler}, + events::{AppEventTx, TuiEvent, TuiEventHandler}, utils::center, widgets::{ clock::{self, ClockState, ClockStateArgs, ClockWidget, Mode as ClockMode}, - edit_time::EditTimeState, + edit_time::{EditTimeState, EditTimeStateArgs, EditTimeWidget}, }, }; @@ -25,8 +25,6 @@ use std::ops::Sub; use std::{cmp::max, time::Duration}; use time::OffsetDateTime; -use super::edit_time::{EditTimeStateArgs, EditTimeWidget}; - pub struct CountdownStateArgs { pub initial_value: Duration, pub current_value: Duration, @@ -34,6 +32,7 @@ pub struct CountdownStateArgs { pub app_time: AppTime, pub with_decis: bool, pub with_notification: bool, + pub app_tx: AppEventTx, } /// State for Countdown Widget @@ -56,6 +55,7 @@ impl CountdownState { with_notification, with_decis, app_time, + app_tx, } = args; Self { @@ -64,6 +64,7 @@ impl CountdownState { current_value, tick_value: Duration::from_millis(TICK_VALUE_MS), with_decis, + app_tx: Some(app_tx.clone()), }) .with_on_done_by_condition(with_notification, || { debug!("on_done COUNTDOWN"); @@ -79,6 +80,7 @@ impl CountdownState { current_value: elapsed_value, tick_value: Duration::from_millis(TICK_VALUE_MS), with_decis: false, + app_tx: None, }) // A previous `elapsed_value > 0` means the `Clock` was running before, // but not in `Initial` state anymore. Updating `Mode` here @@ -154,12 +156,12 @@ impl CountdownState { } } -impl EventHandler for CountdownState { - fn update(&mut self, event: Event) -> Option { +impl TuiEventHandler for CountdownState { + fn update(&mut self, event: TuiEvent) -> Option { let is_edit_clock = self.clock.is_edit_mode(); let is_edit_time = self.edit_time.is_some(); match event { - Event::Tick => { + TuiEvent::Tick => { if !self.clock.is_done() { self.clock.tick(); } else { @@ -175,7 +177,7 @@ impl EventHandler for CountdownState { edit_time.set_max_time(max_time); } } - Event::Key(key) => match key.code { + TuiEvent::Key(key) => match key.code { KeyCode::Char('r') => { // reset both clocks to use intial values self.clock.reset(); diff --git a/src/widgets/pomodoro.rs b/src/widgets/pomodoro.rs index 036bd25..9d3feb9 100644 --- a/src/widgets/pomodoro.rs +++ b/src/widgets/pomodoro.rs @@ -1,7 +1,7 @@ use crate::{ common::Style, constants::TICK_VALUE_MS, - events::{Event, EventHandler}, + events::{AppEventTx, TuiEvent, TuiEventHandler}, utils::center, widgets::clock::{ClockState, ClockStateArgs, ClockWidget, Countdown}, }; @@ -57,6 +57,7 @@ pub struct PomodoroStateArgs { pub current_value_pause: Duration, pub with_decis: bool, pub with_notification: bool, + pub app_tx: AppEventTx, } impl PomodoroState { @@ -69,6 +70,7 @@ impl PomodoroState { current_value_pause, with_decis, with_notification, + app_tx, } = args; Self { mode, @@ -78,6 +80,7 @@ impl PomodoroState { current_value: current_value_work, tick_value: Duration::from_millis(TICK_VALUE_MS), with_decis, + app_tx: Some(app_tx.clone()), }) .with_on_done_by_condition(with_notification, || { debug!("on_done WORK"); @@ -93,6 +96,7 @@ impl PomodoroState { current_value: current_value_pause, tick_value: Duration::from_millis(TICK_VALUE_MS), with_decis, + app_tx: Some(app_tx), }) .with_on_done_by_condition(with_notification, || { debug!("on_done PAUSE"); @@ -140,14 +144,14 @@ impl PomodoroState { } } -impl EventHandler for PomodoroState { - fn update(&mut self, event: Event) -> Option { +impl TuiEventHandler for PomodoroState { + fn update(&mut self, event: TuiEvent) -> Option { let edit_mode = self.get_clock().is_edit_mode(); match event { - Event::Tick => { + TuiEvent::Tick => { self.get_clock_mut().tick(); } - Event::Key(key) => match key.code { + TuiEvent::Key(key) => match key.code { KeyCode::Char('s') => { self.get_clock_mut().toggle_pause(); } diff --git a/src/widgets/timer.rs b/src/widgets/timer.rs index 8149149..9d08950 100644 --- a/src/widgets/timer.rs +++ b/src/widgets/timer.rs @@ -1,6 +1,6 @@ use crate::{ common::Style, - events::{Event, EventHandler}, + events::{TuiEvent, TuiEventHandler}, utils::center, widgets::clock::{self, ClockState, ClockWidget}, }; @@ -31,14 +31,14 @@ impl TimerState { } } -impl EventHandler for TimerState { - fn update(&mut self, event: Event) -> Option { +impl TuiEventHandler for TimerState { + fn update(&mut self, event: TuiEvent) -> Option { let edit_mode = self.clock.is_edit_mode(); match event { - Event::Tick => { + TuiEvent::Tick => { self.clock.tick(); } - Event::Key(key) => match key.code { + TuiEvent::Key(key) => match key.code { KeyCode::Char('s') => { self.clock.toggle_pause(); }