pinakes/crates/pinakes-tui/src/input.rs
NotAShelf 8129c5a6e7
pinakes-tui: cover more API routes in the TUI crate
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id14b6f82d3b9f3c27bee9c214a1bdedc6a6a6964
2026-03-22 17:58:42 +03:00

289 lines
7.6 KiB
Rust

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,
}
}
}