pub mod app;
pub mod event;
pub mod handler;
pub mod home_fetch;
pub mod render;
pub mod views;
pub mod widgets;
pub mod wizard;
use anyhow::Result;
use crossterm::{
event::{DisableMouseCapture, EnableMouseCapture},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::prelude::*;
use crate::config::manager::ConfigManager;
use crate::model::loader::Models;
use self::app::App;
use self::event::{Event, EventLoop};
struct TerminalGuard;
impl Drop for TerminalGuard {
fn drop(&mut self) {
let _ = disable_raw_mode();
let _ = execute!(std::io::stdout(), LeaveAlternateScreen, DisableMouseCapture);
}
}
pub async fn run(models: Models, config_mgr: ConfigManager) -> Result<()> {
enable_raw_mode()?;
let mut stdout = std::io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let _guard = TerminalGuard;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut app = App::new(models, config_mgr);
if app.auth.is_signed_in() {
app.spawn_home_counts_fetch();
}
let event_loop = EventLoop::new(250);
let result = run_loop(&mut terminal, &mut app, &event_loop);
let _ = terminal.show_cursor();
result
}
fn run_loop(
terminal: &mut Terminal<CrosstermBackend<std::io::Stdout>>,
app: &mut App,
event_loop: &EventLoop,
) -> Result<()> {
loop {
terminal.draw(|frame| render::render(frame, app))?;
while let Ok(msg) = app.msg_rx.try_recv() {
handler::handle_wizard_msg(app, msg);
}
while let Ok(msg) = app.home_rx.try_recv() {
app.apply_home_msg(msg);
}
match event_loop.next()? {
Event::Key(key) => {
handler::handle_key(app, key);
}
Event::Tick | Event::Resize(_, _) => {
if app.auth.is_signed_in() && app.home_counts_refresh_due() {
app.spawn_home_counts_fetch();
}
}
}
if app.should_quit {
handler::cancel_wizard(app);
app.abort_home_counts_fetch();
break;
}
}
Ok(())
}