use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use crate::app::View; pub enum Action { Quit, NavigateUp, NavigateDown, NavigateLeft, NavigateRight, Select, Back, Search, Import, Delete, DeleteSelected, Open, TagView, CollectionView, AuditView, SettingsView, DuplicatesView, DatabaseView, QueueView, StatisticsView, TasksView, BooksView, ScanTrigger, Refresh, NextTab, PrevTab, PageUp, PageDown, GoTop, GoBottom, CreateTag, TagMedia, UntagMedia, Help, Edit, Vacuum, Toggle, RunNow, Save, Char(char), Backspace, // Multi-select actions ToggleSelection, SelectAll, ClearSelection, ToggleSelectionMode, BatchDelete, ConfirmBatchDelete, BatchTag, UpdateReadingProgress, // Playlists PlaylistsView, CreatePlaylist, DeletePlaylist, RemoveFromPlaylist, ShufflePlaylist, AddToPlaylist, // Social / detail ToggleFavorite, RateMedia, AddComment, EnrichMedia, ToggleSubtitles, // Transcode ToggleTranscodes, CancelTranscode, // Admin AdminView, AdminTabNext, AdminTabPrev, DeleteUser, DeleteDevice, TestWebhook, None, } #[expect( clippy::missing_const_for_fn, reason = "match arms return non-trivially constructed enum variants" )] pub fn handle_key( key: KeyEvent, in_input_mode: bool, current_view: View, ) -> Action { if in_input_mode { match (key.code, key.modifiers) { (KeyCode::Esc, _) => Action::Back, (KeyCode::Enter, _) => Action::Select, (KeyCode::Char('s'), KeyModifiers::CONTROL) => { match current_view { View::MetadataEdit => Action::Save, _ => Action::Select, } }, (KeyCode::Char(c), _) => Action::Char(c), (KeyCode::Backspace, _) => Action::Backspace, _ => Action::None, } } else { match (key.code, key.modifiers) { (KeyCode::Char('q'), _) | (KeyCode::Char('c'), KeyModifiers::CONTROL) => { Action::Quit }, (KeyCode::Up | KeyCode::Char('k'), _) => Action::NavigateUp, (KeyCode::Down | KeyCode::Char('j'), _) => Action::NavigateDown, (KeyCode::Left | KeyCode::Char('h'), _) => Action::NavigateLeft, (KeyCode::Right | KeyCode::Char('l'), _) => Action::NavigateRight, (KeyCode::Home, _) => Action::GoTop, (KeyCode::End, _) => Action::GoBottom, (KeyCode::Enter, _) => Action::Select, (KeyCode::Esc, _) => Action::Back, (KeyCode::Char('/'), _) => Action::Search, (KeyCode::Char('?'), _) => Action::Help, (KeyCode::Char('i'), _) => Action::Import, (KeyCode::Char('d'), _) => { match current_view { View::Tags | View::Collections => Action::DeleteSelected, View::Playlists => Action::DeletePlaylist, View::Admin => Action::DeleteUser, _ => Action::Delete, } }, (KeyCode::Char('o'), _) => Action::Open, (KeyCode::Char('e'), _) => { match current_view { View::Detail => Action::Edit, _ => Action::None, } }, (KeyCode::Char('p'), _) => { match current_view { View::Detail => Action::UpdateReadingProgress, _ => Action::PlaylistsView, } }, (KeyCode::Char('t'), _) => { match current_view { View::Tasks => Action::Toggle, View::Detail => Action::ToggleTranscodes, _ => Action::TagView, } }, (KeyCode::Char('c'), _) => { match current_view { View::Detail => Action::AddComment, _ => Action::CollectionView, } }, // Multi-select: Ctrl+A for SelectAll (must come before plain 'a') (KeyCode::Char('a'), KeyModifiers::CONTROL) => { match current_view { View::Library | View::Search => Action::SelectAll, _ => Action::None, } }, (KeyCode::Char('a'), _) => Action::AuditView, (KeyCode::Char('b'), _) => Action::BooksView, (KeyCode::Char('S'), _) => { match current_view { View::Playlists => Action::ShufflePlaylist, _ => Action::SettingsView, } }, (KeyCode::Char('B'), _) => Action::DatabaseView, (KeyCode::Char('Q'), _) => Action::QueueView, (KeyCode::Char('X'), _) => Action::StatisticsView, (KeyCode::Char('A'), _) => Action::AdminView, // Use plain D/T for views in non-library contexts, keep for batch ops in // library/search (KeyCode::Char('D'), _) => { match current_view { View::Library | View::Search => Action::BatchDelete, View::Admin => Action::DeleteDevice, _ => Action::DuplicatesView, } }, (KeyCode::Char('T'), _) => { match current_view { View::Library | View::Search => Action::BatchTag, _ => Action::TasksView, } }, // Ctrl+S must come before plain 's' to ensure proper precedence (KeyCode::Char('s'), KeyModifiers::CONTROL) => { match current_view { View::MetadataEdit => Action::Save, _ => Action::None, } }, (KeyCode::Char('s'), _) => Action::ScanTrigger, (KeyCode::Char('r'), _) => Action::Refresh, (KeyCode::Char('n'), _) => { match current_view { View::Playlists => Action::CreatePlaylist, _ => Action::CreateTag, } }, (KeyCode::Char('+'), _) => { match current_view { View::Library | View::Search => Action::AddToPlaylist, _ => Action::TagMedia, } }, (KeyCode::Char('-'), _) => { match current_view { View::Playlists => Action::RemoveFromPlaylist, _ => Action::UntagMedia, } }, (KeyCode::Char('v'), _) => { match current_view { View::Database => Action::Vacuum, _ => Action::ToggleSelectionMode, } }, (KeyCode::Char('x'), _) => { match current_view { View::Tasks => Action::RunNow, View::Detail => Action::CancelTranscode, _ => Action::None, } }, (KeyCode::Char('f'), _) => { match current_view { View::Detail => Action::ToggleFavorite, _ => Action::None, } }, (KeyCode::Char('R'), _) => { match current_view { View::Detail => Action::RateMedia, _ => Action::None, } }, (KeyCode::Char('E'), _) => { match current_view { View::Detail => Action::EnrichMedia, _ => Action::None, } }, (KeyCode::Char('U'), _) => { match current_view { View::Detail => Action::ToggleSubtitles, _ => Action::None, } }, (KeyCode::Char('w'), _) => { match current_view { View::Admin => Action::TestWebhook, _ => Action::None, } }, (KeyCode::Tab, _) => { match current_view { View::Admin => Action::AdminTabNext, _ => Action::NextTab, } }, (KeyCode::BackTab, _) => { match current_view { View::Admin => Action::AdminTabPrev, _ => Action::PrevTab, } }, (KeyCode::PageUp, _) => Action::PageUp, (KeyCode::PageDown, _) => Action::PageDown, // Multi-select keys (KeyCode::Char(' '), _) => { match current_view { View::Library | View::Search => Action::ToggleSelection, _ => Action::None, } }, (KeyCode::Char('u'), _) => { match current_view { View::Library | View::Search => Action::ClearSelection, _ => Action::None, } }, _ => Action::None, } } }