diff --git a/src/ui.rs b/src/ui.rs index c6ecf92..60cc097 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -25,7 +25,7 @@ use debug::DebugWidget; use futures::{FutureExt, StreamExt}; use ratatui::{ prelude::*, - widgets::{Block, Borders}, + widgets::{Block, Borders, Padding}, }; use title::TitleWidget; use tokio::sync::mpsc::UnboundedReceiver; @@ -86,7 +86,6 @@ pub enum UiCommandDispatchActions { ListChannels(args::ListChannelArgs), } - /// APP /// - Listen Event /// - Publish UiCommandDispatchActions @@ -142,7 +141,11 @@ pub async fn ui(args: &UiArgs, db_name: &str) -> Result<()> { Ok(()) } -fn start_backend(db_name: &str, app_recv: std::sync::mpsc::Receiver, executor_dispatch: tokio::sync::mpsc::UnboundedSender) { +fn start_backend( + db_name: &str, + app_recv: std::sync::mpsc::Receiver, + executor_dispatch: tokio::sync::mpsc::UnboundedSender, +) { let db_name = db_name.to_string(); std::thread::spawn(move || { backend::start(db_name, app_recv, executor_dispatch); @@ -227,6 +230,9 @@ async fn handle_events(state: &mut AppState) -> Result<()> { Event::BackendEvent(backend_event) => match backend_event { BackendEvent::ReloadState(channels) => { state.channels = channels; + if state.highlighted_channel.is_none() && !state.channels.is_empty() { + state.highlighted_channel = Some(0); + } } }, Event::Tick => {} @@ -260,9 +266,9 @@ impl<'a> AppStateWidget<'a> { impl<'a> Widget for AppStateWidget<'a> { fn render(self, area: Rect, buf: &mut Buffer) { - let mut horizontal_constraints = vec![Constraint::Percentage(100)]; + let mut horizontal_constraints = vec![Constraint::Fill(5)]; if is_debug_mode(self.app_state) { - horizontal_constraints.push(Constraint::Percentage(20)); + horizontal_constraints.push(Constraint::Fill(1)); } // Split the area into 2 horizontal sections, one for the main app and @@ -282,24 +288,20 @@ impl<'a> Widget for AppStateWidget<'a> { let main_area_splits = Layout::default() .direction(Direction::Vertical) .constraints(vec![ - Constraint::Percentage(10), // Title - Constraint::Percentage(80), // Other app widgets - Constraint::Percentage(10), // Controls + Constraint::Percentage(100), // Channels + Articles + Constraint::Min(4), // Controls + Title ]) .split(main_area) .to_vec(); - // TITLE - let title_area = main_area_splits[0]; - draw_app_widget_styled(Block::default(), &title_area, buf, TitleWidget); - // OTHER APP WIDGETS let child_widgets_areas = Layout::default() .direction(Direction::Horizontal) - .constraints(Constraint::from_percentages(vec![30, 70])) - .split(main_area_splits[1]) + .constraints(Constraint::from_fills([4, 6])) + .split(main_area_splits[0]) .to_vec(); + // CHANNELS let channels_area = child_widgets_areas[0]; draw_app_widget_styled( get_child_widget_style( @@ -311,6 +313,7 @@ impl<'a> Widget for AppStateWidget<'a> { ChannelsWidget::new(self.app_state), ); + // ARTICLES let articles_area = child_widgets_areas[1]; draw_app_widget_styled( get_child_widget_style( @@ -322,8 +325,17 @@ impl<'a> Widget for AppStateWidget<'a> { ArticlesWidget::new(self.app_state), ); + let controls_title = Layout::default() + .direction(Direction::Horizontal) + .constraints(Constraint::from_fills([1, 7])) + .split(main_area_splits[1]); + + // TITLE + let title_area = controls_title[0]; + draw_app_widget_styled(Block::default(), &title_area, buf, TitleWidget); + // CONTROLS - let controls_area = main_area_splits[2]; + let controls_area = controls_title[1]; draw_app_widget_styled(Block::default(), &controls_area, buf, ControlsWidget); } } @@ -361,18 +373,20 @@ where fn get_child_widget_style<'a>(arg: &'a str, focussed: bool) -> Block<'a> { let title = Line::from(arg) - .centered() - .style(Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)); - + .style( + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD), + ) + .centered(); if focussed { - return Block::default() - .title_top(title) - .border_style(Style::default().fg(Color::Blue)) - .borders(Borders::ALL); + return Block::default().title_top(title).bg(Color::DarkGray); } Block::default() .title_top(title) + .fg(Color::DarkGray) + .padding(Padding::uniform(10)) .border_style(Style::default().fg(Color::DarkGray)) } diff --git a/src/ui/articles.rs b/src/ui/articles.rs index 4ec7d57..63d6ffe 100644 --- a/src/ui/articles.rs +++ b/src/ui/articles.rs @@ -3,7 +3,7 @@ use ratatui::{ layout::{Alignment, Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, text::{Line, Span}, - widgets::{Block, Borders, Paragraph, Widget}, + widgets::{Block, Paragraph, Widget}, }; use super::AppState; @@ -26,10 +26,6 @@ impl<'a> Widget for ArticlesWidget<'a> { }; let Some(channel) = selected_channel else { - let para = Paragraph::new("j/k to navigate channels, q to exit") - .block(Block::default().borders(Borders::NONE)) - .alignment(Alignment::Center); - para.render(area, buf); return; }; @@ -42,7 +38,7 @@ impl<'a> Widget for ArticlesWidget<'a> { let total_articles = channel.articles.len().min(total_articles as usize); let article_rows = Layout::default() .direction(Direction::Vertical) - .margin(1) + .margin(2) .constraints( (0..total_articles) .map(|_| Constraint::Length(height_per_entry)) @@ -94,7 +90,7 @@ fn get_article_id_style(highlighted: bool) -> Style { fn get_channel_list_item_block_style(highlighted: bool) -> Style { if highlighted { Style::default() - .bg(Color::LightYellow) + .bg(Color::White) .add_modifier(Modifier::BOLD) } else { Style::default() diff --git a/src/ui/channels.rs b/src/ui/channels.rs index c7de066..6a88f16 100644 --- a/src/ui/channels.rs +++ b/src/ui/channels.rs @@ -30,7 +30,7 @@ impl<'a> Widget for ChannelsWidget<'a> { let total_channels = self.state.channels.len().min(total_channels as usize); let channel_rows = Layout::default() .direction(Direction::Vertical) - .margin(1) + .margin(2) .constraints( (0..total_channels) .map(|_| Constraint::Length(height_per_entry)) @@ -109,7 +109,7 @@ fn get_channel_id_style(highlighted: bool) -> Style { fn get_channel_list_item_block_style(highlighted: bool) -> Style { if highlighted { Style::default() - .bg(Color::LightYellow) + .bg(Color::White) .add_modifier(Modifier::BOLD) } else { Style::default() @@ -142,11 +142,11 @@ impl<'a> Widget for AddChannelWidget<'a> { .title_top(Line::from("Add Channel").centered()) .title_style( Style::default() - .fg(Color::Blue) - .add_modifier(Modifier::BOLD | Modifier::ITALIC | Modifier::UNDERLINED), + .fg(Color::White) + .add_modifier(Modifier::BOLD | Modifier::UNDERLINED), ) .borders(ratatui::widgets::Borders::ALL) - .border_style(Style::default().fg(Color::DarkGray)); + .border_style(Style::default().fg(Color::White)); let para = Paragraph::new(Line::from(self.state)).block(block); diff --git a/src/ui/controls.rs b/src/ui/controls.rs index 4787773..ec1404f 100644 --- a/src/ui/controls.rs +++ b/src/ui/controls.rs @@ -78,7 +78,9 @@ macro_rules! control { ($key:literal) => { Span::styled( $key, - Style::default().fg(Color::Red).add_modifier(Modifier::BOLD), + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD), ) }; } @@ -91,7 +93,7 @@ macro_rules! description { impl Widget for ControlsWidget { fn render(self, area: Rect, buf: &mut Buffer) { - let controls_text = Line::from(vec![ + let controls_text_line_1 = Line::from(vec![ control!("j/k"), description!(" to navigate up/down, "), control!("h/l"), @@ -104,6 +106,14 @@ impl Widget for ControlsWidget { description!(" delete an RSS channel, "), control!("r"), description!(" toggle read state of article, "), + ]) + .style( + Style::default() + .fg(Color::DarkGray) + .add_modifier(Modifier::BOLD), + ); + + let controls_text_line_2 = Line::from(vec![ control!("q"), description!(" to exit"), ]) @@ -111,10 +121,11 @@ impl Widget for ControlsWidget { Style::default() .fg(Color::DarkGray) .add_modifier(Modifier::BOLD), - ); - let para = Paragraph::new(controls_text) + ) + .centered(); + let para = Paragraph::new(vec![controls_text_line_1, controls_text_line_2]) .block(Block::default().borders(Borders::NONE)) - .alignment(Alignment::Center); + .alignment(Alignment::Left); para.render(area, buf); } } diff --git a/src/ui/title.rs b/src/ui/title.rs index 55ccd4f..04cdd69 100644 --- a/src/ui/title.rs +++ b/src/ui/title.rs @@ -1,8 +1,8 @@ use ratatui::{ buffer::Buffer, - layout::{Alignment, Constraint, Layout, Rect}, + layout::{Alignment, Rect}, style::{Color, Modifier, Style}, - widgets::{Block, Paragraph, Widget}, + widgets::{Block, Borders, Paragraph, Widget}, }; pub struct TitleWidget; @@ -10,21 +10,13 @@ pub struct TitleWidget; impl Widget for TitleWidget { fn render(self, area: Rect, buf: &mut Buffer) { let title = "Terminal RSS Manager"; - let areas = Layout::default() - .constraints(Constraint::from_ratios([(1, 3), (1, 3), (1, 3)])) - .split(area) - .to_vec(); - let para = Paragraph::new(title).alignment(Alignment::Center).style( Style::default() - .fg(Color::Black) + .fg(Color::White) .add_modifier(Modifier::BOLD), ); - para.render(areas[1], buf); - - Block::default() - .style(Style::default().bg(Color::LightCyan)) - .render(area, buf); + para.render(area, buf); + Block::default().borders(Borders::RIGHT).render(area, buf); } }