diff --git a/src/app.rs b/src/app.rs index 93d90ea..82646ee 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::snowballing::{Publication, get_publication_by_id}; -use log::{debug, info, warn, error}; +use log::{debug, error, info, warn}; #[derive(Serialize, Deserialize, Default, PartialEq)] pub enum ActivePane { @@ -104,6 +104,8 @@ pub struct App { pub snowballing_step: SnowballingStep, + pub status_message: String, + #[serde(skip)] pub should_quit: bool, } @@ -113,6 +115,7 @@ pub struct App { // TODO: Implement possibility of pushing excluded papers back into pending // TODO: Implement export of included papers as csv for keywording with a spreadsheet // TODO: Implement export of included papers into zotero (Use RIS format somehow) +// TODO: Log everything relevant impl App { // TODO: Show error somehow pub async fn add_seed_paper(&mut self, api_link: &String) { diff --git a/src/main.rs b/src/main.rs index 4254b09..600dd20 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use log::{error, info}; use serde_json; mod app; @@ -68,7 +69,7 @@ struct Args { } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() { let args = Args::parse(); if env::var("RUST_LOG").is_err() { @@ -81,13 +82,23 @@ async fn main() -> Result<(), Box> { OpenOptions::new() .create(true) .append(true) - .open(args.logfile) + .open(&args.logfile) .unwrap(), ))) .init(); - let starting_app_state = deserialize_savefile(&args.savefile)?; + match run(&args).await { + Ok(()) => info!("Application completed successfully"), + Err(e) => { + error!("Application error: {}", e); + print!("{e:?}"); + std::process::exit(1); + } + } +} +async fn run(args: &Args) -> Result<(), Box> { + let starting_app_state = deserialize_savefile(&args.savefile)?; let final_app_state = crate::crossterm::run(starting_app_state).await?; serialize_savefile(&final_app_state, &args.savefile)?; diff --git a/src/ui.rs b/src/ui.rs index 91d469e..d7f3818 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -4,7 +4,7 @@ use crate::{ }; use ratatui::{ Frame, - layout::{Constraint, Direction, Layout, Rect}, + layout::{Constraint, Direction, Layout, Rect, VerticalAlignment}, style::{Color, Modifier, Style, Stylize}, text::{Line, Span}, widgets::{Block, Borders, List, ListItem, ListState, Paragraph}, @@ -66,12 +66,18 @@ fn draw_seeding_tab(f: &mut Frame, app: &mut App) { fn draw_snowballing_tab(f: &mut Frame, app: &mut App) { let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(25), Constraint::Percentage(75)]) + .direction(Direction::Vertical) + .constraints([Constraint::Min(2), Constraint::Length(1)]) .split(f.area()); - draw_left_pane(f, app, chunks[0]); - draw_right_pane(f, app, chunks[1]); + let content_chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Percentage(25), Constraint::Percentage(75)]) + .split(chunks[0]); + + draw_left_pane(f, app, content_chunks[0]); + draw_right_pane(f, app, content_chunks[1]); + draw_status_line(f, app, chunks[1]); } fn format_title<'a>( @@ -314,3 +320,10 @@ fn draw_right_pane(frame: &mut Frame, app: &mut App, area: Rect) { frame.render_stateful_widget(list, area, &mut app.pending_list_state); } + +fn draw_status_line(frame: &mut Frame, app: &App, area: Rect) { + let line = Paragraph::new(app.status_message.clone()) + .style(Style::default().bg(Color::Rgb(60, 56, 54))); + + frame.render_widget(line, area); +}