tododo 0.1.2

A minimal terminal todo manager built with Rust and Ratatui
Documentation
use ratatui::crossterm::event::KeyEvent;

use crate::actions::AppAction;
use crate::app::{App, Screen};

pub fn handle_screen_key(app: &mut App, key: &KeyEvent) -> Option<AppAction> {
    match app.screen {
        Screen::NoteEditor | Screen::CreateTodo => {
            let is_create = matches!(app.screen, Screen::CreateTodo);
            let input: ratatui_textarea::Input = (*key).into();

            if key.code == ratatui::crossterm::event::KeyCode::Esc {
                return if is_create {
                    Some(AppAction::CloseCreateTodo)
                } else {
                    Some(AppAction::CloseNoteEditor)
                };
            }

            if key.code == ratatui::crossterm::event::KeyCode::Char('s')
                && key
                    .modifiers
                    .contains(ratatui::crossterm::event::KeyModifiers::CONTROL)
            {
                let ta_cell = if is_create {
                    app.create_todo_editor.as_ref()
                } else {
                    app.note_editor.as_ref()
                };

                if let Some(ref ta_cell) = ta_cell {
                    let lines: Vec<String> = ta_cell.borrow().lines().to_vec();
                    let title = lines
                        .first()
                        .cloned()
                        .unwrap_or_default()
                        .trim()
                        .to_string();
                    if !title.is_empty() {
                        return if is_create {
                            let note = lines.get(1..).map(|s| s.join("\n")).unwrap_or_default();
                            Some(AppAction::CreateTodo(title, note))
                        } else if let Some(id) = app.selected_id.clone() {
                            let note = lines.get(1..).map(|s| s.join("\n")).unwrap_or_default();
                            Some(AppAction::SaveTodo(id, title, note))
                        } else {
                            None
                        };
                    }
                }
                return None;
            }

            let ta_cell = if is_create {
                app.create_todo_editor.as_ref()
            } else {
                app.note_editor.as_ref()
            };
            if let Some(ref ta_cell) = ta_cell {
                ta_cell.borrow_mut().input(input);
            }
            None
        }
        _ => None,
    }
}

pub fn translate_key(app: &mut App, key: &KeyEvent) -> Option<AppAction> {
    use ratatui::crossterm::event::KeyCode;

    match key.code {
        KeyCode::Esc => match app.screen {
            Screen::List => Some(AppAction::Quit),
            Screen::Detail => Some(AppAction::CloseDetail),
            Screen::NoteEditor => Some(AppAction::CloseNoteEditor),
            Screen::CreateTodo => Some(AppAction::CloseCreateTodo),
            Screen::DeleteConfirm => Some(AppAction::CloseDeleteConfirm),
        },
        KeyCode::Char('q') => {
            if app.screen == Screen::List {
                Some(AppAction::Quit)
            } else {
                None
            }
        }
        KeyCode::Up | KeyCode::Char('k') => {
            if app.screen == Screen::List {
                app.select_previous();
            }
            None
        }
        KeyCode::Down | KeyCode::Char('j') => {
            if app.screen == Screen::List {
                app.select_next();
            }
            None
        }
        KeyCode::Enter => {
            if app.screen == Screen::List {
                if let Some(id) = app.selected_id.clone() {
                    return Some(AppAction::OpenDetail(id));
                }
            } else if app.screen == Screen::Detail {
                return Some(AppAction::CloseDetail);
            }
            None
        }
        KeyCode::Char(' ') => {
            if app.screen == Screen::List || app.screen == Screen::Detail {
                if let Some(id) = &app.selected_id {
                    return Some(AppAction::ToggleTodo(id.clone()));
                }
            }
            None
        }
        KeyCode::Char('e') => {
            if app.screen == Screen::List || app.screen == Screen::Detail {
                if let Some(id) = &app.selected_id {
                    return Some(AppAction::EditTodo(id.clone()));
                }
            }
            None
        }
        KeyCode::Char('p') => {
            if app.screen == Screen::List || app.screen == Screen::Detail {
                if let Some(id) = &app.selected_id {
                    if let Some(todo) = app.todos.iter().find(|t| &t.id == id) {
                        let next_priority = todo.priority.next();
                        return Some(AppAction::SetPriority(
                            id.clone(),
                            next_priority.to_char().to_string(),
                        ));
                    }
                }
            }
            None
        }
        KeyCode::Char('s') => {
            if app.screen == Screen::List || app.screen == Screen::Detail {
                return Some(AppAction::ToggleSortMode);
            }
            None
        }
        KeyCode::Char('a') => {
            if app.screen == Screen::List {
                Some(AppAction::CreateTodoStart)
            } else {
                None
            }
        }
        KeyCode::Char('d') => {
            if (app.screen == Screen::List || app.screen == Screen::Detail)
                && app.selected_id.is_some()
            {
                return Some(AppAction::ShowDeleteConfirm);
            }
            None
        }
        KeyCode::Char('y') => {
            if app.screen == Screen::DeleteConfirm {
                if let Some(id) = app.selected_id.clone() {
                    return Some(AppAction::DeleteTodo(id));
                }
            }
            None
        }
        KeyCode::Char('n') => {
            if app.screen == Screen::DeleteConfirm {
                return Some(AppAction::CloseDeleteConfirm);
            }
            None
        }
        _ => None,
    }
}