feat(app): keyboard event handling with panel switching and CRUD
- App struct with full state (lists, tasks, focus, popups, DB) - Tab cycles focus: Tabs -> TaskList -> Detail -> Tabs - Left/Right arrows switch lists when focus on Tabs - Up/Down navigate tasks (TaskList) or scroll (Detail) - Alt+Up/Down reorder tasks with position persistence - n: create new list or task, d: delete, e: edit title - Enter on Detail opens DatePicker popup - InputPopup with full text editing (navigation, insert, delete) - ConfirmDelete popup before destructive actions - DatePicker adjusts draft_date with Up/Down - main.rs: terminal setup, event loop, raw mode, alternate screen
This commit is contained in:
+59
-3
@@ -1,7 +1,63 @@
|
||||
mod app;
|
||||
mod domain;
|
||||
mod ui;
|
||||
mod infrastructure;
|
||||
mod ui;
|
||||
|
||||
fn main() {
|
||||
println!("Task App - Google Tasks TUI");
|
||||
use std::io;
|
||||
|
||||
use crossterm::event::{self, Event};
|
||||
use crossterm::terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen};
|
||||
use crossterm::ExecutableCommand;
|
||||
use ratatui::backend::CrosstermBackend;
|
||||
use ratatui::Terminal;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::infrastructure::db::Db;
|
||||
use crate::ui::{draw, AppView};
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let db_path = dirs::data_dir()
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("."))
|
||||
.join("task_app")
|
||||
.join("tasks.db");
|
||||
|
||||
std::fs::create_dir_all(db_path.parent().unwrap()).ok();
|
||||
|
||||
let db = Db::new(db_path.to_str().unwrap()).expect("Failed to open database");
|
||||
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = io::stdout();
|
||||
stdout.execute(EnterAlternateScreen)?;
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
let mut app = App::new(db);
|
||||
|
||||
while !app.should_quit {
|
||||
terminal.draw(|frame| {
|
||||
let view = AppView {
|
||||
lists: &app.lists,
|
||||
tasks: &app.tasks,
|
||||
selected_list: app.selected_list,
|
||||
selected_task: app.selected_task,
|
||||
focus: app.focus.clone(),
|
||||
show_popup: app.show_popup.as_ref(),
|
||||
popup_input: &app.popup_input,
|
||||
popup_cursor: app.popup_cursor,
|
||||
draft_date: app.draft_date,
|
||||
network_status: &app.network_status,
|
||||
task_list_scroll: app.task_list_scroll,
|
||||
detail_scroll: app.detail_scroll,
|
||||
};
|
||||
draw(frame, view);
|
||||
})?;
|
||||
|
||||
if let Event::Key(key) = event::read()? {
|
||||
app.handle_key(key);
|
||||
}
|
||||
}
|
||||
|
||||
disable_raw_mode()?;
|
||||
io::stdout().execute(LeaveAlternateScreen)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user