feat: Support alternative keymappings for all keys, featuring hjkl movements

This commit is contained in:
2025-03-17 22:02:15 -06:00
parent c633347ecc
commit 0048d71b74
77 changed files with 1247 additions and 304 deletions
@@ -9,6 +9,7 @@ mod tests {
use crate::test_handler_delegation;
use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator;
#[rstest]
#[case(0, ActiveSonarrBlock::System, ActiveSonarrBlock::Downloads)]
@@ -45,6 +46,77 @@ mod tests {
assert_eq!(app.get_current_route(), right_block.into());
}
#[rstest]
#[case(0, ActiveSonarrBlock::System, ActiveSonarrBlock::Downloads)]
#[case(1, ActiveSonarrBlock::Series, ActiveSonarrBlock::Blocklist)]
#[case(2, ActiveSonarrBlock::Downloads, ActiveSonarrBlock::History)]
#[case(3, ActiveSonarrBlock::Blocklist, ActiveSonarrBlock::RootFolders)]
#[case(4, ActiveSonarrBlock::History, ActiveSonarrBlock::Indexers)]
#[case(5, ActiveSonarrBlock::RootFolders, ActiveSonarrBlock::System)]
#[case(6, ActiveSonarrBlock::Indexers, ActiveSonarrBlock::Series)]
fn test_sonarr_handler_change_tab_left_right_keys_alt_navigation(
#[case] index: usize,
#[case] left_block: ActiveSonarrBlock,
#[case] right_block: ActiveSonarrBlock,
) {
let mut app = App::test_default();
app.data.sonarr_data.main_tabs.set_index(index);
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.alt.unwrap());
assert_eq!(
app.data.sonarr_data.main_tabs.get_active_route(),
left_block.into()
);
assert_eq!(app.get_current_route(), left_block.into());
app.data.sonarr_data.main_tabs.set_index(index);
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.alt.unwrap());
assert_eq!(
app.data.sonarr_data.main_tabs.get_active_route(),
right_block.into()
);
assert_eq!(app.get_current_route(), right_block.into());
}
#[rstest]
#[case(0, ActiveSonarrBlock::Series)]
#[case(1, ActiveSonarrBlock::Downloads)]
#[case(2, ActiveSonarrBlock::Blocklist)]
#[case(3, ActiveSonarrBlock::History)]
#[case(4, ActiveSonarrBlock::RootFolders)]
#[case(5, ActiveSonarrBlock::Indexers)]
#[case(6, ActiveSonarrBlock::System)]
fn test_sonarr_handler_change_tab_left_right_keys_alt_navigation_no_op_when_ignoring_quit_key(
#[case] index: usize,
#[case] block: ActiveSonarrBlock,
) {
let mut app = App::test_default();
app.push_navigation_stack(block.into());
app.should_ignore_quit_key = true;
app.data.sonarr_data.main_tabs.set_index(index);
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.alt.unwrap());
assert_eq!(
app.data.sonarr_data.main_tabs.get_active_route(),
block.into()
);
assert_eq!(app.get_current_route(), block.into());
app.data.sonarr_data.main_tabs.set_index(index);
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.alt.unwrap());
assert_eq!(
app.data.sonarr_data.main_tabs.get_active_route(),
block.into()
);
assert_eq!(app.get_current_route(), block.into());
}
#[rstest]
fn test_delegates_library_blocks_to_library_handler(
#[values(
@@ -59,10 +131,10 @@ mod tests {
ActiveSonarrBlock::AddSeriesSelectRootFolder,
ActiveSonarrBlock::AddSeriesSelectSeriesType,
ActiveSonarrBlock::AddSeriesTagsInput,
// ActiveSonarrBlock::AutomaticallySearchEpisodePrompt,
// ActiveSonarrBlock::AutomaticallySearchSeasonPrompt,
// ActiveSonarrBlock::AutomaticallySearchSeriesPrompt,
// ActiveSonarrBlock::DeleteEpisodeFilePrompt,
ActiveSonarrBlock::AutomaticallySearchEpisodePrompt,
ActiveSonarrBlock::AutomaticallySearchSeasonPrompt,
ActiveSonarrBlock::AutomaticallySearchSeriesPrompt,
ActiveSonarrBlock::DeleteEpisodeFilePrompt,
ActiveSonarrBlock::DeleteSeriesPrompt,
ActiveSonarrBlock::EditSeriesPrompt,
ActiveSonarrBlock::EditSeriesPathInput,
@@ -70,39 +142,36 @@ mod tests {
ActiveSonarrBlock::EditSeriesSelectQualityProfile,
ActiveSonarrBlock::EditSeriesSelectLanguageProfile,
ActiveSonarrBlock::EditSeriesTagsInput,
// ActiveSonarrBlock::EpisodeDetails,
// ActiveSonarrBlock::EpisodeFile,
// ActiveSonarrBlock::EpisodeHistory,
// ActiveSonarrBlock::EpisodesSortPrompt,
// ActiveSonarrBlock::FilterEpisodes,
// ActiveSonarrBlock::FilterEpisodesError,
ActiveSonarrBlock::EpisodeDetails,
ActiveSonarrBlock::EpisodeFile,
ActiveSonarrBlock::EpisodeHistory,
ActiveSonarrBlock::FilterSeries,
ActiveSonarrBlock::FilterSeriesError,
// ActiveSonarrBlock::FilterSeriesHistory,
// ActiveSonarrBlock::FilterSeriesHistoryError,
// ActiveSonarrBlock::ManualEpisodeSearch,
// ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt,
// ActiveSonarrBlock::ManualEpisodeSearchSortPrompt,
// ActiveSonarrBlock::ManualSeasonSearch,
// ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt,
// ActiveSonarrBlock::ManualSeasonSearchSortPrompt,
// ActiveSonarrBlock::SearchEpisodes,
// ActiveSonarrBlock::SearchEpisodesError,
// ActiveSonarrBlock::SearchSeason,
// ActiveSonarrBlock::SearchSeasonError,
ActiveSonarrBlock::FilterSeriesHistory,
ActiveSonarrBlock::FilterSeriesHistoryError,
ActiveSonarrBlock::ManualEpisodeSearch,
ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt,
ActiveSonarrBlock::ManualEpisodeSearchSortPrompt,
ActiveSonarrBlock::ManualSeasonSearch,
ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt,
ActiveSonarrBlock::ManualSeasonSearchSortPrompt,
ActiveSonarrBlock::SearchEpisodes,
ActiveSonarrBlock::SearchEpisodesError,
ActiveSonarrBlock::SearchSeason,
ActiveSonarrBlock::SearchSeasonError,
ActiveSonarrBlock::SearchSeries,
ActiveSonarrBlock::SearchSeriesError,
// ActiveSonarrBlock::SearchSeriesHistory,
// ActiveSonarrBlock::SearchSeriesHistoryError,
// ActiveSonarrBlock::SeasonDetails,
ActiveSonarrBlock::SearchSeriesHistory,
ActiveSonarrBlock::SearchSeriesHistoryError,
ActiveSonarrBlock::SeasonDetails,
ActiveSonarrBlock::Series,
// ActiveSonarrBlock::SeriesDetails,
// ActiveSonarrBlock::SeriesHistory,
// ActiveSonarrBlock::SeriesHistorySortPrompt,
ActiveSonarrBlock::SeriesDetails,
ActiveSonarrBlock::SeriesHistory,
ActiveSonarrBlock::SeriesHistorySortPrompt,
ActiveSonarrBlock::SeriesSortPrompt,
ActiveSonarrBlock::UpdateAllSeriesPrompt,
// ActiveSonarrBlock::UpdateAndScanSeriesPrompt
// ActiveSonarrBlock::SeriesHistoryDetails,
ActiveSonarrBlock::UpdateAndScanSeriesPrompt,
ActiveSonarrBlock::SeriesHistoryDetails
)]
active_sonarr_block: ActiveSonarrBlock,
) {
@@ -222,4 +291,42 @@ mod tests {
active_sonarr_block
);
}
#[test]
fn test_sonarr_handler_accepts() {
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
assert!(SonarrHandler::accepts(active_sonarr_block));
})
}
#[rstest]
fn test_sonarr_handler_ignore_alt_navigation(
#[values(true, false)] should_ignore_quit_key: bool,
) {
let mut app = App::test_default();
app.should_ignore_quit_key = should_ignore_quit_key;
let handler = SonarrHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
}
#[test]
fn test_sonarr_handler_is_ready() {
let mut app = App::test_default();
app.is_loading = true;
let handler = SonarrHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert!(handler.is_ready());
}
}