mod app; mod args; mod audio; mod constants; mod events; mod msg; mod notification; mod terminal; mod ui; use std::{ io::{self, stdout}, sync::mpsc, thread, time::Duration, }; use crossterm::event; use figlet_rs::Toilet; use ratatui::{Terminal, backend::CrosstermBackend}; use app::Termato; use audio::AudioVisualizer; use events::handle_event; use msg::Message; use terminal::TerminalGuard; use ui::render_app; use args::{Cli, CliAction}; use crate::constants::VIZ_NUM_BARS; fn main() -> Result<(), io::Error> { let config = match Cli::parse() { CliAction::PrintHelp => { Cli::print_help(); return Ok(()); } CliAction::PrintVersion => { Cli::print_version(); return Ok(()); } CliAction::Error(err) => { eprintln!("Error: {}", err); eprintln!("Run 'termato --help' for usage instructions."); std::process::exit(1); } CliAction::Run(cfg) => cfg, }; let _guard = TerminalGuard::new()?; let backend = CrosstermBackend::new(stdout()); let mut terminal = Terminal::new(backend)?; let font = Toilet::smblock().unwrap(); let visualizer = if config.enable_visualizer { Some(AudioVisualizer::new(VIZ_NUM_BARS as usize)) } else { None }; let mut termato = Termato::new(config.work_mins, config.break_mins) .with_notifications(config.enable_notifications); let (tx, rx) = mpsc::channel(); thread::spawn(move || { loop { thread::sleep(Duration::from_secs(1)); if tx.send(()).is_err() { break; } } }); while !termato.should_quit() { terminal.draw(|f| render_app(&termato, f, &font, visualizer.as_ref()))?; if event::poll(Duration::from_millis(16))? { let raw_event = event::read()?; if let Some(msg) = handle_event(raw_event) { termato.update(msg); } } if rx.try_recv().is_ok() { termato.update(Message::Tick); } } Ok(()) }