mod app;
mod config;
mod cursor;
mod dashboard;
mod db;
mod integrations;
mod models;
mod passphrase;
mod settings;
mod tasks;
mod termcolor;
mod triggers;
mod ui;
mod update_check;
mod whats_new;
use anyhow::Result;
use crossterm::{
event::{
self, DisableMouseCapture, EnableMouseCapture, Event, KeyEventKind,
KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
},
execute,
terminal::{
disable_raw_mode, enable_raw_mode, supports_keyboard_enhancement, EnterAlternateScreen,
LeaveAlternateScreen,
},
};
use ratatui::{backend::CrosstermBackend, Terminal};
use std::io;
use std::time::Duration;
use app::App;
fn main() -> Result<()> {
enable_raw_mode()?;
let term_palette = termcolor::query_palette();
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let keyboard_enhanced = matches!(supports_keyboard_enhancement(), Ok(true));
if keyboard_enhanced {
execute!(
stdout,
PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
)?;
}
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let db_path = dirs::home_dir()
.unwrap_or_else(|| std::path::PathBuf::from("."))
.join(".timetrack.db");
let mut app = App::new(db_path.to_str().unwrap())?;
app.term_palette = term_palette;
app.available_update = update_check::spawn_check();
if app.secrets.has_encrypted_file() {
app.input_mode = app::InputMode::PassphrasePrompt {
passphrase: String::new(),
cursor_pos: 0,
error_message: None,
confirm_delete: false,
};
} else {
app.check_version()?;
}
let res = run_app(&mut terminal, &mut app);
disable_raw_mode()?;
if keyboard_enhanced {
execute!(terminal.backend_mut(), PopKeyboardEnhancementFlags)?;
}
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
if let Err(err) = res {
println!("Error: {:?}", err);
}
Ok(())
}
fn run_app<B: ratatui::backend::Backend>(terminal: &mut Terminal<B>, app: &mut App) -> Result<()> {
loop {
let _ = app.tick();
terminal.draw(|f| dashboard::draw_dashboard(f, app))?;
if event::poll(Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
if key.kind != KeyEventKind::Press {
continue;
}
let should_quit = dashboard::handle_input(app, key)?;
if should_quit {
return Ok(());
}
}
}
}
}