diff --git a/src/ui.rs b/src/ui.rs index 99399ff..8881b84 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -9,7 +9,7 @@ pub mod title; use std::{ io::Stdout, sync::mpsc::{channel, Receiver, Sender}, - thread, + thread, time::Duration, }; use crate::{ @@ -136,23 +136,54 @@ fn draw(app_state: &AppState, terminal: &mut Terminal>) Ok(()) } +pub enum Event { + UserInput(crossterm::event::Event), + ReloadState, + Tick, +} + fn handle_events(state: &mut AppState, ctx: &TrsEnv) -> Result<()> { - let recv_action = state.receiver.try_recv(); + let event = get_event(state)?; + match event { + Event::UserInput(event) => { + handle_user_input(state, event)?; + } + Event::ReloadState => { + let channels = commands::list_channels(&ctx, &ListChannelArgs { limit: None })?; + state.channels = channels; + } + Event::Tick => {} + }; - if let Ok(_) = recv_action { - let channels = commands::list_channels(&ctx, &ListChannelArgs { limit: None })?; - state.channels = channels; - } + Ok(()) +} - let raw_event = event::read().map_err(|e| TrsError::TuiError(e))?; +fn handle_user_input(state: &mut AppState, event: event::Event) -> Result<()> { if state.show_add_channel_ui { - let event = controls::parse_popup_ui_action(raw_event); - return actions::handle_popup_action(state, event); + let popup_ui_action = controls::parse_popup_ui_action(event); + actions::handle_popup_action(state, popup_ui_action)?; + return Ok(()); } - let event = controls::parse_ui_action(raw_event); - state.last_action = Some(event.clone()); - actions::handle_action(state, event) + let ui_action = controls::parse_ui_action(event); + state.last_action = Some(ui_action.clone()); + actions::handle_action(state, ui_action)?; + return Ok(()); +} + +fn get_event(state: &mut AppState) -> Result { + let recv_action = state.receiver.try_recv(); + if let Ok(_) = recv_action { + return Ok(Event::ReloadState); + } + + let raw_event = event::poll(Duration::from_millis(250)).map_err(|e| TrsError::TuiError(e))?; + if raw_event == false { + return Ok(Event::Tick); + } + + // It's guaranteed that an event is available now + Ok(Event::UserInput(event::read().unwrap())) } struct AppStateWidget<'a> { diff --git a/src/ui/actions.rs b/src/ui/actions.rs index 93be2a6..4e3b19d 100644 --- a/src/ui/actions.rs +++ b/src/ui/actions.rs @@ -60,13 +60,12 @@ pub fn handle_action( .unwrap(); } UiAction::ToggleReadStatus => { - let article = get_highlighted_article_mut(app_state); + let article = get_highlighted_article(app_state); let mut article_id = None; let mut unread = None; if let Some(article) = article { - article.unread = !article.unread; + unread = Some(!article.unread); article_id = Some(article.id); - unread = Some(article.unread); } if let Some(article_id) = article_id { @@ -143,16 +142,10 @@ fn get_highlighted_channel<'a>(app_state: &'a AppState) -> Option<&'a RssChannel .and_then(|idx| app_state.channels.get(idx).or_else(|| None)) } -fn get_highlighted_channel_mut<'a>(app_state: &'a mut AppState) -> Option<&'a mut RssChannelD> { - app_state - .highlighted_channel - .and_then(|idx| app_state.channels.get_mut(idx).or_else(|| None)) -} - -fn get_highlighted_article_mut<'a>(app_state: &'a mut AppState) -> Option<&'a mut RssArticleD> { +fn get_highlighted_article<'a>(app_state: &'a AppState) -> Option<&'a RssArticleD> { let hi_article = app_state.highlighted_article?; - let channel = get_highlighted_channel_mut(app_state)?; - channel.articles.get_mut(hi_article) + let channel = get_highlighted_channel(app_state)?; + channel.articles.get(hi_article) } fn focus_entry_up(app_state: &mut AppState) { diff --git a/src/ui/title.rs b/src/ui/title.rs index 4527863..55ccd4f 100644 --- a/src/ui/title.rs +++ b/src/ui/title.rs @@ -9,7 +9,7 @@ pub struct TitleWidget; impl Widget for TitleWidget { fn render(self, area: Rect, buf: &mut Buffer) { - let title = "Terminal RSS Reader"; + let title = "Terminal RSS Manager"; let areas = Layout::default() .constraints(Constraint::from_ratios([(1, 3), (1, 3), (1, 3)])) .split(area)