Expanded TUI: Lemmy Info + Post History

This commit is contained in:
Neshura 2023-06-27 00:33:00 +02:00
parent 877c7ef324
commit 007570c2e3
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
2 changed files with 60 additions and 39 deletions

View file

@ -144,6 +144,7 @@ impl Config {
post_history[idx].last_post_url = item.url.clone(); post_history[idx].last_post_url = item.url.clone();
} }
None => post_history.push(PrevPost { None => post_history.push(PrevPost {
id: feed.id,
title: data.title, title: data.title,
last_post_url: item.url.clone(), last_post_url: item.url.clone(),
}), }),
@ -163,6 +164,7 @@ pub_struct!(RedditConfig {
}); });
pub_struct!(FeedSetting { pub_struct!(FeedSetting {
id: usize,
feed_url: String, feed_url: String,
communities: FeedCommunities, communities: FeedCommunities,
reddit: FeedRedditSettings, reddit: FeedRedditSettings,
@ -190,6 +192,7 @@ pub_struct!(FeedRedditSettings {
// Posts structs // Posts structs
pub_struct!(PrevPost { pub_struct!(PrevPost {
id: usize,
title: String, title: String,
last_post_url: String, last_post_url: String,
}); });

View file

@ -10,9 +10,9 @@ use lemmy_db_schema::{
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use reqwest::{blocking::Client, StatusCode}; use reqwest::{blocking::Client, StatusCode};
use tui::{backend::{CrosstermBackend, Backend}, Terminal, widgets::{Block, Borders, Cell, Row, Table}, layout::{Layout, Constraint, Direction}, Frame, style::{Style, Modifier, Color}}; use tui::{backend::{CrosstermBackend, Backend}, Terminal, widgets::{Block, Borders, Cell, Row, Table, Paragraph, Wrap}, layout::{Layout, Constraint, Direction, Alignment}, Frame, style::{Style, Modifier, Color}, text::{Span, Spans}};
use crossterm::{event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},}; use crossterm::{event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},};
use std::{thread::{sleep, self}, time::{self, Duration}, io}; use std::{thread::{sleep, self}, time::{self, Duration}, io, vec};
mod config; mod config;
@ -94,12 +94,13 @@ impl Bot {
println!("Posting: {}", post.name); println!("Posting: {}", post.name);
self.post(post.clone()); self.post(post.clone());
}); });
}
pub(crate) fn idle(&self) {
while Utc::now().time() - self.start_time.time() < chrono::Duration::seconds(60) { while Utc::now().time() - self.start_time.time() < chrono::Duration::seconds(60) {
sleep(time::Duration::from_secs(10)); sleep(time::Duration::from_secs(10));
} }
}
}
} }
fn list_posts(auth: &Sensitive<String>, base: String) -> GetPostsResponse { fn list_posts(auth: &Sensitive<String>, base: String) -> GetPostsResponse {
@ -121,55 +122,85 @@ fn list_posts(auth: &Sensitive<String>, base: String) -> GetPostsResponse {
return serde_json::from_str(&res).unwrap(); return serde_json::from_str(&res).unwrap();
} }
fn run_bot() { fn run_bot(mut terminal: Terminal<CrosstermBackend<&io::Stdout>>) {
// Get all needed auth tokens at the start // Get all needed auth tokens at the start
let mut old = Utc::now().time(); let mut old = Utc::now().time();
let mut this = Bot::new(); let mut this = Bot::new();
println!("{}", this.secrets.lemmy.username);
this.login(); this.login();
this.community_ids.load(&this.auth, &this.config.instance); this.community_ids.load(&this.auth, &this.config.instance);
// Create empty eTag list
println!("TODO: Etag list");
// Enter a loop (not for debugging) // Enter a loop (not for debugging)
loop { loop {
this.run_once(old); this.run_once(old);
// Update UI
terminal.draw(|f| {
ui(f, &this);
}).unwrap();
thread::sleep(Duration::from_secs(5));
disable_raw_mode().unwrap();
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
).unwrap();
terminal.show_cursor().unwrap();
this.idle();
} }
} }
fn ui<B: Backend>(f: &mut Frame<B>) { fn ui<B: Backend>(f: &mut Frame<B>, state: &Bot) {
let chunks = Layout::default() let chunks = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(1) .margin(1)
.constraints( .constraints(
[ [
Constraint::Percentage(10), Constraint::Percentage(15),
Constraint::Percentage(90), Constraint::Percentage(90),
].as_ref() ].as_ref()
) )
.split(f.size()); .split(f.size());
// Account Infos
let block = Block::default() let account_info = vec![
.title("Block") Row::new(vec![
.borders(Borders::ALL); Cell::from(format!("Lemmy Username: {} |", state.secrets.lemmy.username)),
Cell::from(format!("Lemmy Instance: {} |", state.config.instance))
])
];
let block = Table::new(account_info)
.block(Block::default().title("Account info").borders(Borders::ALL))
.widths(&[
Constraint::Percentage(15),
Constraint::Percentage(20),
Constraint::Percentage(20),
Constraint::Percentage(20),
Constraint::Percentage(20),
]);
f.render_widget(block, chunks[0]); f.render_widget(block, chunks[0]);
// Post Table
let selected_style = Style::default().add_modifier(Modifier::REVERSED); let selected_style = Style::default().add_modifier(Modifier::REVERSED);
let normal_style = Style::default().bg(Color::Blue); let normal_style = Style::default().bg(Color::Blue);
let header_cells = ["Series", "Community", "Last Post"] let header_cells = ["Series", "Community", "Reddit", "Discord", "Last Post"]
.iter() .iter()
.map(|h| Cell::from(*h).style(Style::default().fg(Color::Red))); .map(|h| Cell::from(*h).style(Style::default().fg(Color::Red)));
let header = Row::new(header_cells) let header = Row::new(header_cells)
.style(normal_style) .style(normal_style)
.height(1) .height(1)
.bottom_margin(1); .bottom_margin(1);
let rows = [ let rows = state.post_history.iter().map(|post| {
Row::new([Cell::from("a1"), Cell::from("a2"), Cell::from("a3")]).height(1 as u16).bottom_margin(1), let config = &state.config.feeds[post.id];
Row::new([Cell::from("b1"), Cell::from("b2"), Cell::from("b3")]).height(1 as u16).bottom_margin(1), Row::new([Cell::from(post.title.clone()), Cell::from(format!("{}", config.communities.chapter)), Cell::from(format!("{}", config.reddit.enabled as u8)), Cell::from("0"), Cell::from(post.last_post_url.clone())]).height(1 as u16).bottom_margin(1)
Row::new([Cell::from("unicorn"), Cell::from("c2"), Cell::from("c3")]).height(2 as u16).bottom_margin(1) });
];
let t = Table::new(rows) let t = Table::new(rows)
.header(header) .header(header)
@ -177,9 +208,11 @@ fn ui<B: Backend>(f: &mut Frame<B>) {
.highlight_style(selected_style) .highlight_style(selected_style)
.highlight_symbol(">> ") .highlight_symbol(">> ")
.widths(&[ .widths(&[
Constraint::Percentage(30),
Constraint::Percentage(10),
Constraint::Percentage(5),
Constraint::Percentage(5),
Constraint::Percentage(50), Constraint::Percentage(50),
Constraint::Length(30),
Constraint::Min(10),
]); ]);
f.render_widget(t, chunks[1]); f.render_widget(t, chunks[1]);
} }
@ -187,23 +220,8 @@ fn ui<B: Backend>(f: &mut Frame<B>) {
fn main() -> Result<(), io::Error> { fn main() -> Result<(), io::Error> {
let stdout = io::stdout(); let stdout = io::stdout();
let backend = CrosstermBackend::new(&stdout); let backend = CrosstermBackend::new(&stdout);
let mut terminal = Terminal::new(backend)?; let terminal = Terminal::new(backend)?;
terminal.draw(|f| { run_bot(terminal);
ui(f);
})?;
thread::sleep(Duration::from_secs(5));
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
run_bot();
Ok(()) Ok(())
} }