add sync, ui stuff
This commit is contained in:
parent
23f912d845
commit
f30ef8b06c
58
src/ui.rs
58
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<UiCommandDispatchActions>, executor_dispatch: tokio::sync::mpsc::UnboundedSender<BackendEvent>) {
|
||||
fn start_backend(
|
||||
db_name: &str,
|
||||
app_recv: std::sync::mpsc::Receiver<UiCommandDispatchActions>,
|
||||
executor_dispatch: tokio::sync::mpsc::UnboundedSender<BackendEvent>,
|
||||
) {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user