Merge pull request #39 from Dark-Alex-17/alternative-keymappings

Alternative keymappings
This commit is contained in:
Alex Clarke
2025-04-01 10:11:22 -06:00
committed by GitHub
80 changed files with 1593 additions and 501 deletions
+2 -2
View File
@@ -98,7 +98,7 @@ mod tests {
assert!(!app.is_loading); assert!(!app.is_loading);
assert!(!app.is_routing); assert!(!app.is_routing);
assert!(!app.should_refresh); assert!(!app.should_refresh);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app.cli_mode); assert!(!app.cli_mode);
} }
@@ -118,7 +118,7 @@ mod tests {
assert!(!app.is_loading); assert!(!app.is_loading);
assert!(!app.is_routing); assert!(!app.is_routing);
assert!(!app.should_refresh); assert!(!app.should_refresh);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app.cli_mode); assert!(!app.cli_mode);
} }
+61 -1
View File
@@ -44,128 +44,188 @@ generate_keybindings! {
#[derive(Clone, Copy, Eq, PartialEq, Debug)] #[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct KeyBinding { pub struct KeyBinding {
pub key: Key, pub key: Key,
pub alt: Option<Key>,
pub desc: &'static str, pub desc: &'static str,
} }
pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings { pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
add: KeyBinding { add: KeyBinding {
key: Key::Char('a'), key: Key::Char('a'),
alt: None,
desc: "add", desc: "add",
}, },
up: KeyBinding { up: KeyBinding {
key: Key::Up, key: Key::Up,
alt: Some(Key::Char('k')),
desc: "up", desc: "up",
}, },
down: KeyBinding { down: KeyBinding {
key: Key::Down, key: Key::Down,
alt: Some(Key::Char('j')),
desc: "down", desc: "down",
}, },
left: KeyBinding { left: KeyBinding {
key: Key::Left, key: Key::Left,
alt: Some(Key::Char('h')),
desc: "left", desc: "left",
}, },
right: KeyBinding { right: KeyBinding {
key: Key::Right, key: Key::Right,
alt: Some(Key::Char('l')),
desc: "right", desc: "right",
}, },
backspace: KeyBinding { backspace: KeyBinding {
key: Key::Backspace, key: Key::Backspace,
alt: Some(Key::Ctrl('h')),
desc: "backspace", desc: "backspace",
}, },
next_servarr: KeyBinding { next_servarr: KeyBinding {
key: Key::Tab, key: Key::Tab,
alt: None,
desc: "next servarr", desc: "next servarr",
}, },
previous_servarr: KeyBinding { previous_servarr: KeyBinding {
key: Key::BackTab, key: Key::BackTab,
alt: None,
desc: "previous servarr", desc: "previous servarr",
}, },
clear: KeyBinding { clear: KeyBinding {
key: Key::Char('c'), key: Key::Char('c'),
alt: None,
desc: "clear", desc: "clear",
}, },
auto_search: KeyBinding { auto_search: KeyBinding {
key: Key::Char('S'), key: Key::Char('S'),
alt: None,
desc: "auto search", desc: "auto search",
}, },
search: KeyBinding { search: KeyBinding {
key: Key::Char('s'), key: Key::Char('s'),
alt: None,
desc: "search", desc: "search",
}, },
settings: KeyBinding { settings: KeyBinding {
key: Key::Char('S'), key: Key::Char('S'),
alt: None,
desc: "settings", desc: "settings",
}, },
filter: KeyBinding { filter: KeyBinding {
key: Key::Char('f'), key: Key::Char('f'),
alt: None,
desc: "filter", desc: "filter",
}, },
sort: KeyBinding { sort: KeyBinding {
key: Key::Char('o'), key: Key::Char('o'),
alt: None,
desc: "sort", desc: "sort",
}, },
edit: KeyBinding { edit: KeyBinding {
key: Key::Char('e'), key: Key::Char('e'),
alt: None,
desc: "edit", desc: "edit",
}, },
events: KeyBinding { events: KeyBinding {
key: Key::Char('e'), key: Key::Char('e'),
alt: None,
desc: "events", desc: "events",
}, },
logs: KeyBinding { logs: KeyBinding {
key: Key::Char('l'), key: Key::Char('L'),
alt: None,
desc: "logs", desc: "logs",
}, },
tasks: KeyBinding { tasks: KeyBinding {
key: Key::Char('t'), key: Key::Char('t'),
alt: None,
desc: "tasks", desc: "tasks",
}, },
test: KeyBinding { test: KeyBinding {
key: Key::Char('t'), key: Key::Char('t'),
alt: None,
desc: "test", desc: "test",
}, },
test_all: KeyBinding { test_all: KeyBinding {
key: Key::Char('T'), key: Key::Char('T'),
alt: None,
desc: "test all", desc: "test all",
}, },
toggle_monitoring: KeyBinding { toggle_monitoring: KeyBinding {
key: Key::Char('m'), key: Key::Char('m'),
alt: None,
desc: "toggle monitoring", desc: "toggle monitoring",
}, },
refresh: KeyBinding { refresh: KeyBinding {
key: Key::Ctrl('r'), key: Key::Ctrl('r'),
alt: None,
desc: "refresh", desc: "refresh",
}, },
update: KeyBinding { update: KeyBinding {
key: Key::Char('u'), key: Key::Char('u'),
alt: None,
desc: "update", desc: "update",
}, },
home: KeyBinding { home: KeyBinding {
key: Key::Home, key: Key::Home,
alt: None,
desc: "home", desc: "home",
}, },
end: KeyBinding { end: KeyBinding {
key: Key::End, key: Key::End,
alt: None,
desc: "end", desc: "end",
}, },
delete: KeyBinding { delete: KeyBinding {
key: Key::Delete, key: Key::Delete,
alt: None,
desc: "delete", desc: "delete",
}, },
submit: KeyBinding { submit: KeyBinding {
key: Key::Enter, key: Key::Enter,
alt: None,
desc: "submit", desc: "submit",
}, },
confirm: KeyBinding { confirm: KeyBinding {
key: Key::Ctrl('s'), key: Key::Ctrl('s'),
alt: None,
desc: "submit", desc: "submit",
}, },
quit: KeyBinding { quit: KeyBinding {
key: Key::Char('q'), key: Key::Char('q'),
alt: None,
desc: "quit", desc: "quit",
}, },
esc: KeyBinding { esc: KeyBinding {
key: Key::Esc, key: Key::Esc,
alt: None,
desc: "close", desc: "close",
}, },
}; };
#[macro_export]
macro_rules! matches_key {
($binding:ident, $key:expr) => {
$crate::app::key_binding::DEFAULT_KEYBINDINGS.$binding.key == $key
|| ($crate::app::key_binding::DEFAULT_KEYBINDINGS
.$binding
.alt
.is_some()
&& $crate::app::key_binding::DEFAULT_KEYBINDINGS
.$binding
.alt
.unwrap()
== $key)
};
($binding:ident, $key:expr, $ignore_special_keys:expr) => {
$crate::app::key_binding::DEFAULT_KEYBINDINGS.$binding.key == $key
|| !$ignore_special_keys
&& ($crate::app::key_binding::DEFAULT_KEYBINDINGS
.$binding
.alt
.is_some()
&& $crate::app::key_binding::DEFAULT_KEYBINDINGS
.$binding
.alt
.unwrap()
== $key)
};
}
+71 -30
View File
@@ -5,44 +5,85 @@ mod test {
use crate::app::key_binding::{KeyBinding, DEFAULT_KEYBINDINGS}; use crate::app::key_binding::{KeyBinding, DEFAULT_KEYBINDINGS};
use crate::event::Key; use crate::event::Key;
use crate::matches_key;
#[rstest] #[rstest]
#[case(DEFAULT_KEYBINDINGS.add, Key::Char('a'), "add")] #[case(DEFAULT_KEYBINDINGS.add, Key::Char('a'), None, "add")]
#[case(DEFAULT_KEYBINDINGS.up, Key::Up, "up")] #[case(DEFAULT_KEYBINDINGS.up, Key::Up, Some(Key::Char('k')), "up")]
#[case(DEFAULT_KEYBINDINGS.down, Key::Down, "down")] #[case(DEFAULT_KEYBINDINGS.down, Key::Down, Some(Key::Char('j')), "down")]
#[case(DEFAULT_KEYBINDINGS.left, Key::Left, "left")] #[case(DEFAULT_KEYBINDINGS.left, Key::Left, Some(Key::Char('h')), "left")]
#[case(DEFAULT_KEYBINDINGS.right, Key::Right, "right")] #[case(DEFAULT_KEYBINDINGS.right, Key::Right, Some(Key::Char('l')), "right")]
#[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, "backspace")] #[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, Some(Key::Ctrl('h')), "backspace")]
#[case(DEFAULT_KEYBINDINGS.next_servarr, Key::Tab, "next servarr")] #[case(DEFAULT_KEYBINDINGS.next_servarr, Key::Tab, None, "next servarr")]
#[case(DEFAULT_KEYBINDINGS.previous_servarr, Key::BackTab, "previous servarr")] #[case(DEFAULT_KEYBINDINGS.previous_servarr, Key::BackTab, None, "previous servarr")]
#[case(DEFAULT_KEYBINDINGS.clear, Key::Char('c'), "clear")] #[case(DEFAULT_KEYBINDINGS.clear, Key::Char('c'), None, "clear")]
#[case(DEFAULT_KEYBINDINGS.auto_search, Key::Char('S'), "auto search")] #[case(DEFAULT_KEYBINDINGS.auto_search, Key::Char('S'), None, "auto search")]
#[case(DEFAULT_KEYBINDINGS.search, Key::Char('s'), "search")] #[case(DEFAULT_KEYBINDINGS.search, Key::Char('s'), None, "search")]
#[case(DEFAULT_KEYBINDINGS.settings, Key::Char('S'), "settings")] #[case(DEFAULT_KEYBINDINGS.settings, Key::Char('S'), None, "settings")]
#[case(DEFAULT_KEYBINDINGS.filter, Key::Char('f'), "filter")] #[case(DEFAULT_KEYBINDINGS.filter, Key::Char('f'), None, "filter")]
#[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), "sort")] #[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), None, "sort")]
#[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), "edit")] #[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), None, "edit")]
#[case(DEFAULT_KEYBINDINGS.events, Key::Char('e'), "events")] #[case(DEFAULT_KEYBINDINGS.events, Key::Char('e'), None, "events")]
#[case(DEFAULT_KEYBINDINGS.logs, Key::Char('l'), "logs")] #[case(DEFAULT_KEYBINDINGS.logs, Key::Char('L'), None, "logs")]
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")] #[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), None, "tasks")]
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")] #[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), None, "test")]
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), "test all")] #[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), None, "test all")]
#[case(DEFAULT_KEYBINDINGS.toggle_monitoring, Key::Char('m'), "toggle monitoring")] #[case(DEFAULT_KEYBINDINGS.toggle_monitoring, Key::Char('m'), None, "toggle monitoring")]
#[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), "refresh")] #[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), None, "refresh")]
#[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), "update")] #[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), None, "update")]
#[case(DEFAULT_KEYBINDINGS.home, Key::Home, "home")] #[case(DEFAULT_KEYBINDINGS.home, Key::Home, None, "home")]
#[case(DEFAULT_KEYBINDINGS.end, Key::End, "end")] #[case(DEFAULT_KEYBINDINGS.end, Key::End, None, "end")]
#[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, "delete")] #[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, None, "delete")]
#[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, "submit")] #[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, None, "submit")]
#[case(DEFAULT_KEYBINDINGS.confirm, Key::Ctrl('s'), "submit")] #[case(DEFAULT_KEYBINDINGS.confirm, Key::Ctrl('s'), None, "submit")]
#[case(DEFAULT_KEYBINDINGS.quit, Key::Char('q'), "quit")] #[case(DEFAULT_KEYBINDINGS.quit, Key::Char('q'), None, "quit")]
#[case(DEFAULT_KEYBINDINGS.esc, Key::Esc, "close")] #[case(DEFAULT_KEYBINDINGS.esc, Key::Esc, None, "close")]
fn test_default_key_bindings_and_descriptions( fn test_default_key_bindings_and_descriptions(
#[case] key_binding: KeyBinding, #[case] key_binding: KeyBinding,
#[case] expected_key: Key, #[case] expected_key: Key,
#[case] expected_alt_key: Option<Key>,
#[case] expected_desc: &str, #[case] expected_desc: &str,
) { ) {
assert_eq!(key_binding.key, expected_key); assert_eq!(key_binding.key, expected_key);
assert_eq!(key_binding.alt, expected_alt_key);
assert_str_eq!(key_binding.desc, expected_desc); assert_str_eq!(key_binding.desc, expected_desc);
} }
#[test]
fn test_matches_key_macro() {
let key = Key::Char('t');
assert!(matches_key!(test, key));
assert!(!matches_key!(test, Key::Char('T')));
}
#[test]
fn test_matches_key_macro_with_alt_keybinding() {
let alt_key = Key::Char('k');
let key = Key::Up;
assert!(matches_key!(up, key));
assert!(matches_key!(up, alt_key));
assert!(!matches_key!(up, Key::Char('t')));
}
#[test]
fn test_matches_key_macro_with_alt_keybinding_uses_alt_key_when_ignore_special_keys_is_false() {
let alt_key = Key::Char('k');
let key = Key::Up;
assert!(matches_key!(up, key, false));
assert!(matches_key!(up, alt_key, false));
assert!(!matches_key!(up, Key::Char('t'), false));
}
#[test]
fn test_matches_key_macro_with_alt_keybinding_ignores_alt_key_when_ignore_special_keys_is_true() {
let alt_key = Key::Char('k');
let key = Key::Up;
assert!(matches_key!(up, key, true));
assert!(!matches_key!(up, alt_key, true));
assert!(!matches_key!(up, Key::Char('t'), true));
}
} }
+2 -2
View File
@@ -39,7 +39,7 @@ pub struct App<'a> {
pub is_routing: bool, pub is_routing: bool,
pub is_loading: bool, pub is_loading: bool,
pub should_refresh: bool, pub should_refresh: bool,
pub should_ignore_quit_key: bool, pub ignore_special_keys_for_textbox_input: bool,
pub cli_mode: bool, pub cli_mode: bool,
pub data: Data<'a>, pub data: Data<'a>,
} }
@@ -224,7 +224,7 @@ impl Default for App<'_> {
is_loading: false, is_loading: false,
is_routing: false, is_routing: false,
should_refresh: false, should_refresh: false,
should_ignore_quit_key: false, ignore_special_keys_for_textbox_input: false,
cli_mode: false, cli_mode: false,
data: Data::default(), data: Data::default(),
} }
+24 -23
View File
@@ -1,9 +1,9 @@
use radarr_handlers::RadarrHandler; use radarr_handlers::RadarrHandler;
use sonarr_handlers::SonarrHandler; use sonarr_handlers::SonarrHandler;
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::matches_key;
use crate::models::{HorizontallyScrollableText, Route}; use crate::models::{HorizontallyScrollableText, Route};
mod radarr_handlers; mod radarr_handlers;
@@ -22,40 +22,42 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route> + Copy> {
fn handle_key_event(&mut self) { fn handle_key_event(&mut self) {
let key = self.get_key(); let key = self.get_key();
match key { match key {
_ if key == DEFAULT_KEYBINDINGS.up.key => { _ if matches_key!(up, key, self.ignore_special_keys()) => {
if self.is_ready() { if self.is_ready() {
self.handle_scroll_up(); self.handle_scroll_up();
} }
} }
_ if key == DEFAULT_KEYBINDINGS.down.key => { _ if matches_key!(down, key, self.ignore_special_keys()) => {
if self.is_ready() { if self.is_ready() {
self.handle_scroll_down(); self.handle_scroll_down();
} }
} }
_ if key == DEFAULT_KEYBINDINGS.home.key => { _ if matches_key!(home, key) => {
if self.is_ready() { if self.is_ready() {
self.handle_home(); self.handle_home();
} }
} }
_ if key == DEFAULT_KEYBINDINGS.end.key => { _ if matches_key!(end, key) => {
if self.is_ready() { if self.is_ready() {
self.handle_end(); self.handle_end();
} }
} }
_ if key == DEFAULT_KEYBINDINGS.delete.key => { _ if matches_key!(delete, key) => {
if self.is_ready() { if self.is_ready() {
self.handle_delete(); self.handle_delete();
} }
} }
_ if key == DEFAULT_KEYBINDINGS.left.key || key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(left, key, self.ignore_special_keys())
|| matches_key!(right, key, self.ignore_special_keys()) =>
{
self.handle_left_right_action() self.handle_left_right_action()
} }
_ if key == DEFAULT_KEYBINDINGS.submit.key => { _ if matches_key!(submit, key) => {
if self.is_ready() { if self.is_ready() {
self.handle_submit(); self.handle_submit();
} }
} }
_ if key == DEFAULT_KEYBINDINGS.esc.key => self.handle_esc(), _ if matches_key!(esc, key) => self.handle_esc(),
_ => { _ => {
if self.is_ready() { if self.is_ready() {
self.handle_char_key_event(); self.handle_char_key_event();
@@ -71,6 +73,7 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route> + Copy> {
fn accepts(active_block: T) -> bool; fn accepts(active_block: T) -> bool;
fn new(key: Key, app: &'a mut App<'b>, active_block: T, context: Option<T>) -> Self; fn new(key: Key, app: &'a mut App<'b>, active_block: T, context: Option<T>) -> Self;
fn get_key(&self) -> Key; fn get_key(&self) -> Key;
fn ignore_special_keys(&self) -> bool;
fn is_ready(&self) -> bool; fn is_ready(&self) -> bool;
fn handle_scroll_up(&mut self); fn handle_scroll_up(&mut self);
fn handle_scroll_down(&mut self); fn handle_scroll_down(&mut self);
@@ -84,12 +87,12 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route> + Copy> {
} }
pub fn handle_events(key: Key, app: &mut App<'_>) { pub fn handle_events(key: Key, app: &mut App<'_>) {
if key == DEFAULT_KEYBINDINGS.next_servarr.key { if matches_key!(next_servarr, key) {
app.reset(); app.reset();
app.server_tabs.next(); app.server_tabs.next();
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route()); app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
app.cancellation_token.cancel(); app.cancellation_token.cancel();
} else if key == DEFAULT_KEYBINDINGS.previous_servarr.key { } else if matches_key!(previous_servarr, key) {
app.reset(); app.reset();
app.server_tabs.previous(); app.server_tabs.previous();
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route()); app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
@@ -115,17 +118,15 @@ fn handle_clear_errors(app: &mut App<'_>) {
fn handle_prompt_toggle(app: &mut App<'_>, key: Key) { fn handle_prompt_toggle(app: &mut App<'_>, key: Key) {
match key { match key {
_ if key == DEFAULT_KEYBINDINGS.left.key || key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(left, key) || matches_key!(right, key) => match app.get_current_route() {
match app.get_current_route() { Route::Radarr(_, _) => {
Route::Radarr(_, _) => { app.data.radarr_data.prompt_confirm = !app.data.radarr_data.prompt_confirm
app.data.radarr_data.prompt_confirm = !app.data.radarr_data.prompt_confirm
}
Route::Sonarr(_, _) => {
app.data.sonarr_data.prompt_confirm = !app.data.sonarr_data.prompt_confirm
}
_ => (),
} }
} Route::Sonarr(_, _) => {
app.data.sonarr_data.prompt_confirm = !app.data.sonarr_data.prompt_confirm
}
_ => (),
},
_ => (), _ => (),
} }
} }
@@ -149,7 +150,7 @@ macro_rules! handle_text_box_left_right_keys {
macro_rules! handle_text_box_keys { macro_rules! handle_text_box_keys {
($self:expr, $key:expr, $input:expr) => { ($self:expr, $key:expr, $input:expr) => {
match $self.key { match $self.key {
_ if $key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.backspace.key => { _ if $crate::matches_key!(backspace, $key) => {
$input.pop(); $input.pop();
} }
Key::Char(character) => { Key::Char(character) => {
@@ -165,7 +166,7 @@ macro_rules! handle_prompt_left_right_keys {
($self:expr, $confirm_prompt:expr, $data:ident) => { ($self:expr, $confirm_prompt:expr, $data:ident) => {
if $self.app.data.$data.selected_block.get_active_block() == $confirm_prompt { if $self.app.data.$data.selected_block.get_active_block() == $confirm_prompt {
handle_prompt_toggle($self.app, $self.key); handle_prompt_toggle($self.app, $self.key);
} else if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.left.key { } else if $crate::matches_key!(left, $self.key) {
$self.app.data.$data.selected_block.left(); $self.app.data.$data.selected_block.left();
} else { } else {
$self.app.data.$data.selected_block.right(); $self.app.data.$data.selected_block.right();
@@ -4,6 +4,7 @@ mod tests {
use chrono::DateTime; use chrono::DateTime;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -541,6 +542,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_blocklist_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = BlocklistHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_blocklist_item_id() { fn test_extract_blocklist_item_id() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
@@ -9,6 +7,7 @@ use crate::models::radarr_models::BlocklistItem;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
use crate::models::stateful_table::SortOption; use crate::models::stateful_table::SortOption;
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "blocklist_handler_tests.rs"] #[path = "blocklist_handler_tests.rs"]
@@ -51,6 +50,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
BLOCKLIST_BLOCKS.contains(&active_block) BLOCKLIST_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -143,10 +146,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
let key = self.key; let key = self.key;
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::Blocklist => match self.key { ActiveRadarrBlock::Blocklist => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.clear.key => { _ if matches_key!(clear, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into());
@@ -154,7 +157,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
_ => (), _ => (),
}, },
ActiveRadarrBlock::DeleteBlocklistItemPrompt => { ActiveRadarrBlock::DeleteBlocklistItemPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteBlocklistItem( self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteBlocklistItem(
self.extract_blocklist_item_id(), self.extract_blocklist_item_id(),
@@ -164,7 +167,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
} }
} }
ActiveRadarrBlock::BlocklistClearAllItemsPrompt => { ActiveRadarrBlock::BlocklistClearAllItemsPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::ClearBlocklist); self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::ClearBlocklist);
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::KeyEventHandler; use crate::handlers::KeyEventHandler;
use crate::models::radarr_models::CollectionMovie; use crate::models::radarr_models::CollectionMovie;
@@ -11,6 +9,7 @@ use crate::models::servarr_data::radarr::radarr_data::{
}; };
use crate::models::stateful_table::StatefulTable; use crate::models::stateful_table::StatefulTable;
use crate::models::BlockSelectionState; use crate::models::BlockSelectionState;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "collection_details_handler_tests.rs"] #[path = "collection_details_handler_tests.rs"]
@@ -46,6 +45,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
COLLECTION_DETAILS_BLOCKS.contains(&active_block) COLLECTION_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -130,7 +133,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
if self.active_radarr_block == ActiveRadarrBlock::CollectionDetails if self.active_radarr_block == ActiveRadarrBlock::CollectionDetails
&& self.key == DEFAULT_KEYBINDINGS.edit.key && matches_key!(edit, self.key)
{ {
self.app.push_navigation_stack( self.app.push_navigation_stack(
( (
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_str_eq; use pretty_assertions::assert_str_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -278,6 +279,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_collection_details_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = CollectionDetailsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_collection_details_handler_not_ready_when_loading() { fn test_collection_details_handler_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -589,6 +589,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_collections_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = CollectionsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_collections_handler_not_ready_when_loading() { fn test_collections_handler_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -7,7 +6,7 @@ use crate::models::servarr_data::radarr::modals::EditCollectionModal;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_COLLECTION_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_COLLECTION_BLOCKS};
use crate::models::Scrollable; use crate::models::Scrollable;
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{handle_text_box_keys, handle_text_box_left_right_keys, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "edit_collection_handler_tests.rs"] #[path = "edit_collection_handler_tests.rs"]
@@ -69,6 +68,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
EDIT_COLLECTION_BLOCKS.contains(&active_block) EDIT_COLLECTION_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -262,7 +265,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
) )
.into(), .into(),
); );
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveRadarrBlock::EditCollectionToggleMonitored => { ActiveRadarrBlock::EditCollectionToggleMonitored => {
self self
@@ -311,7 +314,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => self.app.pop_navigation_stack(), | ActiveRadarrBlock::EditCollectionSelectQualityProfile => self.app.pop_navigation_stack(),
ActiveRadarrBlock::EditCollectionRootFolderPathInput => { ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => (), _ => (),
} }
@@ -321,7 +324,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::EditCollectionRootFolderPathInput => { ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveRadarrBlock::EditCollectionPrompt => { ActiveRadarrBlock::EditCollectionPrompt => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
@@ -354,7 +357,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
ActiveRadarrBlock::EditCollectionPrompt => { ActiveRadarrBlock::EditCollectionPrompt => {
if self.app.data.radarr_data.selected_block.get_active_block() if self.app.data.radarr_data.selected_block.get_active_block()
== ActiveRadarrBlock::EditCollectionConfirmPrompt == ActiveRadarrBlock::EditCollectionConfirmPrompt
&& key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, key)
{ {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection( self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection(
@@ -2,6 +2,7 @@
mod tests { mod tests {
use bimap::BiMap; use bimap::BiMap;
use pretty_assertions::assert_str_eq; use pretty_assertions::assert_str_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -457,7 +458,7 @@ mod tests {
#[test] #[test]
fn test_edit_collection_root_folder_path_input_submit() { fn test_edit_collection_root_folder_path_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal { app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
path: "Test Path".into(), path: "Test Path".into(),
..EditCollectionModal::default() ..EditCollectionModal::default()
@@ -473,7 +474,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -759,7 +760,7 @@ mod tests {
assert_eq!(app.data.radarr_data.prompt_confirm_action, None); assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
if selected_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput { if selected_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
} }
@@ -791,7 +792,7 @@ mod tests {
); );
if active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput { if active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
} }
} }
@@ -811,7 +812,7 @@ mod tests {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default()); app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into()); app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
@@ -823,7 +824,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::EditCollectionPrompt.into() ActiveRadarrBlock::EditCollectionPrompt.into()
@@ -926,7 +927,7 @@ mod tests {
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default()); app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
EditCollectionHandler::new( EditCollectionHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditCollectionRootFolderPathInput, ActiveRadarrBlock::EditCollectionRootFolderPathInput,
None, None,
@@ -942,7 +943,7 @@ mod tests {
.unwrap() .unwrap()
.path .path
.text, .text,
"h" "a"
); );
} }
@@ -1019,6 +1020,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_edit_collection_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = EditCollectionHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_edit_collection_params() { fn test_build_edit_collection_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler; use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler;
use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler; use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
@@ -14,6 +12,7 @@ use crate::models::servarr_data::radarr::radarr_data::{
use crate::models::stateful_table::SortOption; use crate::models::stateful_table::SortOption;
use crate::models::BlockSelectionState; use crate::models::BlockSelectionState;
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, matches_key};
mod collection_details_handler; mod collection_details_handler;
mod edit_collection_handler; mod edit_collection_handler;
@@ -73,6 +72,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|| COLLECTIONS_BLOCKS.contains(&active_block) || COLLECTIONS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -145,7 +148,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
let key = self.key; let key = self.key;
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::Collections => match self.key { ActiveRadarrBlock::Collections => match self.key {
_ if key == DEFAULT_KEYBINDINGS.edit.key => { _ if matches_key!(edit, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
@@ -154,18 +157,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
self.app.data.radarr_data.selected_block = self.app.data.radarr_data.selected_block =
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS); BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ => (), _ => (),
}, },
ActiveRadarrBlock::UpdateAllCollectionsPrompt => { ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections); self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -387,6 +388,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_downloads_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = DownloadsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_download_id() { fn test_extract_download_id() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,13 +1,12 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
use crate::models::radarr_models::DownloadRecord; use crate::models::radarr_models::DownloadRecord;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "downloads_handler_tests.rs"] #[path = "downloads_handler_tests.rs"]
@@ -47,6 +46,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
DOWNLOADS_BLOCKS.contains(&active_block) DOWNLOADS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -130,18 +133,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
let key = self.key; let key = self.key;
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::Downloads => match self.key { ActiveRadarrBlock::Downloads => match self.key {
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::UpdateDownloadsPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::UpdateDownloadsPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ => (), _ => (),
}, },
ActiveRadarrBlock::DeleteDownloadPrompt => { ActiveRadarrBlock::DeleteDownloadPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::DeleteDownload(self.extract_download_id())); Some(RadarrEvent::DeleteDownload(self.extract_download_id()));
@@ -150,7 +153,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
} }
} }
ActiveRadarrBlock::UpdateDownloadsPrompt => { ActiveRadarrBlock::UpdateDownloadsPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads); self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads);
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -6,7 +5,9 @@ use crate::models::servarr_data::modals::EditIndexerModal;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::servarr_models::EditIndexerParams; use crate::models::servarr_models::EditIndexerParams;
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{
handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys, matches_key,
};
#[cfg(test)] #[cfg(test)]
#[path = "edit_indexer_handler_tests.rs"] #[path = "edit_indexer_handler_tests.rs"]
@@ -65,6 +66,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
EDIT_INDEXER_BLOCKS.contains(&active_block) EDIT_INDEXER_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -356,7 +361,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
| ActiveRadarrBlock::EditIndexerSeedRatioInput | ActiveRadarrBlock::EditIndexerSeedRatioInput
| ActiveRadarrBlock::EditIndexerTagsInput => { | ActiveRadarrBlock::EditIndexerTagsInput => {
self.app.push_navigation_stack(selected_block.into()); self.app.push_navigation_stack(selected_block.into());
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveRadarrBlock::EditIndexerPriorityInput => self ActiveRadarrBlock::EditIndexerPriorityInput => self
.app .app
@@ -402,7 +407,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
| ActiveRadarrBlock::EditIndexerSeedRatioInput | ActiveRadarrBlock::EditIndexerSeedRatioInput
| ActiveRadarrBlock::EditIndexerTagsInput => { | ActiveRadarrBlock::EditIndexerTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveRadarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(), ActiveRadarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(),
_ => (), _ => (),
@@ -423,7 +428,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
| ActiveRadarrBlock::EditIndexerPriorityInput | ActiveRadarrBlock::EditIndexerPriorityInput
| ActiveRadarrBlock::EditIndexerTagsInput => { | ActiveRadarrBlock::EditIndexerTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => self.app.pop_navigation_stack(), _ => self.app.pop_navigation_stack(),
} }
@@ -504,7 +509,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
ActiveRadarrBlock::EditIndexerPrompt => { ActiveRadarrBlock::EditIndexerPrompt => {
if self.app.data.radarr_data.selected_block.get_active_block() if self.app.data.radarr_data.selected_block.get_active_block()
== ActiveRadarrBlock::EditIndexerConfirmPrompt == ActiveRadarrBlock::EditIndexerConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
@@ -10,6 +10,7 @@ mod tests {
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::servarr_models::EditIndexerParams; use crate::models::servarr_models::EditIndexerParams;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
mod test_handle_scroll_up_and_down { mod test_handle_scroll_up_and_down {
@@ -1002,7 +1003,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), block.into()); assert_eq!(app.get_current_route(), block.into());
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
#[test] #[test]
@@ -1027,7 +1028,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::EditIndexerPriorityInput.into() ActiveRadarrBlock::EditIndexerPriorityInput.into()
); );
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
#[test] #[test]
@@ -1193,7 +1194,7 @@ mod tests {
fn test_edit_indexer_name_input_submit() { fn test_edit_indexer_name_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into()); app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal {
name: "Test".into(), name: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1209,7 +1210,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -1229,7 +1230,7 @@ mod tests {
fn test_edit_indexer_url_input_submit() { fn test_edit_indexer_url_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into()); app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal {
url: "Test".into(), url: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1245,7 +1246,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -1265,7 +1266,7 @@ mod tests {
fn test_edit_indexer_api_key_input_submit() { fn test_edit_indexer_api_key_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into()); app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal {
api_key: "Test".into(), api_key: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1281,7 +1282,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -1301,7 +1302,7 @@ mod tests {
fn test_edit_indexer_seed_ratio_input_submit() { fn test_edit_indexer_seed_ratio_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into()); app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal {
seed_ratio: "Test".into(), seed_ratio: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1317,7 +1318,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -1337,7 +1338,7 @@ mod tests {
fn test_edit_indexer_tags_input_submit() { fn test_edit_indexer_tags_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into()); app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal {
tags: "Test".into(), tags: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1353,7 +1354,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -1417,12 +1418,12 @@ mod tests {
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into()); app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.push_navigation_stack(active_radarr_block.into()); app.push_navigation_stack(active_radarr_block.into());
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
EditIndexerHandler::new(ESC_KEY, &mut app, active_radarr_block, None).handle(); EditIndexerHandler::new(ESC_KEY, &mut app, active_radarr_block, None).handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.data.radarr_data.edit_indexer_modal, app.data.radarr_data.edit_indexer_modal,
Some(EditIndexerModal::default()) Some(EditIndexerModal::default())
@@ -1597,7 +1598,7 @@ mod tests {
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditIndexerNameInput, ActiveRadarrBlock::EditIndexerNameInput,
None, None,
@@ -1613,7 +1614,7 @@ mod tests {
.unwrap() .unwrap()
.name .name
.text, .text,
"h" "a"
); );
} }
@@ -1624,7 +1625,7 @@ mod tests {
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditIndexerUrlInput, ActiveRadarrBlock::EditIndexerUrlInput,
None, None,
@@ -1640,7 +1641,7 @@ mod tests {
.unwrap() .unwrap()
.url .url
.text, .text,
"h" "a"
); );
} }
@@ -1651,7 +1652,7 @@ mod tests {
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditIndexerApiKeyInput, ActiveRadarrBlock::EditIndexerApiKeyInput,
None, None,
@@ -1667,7 +1668,7 @@ mod tests {
.unwrap() .unwrap()
.api_key .api_key
.text, .text,
"h" "a"
); );
} }
@@ -1678,7 +1679,7 @@ mod tests {
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditIndexerSeedRatioInput, ActiveRadarrBlock::EditIndexerSeedRatioInput,
None, None,
@@ -1694,7 +1695,7 @@ mod tests {
.unwrap() .unwrap()
.seed_ratio .seed_ratio
.text, .text,
"h" "a"
); );
} }
@@ -1705,7 +1706,7 @@ mod tests {
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditIndexerTagsInput, ActiveRadarrBlock::EditIndexerTagsInput,
None, None,
@@ -1721,7 +1722,7 @@ mod tests {
.unwrap() .unwrap()
.tags .tags
.text, .text,
"h" "a"
); );
} }
@@ -1793,6 +1794,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_edit_indexer_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = EditIndexerHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_edit_indexer_params() { fn test_build_edit_indexer_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -7,7 +6,9 @@ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS, ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS,
}; };
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{
handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys, matches_key,
};
#[cfg(test)] #[cfg(test)]
#[path = "edit_indexer_settings_handler_tests.rs"] #[path = "edit_indexer_settings_handler_tests.rs"]
@@ -37,6 +38,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
INDEXER_SETTINGS_BLOCKS.contains(&active_block) INDEXER_SETTINGS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -207,7 +212,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
self.app.push_navigation_stack( self.app.push_navigation_stack(
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into(), ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into(),
); );
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveRadarrBlock::IndexerSettingsTogglePreferIndexerFlags => { ActiveRadarrBlock::IndexerSettingsTogglePreferIndexerFlags => {
let indexer_settings = self.app.data.radarr_data.indexer_settings.as_mut().unwrap(); let indexer_settings = self.app.data.radarr_data.indexer_settings.as_mut().unwrap();
@@ -224,7 +229,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
} }
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput => { ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput ActiveRadarrBlock::IndexerSettingsMinimumAgeInput
| ActiveRadarrBlock::IndexerSettingsRetentionInput | ActiveRadarrBlock::IndexerSettingsRetentionInput
@@ -244,7 +249,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
} }
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput => { ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => self.app.pop_navigation_stack(), _ => self.app.pop_navigation_stack(),
} }
@@ -269,7 +274,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
ActiveRadarrBlock::AllIndexerSettingsPrompt => { ActiveRadarrBlock::AllIndexerSettingsPrompt => {
if self.app.data.radarr_data.selected_block.get_active_block() if self.app.data.radarr_data.selected_block.get_active_block()
== ActiveRadarrBlock::IndexerSettingsConfirmPrompt == ActiveRadarrBlock::IndexerSettingsConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some( self.app.data.radarr_data.prompt_confirm_action = Some(
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -602,7 +603,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into() ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
#[test] #[test]
@@ -716,7 +717,7 @@ mod tests {
#[test] #[test]
fn test_edit_indexer_settings_whitelisted_subtitle_tags_input_submit() { fn test_edit_indexer_settings_whitelisted_subtitle_tags_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.indexer_settings = Some(IndexerSettings { app.data.radarr_data.indexer_settings = Some(IndexerSettings {
whitelisted_hardcoded_subs: "Test tags".into(), whitelisted_hardcoded_subs: "Test tags".into(),
..IndexerSettings::default() ..IndexerSettings::default()
@@ -734,7 +735,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -814,7 +815,7 @@ mod tests {
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into(), ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into(),
); );
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default()); app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
IndexerSettingsHandler::new( IndexerSettingsHandler::new(
ESC_KEY, ESC_KEY,
@@ -825,7 +826,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.data.radarr_data.indexer_settings, app.data.radarr_data.indexer_settings,
Some(IndexerSettings::default()) Some(IndexerSettings::default())
@@ -907,7 +908,7 @@ mod tests {
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default()); app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
IndexerSettingsHandler::new( IndexerSettingsHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput, ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
None, None,
@@ -923,7 +924,7 @@ mod tests {
.unwrap() .unwrap()
.whitelisted_hardcoded_subs .whitelisted_hardcoded_subs
.text, .text,
"h" "a"
); );
} }
@@ -970,6 +971,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_indexer_settings_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = IndexerSettingsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_edit_indexer_settings_body() { fn test_build_edit_indexer_settings_body() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -633,6 +633,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_indexers_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = IndexersHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_indexer_id() { fn test_extract_indexer_id() {
let mut app = App::test_default(); let mut app = App::test_default();
+10 -7
View File
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::radarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler; use crate::handlers::radarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
use crate::handlers::radarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler; use crate::handlers::radarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
@@ -15,6 +13,7 @@ use crate::models::servarr_data::radarr::radarr_data::{
use crate::models::servarr_models::Indexer; use crate::models::servarr_models::Indexer;
use crate::models::BlockSelectionState; use crate::models::BlockSelectionState;
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, matches_key};
mod edit_indexer_handler; mod edit_indexer_handler;
mod edit_indexer_settings_handler; mod edit_indexer_settings_handler;
@@ -70,6 +69,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|| INDEXERS_BLOCKS.contains(&active_block) || INDEXERS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -169,20 +172,20 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
let key = self.key; let key = self.key;
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::Indexers => match self.key { ActiveRadarrBlock::Indexers => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.test.key => { _ if matches_key!(test, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into()); .push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
} }
_ if key == DEFAULT_KEYBINDINGS.test_all.key => { _ if matches_key!(test_all, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::TestAllIndexers.into()); .push_navigation_stack(ActiveRadarrBlock::TestAllIndexers.into());
} }
_ if key == DEFAULT_KEYBINDINGS.settings.key => { _ if matches_key!(settings, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
@@ -192,7 +195,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
_ => (), _ => (),
}, },
ActiveRadarrBlock::DeleteIndexerPrompt => { ActiveRadarrBlock::DeleteIndexerPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::DeleteIndexer(self.extract_indexer_id())); Some(RadarrEvent::DeleteIndexer(self.extract_indexer_id()));
@@ -48,6 +48,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for TestAllIndexersHandl
active_block == ActiveRadarrBlock::TestAllIndexers active_block == ActiveRadarrBlock::TestAllIndexers
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -7,6 +7,7 @@ mod tests {
use crate::models::servarr_data::modals::IndexerTestResultModalItem; use crate::models::servarr_data::modals::IndexerTestResultModalItem;
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::models::stateful_table::StatefulTable; use crate::models::stateful_table::StatefulTable;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
mod test_handle_esc { mod test_handle_esc {
@@ -48,6 +49,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_test_all_indexers_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = TestAllIndexersHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_test_all_indexers_handler_is_not_ready_when_loading() { fn test_test_all_indexers_handler_is_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::radarr_models::{ use crate::models::radarr_models::{
@@ -11,7 +10,9 @@ use crate::models::servarr_data::radarr::radarr_data::{
use crate::models::stateful_table::StatefulTable; use crate::models::stateful_table::StatefulTable;
use crate::models::{BlockSelectionState, Scrollable}; use crate::models::{BlockSelectionState, Scrollable};
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, App, Key}; use crate::{
handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, matches_key, App, Key,
};
#[cfg(test)] #[cfg(test)]
#[path = "add_movie_handler_tests.rs"] #[path = "add_movie_handler_tests.rs"]
@@ -132,6 +133,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
ADD_MOVIE_BLOCKS.contains(&active_block) ADD_MOVIE_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -404,7 +409,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchResults.into()); .push_navigation_stack(ActiveRadarrBlock::AddMovieSearchResults.into());
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ if self.active_radarr_block == ActiveRadarrBlock::AddMovieSearchResults _ if self.active_radarr_block == ActiveRadarrBlock::AddMovieSearchResults
&& self.app.data.radarr_data.add_searched_movies.is_some() => && self.app.data.radarr_data.add_searched_movies.is_some() =>
@@ -468,7 +473,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
) )
.into(), .into(),
); );
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
_ => (), _ => (),
} }
@@ -479,7 +484,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
| ActiveRadarrBlock::AddMovieSelectRootFolder => self.app.pop_navigation_stack(), | ActiveRadarrBlock::AddMovieSelectRootFolder => self.app.pop_navigation_stack(),
ActiveRadarrBlock::AddMovieTagsInput => { ActiveRadarrBlock::AddMovieTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => (), _ => (),
} }
@@ -490,12 +495,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
ActiveRadarrBlock::AddMovieSearchInput => { ActiveRadarrBlock::AddMovieSearchInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.radarr_data.add_movie_search = None; self.app.data.radarr_data.add_movie_search = None;
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveRadarrBlock::AddMovieSearchResults | ActiveRadarrBlock::AddMovieEmptySearchResults => { ActiveRadarrBlock::AddMovieSearchResults | ActiveRadarrBlock::AddMovieEmptySearchResults => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.radarr_data.add_searched_movies = None; self.app.data.radarr_data.add_searched_movies = None;
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveRadarrBlock::AddMoviePrompt => { ActiveRadarrBlock::AddMoviePrompt => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
@@ -509,7 +514,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
| ActiveRadarrBlock::AddMovieSelectRootFolder => self.app.pop_navigation_stack(), | ActiveRadarrBlock::AddMovieSelectRootFolder => self.app.pop_navigation_stack(),
ActiveRadarrBlock::AddMovieTagsInput => { ActiveRadarrBlock::AddMovieTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => (), _ => (),
} }
@@ -542,7 +547,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
ActiveRadarrBlock::AddMoviePrompt => { ActiveRadarrBlock::AddMoviePrompt => {
if self.app.data.radarr_data.selected_block.get_active_block() if self.app.data.radarr_data.selected_block.get_active_block()
== ActiveRadarrBlock::AddMovieConfirmPrompt == ActiveRadarrBlock::AddMovieConfirmPrompt
&& key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, key)
{ {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
@@ -782,7 +782,7 @@ mod tests {
#[test] #[test]
fn test_add_movie_search_input_submit() { fn test_add_movie_search_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.add_movie_search = Some("test".into()); app.data.radarr_data.add_movie_search = Some("test".into());
AddMovieHandler::new( AddMovieHandler::new(
@@ -793,7 +793,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::AddMovieSearchResults.into() ActiveRadarrBlock::AddMovieSearchResults.into()
@@ -805,7 +805,7 @@ mod tests {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default()); app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default());
app.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into()); app.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
AddMovieHandler::new( AddMovieHandler::new(
SUBMIT_KEY, SUBMIT_KEY,
@@ -815,7 +815,7 @@ mod tests {
) )
.handle(); .handle();
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::AddMovieSearchInput.into() ActiveRadarrBlock::AddMovieSearchInput.into()
@@ -1093,7 +1093,7 @@ mod tests {
assert_eq!(app.data.radarr_data.prompt_confirm_action, None); assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
if selected_block == ActiveRadarrBlock::AddMovieTagsInput { if selected_block == ActiveRadarrBlock::AddMovieTagsInput {
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
} }
@@ -1126,7 +1126,7 @@ mod tests {
); );
if active_radarr_block == ActiveRadarrBlock::AddMovieTagsInput { if active_radarr_block == ActiveRadarrBlock::AddMovieTagsInput {
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
} }
} }
@@ -1149,7 +1149,7 @@ mod tests {
let mut app = App::test_default(); let mut app = App::test_default();
app.is_loading = is_ready; app.is_loading = is_ready;
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into()); app.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into());
AddMovieHandler::new( AddMovieHandler::new(
@@ -1160,7 +1160,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert_eq!(app.data.radarr_data.add_movie_search, None); assert_eq!(app.data.radarr_data.add_movie_search, None);
} }
@@ -1169,7 +1169,7 @@ mod tests {
fn test_add_movie_input_esc() { fn test_add_movie_input_esc() {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
app.push_navigation_stack(ActiveRadarrBlock::AddMovieTagsInput.into()); app.push_navigation_stack(ActiveRadarrBlock::AddMovieTagsInput.into());
@@ -1181,7 +1181,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::AddMoviePrompt.into() ActiveRadarrBlock::AddMoviePrompt.into()
@@ -1213,7 +1213,7 @@ mod tests {
ActiveRadarrBlock::AddMovieSearchInput.into() ActiveRadarrBlock::AddMovieSearchInput.into()
); );
assert!(app.data.radarr_data.add_searched_movies.is_none()); assert!(app.data.radarr_data.add_searched_movies.is_none());
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
#[test] #[test]
@@ -1259,7 +1259,7 @@ mod tests {
fn test_add_movie_tags_input_esc() { fn test_add_movie_tags_input_esc() {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
app.push_navigation_stack(ActiveRadarrBlock::AddMovieTagsInput.into()); app.push_navigation_stack(ActiveRadarrBlock::AddMovieTagsInput.into());
@@ -1271,7 +1271,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::AddMoviePrompt.into() ActiveRadarrBlock::AddMoviePrompt.into()
@@ -1395,7 +1395,7 @@ mod tests {
app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default()); app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default());
AddMovieHandler::new( AddMovieHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::AddMovieSearchInput, ActiveRadarrBlock::AddMovieSearchInput,
None, None,
@@ -1404,7 +1404,7 @@ mod tests {
assert_str_eq!( assert_str_eq!(
app.data.radarr_data.add_movie_search.as_ref().unwrap().text, app.data.radarr_data.add_movie_search.as_ref().unwrap().text,
"h" "a"
); );
} }
@@ -1414,7 +1414,7 @@ mod tests {
app.data.radarr_data.add_movie_modal = Some(AddMovieModal::default()); app.data.radarr_data.add_movie_modal = Some(AddMovieModal::default());
AddMovieHandler::new( AddMovieHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::AddMovieTagsInput, ActiveRadarrBlock::AddMovieTagsInput,
None, None,
@@ -1430,7 +1430,7 @@ mod tests {
.unwrap() .unwrap()
.tags .tags
.text, .text,
"h" "a"
); );
} }
@@ -1523,6 +1523,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_add_movie_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = AddMovieHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_add_movie_search_no_panic_on_none_search_result() { fn test_add_movie_search_no_panic_on_none_search_result() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,7 +1,7 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::matches_key;
use crate::models::radarr_models::DeleteMovieParams; use crate::models::radarr_models::DeleteMovieParams;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DELETE_MOVIE_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DELETE_MOVIE_BLOCKS};
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
@@ -37,6 +37,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
DELETE_MOVIE_BLOCKS.contains(&active_block) DELETE_MOVIE_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -122,7 +126,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt
&& self.app.data.radarr_data.selected_block.get_active_block() && self.app.data.radarr_data.selected_block.get_active_block()
== ActiveRadarrBlock::DeleteMovieConfirmPrompt == ActiveRadarrBlock::DeleteMovieConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -313,6 +314,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_delete_movie_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = DeleteMovieHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_delete_movie_params() { fn test_build_delete_movie_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -7,7 +6,7 @@ use crate::models::servarr_data::radarr::modals::EditMovieModal;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_MOVIE_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_MOVIE_BLOCKS};
use crate::models::Scrollable; use crate::models::Scrollable;
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{handle_text_box_keys, handle_text_box_left_right_keys, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "edit_movie_handler_tests.rs"] #[path = "edit_movie_handler_tests.rs"]
@@ -68,6 +67,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
EDIT_MOVIE_BLOCKS.contains(&active_block) EDIT_MOVIE_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -290,7 +293,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
) )
.into(), .into(),
); );
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveRadarrBlock::EditMovieToggleMonitored => { ActiveRadarrBlock::EditMovieToggleMonitored => {
self self
@@ -319,7 +322,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
| ActiveRadarrBlock::EditMovieSelectQualityProfile => self.app.pop_navigation_stack(), | ActiveRadarrBlock::EditMovieSelectQualityProfile => self.app.pop_navigation_stack(),
ActiveRadarrBlock::EditMoviePathInput | ActiveRadarrBlock::EditMovieTagsInput => { ActiveRadarrBlock::EditMoviePathInput | ActiveRadarrBlock::EditMovieTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => (), _ => (),
} }
@@ -329,7 +332,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::EditMovieTagsInput | ActiveRadarrBlock::EditMoviePathInput => { ActiveRadarrBlock::EditMovieTagsInput | ActiveRadarrBlock::EditMoviePathInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveRadarrBlock::EditMoviePrompt => { ActiveRadarrBlock::EditMoviePrompt => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
@@ -376,7 +379,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
ActiveRadarrBlock::EditMoviePrompt => { ActiveRadarrBlock::EditMoviePrompt => {
if self.app.data.radarr_data.selected_block.get_active_block() if self.app.data.radarr_data.selected_block.get_active_block()
== ActiveRadarrBlock::EditMovieConfirmPrompt == ActiveRadarrBlock::EditMovieConfirmPrompt
&& key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, key)
{ {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
@@ -2,6 +2,7 @@
mod tests { mod tests {
use bimap::BiMap; use bimap::BiMap;
use pretty_assertions::assert_str_eq; use pretty_assertions::assert_str_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -548,7 +549,7 @@ mod tests {
#[test] #[test]
fn test_edit_movie_path_input_submit() { fn test_edit_movie_path_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal { app.data.radarr_data.edit_movie_modal = Some(EditMovieModal {
path: "Test Path".into(), path: "Test Path".into(),
..EditMovieModal::default() ..EditMovieModal::default()
@@ -564,7 +565,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -583,7 +584,7 @@ mod tests {
#[test] #[test]
fn test_edit_movie_tags_input_submit() { fn test_edit_movie_tags_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal { app.data.radarr_data.edit_movie_modal = Some(EditMovieModal {
tags: "Test Tags".into(), tags: "Test Tags".into(),
..EditMovieModal::default() ..EditMovieModal::default()
@@ -599,7 +600,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.radarr_data .radarr_data
@@ -813,7 +814,7 @@ mod tests {
if selected_block == ActiveRadarrBlock::EditMoviePathInput if selected_block == ActiveRadarrBlock::EditMoviePathInput
|| selected_block == ActiveRadarrBlock::EditMovieTagsInput || selected_block == ActiveRadarrBlock::EditMovieTagsInput
{ {
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
} }
@@ -851,7 +852,7 @@ mod tests {
.into() .into()
); );
assert_eq!(app.data.radarr_data.prompt_confirm_action, None); assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
#[rstest] #[rstest]
@@ -885,7 +886,7 @@ mod tests {
if active_radarr_block == ActiveRadarrBlock::EditMoviePathInput if active_radarr_block == ActiveRadarrBlock::EditMoviePathInput
|| active_radarr_block == ActiveRadarrBlock::EditMovieTagsInput || active_radarr_block == ActiveRadarrBlock::EditMovieTagsInput
{ {
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
} }
} }
@@ -911,13 +912,13 @@ mod tests {
) { ) {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
app.push_navigation_stack(active_radarr_block.into()); app.push_navigation_stack(active_radarr_block.into());
EditMovieHandler::new(ESC_KEY, &mut app, active_radarr_block, None).handle(); EditMovieHandler::new(ESC_KEY, &mut app, active_radarr_block, None).handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::EditMoviePrompt.into() ActiveRadarrBlock::EditMoviePrompt.into()
@@ -1033,7 +1034,7 @@ mod tests {
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default()); app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
EditMovieHandler::new( EditMovieHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditMoviePathInput, ActiveRadarrBlock::EditMoviePathInput,
None, None,
@@ -1049,7 +1050,7 @@ mod tests {
.unwrap() .unwrap()
.path .path
.text, .text,
"h" "a"
); );
} }
@@ -1059,7 +1060,7 @@ mod tests {
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default()); app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
EditMovieHandler::new( EditMovieHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::EditMovieTagsInput, ActiveRadarrBlock::EditMovieTagsInput,
None, None,
@@ -1075,7 +1076,7 @@ mod tests {
.unwrap() .unwrap()
.tags .tags
.text, .text,
"h" "a"
); );
} }
@@ -1148,6 +1149,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_edit_movie_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = EditMovieHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_edit_movie_params() { fn test_build_edit_movie_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -331,7 +331,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::AddMovieSearchInput.into() ActiveRadarrBlock::AddMovieSearchInput.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.add_movie_search.is_some()); assert!(app.data.radarr_data.add_movie_search.is_some());
} }
@@ -355,7 +355,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.add_movie_search.is_none()); assert!(app.data.radarr_data.add_movie_search.is_none());
} }
@@ -777,6 +777,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_library_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = LibraryHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_library_handler_not_ready_when_loading() { fn test_library_handler_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
+11 -8
View File
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
@@ -8,7 +7,6 @@ use crate::handlers::radarr_handlers::library::edit_movie_handler::EditMovieHand
use crate::handlers::radarr_handlers::library::movie_details_handler::MovieDetailsHandler; use crate::handlers::radarr_handlers::library::movie_details_handler::MovieDetailsHandler;
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
use crate::handle_table_events;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::models::radarr_models::Movie; use crate::models::radarr_models::Movie;
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
@@ -17,6 +15,7 @@ use crate::models::servarr_data::radarr::radarr_data::{
use crate::models::stateful_table::SortOption; use crate::models::stateful_table::SortOption;
use crate::models::{BlockSelectionState, HorizontallyScrollableText}; use crate::models::{BlockSelectionState, HorizontallyScrollableText};
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, matches_key};
mod add_movie_handler; mod add_movie_handler;
mod delete_movie_handler; mod delete_movie_handler;
@@ -81,6 +80,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|| LIBRARY_BLOCKS.contains(&active_block) || LIBRARY_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -161,7 +164,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
let key = self.key; let key = self.key;
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::Movies => match self.key { ActiveRadarrBlock::Movies => match self.key {
_ if key == DEFAULT_KEYBINDINGS.edit.key => { _ if matches_key!(edit, key) => {
self.app.push_navigation_stack( self.app.push_navigation_stack(
( (
ActiveRadarrBlock::EditMoviePrompt, ActiveRadarrBlock::EditMoviePrompt,
@@ -173,25 +176,25 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
self.app.data.radarr_data.selected_block = self.app.data.radarr_data.selected_block =
BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS); BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
} }
_ if key == DEFAULT_KEYBINDINGS.add.key => { _ if matches_key!(add, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into()); .push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into());
self.app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default()); self.app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default());
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::UpdateAllMoviesPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::UpdateAllMoviesPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ => (), _ => (),
}, },
ActiveRadarrBlock::UpdateAllMoviesPrompt => { ActiveRadarrBlock::UpdateAllMoviesPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies); self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
@@ -1,9 +1,7 @@
use serde_json::Number; use serde_json::Number;
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::radarr_models::{ use crate::models::radarr_models::{
@@ -16,6 +14,7 @@ use crate::models::servarr_models::Language;
use crate::models::stateful_table::SortOption; use crate::models::stateful_table::SortOption;
use crate::models::{BlockSelectionState, Scrollable}; use crate::models::{BlockSelectionState, Scrollable};
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "movie_details_handler_tests.rs"] #[path = "movie_details_handler_tests.rs"]
@@ -136,6 +135,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
MOVIE_DETAILS_BLOCKS.contains(&active_block) MOVIE_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -245,13 +248,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
| ActiveRadarrBlock::Cast | ActiveRadarrBlock::Cast
| ActiveRadarrBlock::Crew | ActiveRadarrBlock::Crew
| ActiveRadarrBlock::ManualSearch => match self.key { | ActiveRadarrBlock::ManualSearch => match self.key {
_ if self.key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, self.key) => {
self.app.data.radarr_data.movie_info_tabs.previous(); self.app.data.radarr_data.movie_info_tabs.previous();
self.app.pop_and_push_navigation_stack( self.app.pop_and_push_navigation_stack(
self.app.data.radarr_data.movie_info_tabs.get_active_route(), self.app.data.radarr_data.movie_info_tabs.get_active_route(),
); );
} }
_ if self.key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, self.key) => {
self.app.data.radarr_data.movie_info_tabs.next(); self.app.data.radarr_data.movie_info_tabs.next();
self.app.pop_and_push_navigation_stack( self.app.pop_and_push_navigation_stack(
self.app.data.radarr_data.movie_info_tabs.get_active_route(), self.app.data.radarr_data.movie_info_tabs.get_active_route(),
@@ -332,12 +335,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
| ActiveRadarrBlock::Cast | ActiveRadarrBlock::Cast
| ActiveRadarrBlock::Crew | ActiveRadarrBlock::Crew
| ActiveRadarrBlock::ManualSearch => match self.key { | ActiveRadarrBlock::ManualSearch => match self.key {
_ if key == DEFAULT_KEYBINDINGS.auto_search.key => { _ if matches_key!(auto_search, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::AutomaticallySearchMoviePrompt.into()); .push_navigation_stack(ActiveRadarrBlock::AutomaticallySearchMoviePrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.edit.key => { _ if matches_key!(edit, key) => {
self.app.push_navigation_stack( self.app.push_navigation_stack(
( (
ActiveRadarrBlock::EditMoviePrompt, ActiveRadarrBlock::EditMoviePrompt,
@@ -349,35 +352,33 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
self.app.data.radarr_data.selected_block = self.app.data.radarr_data.selected_block =
BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS); BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::UpdateAndScanPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::UpdateAndScanPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self self
.app .app
.pop_and_push_navigation_stack(self.active_radarr_block.into()); .pop_and_push_navigation_stack(self.active_radarr_block.into());
} }
_ => (), _ => (),
}, },
ActiveRadarrBlock::AutomaticallySearchMoviePrompt ActiveRadarrBlock::AutomaticallySearchMoviePrompt if matches_key!(confirm, key) => {
if key == DEFAULT_KEYBINDINGS.confirm.key =>
{
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::TriggerAutomaticSearch(self.extract_movie_id())); Some(RadarrEvent::TriggerAutomaticSearch(self.extract_movie_id()));
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
} }
ActiveRadarrBlock::UpdateAndScanPrompt if key == DEFAULT_KEYBINDINGS.confirm.key => { ActiveRadarrBlock::UpdateAndScanPrompt if matches_key!(confirm, key) => {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::UpdateAndScan(self.extract_movie_id())); Some(RadarrEvent::UpdateAndScan(self.extract_movie_id()));
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
} }
ActiveRadarrBlock::ManualSearchConfirmPrompt if key == DEFAULT_KEYBINDINGS.confirm.key => { ActiveRadarrBlock::ManualSearchConfirmPrompt if matches_key!(confirm, key) => {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DownloadRelease( self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DownloadRelease(
self.build_radarr_release_download_body(), self.build_radarr_release_download_body(),
@@ -1042,6 +1042,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_movie_details_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = MovieDetailsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[rstest] #[rstest]
fn test_movie_details_handler_is_not_ready_when_loading( fn test_movie_details_handler_is_not_ready_when_loading(
#[values( #[values(
+9 -6
View File
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::handlers::radarr_handlers::blocklist::BlocklistHandler; use crate::handlers::radarr_handlers::blocklist::BlocklistHandler;
use crate::handlers::radarr_handlers::collections::CollectionsHandler; use crate::handlers::radarr_handlers::collections::CollectionsHandler;
use crate::handlers::radarr_handlers::downloads::DownloadsHandler; use crate::handlers::radarr_handlers::downloads::DownloadsHandler;
@@ -8,7 +7,7 @@ use crate::handlers::radarr_handlers::root_folders::RootFoldersHandler;
use crate::handlers::radarr_handlers::system::SystemHandler; use crate::handlers::radarr_handlers::system::SystemHandler;
use crate::handlers::KeyEventHandler; use crate::handlers::KeyEventHandler;
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::{App, Key}; use crate::{matches_key, App, Key};
mod blocklist; mod blocklist;
mod collections; mod collections;
@@ -65,6 +64,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
true true
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -109,11 +112,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
pub fn handle_change_tab_left_right_keys(app: &mut App<'_>, key: Key) { pub fn handle_change_tab_left_right_keys(app: &mut App<'_>, key: Key) {
let key_ref = key; let key_ref = key;
match key_ref { match key_ref {
_ if key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, key, app.ignore_special_keys_for_textbox_input) => {
app.data.radarr_data.main_tabs.previous(); app.data.radarr_data.main_tabs.previous();
app.pop_and_push_navigation_stack(app.data.radarr_data.main_tabs.get_active_route()); app.pop_and_push_navigation_stack(app.data.radarr_data.main_tabs.get_active_route());
} }
_ if key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, key, app.ignore_special_keys_for_textbox_input) => {
app.data.radarr_data.main_tabs.next(); app.data.radarr_data.main_tabs.next();
app.pop_and_push_navigation_stack(app.data.radarr_data.main_tabs.get_active_route()); app.pop_and_push_navigation_stack(app.data.radarr_data.main_tabs.get_active_route());
} }
@@ -139,7 +142,7 @@ macro_rules! search_table {
}; };
$app.data.radarr_data.is_searching = false; $app.data.radarr_data.is_searching = false;
$app.should_ignore_quit_key = false; $app.ignore_special_keys_for_textbox_input = false;
if search_index.is_some() { if search_index.is_some() {
$app.pop_navigation_stack(); $app.pop_navigation_stack();
@@ -166,7 +169,7 @@ macro_rules! search_table {
}; };
$app.data.radarr_data.is_searching = false; $app.data.radarr_data.is_searching = false;
$app.should_ignore_quit_key = false; $app.ignore_special_keys_for_textbox_input = false;
if search_index.is_some() { if search_index.is_some() {
$app.pop_navigation_stack(); $app.pop_navigation_stack();
@@ -46,6 +46,76 @@ mod tests {
assert_eq!(app.get_current_route(), right_block.into()); assert_eq!(app.get_current_route(), right_block.into());
} }
#[rstest]
#[case(0, ActiveRadarrBlock::System, ActiveRadarrBlock::Collections)]
#[case(1, ActiveRadarrBlock::Movies, ActiveRadarrBlock::Downloads)]
#[case(2, ActiveRadarrBlock::Collections, ActiveRadarrBlock::Blocklist)]
#[case(3, ActiveRadarrBlock::Downloads, ActiveRadarrBlock::RootFolders)]
#[case(4, ActiveRadarrBlock::Blocklist, ActiveRadarrBlock::Indexers)]
#[case(5, ActiveRadarrBlock::RootFolders, ActiveRadarrBlock::System)]
#[case(6, ActiveRadarrBlock::Indexers, ActiveRadarrBlock::Movies)]
fn test_radarr_handler_change_tab_left_right_keys_alt_navigation(
#[case] index: usize,
#[case] left_block: ActiveRadarrBlock,
#[case] right_block: ActiveRadarrBlock,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = false;
app.data.radarr_data.main_tabs.set_index(index);
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.alt.unwrap());
assert_eq!(
app.data.radarr_data.main_tabs.get_active_route(),
left_block.into()
);
assert_eq!(app.get_current_route(), left_block.into());
app.data.radarr_data.main_tabs.set_index(index);
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.alt.unwrap());
assert_eq!(
app.data.radarr_data.main_tabs.get_active_route(),
right_block.into()
);
assert_eq!(app.get_current_route(), right_block.into());
}
#[rstest]
#[case(0, ActiveRadarrBlock::Movies)]
#[case(1, ActiveRadarrBlock::Collections)]
#[case(2, ActiveRadarrBlock::Downloads)]
#[case(3, ActiveRadarrBlock::Blocklist)]
#[case(4, ActiveRadarrBlock::RootFolders)]
#[case(5, ActiveRadarrBlock::Indexers)]
#[case(6, ActiveRadarrBlock::System)]
fn test_radarr_handler_change_tab_left_right_keys_alt_navigation_no_op_when_ignoring_quit_key(
#[case] index: usize,
#[case] block: ActiveRadarrBlock,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(block.into());
app.data.radarr_data.main_tabs.set_index(index);
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.alt.unwrap());
assert_eq!(
app.data.radarr_data.main_tabs.get_active_route(),
block.into()
);
assert_eq!(app.get_current_route(), block.into());
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.alt.unwrap());
assert_eq!(
app.data.radarr_data.main_tabs.get_active_route(),
block.into()
);
assert_eq!(app.get_current_route(), block.into());
}
#[rstest] #[rstest]
fn test_delegates_system_blocks_to_system_handler( fn test_delegates_system_blocks_to_system_handler(
#[values( #[values(
@@ -217,6 +287,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_radarr_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = RadarrHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::Movies,
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_radarr_handler_is_ready() { fn test_radarr_handler_is_ready() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
@@ -8,7 +7,9 @@ use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ROOT_F
use crate::models::servarr_models::{AddRootFolderBody, RootFolder}; use crate::models::servarr_models::{AddRootFolderBody, RootFolder};
use crate::models::HorizontallyScrollableText; use crate::models::HorizontallyScrollableText;
use crate::network::radarr_network::RadarrEvent; use crate::network::radarr_network::RadarrEvent;
use crate::{handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{
handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, matches_key,
};
#[cfg(test)] #[cfg(test)]
#[path = "root_folders_handler_tests.rs"] #[path = "root_folders_handler_tests.rs"]
@@ -68,6 +69,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
ROOT_FOLDERS_BLOCKS.contains(&active_block) ROOT_FOLDERS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -168,7 +173,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
self.build_add_root_folder_body(), self.build_add_root_folder_body(),
)); ));
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
} }
_ => (), _ => (),
@@ -181,7 +186,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.radarr_data.edit_root_folder = None; self.app.data.radarr_data.edit_root_folder = None;
self.app.data.radarr_data.prompt_confirm = false; self.app.data.radarr_data.prompt_confirm = false;
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveRadarrBlock::DeleteRootFolderPrompt => { ActiveRadarrBlock::DeleteRootFolderPrompt => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
@@ -195,15 +200,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
let key = self.key; let key = self.key;
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::RootFolders => match self.key { ActiveRadarrBlock::RootFolders => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.add.key => { _ if matches_key!(add, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
self.app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default()); self.app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
_ => (), _ => (),
}, },
@@ -215,7 +220,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
) )
} }
ActiveRadarrBlock::DeleteRootFolderPrompt => { ActiveRadarrBlock::DeleteRootFolderPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::DeleteRootFolder(self.extract_root_folder_id())); Some(RadarrEvent::DeleteRootFolder(self.extract_root_folder_id()));
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -262,7 +263,7 @@ mod tests {
.set_items(vec![RootFolder::default()]); .set_items(vec![RootFolder::default()]);
app.data.radarr_data.edit_root_folder = Some("Test".into()); app.data.radarr_data.edit_root_folder = Some("Test".into());
app.data.radarr_data.prompt_confirm = true; app.data.radarr_data.prompt_confirm = true;
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into()); app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
@@ -275,7 +276,7 @@ mod tests {
.handle(); .handle();
assert!(app.data.radarr_data.prompt_confirm); assert!(app.data.radarr_data.prompt_confirm);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.data.radarr_data.prompt_confirm_action, app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::AddRootFolder(expected_add_root_folder_body)) Some(RadarrEvent::AddRootFolder(expected_add_root_folder_body))
@@ -291,7 +292,7 @@ mod tests {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default()); app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
app.data.radarr_data.prompt_confirm = false; app.data.radarr_data.prompt_confirm = false;
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into()); app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
@@ -304,7 +305,7 @@ mod tests {
.handle(); .handle();
assert!(!app.data.radarr_data.prompt_confirm); assert!(!app.data.radarr_data.prompt_confirm);
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.prompt_confirm_action.is_none()); assert!(app.data.radarr_data.prompt_confirm_action.is_none());
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
@@ -406,7 +407,7 @@ mod tests {
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into()); app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
app.data.radarr_data.edit_root_folder = Some("/nfs/test".into()); app.data.radarr_data.edit_root_folder = Some("/nfs/test".into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
RootFoldersHandler::new( RootFoldersHandler::new(
ESC_KEY, ESC_KEY,
@@ -423,7 +424,7 @@ mod tests {
assert!(app.data.radarr_data.edit_root_folder.is_none()); assert!(app.data.radarr_data.edit_root_folder.is_none());
assert!(!app.data.radarr_data.prompt_confirm); assert!(!app.data.radarr_data.prompt_confirm);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
#[rstest] #[rstest]
@@ -472,7 +473,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::AddRootFolderPrompt.into() ActiveRadarrBlock::AddRootFolderPrompt.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.edit_root_folder.is_some()); assert!(app.data.radarr_data.edit_root_folder.is_some());
} }
@@ -499,7 +500,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::RootFolders.into() ActiveRadarrBlock::RootFolders.into()
); );
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.edit_root_folder.is_none()); assert!(app.data.radarr_data.edit_root_folder.is_none());
} }
@@ -589,7 +590,7 @@ mod tests {
app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default()); app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
RootFoldersHandler::new( RootFoldersHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::AddRootFolderPrompt, ActiveRadarrBlock::AddRootFolderPrompt,
None, None,
@@ -598,7 +599,7 @@ mod tests {
assert_str_eq!( assert_str_eq!(
app.data.radarr_data.edit_root_folder.as_ref().unwrap().text, app.data.radarr_data.edit_root_folder.as_ref().unwrap().text,
"h" "a"
); );
} }
@@ -644,6 +645,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_root_folders_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = RootFoldersHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_add_root_folder_body() { fn test_build_add_root_folder_body() {
let mut app = App::test_default(); let mut app = App::test_default();
+10 -6
View File
@@ -1,9 +1,9 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::radarr_handlers::system::system_details_handler::SystemDetailsHandler; use crate::handlers::radarr_handlers::system::system_details_handler::SystemDetailsHandler;
use crate::handlers::{handle_clear_errors, KeyEventHandler}; use crate::handlers::{handle_clear_errors, KeyEventHandler};
use crate::matches_key;
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::models::Scrollable; use crate::models::Scrollable;
@@ -35,6 +35,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
SystemDetailsHandler::accepts(active_block) || active_block == ActiveRadarrBlock::System SystemDetailsHandler::accepts(active_block) || active_block == ActiveRadarrBlock::System
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -86,15 +90,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
if self.active_radarr_block == ActiveRadarrBlock::System { if self.active_radarr_block == ActiveRadarrBlock::System {
let key = self.key; let key = self.key;
match self.key { match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.events.key => { _ if matches_key!(events, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::SystemQueuedEvents.into()); .push_navigation_stack(ActiveRadarrBlock::SystemQueuedEvents.into());
} }
_ if key == DEFAULT_KEYBINDINGS.logs.key => { _ if matches_key!(logs, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::SystemLogs.into()); .push_navigation_stack(ActiveRadarrBlock::SystemLogs.into());
@@ -106,12 +110,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
.set_items(self.app.data.radarr_data.logs.items.to_vec()); .set_items(self.app.data.radarr_data.logs.items.to_vec());
self.app.data.radarr_data.log_details.scroll_to_bottom(); self.app.data.radarr_data.log_details.scroll_to_bottom();
} }
_ if key == DEFAULT_KEYBINDINGS.tasks.key => { _ if matches_key!(tasks, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into()); .push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveRadarrBlock::SystemUpdates.into()); .push_navigation_stack(ActiveRadarrBlock::SystemUpdates.into());
@@ -1,7 +1,7 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::matches_key;
use crate::models::radarr_models::RadarrTaskName; use crate::models::radarr_models::RadarrTaskName;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS};
use crate::models::stateful_list::StatefulList; use crate::models::stateful_list::StatefulList;
@@ -36,6 +36,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
SYSTEM_DETAILS_BLOCKS.contains(&active_block) SYSTEM_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -114,7 +118,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::SystemLogs => match self.key { ActiveRadarrBlock::SystemLogs => match self.key {
_ if key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, key) => {
self self
.app .app
.data .data
@@ -124,7 +128,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
.iter() .iter()
.for_each(|log| log.scroll_right()); .for_each(|log| log.scroll_right());
} }
_ if key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, key) => {
self self
.app .app
.data .data
@@ -178,14 +182,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
} }
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
if SYSTEM_DETAILS_BLOCKS.contains(&self.active_radarr_block) if SYSTEM_DETAILS_BLOCKS.contains(&self.active_radarr_block) && matches_key!(refresh, self.key)
&& self.key == DEFAULT_KEYBINDINGS.refresh.key
{ {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
if self.active_radarr_block == ActiveRadarrBlock::SystemTaskStartConfirmPrompt if self.active_radarr_block == ActiveRadarrBlock::SystemTaskStartConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.radarr_data.prompt_confirm = true; self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = self.app.data.radarr_data.prompt_confirm_action =
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -938,6 +939,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_system_details_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = SystemDetailsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_task_name() { fn test_extract_task_name() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -450,6 +450,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_system_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = SystemHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveRadarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_system_handler_is_not_ready_when_loading() { fn test_system_handler_is_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -4,6 +4,7 @@ mod tests {
use chrono::DateTime; use chrono::DateTime;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -513,6 +514,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_blocklist_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = BlocklistHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_blocklist_item_id() { fn test_extract_blocklist_item_id() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
@@ -9,6 +7,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, BLOCKL
use crate::models::sonarr_models::BlocklistItem; use crate::models::sonarr_models::BlocklistItem;
use crate::models::stateful_table::SortOption; use crate::models::stateful_table::SortOption;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "blocklist_handler_tests.rs"] #[path = "blocklist_handler_tests.rs"]
@@ -51,6 +50,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for BlocklistHandler<'a,
BLOCKLIST_BLOCKS.contains(&active_block) BLOCKLIST_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -143,10 +146,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for BlocklistHandler<'a,
let key = self.key; let key = self.key;
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::Blocklist => match self.key { ActiveSonarrBlock::Blocklist => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.clear.key => { _ if matches_key!(clear, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::BlocklistClearAllItemsPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::BlocklistClearAllItemsPrompt.into());
@@ -154,7 +157,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for BlocklistHandler<'a,
_ => (), _ => (),
}, },
ActiveSonarrBlock::DeleteBlocklistItemPrompt => { ActiveSonarrBlock::DeleteBlocklistItemPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteBlocklistItem( self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteBlocklistItem(
self.extract_blocklist_item_id(), self.extract_blocklist_item_id(),
@@ -164,7 +167,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for BlocklistHandler<'a,
} }
} }
ActiveSonarrBlock::BlocklistClearAllItemsPrompt => { ActiveSonarrBlock::BlocklistClearAllItemsPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::ClearBlocklist); self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::ClearBlocklist);
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -389,6 +390,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_downloads_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = DownloadsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_download_id() { fn test_extract_download_id() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,13 +1,12 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DOWNLOADS_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DOWNLOADS_BLOCKS};
use crate::models::sonarr_models::DownloadRecord; use crate::models::sonarr_models::DownloadRecord;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "downloads_handler_tests.rs"] #[path = "downloads_handler_tests.rs"]
@@ -47,6 +46,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for DownloadsHandler<'a,
DOWNLOADS_BLOCKS.contains(&active_block) DOWNLOADS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -130,18 +133,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for DownloadsHandler<'a,
let key = self.key; let key = self.key;
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::Downloads => match self.key { ActiveSonarrBlock::Downloads => match self.key {
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::UpdateDownloadsPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::UpdateDownloadsPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ => (), _ => (),
}, },
ActiveSonarrBlock::DeleteDownloadPrompt => { ActiveSonarrBlock::DeleteDownloadPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
Some(SonarrEvent::DeleteDownload(self.extract_download_id())); Some(SonarrEvent::DeleteDownload(self.extract_download_id()));
@@ -150,7 +153,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for DownloadsHandler<'a,
} }
} }
ActiveSonarrBlock::UpdateDownloadsPrompt => { ActiveSonarrBlock::UpdateDownloadsPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::UpdateDownloads); self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::UpdateDownloads);
@@ -4,6 +4,7 @@ mod tests {
use chrono::DateTime; use chrono::DateTime;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -306,6 +307,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_history_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = HistoryHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_history_handler_not_ready_when_loading() { fn test_history_handler_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
+6 -3
View File
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_clear_errors, KeyEventHandler}; use crate::handlers::{handle_clear_errors, KeyEventHandler};
@@ -9,6 +7,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTOR
use crate::models::servarr_models::Language; use crate::models::servarr_models::Language;
use crate::models::sonarr_models::SonarrHistoryItem; use crate::models::sonarr_models::SonarrHistoryItem;
use crate::models::stateful_table::SortOption; use crate::models::stateful_table::SortOption;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "history_handler_tests.rs"] #[path = "history_handler_tests.rs"]
@@ -52,6 +51,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for HistoryHandler<'a, '
HISTORY_BLOCKS.contains(&active_block) HISTORY_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -110,7 +113,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for HistoryHandler<'a, '
let key = self.key; let key = self.key;
if self.active_sonarr_block == ActiveSonarrBlock::History { if self.active_sonarr_block == ActiveSonarrBlock::History {
match self.key { match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ => (), _ => (),
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -6,7 +5,9 @@ use crate::models::servarr_data::modals::EditIndexerModal;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::servarr_models::EditIndexerParams; use crate::models::servarr_models::EditIndexerParams;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{
handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys, matches_key,
};
#[cfg(test)] #[cfg(test)]
#[path = "edit_indexer_handler_tests.rs"] #[path = "edit_indexer_handler_tests.rs"]
@@ -64,6 +65,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditIndexerHandler<'
EDIT_INDEXER_BLOCKS.contains(&active_block) EDIT_INDEXER_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -355,7 +360,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditIndexerHandler<'
| ActiveSonarrBlock::EditIndexerSeedRatioInput | ActiveSonarrBlock::EditIndexerSeedRatioInput
| ActiveSonarrBlock::EditIndexerTagsInput => { | ActiveSonarrBlock::EditIndexerTagsInput => {
self.app.push_navigation_stack(selected_block.into()); self.app.push_navigation_stack(selected_block.into());
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveSonarrBlock::EditIndexerPriorityInput => self ActiveSonarrBlock::EditIndexerPriorityInput => self
.app .app
@@ -401,7 +406,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditIndexerHandler<'
| ActiveSonarrBlock::EditIndexerSeedRatioInput | ActiveSonarrBlock::EditIndexerSeedRatioInput
| ActiveSonarrBlock::EditIndexerTagsInput => { | ActiveSonarrBlock::EditIndexerTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveSonarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(), ActiveSonarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(),
_ => (), _ => (),
@@ -422,7 +427,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditIndexerHandler<'
| ActiveSonarrBlock::EditIndexerPriorityInput | ActiveSonarrBlock::EditIndexerPriorityInput
| ActiveSonarrBlock::EditIndexerTagsInput => { | ActiveSonarrBlock::EditIndexerTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => self.app.pop_navigation_stack(), _ => self.app.pop_navigation_stack(),
} }
@@ -503,7 +508,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditIndexerHandler<'
ActiveSonarrBlock::EditIndexerPrompt => { ActiveSonarrBlock::EditIndexerPrompt => {
if self.app.data.sonarr_data.selected_block.get_active_block() if self.app.data.sonarr_data.selected_block.get_active_block()
== ActiveSonarrBlock::EditIndexerConfirmPrompt == ActiveSonarrBlock::EditIndexerConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
@@ -10,6 +10,7 @@ mod tests {
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::servarr_models::EditIndexerParams; use crate::models::servarr_models::EditIndexerParams;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
mod test_handle_scroll_up_and_down { mod test_handle_scroll_up_and_down {
@@ -1002,7 +1003,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), block.into()); assert_eq!(app.get_current_route(), block.into());
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
#[test] #[test]
@@ -1027,7 +1028,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::EditIndexerPriorityInput.into() ActiveSonarrBlock::EditIndexerPriorityInput.into()
); );
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
#[test] #[test]
@@ -1193,7 +1194,7 @@ mod tests {
fn test_edit_indexer_name_input_submit() { fn test_edit_indexer_name_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into()); app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal {
name: "Test".into(), name: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1209,7 +1210,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.sonarr_data .sonarr_data
@@ -1229,7 +1230,7 @@ mod tests {
fn test_edit_indexer_url_input_submit() { fn test_edit_indexer_url_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into()); app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal {
url: "Test".into(), url: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1245,7 +1246,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.sonarr_data .sonarr_data
@@ -1265,7 +1266,7 @@ mod tests {
fn test_edit_indexer_api_key_input_submit() { fn test_edit_indexer_api_key_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into()); app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal {
api_key: "Test".into(), api_key: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1281,7 +1282,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.sonarr_data .sonarr_data
@@ -1301,7 +1302,7 @@ mod tests {
fn test_edit_indexer_seed_ratio_input_submit() { fn test_edit_indexer_seed_ratio_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into()); app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal {
seed_ratio: "Test".into(), seed_ratio: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1317,7 +1318,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.sonarr_data .sonarr_data
@@ -1337,7 +1338,7 @@ mod tests {
fn test_edit_indexer_tags_input_submit() { fn test_edit_indexer_tags_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into()); app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal { app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal {
tags: "Test".into(), tags: "Test".into(),
..EditIndexerModal::default() ..EditIndexerModal::default()
@@ -1353,7 +1354,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.sonarr_data .sonarr_data
@@ -1417,12 +1418,12 @@ mod tests {
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into()); app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
app.push_navigation_stack(active_sonarr_block.into()); app.push_navigation_stack(active_sonarr_block.into());
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
EditIndexerHandler::new(ESC_KEY, &mut app, active_sonarr_block, None).handle(); EditIndexerHandler::new(ESC_KEY, &mut app, active_sonarr_block, None).handle();
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into()); assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.data.sonarr_data.edit_indexer_modal, app.data.sonarr_data.edit_indexer_modal,
Some(EditIndexerModal::default()) Some(EditIndexerModal::default())
@@ -1597,7 +1598,7 @@ mod tests {
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::EditIndexerNameInput, ActiveSonarrBlock::EditIndexerNameInput,
None, None,
@@ -1613,7 +1614,7 @@ mod tests {
.unwrap() .unwrap()
.name .name
.text, .text,
"h" "a"
); );
} }
@@ -1624,7 +1625,7 @@ mod tests {
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::EditIndexerUrlInput, ActiveSonarrBlock::EditIndexerUrlInput,
None, None,
@@ -1640,7 +1641,7 @@ mod tests {
.unwrap() .unwrap()
.url .url
.text, .text,
"h" "a"
); );
} }
@@ -1651,7 +1652,7 @@ mod tests {
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::EditIndexerApiKeyInput, ActiveSonarrBlock::EditIndexerApiKeyInput,
None, None,
@@ -1667,7 +1668,7 @@ mod tests {
.unwrap() .unwrap()
.api_key .api_key
.text, .text,
"h" "a"
); );
} }
@@ -1678,7 +1679,7 @@ mod tests {
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::EditIndexerSeedRatioInput, ActiveSonarrBlock::EditIndexerSeedRatioInput,
None, None,
@@ -1694,7 +1695,7 @@ mod tests {
.unwrap() .unwrap()
.seed_ratio .seed_ratio
.text, .text,
"h" "a"
); );
} }
@@ -1705,7 +1706,7 @@ mod tests {
app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default()); app.data.sonarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::new( EditIndexerHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::EditIndexerTagsInput, ActiveSonarrBlock::EditIndexerTagsInput,
None, None,
@@ -1721,7 +1722,7 @@ mod tests {
.unwrap() .unwrap()
.tags .tags
.text, .text,
"h" "a"
); );
} }
@@ -1793,6 +1794,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_edit_indexer_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = EditIndexerHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_edit_indexer_params() { fn test_build_edit_indexer_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,13 +1,12 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_prompt_left_right_keys;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::servarr_data::sonarr::sonarr_data::{ use crate::models::servarr_data::sonarr::sonarr_data::{
ActiveSonarrBlock, INDEXER_SETTINGS_BLOCKS, ActiveSonarrBlock, INDEXER_SETTINGS_BLOCKS,
}; };
use crate::models::sonarr_models::IndexerSettings; use crate::models::sonarr_models::IndexerSettings;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_prompt_left_right_keys, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "edit_indexer_settings_handler_tests.rs"] #[path = "edit_indexer_settings_handler_tests.rs"]
@@ -37,6 +36,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexerSettingsHandl
INDEXER_SETTINGS_BLOCKS.contains(&active_block) INDEXER_SETTINGS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -183,7 +186,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexerSettingsHandl
if self.active_sonarr_block == ActiveSonarrBlock::AllIndexerSettingsPrompt if self.active_sonarr_block == ActiveSonarrBlock::AllIndexerSettingsPrompt
&& self.app.data.sonarr_data.selected_block.get_active_block() && self.app.data.sonarr_data.selected_block.get_active_block()
== ActiveSonarrBlock::IndexerSettingsConfirmPrompt == ActiveSonarrBlock::IndexerSettingsConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::EditAllIndexerSettings( self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::EditAllIndexerSettings(
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -521,6 +522,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_indexer_settings_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = IndexerSettingsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_edit_indexer_settings_params() { fn test_build_edit_indexer_settings_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -643,6 +643,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_indexers_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = IndexersHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_indexer_id() { fn test_extract_indexer_id() {
let mut app = App::test_default(); let mut app = App::test_default();
+10 -7
View File
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::sonarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler; use crate::handlers::sonarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
use crate::handlers::sonarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler; use crate::handlers::sonarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
@@ -15,6 +13,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{
use crate::models::servarr_models::Indexer; use crate::models::servarr_models::Indexer;
use crate::models::BlockSelectionState; use crate::models::BlockSelectionState;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, matches_key};
mod edit_indexer_handler; mod edit_indexer_handler;
mod edit_indexer_settings_handler; mod edit_indexer_settings_handler;
@@ -70,6 +69,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexersHandler<'a,
|| INDEXERS_BLOCKS.contains(&active_block) || INDEXERS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -168,20 +171,20 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexersHandler<'a,
let key = self.key; let key = self.key;
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::Indexers => match self.key { ActiveSonarrBlock::Indexers => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.test.key => { _ if matches_key!(test, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::TestIndexer.into()); .push_navigation_stack(ActiveSonarrBlock::TestIndexer.into());
} }
_ if key == DEFAULT_KEYBINDINGS.test_all.key => { _ if matches_key!(test_all, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::TestAllIndexers.into()); .push_navigation_stack(ActiveSonarrBlock::TestAllIndexers.into());
} }
_ if key == DEFAULT_KEYBINDINGS.settings.key => { _ if matches_key!(settings, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
@@ -191,7 +194,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexersHandler<'a,
_ => (), _ => (),
}, },
ActiveSonarrBlock::DeleteIndexerPrompt => { ActiveSonarrBlock::DeleteIndexerPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
Some(SonarrEvent::DeleteIndexer(self.extract_indexer_id())); Some(SonarrEvent::DeleteIndexer(self.extract_indexer_id()));
@@ -48,6 +48,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for TestAllIndexersHandl
active_block == ActiveSonarrBlock::TestAllIndexers active_block == ActiveSonarrBlock::TestAllIndexers
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -7,6 +7,7 @@ mod tests {
use crate::models::servarr_data::modals::IndexerTestResultModalItem; use crate::models::servarr_data::modals::IndexerTestResultModalItem;
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock; use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::stateful_table::StatefulTable; use crate::models::stateful_table::StatefulTable;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
mod test_handle_esc { mod test_handle_esc {
@@ -48,6 +49,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_test_all_indexers_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = TestAllIndexersHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_test_all_indexers_handler_is_not_ready_when_loading() { fn test_test_all_indexers_handler_is_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::servarr_data::sonarr::modals::AddSeriesModal; use crate::models::servarr_data::sonarr::modals::AddSeriesModal;
@@ -9,7 +8,9 @@ use crate::models::sonarr_models::{AddSeriesBody, AddSeriesOptions, AddSeriesSea
use crate::models::stateful_table::StatefulTable; use crate::models::stateful_table::StatefulTable;
use crate::models::{BlockSelectionState, Scrollable}; use crate::models::{BlockSelectionState, Scrollable};
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, App, Key}; use crate::{
handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, matches_key, App, Key,
};
#[cfg(test)] #[cfg(test)]
#[path = "add_series_handler_tests.rs"] #[path = "add_series_handler_tests.rs"]
@@ -126,6 +127,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a,
ADD_SERIES_BLOCKS.contains(&active_block) ADD_SERIES_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -440,7 +445,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a,
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchResults.into()); .push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchResults.into());
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ if self.active_sonarr_block == ActiveSonarrBlock::AddSeriesSearchResults _ if self.active_sonarr_block == ActiveSonarrBlock::AddSeriesSearchResults
&& self.app.data.sonarr_data.add_searched_series.is_some() => && self.app.data.sonarr_data.add_searched_series.is_some() =>
@@ -509,7 +514,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a,
.get_active_block() .get_active_block()
.into(), .into(),
); );
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveSonarrBlock::AddSeriesToggleUseSeasonFolder => { ActiveSonarrBlock::AddSeriesToggleUseSeasonFolder => {
self self
@@ -538,7 +543,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a,
| ActiveSonarrBlock::AddSeriesSelectRootFolder => self.app.pop_navigation_stack(), | ActiveSonarrBlock::AddSeriesSelectRootFolder => self.app.pop_navigation_stack(),
ActiveSonarrBlock::AddSeriesTagsInput => { ActiveSonarrBlock::AddSeriesTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => (), _ => (),
} }
@@ -549,13 +554,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a,
ActiveSonarrBlock::AddSeriesSearchInput => { ActiveSonarrBlock::AddSeriesSearchInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.sonarr_data.add_series_search = None; self.app.data.sonarr_data.add_series_search = None;
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveSonarrBlock::AddSeriesSearchResults ActiveSonarrBlock::AddSeriesSearchResults
| ActiveSonarrBlock::AddSeriesEmptySearchResults => { | ActiveSonarrBlock::AddSeriesEmptySearchResults => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.sonarr_data.add_searched_series = None; self.app.data.sonarr_data.add_searched_series = None;
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveSonarrBlock::AddSeriesPrompt => { ActiveSonarrBlock::AddSeriesPrompt => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
@@ -570,7 +575,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a,
| ActiveSonarrBlock::AddSeriesSelectRootFolder => self.app.pop_navigation_stack(), | ActiveSonarrBlock::AddSeriesSelectRootFolder => self.app.pop_navigation_stack(),
ActiveSonarrBlock::AddSeriesTagsInput => { ActiveSonarrBlock::AddSeriesTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => (), _ => (),
} }
@@ -609,7 +614,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a,
ActiveSonarrBlock::AddSeriesPrompt => { ActiveSonarrBlock::AddSeriesPrompt => {
if self.app.data.sonarr_data.selected_block.get_active_block() if self.app.data.sonarr_data.selected_block.get_active_block()
== ActiveSonarrBlock::AddSeriesConfirmPrompt == ActiveSonarrBlock::AddSeriesConfirmPrompt
&& key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, key)
{ {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
@@ -2,6 +2,7 @@
mod tests { mod tests {
use bimap::BiMap; use bimap::BiMap;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -912,7 +913,7 @@ mod tests {
fn test_add_series_search_input_submit() { fn test_add_series_search_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.push_navigation_stack(ActiveSonarrBlock::Series.into()); app.push_navigation_stack(ActiveSonarrBlock::Series.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.add_series_search = Some("test".into()); app.data.sonarr_data.add_series_search = Some("test".into());
AddSeriesHandler::new( AddSeriesHandler::new(
@@ -923,7 +924,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::AddSeriesSearchResults.into() ActiveSonarrBlock::AddSeriesSearchResults.into()
@@ -936,7 +937,7 @@ mod tests {
app.data.sonarr_data.add_series_search = Some(HorizontallyScrollableText::default()); app.data.sonarr_data.add_series_search = Some(HorizontallyScrollableText::default());
app.push_navigation_stack(ActiveSonarrBlock::Series.into()); app.push_navigation_stack(ActiveSonarrBlock::Series.into());
app.push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchInput.into()); app.push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchInput.into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
AddSeriesHandler::new( AddSeriesHandler::new(
SUBMIT_KEY, SUBMIT_KEY,
@@ -946,7 +947,7 @@ mod tests {
) )
.handle(); .handle();
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::AddSeriesSearchInput.into() ActiveSonarrBlock::AddSeriesSearchInput.into()
@@ -1230,7 +1231,7 @@ mod tests {
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None); assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
if selected_block == ActiveSonarrBlock::AddSeriesTagsInput { if selected_block == ActiveSonarrBlock::AddSeriesTagsInput {
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
} }
@@ -1259,7 +1260,7 @@ mod tests {
); );
if active_sonarr_block == ActiveSonarrBlock::AddSeriesTagsInput { if active_sonarr_block == ActiveSonarrBlock::AddSeriesTagsInput {
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
} }
@@ -1336,7 +1337,7 @@ mod tests {
let mut app = App::test_default(); let mut app = App::test_default();
app.is_loading = is_ready; app.is_loading = is_ready;
app.data.sonarr_data = create_test_sonarr_data(); app.data.sonarr_data = create_test_sonarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveSonarrBlock::Series.into()); app.push_navigation_stack(ActiveSonarrBlock::Series.into());
app.push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchInput.into()); app.push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchInput.into());
@@ -1348,7 +1349,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into()); assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into());
assert_eq!(app.data.sonarr_data.add_series_search, None); assert_eq!(app.data.sonarr_data.add_series_search, None);
} }
@@ -1357,7 +1358,7 @@ mod tests {
fn test_add_series_input_esc() { fn test_add_series_input_esc() {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.sonarr_data = create_test_sonarr_data(); app.data.sonarr_data = create_test_sonarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveSonarrBlock::Series.into()); app.push_navigation_stack(ActiveSonarrBlock::Series.into());
app.push_navigation_stack(ActiveSonarrBlock::AddSeriesPrompt.into()); app.push_navigation_stack(ActiveSonarrBlock::AddSeriesPrompt.into());
app.push_navigation_stack(ActiveSonarrBlock::AddSeriesTagsInput.into()); app.push_navigation_stack(ActiveSonarrBlock::AddSeriesTagsInput.into());
@@ -1370,7 +1371,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::AddSeriesPrompt.into() ActiveSonarrBlock::AddSeriesPrompt.into()
@@ -1403,7 +1404,7 @@ mod tests {
ActiveSonarrBlock::AddSeriesSearchInput.into() ActiveSonarrBlock::AddSeriesSearchInput.into()
); );
assert!(app.data.sonarr_data.add_searched_series.is_none()); assert!(app.data.sonarr_data.add_searched_series.is_none());
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
#[test] #[test]
@@ -1451,7 +1452,7 @@ mod tests {
fn test_add_series_tags_input_esc() { fn test_add_series_tags_input_esc() {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.sonarr_data = create_test_sonarr_data(); app.data.sonarr_data = create_test_sonarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveSonarrBlock::Series.into()); app.push_navigation_stack(ActiveSonarrBlock::Series.into());
app.push_navigation_stack(ActiveSonarrBlock::AddSeriesPrompt.into()); app.push_navigation_stack(ActiveSonarrBlock::AddSeriesPrompt.into());
app.push_navigation_stack(ActiveSonarrBlock::AddSeriesTagsInput.into()); app.push_navigation_stack(ActiveSonarrBlock::AddSeriesTagsInput.into());
@@ -1464,7 +1465,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::AddSeriesPrompt.into() ActiveSonarrBlock::AddSeriesPrompt.into()
@@ -1570,7 +1571,7 @@ mod tests {
app.data.sonarr_data.add_series_search = Some(HorizontallyScrollableText::default()); app.data.sonarr_data.add_series_search = Some(HorizontallyScrollableText::default());
AddSeriesHandler::new( AddSeriesHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::AddSeriesSearchInput, ActiveSonarrBlock::AddSeriesSearchInput,
None, None,
@@ -1585,7 +1586,7 @@ mod tests {
.as_ref() .as_ref()
.unwrap() .unwrap()
.text, .text,
"h" "a"
); );
} }
@@ -1596,7 +1597,7 @@ mod tests {
app.data.sonarr_data.add_series_modal = Some(AddSeriesModal::default()); app.data.sonarr_data.add_series_modal = Some(AddSeriesModal::default());
AddSeriesHandler::new( AddSeriesHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::AddSeriesTagsInput, ActiveSonarrBlock::AddSeriesTagsInput,
None, None,
@@ -1612,7 +1613,7 @@ mod tests {
.unwrap() .unwrap()
.tags .tags
.text, .text,
"h" "a"
); );
} }
@@ -1714,6 +1715,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_add_series_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = AddSeriesHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_add_series_search_no_panic_on_none_search_result() { fn test_add_series_search_no_panic_on_none_search_result() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,9 +1,10 @@
use crate::models::sonarr_models::DeleteSeriesParams; use crate::models::sonarr_models::DeleteSeriesParams;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{ use crate::{
app::{key_binding::DEFAULT_KEYBINDINGS, App}, app::App,
event::Key, event::Key,
handlers::{handle_prompt_toggle, KeyEventHandler}, handlers::{handle_prompt_toggle, KeyEventHandler},
matches_key,
models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DELETE_SERIES_BLOCKS}, models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DELETE_SERIES_BLOCKS},
}; };
@@ -38,6 +39,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for DeleteSeriesHandler<
DELETE_SERIES_BLOCKS.contains(&active_block) DELETE_SERIES_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -123,7 +128,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for DeleteSeriesHandler<
if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt
&& self.app.data.sonarr_data.selected_block.get_active_block() && self.app.data.sonarr_data.selected_block.get_active_block()
== ActiveSonarrBlock::DeleteSeriesConfirmPrompt == ActiveSonarrBlock::DeleteSeriesConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -320,6 +321,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_delete_series_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = DeleteSeriesHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_delete_series_params() { fn test_build_delete_series_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -7,7 +6,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_S
use crate::models::sonarr_models::EditSeriesParams; use crate::models::sonarr_models::EditSeriesParams;
use crate::models::Scrollable; use crate::models::Scrollable;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{handle_text_box_keys, handle_text_box_left_right_keys, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "edit_series_handler_tests.rs"] #[path = "edit_series_handler_tests.rs"]
@@ -83,6 +82,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditSeriesHandler<'a
EDIT_SERIES_BLOCKS.contains(&active_block) EDIT_SERIES_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -342,7 +345,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditSeriesHandler<'a
) )
.into(), .into(),
); );
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
ActiveSonarrBlock::EditSeriesToggleMonitored => { ActiveSonarrBlock::EditSeriesToggleMonitored => {
self self
@@ -392,7 +395,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditSeriesHandler<'a
| ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self.app.pop_navigation_stack(), | ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self.app.pop_navigation_stack(),
ActiveSonarrBlock::EditSeriesPathInput | ActiveSonarrBlock::EditSeriesTagsInput => { ActiveSonarrBlock::EditSeriesPathInput | ActiveSonarrBlock::EditSeriesTagsInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
_ => (), _ => (),
} }
@@ -402,7 +405,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditSeriesHandler<'a
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::EditSeriesTagsInput | ActiveSonarrBlock::EditSeriesPathInput => { ActiveSonarrBlock::EditSeriesTagsInput | ActiveSonarrBlock::EditSeriesPathInput => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveSonarrBlock::EditSeriesPrompt => { ActiveSonarrBlock::EditSeriesPrompt => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
@@ -450,7 +453,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditSeriesHandler<'a
ActiveSonarrBlock::EditSeriesPrompt => { ActiveSonarrBlock::EditSeriesPrompt => {
if self.app.data.sonarr_data.selected_block.get_active_block() if self.app.data.sonarr_data.selected_block.get_active_block()
== ActiveSonarrBlock::EditSeriesConfirmPrompt == ActiveSonarrBlock::EditSeriesConfirmPrompt
&& key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, key)
{ {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
@@ -2,6 +2,7 @@
mod tests { mod tests {
use bimap::BiMap; use bimap::BiMap;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -677,7 +678,7 @@ mod tests {
#[test] #[test]
fn test_edit_series_path_input_submit() { fn test_edit_series_path_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal { app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal {
path: "Test Path".into(), path: "Test Path".into(),
..EditSeriesModal::default() ..EditSeriesModal::default()
@@ -694,7 +695,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.sonarr_data .sonarr_data
@@ -713,7 +714,7 @@ mod tests {
#[test] #[test]
fn test_edit_series_tags_input_submit() { fn test_edit_series_tags_input_submit() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal { app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal {
tags: "Test Tags".into(), tags: "Test Tags".into(),
..EditSeriesModal::default() ..EditSeriesModal::default()
@@ -730,7 +731,7 @@ mod tests {
) )
.handle(); .handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(!app assert!(!app
.data .data
.sonarr_data .sonarr_data
@@ -1010,7 +1011,7 @@ mod tests {
if selected_block == ActiveSonarrBlock::EditSeriesPathInput if selected_block == ActiveSonarrBlock::EditSeriesPathInput
|| selected_block == ActiveSonarrBlock::EditSeriesTagsInput || selected_block == ActiveSonarrBlock::EditSeriesTagsInput
{ {
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
} }
} }
@@ -1049,7 +1050,7 @@ mod tests {
.into() .into()
); );
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None); assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
#[rstest] #[rstest]
@@ -1085,7 +1086,7 @@ mod tests {
if active_sonarr_block == ActiveSonarrBlock::EditSeriesPathInput if active_sonarr_block == ActiveSonarrBlock::EditSeriesPathInput
|| active_sonarr_block == ActiveSonarrBlock::EditSeriesTagsInput || active_sonarr_block == ActiveSonarrBlock::EditSeriesTagsInput
{ {
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
} }
} }
@@ -1111,14 +1112,14 @@ mod tests {
) { ) {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.sonarr_data = create_test_sonarr_data(); app.data.sonarr_data = create_test_sonarr_data();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveSonarrBlock::Series.into()); app.push_navigation_stack(ActiveSonarrBlock::Series.into());
app.push_navigation_stack(ActiveSonarrBlock::EditSeriesPrompt.into()); app.push_navigation_stack(ActiveSonarrBlock::EditSeriesPrompt.into());
app.push_navigation_stack(active_sonarr_block.into()); app.push_navigation_stack(active_sonarr_block.into());
EditSeriesHandler::new(ESC_KEY, &mut app, active_sonarr_block, None).handle(); EditSeriesHandler::new(ESC_KEY, &mut app, active_sonarr_block, None).handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::EditSeriesPrompt.into() ActiveSonarrBlock::EditSeriesPrompt.into()
@@ -1243,7 +1244,7 @@ mod tests {
app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal::default()); app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal::default());
EditSeriesHandler::new( EditSeriesHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::EditSeriesPathInput, ActiveSonarrBlock::EditSeriesPathInput,
None, None,
@@ -1259,7 +1260,7 @@ mod tests {
.unwrap() .unwrap()
.path .path
.text, .text,
"h" "a"
); );
} }
@@ -1270,7 +1271,7 @@ mod tests {
app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal::default()); app.data.sonarr_data.edit_series_modal = Some(EditSeriesModal::default());
EditSeriesHandler::new( EditSeriesHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::EditSeriesTagsInput, ActiveSonarrBlock::EditSeriesTagsInput,
None, None,
@@ -1286,7 +1287,7 @@ mod tests {
.unwrap() .unwrap()
.tags .tags
.text, .text,
"h" "a"
); );
} }
@@ -1368,6 +1369,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_edit_series_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = EditSeriesHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_build_edit_series_params() { fn test_build_edit_series_params() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,13 +1,12 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::sonarr_handlers::library::season_details_handler::releases_sorting_options; use crate::handlers::sonarr_handlers::library::season_details_handler::releases_sorting_options;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EPISODE_DETAILS_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EPISODE_DETAILS_BLOCKS};
use crate::models::sonarr_models::{SonarrHistoryItem, SonarrRelease, SonarrReleaseDownloadBody}; use crate::models::sonarr_models::{SonarrHistoryItem, SonarrRelease, SonarrReleaseDownloadBody};
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "episode_details_handler_tests.rs"] #[path = "episode_details_handler_tests.rs"]
@@ -88,6 +87,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EpisodeDetailsHandle
EPISODE_DETAILS_BLOCKS.contains(&active_block) EPISODE_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -142,7 +145,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EpisodeDetailsHandle
| ActiveSonarrBlock::EpisodeHistory | ActiveSonarrBlock::EpisodeHistory
| ActiveSonarrBlock::EpisodeFile | ActiveSonarrBlock::EpisodeFile
| ActiveSonarrBlock::ManualEpisodeSearch => match self.key { | ActiveSonarrBlock::ManualEpisodeSearch => match self.key {
_ if self.key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, self.key) => {
self self
.app .app
.data .data
@@ -170,7 +173,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EpisodeDetailsHandle
.get_active_route(), .get_active_route(),
); );
} }
_ if self.key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, self.key) => {
self self
.app .app
.data .data
@@ -306,21 +309,19 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EpisodeDetailsHandle
| ActiveSonarrBlock::EpisodeHistory | ActiveSonarrBlock::EpisodeHistory
| ActiveSonarrBlock::EpisodeFile | ActiveSonarrBlock::EpisodeFile
| ActiveSonarrBlock::ManualEpisodeSearch => match self.key { | ActiveSonarrBlock::ManualEpisodeSearch => match self.key {
_ if self.key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, self.key) => {
self self
.app .app
.pop_and_push_navigation_stack(self.active_sonarr_block.into()); .pop_and_push_navigation_stack(self.active_sonarr_block.into());
} }
_ if self.key == DEFAULT_KEYBINDINGS.auto_search.key => { _ if matches_key!(auto_search, self.key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchEpisodePrompt.into()); .push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchEpisodePrompt.into());
} }
_ => (), _ => (),
}, },
ActiveSonarrBlock::AutomaticallySearchEpisodePrompt ActiveSonarrBlock::AutomaticallySearchEpisodePrompt if matches_key!(confirm, key) => {
if key == DEFAULT_KEYBINDINGS.confirm.key =>
{
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some( self.app.data.sonarr_data.prompt_confirm_action = Some(
SonarrEvent::TriggerAutomaticEpisodeSearch(self.extract_episode_id()), SonarrEvent::TriggerAutomaticEpisodeSearch(self.extract_episode_id()),
@@ -328,9 +329,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EpisodeDetailsHandle
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
} }
ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt if matches_key!(confirm, key) => {
if key == DEFAULT_KEYBINDINGS.confirm.key =>
{
if self.app.data.sonarr_data.prompt_confirm { if self.app.data.sonarr_data.prompt_confirm {
let SonarrRelease { let SonarrRelease {
guid, indexer_id, .. guid, indexer_id, ..
@@ -625,6 +625,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_episode_details_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = EpisodeDetailsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_episode_id() { fn test_extract_episode_id() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -316,7 +316,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::AddSeriesSearchInput.into() ActiveSonarrBlock::AddSeriesSearchInput.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert!(app.data.sonarr_data.add_series_search.is_some()); assert!(app.data.sonarr_data.add_series_search.is_some());
} }
@@ -340,7 +340,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into()); assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(app.data.sonarr_data.add_series_search.is_none()); assert!(app.data.sonarr_data.add_series_search.is_none());
} }
@@ -827,6 +827,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_library_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = LibraryHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_library_handler_not_ready_when_loading() { fn test_library_handler_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
+11 -7
View File
@@ -8,6 +8,7 @@ use crate::{
event::Key, event::Key,
handle_table_events, handle_table_events,
handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler}, handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler},
matches_key,
models::{ models::{
servarr_data::sonarr::sonarr_data::{ servarr_data::sonarr::sonarr_data::{
ActiveSonarrBlock, DELETE_SERIES_SELECTION_BLOCKS, EDIT_SERIES_SELECTION_BLOCKS, ActiveSonarrBlock, DELETE_SERIES_SELECTION_BLOCKS, EDIT_SERIES_SELECTION_BLOCKS,
@@ -21,7 +22,6 @@ use crate::{
}; };
use super::handle_change_tab_left_right_keys; use super::handle_change_tab_left_right_keys;
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::handlers::sonarr_handlers::library::episode_details_handler::EpisodeDetailsHandler; use crate::handlers::sonarr_handlers::library::episode_details_handler::EpisodeDetailsHandler;
use crate::handlers::sonarr_handlers::library::season_details_handler::SeasonDetailsHandler; use crate::handlers::sonarr_handlers::library::season_details_handler::SeasonDetailsHandler;
use crate::handlers::sonarr_handlers::library::series_details_handler::SeriesDetailsHandler; use crate::handlers::sonarr_handlers::library::series_details_handler::SeriesDetailsHandler;
@@ -102,6 +102,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for LibraryHandler<'a, '
|| LIBRARY_BLOCKS.contains(&active_block) || LIBRARY_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -182,7 +186,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for LibraryHandler<'a, '
let key = self.key; let key = self.key;
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::Series => match self.key { ActiveSonarrBlock::Series => match self.key {
_ if key == DEFAULT_KEYBINDINGS.edit.key => { _ if matches_key!(edit, key) => {
self.app.push_navigation_stack( self.app.push_navigation_stack(
( (
ActiveSonarrBlock::EditSeriesPrompt, ActiveSonarrBlock::EditSeriesPrompt,
@@ -194,25 +198,25 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for LibraryHandler<'a, '
self.app.data.sonarr_data.selected_block = self.app.data.sonarr_data.selected_block =
BlockSelectionState::new(EDIT_SERIES_SELECTION_BLOCKS); BlockSelectionState::new(EDIT_SERIES_SELECTION_BLOCKS);
} }
_ if key == DEFAULT_KEYBINDINGS.add.key => { _ if matches_key!(add, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchInput.into()); .push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchInput.into());
self.app.data.sonarr_data.add_series_search = Some(HorizontallyScrollableText::default()); self.app.data.sonarr_data.add_series_search = Some(HorizontallyScrollableText::default());
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::UpdateAllSeriesPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::UpdateAllSeriesPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ => (), _ => (),
}, },
ActiveSonarrBlock::UpdateAllSeriesPrompt => { ActiveSonarrBlock::UpdateAllSeriesPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::UpdateAllSeries); self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::UpdateAllSeries);
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::sonarr_handlers::history::history_sorting_options; use crate::handlers::sonarr_handlers::history::history_sorting_options;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -12,6 +10,7 @@ use crate::models::sonarr_models::{
}; };
use crate::models::stateful_table::SortOption; use crate::models::stateful_table::SortOption;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, matches_key};
use serde_json::Number; use serde_json::Number;
#[cfg(test)] #[cfg(test)]
@@ -140,6 +139,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler
SEASON_DETAILS_BLOCKS.contains(&active_block) SEASON_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -193,7 +196,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler
ActiveSonarrBlock::SeasonDetails ActiveSonarrBlock::SeasonDetails
| ActiveSonarrBlock::SeasonHistory | ActiveSonarrBlock::SeasonHistory
| ActiveSonarrBlock::ManualSeasonSearch => match self.key { | ActiveSonarrBlock::ManualSeasonSearch => match self.key {
_ if self.key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, self.key) => {
self self
.app .app
.data .data
@@ -215,7 +218,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler
.get_active_route(), .get_active_route(),
); );
} }
_ if self.key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, self.key) => {
self self
.app .app
.data .data
@@ -378,7 +381,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
let key = self.key; let key = self.key;
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::SeasonDetails if self.key == DEFAULT_KEYBINDINGS.toggle_monitoring.key => { ActiveSonarrBlock::SeasonDetails if matches_key!(toggle_monitoring, self.key) => {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some( self.app.data.sonarr_data.prompt_confirm_action = Some(
SonarrEvent::ToggleEpisodeMonitoring(self.extract_episode_id()), SonarrEvent::ToggleEpisodeMonitoring(self.extract_episode_id()),
@@ -391,21 +394,19 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler
ActiveSonarrBlock::SeasonDetails ActiveSonarrBlock::SeasonDetails
| ActiveSonarrBlock::SeasonHistory | ActiveSonarrBlock::SeasonHistory
| ActiveSonarrBlock::ManualSeasonSearch => match self.key { | ActiveSonarrBlock::ManualSeasonSearch => match self.key {
_ if self.key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, self.key) => {
self self
.app .app
.pop_and_push_navigation_stack(self.active_sonarr_block.into()); .pop_and_push_navigation_stack(self.active_sonarr_block.into());
} }
_ if self.key == DEFAULT_KEYBINDINGS.auto_search.key => { _ if matches_key!(auto_search, self.key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchSeasonPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchSeasonPrompt.into());
} }
_ => (), _ => (),
}, },
ActiveSonarrBlock::AutomaticallySearchSeasonPrompt ActiveSonarrBlock::AutomaticallySearchSeasonPrompt if matches_key!(confirm, key) => {
if key == DEFAULT_KEYBINDINGS.confirm.key =>
{
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some( self.app.data.sonarr_data.prompt_confirm_action = Some(
SonarrEvent::TriggerAutomaticSeasonSearch(self.extract_series_id_season_number_tuple()), SonarrEvent::TriggerAutomaticSeasonSearch(self.extract_series_id_season_number_tuple()),
@@ -413,7 +414,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
} }
ActiveSonarrBlock::DeleteEpisodeFilePrompt if key == DEFAULT_KEYBINDINGS.confirm.key => { ActiveSonarrBlock::DeleteEpisodeFilePrompt if matches_key!(confirm, key) => {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteEpisodeFile( self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteEpisodeFile(
self.extract_episode_file_id(), self.extract_episode_file_id(),
@@ -421,9 +422,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
} }
ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt if matches_key!(confirm, key) => {
if key == DEFAULT_KEYBINDINGS.confirm.key =>
{
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
let SonarrRelease { let SonarrRelease {
guid, indexer_id, .. guid, indexer_id, ..
@@ -789,6 +789,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_season_details_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = SeasonDetailsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_episode_file_id() { fn test_extract_episode_file_id() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -1,7 +1,5 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handle_table_events;
use crate::handlers::sonarr_handlers::history::history_sorting_options; use crate::handlers::sonarr_handlers::history::history_sorting_options;
use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::table_handler::TableHandlingConfig;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -11,6 +9,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{
use crate::models::sonarr_models::{Season, SonarrHistoryItem}; use crate::models::sonarr_models::{Season, SonarrHistoryItem};
use crate::models::BlockSelectionState; use crate::models::BlockSelectionState;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, matches_key};
#[cfg(test)] #[cfg(test)]
#[path = "series_details_handler_tests.rs"] #[path = "series_details_handler_tests.rs"]
@@ -91,6 +90,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
SERIES_DETAILS_BLOCKS.contains(&active_block) SERIES_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -130,7 +133,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
fn handle_left_right_action(&mut self) { fn handle_left_right_action(&mut self) {
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::SeriesDetails | ActiveSonarrBlock::SeriesHistory => match self.key { ActiveSonarrBlock::SeriesDetails | ActiveSonarrBlock::SeriesHistory => match self.key {
_ if self.key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, self.key) => {
self.app.data.sonarr_data.series_info_tabs.previous(); self.app.data.sonarr_data.series_info_tabs.previous();
self.app.pop_and_push_navigation_stack( self.app.pop_and_push_navigation_stack(
self self
@@ -141,7 +144,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
.get_active_route(), .get_active_route(),
); );
} }
_ if self.key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, self.key) => {
self.app.data.sonarr_data.series_info_tabs.next(); self.app.data.sonarr_data.series_info_tabs.next();
self.app.pop_and_push_navigation_stack( self.app.pop_and_push_navigation_stack(
self self
@@ -250,20 +253,20 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
let key = self.key; let key = self.key;
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::SeriesDetails => match self.key { ActiveSonarrBlock::SeriesDetails => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => self _ if matches_key!(refresh, key) => self
.app .app
.pop_and_push_navigation_stack(self.active_sonarr_block.into()), .pop_and_push_navigation_stack(self.active_sonarr_block.into()),
_ if key == DEFAULT_KEYBINDINGS.auto_search.key => { _ if matches_key!(auto_search, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchSeriesPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchSeriesPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::UpdateAndScanSeriesPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::UpdateAndScanSeriesPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.edit.key => { _ if matches_key!(edit, key) => {
self.app.push_navigation_stack( self.app.push_navigation_stack(
( (
ActiveSonarrBlock::EditSeriesPrompt, ActiveSonarrBlock::EditSeriesPrompt,
@@ -275,7 +278,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
self.app.data.sonarr_data.selected_block = self.app.data.sonarr_data.selected_block =
BlockSelectionState::new(EDIT_SERIES_SELECTION_BLOCKS); BlockSelectionState::new(EDIT_SERIES_SELECTION_BLOCKS);
} }
_ if key == DEFAULT_KEYBINDINGS.toggle_monitoring.key => { _ if matches_key!(toggle_monitoring, key) => {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some( self.app.data.sonarr_data.prompt_confirm_action = Some(
SonarrEvent::ToggleSeasonMonitoring(self.extract_series_id_season_number_tuple()), SonarrEvent::ToggleSeasonMonitoring(self.extract_series_id_season_number_tuple()),
@@ -288,15 +291,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
_ => (), _ => (),
}, },
ActiveSonarrBlock::SeriesHistory => match self.key { ActiveSonarrBlock::SeriesHistory => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => self _ if matches_key!(refresh, key) => self
.app .app
.pop_and_push_navigation_stack(self.active_sonarr_block.into()), .pop_and_push_navigation_stack(self.active_sonarr_block.into()),
_ if key == DEFAULT_KEYBINDINGS.auto_search.key => { _ if matches_key!(auto_search, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchSeriesPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::AutomaticallySearchSeriesPrompt.into());
} }
_ if key == DEFAULT_KEYBINDINGS.edit.key => { _ if matches_key!(edit, key) => {
self.app.push_navigation_stack( self.app.push_navigation_stack(
( (
ActiveSonarrBlock::EditSeriesPrompt, ActiveSonarrBlock::EditSeriesPrompt,
@@ -308,7 +311,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
self.app.data.sonarr_data.selected_block = self.app.data.sonarr_data.selected_block =
BlockSelectionState::new(EDIT_SERIES_SELECTION_BLOCKS); BlockSelectionState::new(EDIT_SERIES_SELECTION_BLOCKS);
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::UpdateAndScanSeriesPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::UpdateAndScanSeriesPrompt.into());
@@ -316,7 +319,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler
_ => (), _ => (),
}, },
ActiveSonarrBlock::AutomaticallySearchSeriesPrompt => { ActiveSonarrBlock::AutomaticallySearchSeriesPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = Some( self.app.data.sonarr_data.prompt_confirm_action = Some(
SonarrEvent::TriggerAutomaticSeriesSearch(self.extract_series_id()), SonarrEvent::TriggerAutomaticSeriesSearch(self.extract_series_id()),
@@ -611,6 +611,25 @@ mod tests {
}); });
} }
#[rstest]
fn test_series_details_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = SeriesDetailsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_series_id_season_number_tuple() { fn test_extract_series_id_season_number_tuple() {
let mut app = App::test_default(); let mut app = App::test_default();
+7 -5
View File
@@ -7,9 +7,7 @@ use root_folders::RootFoldersHandler;
use system::SystemHandler; use system::SystemHandler;
use crate::{ use crate::{
app::{key_binding::DEFAULT_KEYBINDINGS, App}, app::App, event::Key, matches_key, models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock,
event::Key,
models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock,
}; };
use super::KeyEventHandler; use super::KeyEventHandler;
@@ -69,6 +67,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SonarrHandler<'a, 'b
true true
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -113,11 +115,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SonarrHandler<'a, 'b
pub fn handle_change_tab_left_right_keys(app: &mut App<'_>, key: Key) { pub fn handle_change_tab_left_right_keys(app: &mut App<'_>, key: Key) {
let key_ref = key; let key_ref = key;
match key_ref { match key_ref {
_ if key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, key, app.ignore_special_keys_for_textbox_input) => {
app.data.sonarr_data.main_tabs.previous(); app.data.sonarr_data.main_tabs.previous();
app.pop_and_push_navigation_stack(app.data.sonarr_data.main_tabs.get_active_route()); app.pop_and_push_navigation_stack(app.data.sonarr_data.main_tabs.get_active_route());
} }
_ if key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, key, app.ignore_special_keys_for_textbox_input) => {
app.data.sonarr_data.main_tabs.next(); app.data.sonarr_data.main_tabs.next();
app.pop_and_push_navigation_stack(app.data.sonarr_data.main_tabs.get_active_route()); app.pop_and_push_navigation_stack(app.data.sonarr_data.main_tabs.get_active_route());
} }
@@ -1,4 +1,3 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
@@ -8,7 +7,9 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, ROOT_F
use crate::models::servarr_models::{AddRootFolderBody, RootFolder}; use crate::models::servarr_models::{AddRootFolderBody, RootFolder};
use crate::models::HorizontallyScrollableText; use crate::models::HorizontallyScrollableText;
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::{handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys}; use crate::{
handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, matches_key,
};
#[cfg(test)] #[cfg(test)]
#[path = "root_folders_handler_tests.rs"] #[path = "root_folders_handler_tests.rs"]
@@ -66,6 +67,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for RootFoldersHandler<'
ROOT_FOLDERS_BLOCKS.contains(&active_block) ROOT_FOLDERS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -166,7 +171,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for RootFoldersHandler<'
self.build_add_root_folder_body(), self.build_add_root_folder_body(),
)); ));
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
} }
_ => (), _ => (),
@@ -179,7 +184,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for RootFoldersHandler<'
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.sonarr_data.edit_root_folder = None; self.app.data.sonarr_data.edit_root_folder = None;
self.app.data.sonarr_data.prompt_confirm = false; self.app.data.sonarr_data.prompt_confirm = false;
self.app.should_ignore_quit_key = false; self.app.ignore_special_keys_for_textbox_input = false;
} }
ActiveSonarrBlock::DeleteRootFolderPrompt => { ActiveSonarrBlock::DeleteRootFolderPrompt => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
@@ -193,15 +198,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for RootFoldersHandler<'
let key = self.key; let key = self.key;
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::RootFolders => match self.key { ActiveSonarrBlock::RootFolders => match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.add.key => { _ if matches_key!(add, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into()); .push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into());
self.app.data.sonarr_data.edit_root_folder = Some(HorizontallyScrollableText::default()); self.app.data.sonarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
self.app.should_ignore_quit_key = true; self.app.ignore_special_keys_for_textbox_input = true;
} }
_ => (), _ => (),
}, },
@@ -213,7 +218,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for RootFoldersHandler<'
) )
} }
ActiveSonarrBlock::DeleteRootFolderPrompt => { ActiveSonarrBlock::DeleteRootFolderPrompt => {
if key == DEFAULT_KEYBINDINGS.confirm.key { if matches_key!(confirm, key) {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
Some(SonarrEvent::DeleteRootFolder(self.extract_root_folder_id())); Some(SonarrEvent::DeleteRootFolder(self.extract_root_folder_id()));
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -269,7 +270,7 @@ mod tests {
.set_items(vec![RootFolder::default()]); .set_items(vec![RootFolder::default()]);
app.data.sonarr_data.edit_root_folder = Some("Test".into()); app.data.sonarr_data.edit_root_folder = Some("Test".into());
app.data.sonarr_data.prompt_confirm = true; app.data.sonarr_data.prompt_confirm = true;
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveSonarrBlock::RootFolders.into()); app.push_navigation_stack(ActiveSonarrBlock::RootFolders.into());
app.push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into()); app.push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into());
@@ -282,7 +283,7 @@ mod tests {
.handle(); .handle();
assert!(app.data.sonarr_data.prompt_confirm); assert!(app.data.sonarr_data.prompt_confirm);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.data.sonarr_data.prompt_confirm_action, app.data.sonarr_data.prompt_confirm_action,
Some(SonarrEvent::AddRootFolder(expected_add_root_folder_body)) Some(SonarrEvent::AddRootFolder(expected_add_root_folder_body))
@@ -299,7 +300,7 @@ mod tests {
let mut app = App::test_default(); let mut app = App::test_default();
app.data.sonarr_data.edit_root_folder = Some(HorizontallyScrollableText::default()); app.data.sonarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
app.data.sonarr_data.prompt_confirm = false; app.data.sonarr_data.prompt_confirm = false;
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveSonarrBlock::RootFolders.into()); app.push_navigation_stack(ActiveSonarrBlock::RootFolders.into());
app.push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into()); app.push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into());
@@ -312,7 +313,7 @@ mod tests {
.handle(); .handle();
assert!(!app.data.sonarr_data.prompt_confirm); assert!(!app.data.sonarr_data.prompt_confirm);
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert!(app.data.sonarr_data.prompt_confirm_action.is_none()); assert!(app.data.sonarr_data.prompt_confirm_action.is_none());
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
@@ -414,7 +415,7 @@ mod tests {
app.push_navigation_stack(ActiveSonarrBlock::RootFolders.into()); app.push_navigation_stack(ActiveSonarrBlock::RootFolders.into());
app.push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into()); app.push_navigation_stack(ActiveSonarrBlock::AddRootFolderPrompt.into());
app.data.sonarr_data.edit_root_folder = Some("/nfs/test".into()); app.data.sonarr_data.edit_root_folder = Some("/nfs/test".into());
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
RootFoldersHandler::new( RootFoldersHandler::new(
ESC_KEY, ESC_KEY,
@@ -431,7 +432,7 @@ mod tests {
assert!(app.data.sonarr_data.edit_root_folder.is_none()); assert!(app.data.sonarr_data.edit_root_folder.is_none());
assert!(!app.data.sonarr_data.prompt_confirm); assert!(!app.data.sonarr_data.prompt_confirm);
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
} }
#[rstest] #[rstest]
@@ -481,7 +482,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::AddRootFolderPrompt.into() ActiveSonarrBlock::AddRootFolderPrompt.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert!(app.data.sonarr_data.edit_root_folder.is_some()); assert!(app.data.sonarr_data.edit_root_folder.is_some());
} }
@@ -508,7 +509,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveSonarrBlock::RootFolders.into() ActiveSonarrBlock::RootFolders.into()
); );
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(app.data.sonarr_data.edit_root_folder.is_none()); assert!(app.data.sonarr_data.edit_root_folder.is_none());
} }
@@ -600,7 +601,7 @@ mod tests {
app.data.sonarr_data.edit_root_folder = Some(HorizontallyScrollableText::default()); app.data.sonarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
RootFoldersHandler::new( RootFoldersHandler::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveSonarrBlock::AddRootFolderPrompt, ActiveSonarrBlock::AddRootFolderPrompt,
None, None,
@@ -609,7 +610,7 @@ mod tests {
assert_str_eq!( assert_str_eq!(
app.data.sonarr_data.edit_root_folder.as_ref().unwrap().text, app.data.sonarr_data.edit_root_folder.as_ref().unwrap().text,
"h" "a"
); );
} }
@@ -655,6 +656,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_root_folders_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = RootFoldersHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_root_folder_id() { fn test_extract_root_folder_id() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -9,6 +9,7 @@ mod tests {
use crate::test_handler_delegation; use crate::test_handler_delegation;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest; use rstest::rstest;
use strum::IntoEnumIterator;
#[rstest] #[rstest]
#[case(0, ActiveSonarrBlock::System, ActiveSonarrBlock::Downloads)] #[case(0, ActiveSonarrBlock::System, ActiveSonarrBlock::Downloads)]
@@ -45,6 +46,77 @@ mod tests {
assert_eq!(app.get_current_route(), right_block.into()); 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.ignore_special_keys_for_textbox_input = 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] #[rstest]
fn test_delegates_library_blocks_to_library_handler( fn test_delegates_library_blocks_to_library_handler(
#[values( #[values(
@@ -59,10 +131,10 @@ mod tests {
ActiveSonarrBlock::AddSeriesSelectRootFolder, ActiveSonarrBlock::AddSeriesSelectRootFolder,
ActiveSonarrBlock::AddSeriesSelectSeriesType, ActiveSonarrBlock::AddSeriesSelectSeriesType,
ActiveSonarrBlock::AddSeriesTagsInput, ActiveSonarrBlock::AddSeriesTagsInput,
// ActiveSonarrBlock::AutomaticallySearchEpisodePrompt, ActiveSonarrBlock::AutomaticallySearchEpisodePrompt,
// ActiveSonarrBlock::AutomaticallySearchSeasonPrompt, ActiveSonarrBlock::AutomaticallySearchSeasonPrompt,
// ActiveSonarrBlock::AutomaticallySearchSeriesPrompt, ActiveSonarrBlock::AutomaticallySearchSeriesPrompt,
// ActiveSonarrBlock::DeleteEpisodeFilePrompt, ActiveSonarrBlock::DeleteEpisodeFilePrompt,
ActiveSonarrBlock::DeleteSeriesPrompt, ActiveSonarrBlock::DeleteSeriesPrompt,
ActiveSonarrBlock::EditSeriesPrompt, ActiveSonarrBlock::EditSeriesPrompt,
ActiveSonarrBlock::EditSeriesPathInput, ActiveSonarrBlock::EditSeriesPathInput,
@@ -70,39 +142,36 @@ mod tests {
ActiveSonarrBlock::EditSeriesSelectQualityProfile, ActiveSonarrBlock::EditSeriesSelectQualityProfile,
ActiveSonarrBlock::EditSeriesSelectLanguageProfile, ActiveSonarrBlock::EditSeriesSelectLanguageProfile,
ActiveSonarrBlock::EditSeriesTagsInput, ActiveSonarrBlock::EditSeriesTagsInput,
// ActiveSonarrBlock::EpisodeDetails, ActiveSonarrBlock::EpisodeDetails,
// ActiveSonarrBlock::EpisodeFile, ActiveSonarrBlock::EpisodeFile,
// ActiveSonarrBlock::EpisodeHistory, ActiveSonarrBlock::EpisodeHistory,
// ActiveSonarrBlock::EpisodesSortPrompt,
// ActiveSonarrBlock::FilterEpisodes,
// ActiveSonarrBlock::FilterEpisodesError,
ActiveSonarrBlock::FilterSeries, ActiveSonarrBlock::FilterSeries,
ActiveSonarrBlock::FilterSeriesError, ActiveSonarrBlock::FilterSeriesError,
// ActiveSonarrBlock::FilterSeriesHistory, ActiveSonarrBlock::FilterSeriesHistory,
// ActiveSonarrBlock::FilterSeriesHistoryError, ActiveSonarrBlock::FilterSeriesHistoryError,
// ActiveSonarrBlock::ManualEpisodeSearch, ActiveSonarrBlock::ManualEpisodeSearch,
// ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt, ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt,
// ActiveSonarrBlock::ManualEpisodeSearchSortPrompt, ActiveSonarrBlock::ManualEpisodeSearchSortPrompt,
// ActiveSonarrBlock::ManualSeasonSearch, ActiveSonarrBlock::ManualSeasonSearch,
// ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt, ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt,
// ActiveSonarrBlock::ManualSeasonSearchSortPrompt, ActiveSonarrBlock::ManualSeasonSearchSortPrompt,
// ActiveSonarrBlock::SearchEpisodes, ActiveSonarrBlock::SearchEpisodes,
// ActiveSonarrBlock::SearchEpisodesError, ActiveSonarrBlock::SearchEpisodesError,
// ActiveSonarrBlock::SearchSeason, ActiveSonarrBlock::SearchSeason,
// ActiveSonarrBlock::SearchSeasonError, ActiveSonarrBlock::SearchSeasonError,
ActiveSonarrBlock::SearchSeries, ActiveSonarrBlock::SearchSeries,
ActiveSonarrBlock::SearchSeriesError, ActiveSonarrBlock::SearchSeriesError,
// ActiveSonarrBlock::SearchSeriesHistory, ActiveSonarrBlock::SearchSeriesHistory,
// ActiveSonarrBlock::SearchSeriesHistoryError, ActiveSonarrBlock::SearchSeriesHistoryError,
// ActiveSonarrBlock::SeasonDetails, ActiveSonarrBlock::SeasonDetails,
ActiveSonarrBlock::Series, ActiveSonarrBlock::Series,
// ActiveSonarrBlock::SeriesDetails, ActiveSonarrBlock::SeriesDetails,
// ActiveSonarrBlock::SeriesHistory, ActiveSonarrBlock::SeriesHistory,
// ActiveSonarrBlock::SeriesHistorySortPrompt, ActiveSonarrBlock::SeriesHistorySortPrompt,
ActiveSonarrBlock::SeriesSortPrompt, ActiveSonarrBlock::SeriesSortPrompt,
ActiveSonarrBlock::UpdateAllSeriesPrompt, ActiveSonarrBlock::UpdateAllSeriesPrompt,
// ActiveSonarrBlock::UpdateAndScanSeriesPrompt ActiveSonarrBlock::UpdateAndScanSeriesPrompt,
// ActiveSonarrBlock::SeriesHistoryDetails, ActiveSonarrBlock::SeriesHistoryDetails
)] )]
active_sonarr_block: ActiveSonarrBlock, active_sonarr_block: ActiveSonarrBlock,
) { ) {
@@ -222,4 +291,45 @@ mod tests {
active_sonarr_block 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_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = SonarrHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[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());
}
} }
+10 -6
View File
@@ -1,9 +1,9 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::sonarr_handlers::system::system_details_handler::SystemDetailsHandler; use crate::handlers::sonarr_handlers::system::system_details_handler::SystemDetailsHandler;
use crate::handlers::{handle_clear_errors, KeyEventHandler}; use crate::handlers::{handle_clear_errors, KeyEventHandler};
use crate::matches_key;
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock; use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::Scrollable; use crate::models::Scrollable;
@@ -35,6 +35,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SystemHandler<'a, 'b
SystemDetailsHandler::accepts(active_block) || active_block == ActiveSonarrBlock::System SystemDetailsHandler::accepts(active_block) || active_block == ActiveSonarrBlock::System
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -86,15 +90,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SystemHandler<'a, 'b
if self.active_sonarr_block == ActiveSonarrBlock::System { if self.active_sonarr_block == ActiveSonarrBlock::System {
let key = self.key; let key = self.key;
match self.key { match self.key {
_ if key == DEFAULT_KEYBINDINGS.refresh.key => { _ if matches_key!(refresh, key) => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ if key == DEFAULT_KEYBINDINGS.events.key => { _ if matches_key!(events, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::SystemQueuedEvents.into()); .push_navigation_stack(ActiveSonarrBlock::SystemQueuedEvents.into());
} }
_ if key == DEFAULT_KEYBINDINGS.logs.key => { _ if matches_key!(logs, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::SystemLogs.into()); .push_navigation_stack(ActiveSonarrBlock::SystemLogs.into());
@@ -106,12 +110,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SystemHandler<'a, 'b
.set_items(self.app.data.sonarr_data.logs.items.to_vec()); .set_items(self.app.data.sonarr_data.logs.items.to_vec());
self.app.data.sonarr_data.log_details.scroll_to_bottom(); self.app.data.sonarr_data.log_details.scroll_to_bottom();
} }
_ if key == DEFAULT_KEYBINDINGS.tasks.key => { _ if matches_key!(tasks, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::SystemTasks.into()); .push_navigation_stack(ActiveSonarrBlock::SystemTasks.into());
} }
_ if key == DEFAULT_KEYBINDINGS.update.key => { _ if matches_key!(update, key) => {
self self
.app .app
.push_navigation_stack(ActiveSonarrBlock::SystemUpdates.into()); .push_navigation_stack(ActiveSonarrBlock::SystemUpdates.into());
@@ -1,7 +1,7 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::matches_key;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SYSTEM_DETAILS_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SYSTEM_DETAILS_BLOCKS};
use crate::models::sonarr_models::SonarrTaskName; use crate::models::sonarr_models::SonarrTaskName;
use crate::models::stateful_list::StatefulList; use crate::models::stateful_list::StatefulList;
@@ -36,6 +36,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SystemDetailsHandler
SYSTEM_DETAILS_BLOCKS.contains(&active_block) SYSTEM_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -114,7 +118,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SystemDetailsHandler
match self.active_sonarr_block { match self.active_sonarr_block {
ActiveSonarrBlock::SystemLogs => match self.key { ActiveSonarrBlock::SystemLogs => match self.key {
_ if key == DEFAULT_KEYBINDINGS.left.key => { _ if matches_key!(left, key) => {
self self
.app .app
.data .data
@@ -124,7 +128,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SystemDetailsHandler
.iter() .iter()
.for_each(|log| log.scroll_right()); .for_each(|log| log.scroll_right());
} }
_ if key == DEFAULT_KEYBINDINGS.right.key => { _ if matches_key!(right, key) => {
self self
.app .app
.data .data
@@ -178,14 +182,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SystemDetailsHandler
} }
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
if SYSTEM_DETAILS_BLOCKS.contains(&self.active_sonarr_block) if SYSTEM_DETAILS_BLOCKS.contains(&self.active_sonarr_block) && matches_key!(refresh, self.key)
&& self.key == DEFAULT_KEYBINDINGS.refresh.key
{ {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
if self.active_sonarr_block == ActiveSonarrBlock::SystemTaskStartConfirmPrompt if self.active_sonarr_block == ActiveSonarrBlock::SystemTaskStartConfirmPrompt
&& self.key == DEFAULT_KEYBINDINGS.confirm.key && matches_key!(confirm, self.key)
{ {
self.app.data.sonarr_data.prompt_confirm = true; self.app.data.sonarr_data.prompt_confirm = true;
self.app.data.sonarr_data.prompt_confirm_action = self.app.data.sonarr_data.prompt_confirm_action =
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
@@ -960,6 +961,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_system_details_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = SystemDetailsHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_extract_task_name() { fn test_extract_task_name() {
let mut app = App::test_default(); let mut app = App::test_default();
@@ -456,6 +456,25 @@ mod tests {
}) })
} }
#[rstest]
fn test_system_handler_ignore_special_keys(
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
) {
let mut app = App::test_default();
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
let handler = SystemHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveSonarrBlock::default(),
None,
);
assert_eq!(
handler.ignore_special_keys(),
ignore_special_keys_for_textbox_input
);
}
#[test] #[test]
fn test_system_handler_is_not_ready_when_loading() { fn test_system_handler_is_not_ready_when_loading() {
let mut app = App::test_default(); let mut app = App::test_default();
+17 -17
View File
@@ -42,17 +42,17 @@ macro_rules! handle_table_events {
fn [<handle_ $name _table_events>](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { fn [<handle_ $name _table_events>](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool {
if $self.is_ready() { if $self.is_ready() {
match $self.key { match $self.key {
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.up.key => $self.[<handle_ $name _table_scroll_up>](config), _ if $crate::matches_key!(up, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_scroll_up>](config),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.down.key => $self.[<handle_ $name _table_scroll_down>](config), _ if $crate::matches_key!(down, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_scroll_down>](config),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.home.key => $self.[<handle_ $name _table_home>](config), _ if $crate::matches_key!(home, $self.key) => $self.[<handle_ $name _table_home>](config),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.end.key => $self.[<handle_ $name _table_end>](config), _ if $crate::matches_key!(end, $self.key) => $self.[<handle_ $name _table_end>](config),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.left.key _ if $crate::matches_key!(left, $self.key, $self.ignore_special_keys())
|| $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.right.key => || $crate::matches_key!(right, $self.key, $self.ignore_special_keys()) =>
{ {
$self.[<handle_ $name _table_left_right>](config) $self.[<handle_ $name _table_left_right>](config)
} }
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.submit.key => $self.[<handle_ $name _table_submit>](config), _ if $crate::matches_key!(submit, $self.key) => $self.[<handle_ $name _table_submit>](config),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.esc.key => $self.[<handle_ $name _table_esc>](config), _ if $crate::matches_key!(esc, $self.key) => $self.[<handle_ $name _table_esc>](config),
_ if config.searching_block.is_some() _ if config.searching_block.is_some()
&& $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() => && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() =>
{ {
@@ -63,11 +63,11 @@ macro_rules! handle_table_events {
{ {
$self.[<handle_ $name _table_filter_box_input>]() $self.[<handle_ $name _table_filter_box_input>]()
} }
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.filter.key _ if $crate::matches_key!(filter, $self.key)
&& config.filtering_block.is_some() => $self.[<handle_ $name _table_filter_key>](config), && config.filtering_block.is_some() => $self.[<handle_ $name _table_filter_key>](config),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.search.key _ if $crate::matches_key!(search, $self.key)
&& config.searching_block.is_some() => $self.[<handle_ $name _table_search_key>](config), && config.searching_block.is_some() => $self.[<handle_ $name _table_search_key>](config),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.sort.key _ if $crate::matches_key!(sort, $self.key)
&& config.sorting_block.is_some() => $self.[<handle_ $name _table_sort_key>](config), && config.sorting_block.is_some() => $self.[<handle_ $name _table_sort_key>](config),
_ => false, _ => false,
} }
@@ -244,7 +244,7 @@ macro_rules! handle_table_events {
&& $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() => && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() =>
{ {
$self.app.pop_navigation_stack(); $self.app.pop_navigation_stack();
$self.app.should_ignore_quit_key = false; $self.app.ignore_special_keys_for_textbox_input = false;
if $table.search.is_some() { if $table.search.is_some() {
let search_field_fn = config let search_field_fn = config
@@ -267,7 +267,7 @@ macro_rules! handle_table_events {
&& $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap() => && $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap() =>
{ {
$self.app.pop_navigation_stack(); $self.app.pop_navigation_stack();
$self.app.should_ignore_quit_key = false; $self.app.ignore_special_keys_for_textbox_input = false;
if $table.filter.is_some() { if $table.filter.is_some() {
let filter_field_fn = config let filter_field_fn = config
@@ -305,7 +305,7 @@ macro_rules! handle_table_events {
{ {
$self.app.pop_navigation_stack(); $self.app.pop_navigation_stack();
$table.reset_search(); $table.reset_search();
$self.app.should_ignore_quit_key = false; $self.app.ignore_special_keys_for_textbox_input = false;
true true
} }
_ if (config.filtering_block.is_some() _ if (config.filtering_block.is_some()
@@ -315,7 +315,7 @@ macro_rules! handle_table_events {
{ {
$self.app.pop_navigation_stack(); $self.app.pop_navigation_stack();
$table.reset_filter(); $table.reset_filter();
$self.app.should_ignore_quit_key = false; $self.app.ignore_special_keys_for_textbox_input = false;
true true
} }
_ if config.table_block == $self.app.get_current_route() _ if config.table_block == $self.app.get_current_route()
@@ -335,7 +335,7 @@ macro_rules! handle_table_events {
.push_navigation_stack(config.filtering_block.expect("Filtering block is undefined").into()); .push_navigation_stack(config.filtering_block.expect("Filtering block is undefined").into());
$table.reset_filter(); $table.reset_filter();
$table.filter = Some($crate::models::HorizontallyScrollableText::default()); $table.filter = Some($crate::models::HorizontallyScrollableText::default());
$self.app.should_ignore_quit_key = true; $self.app.ignore_special_keys_for_textbox_input = true;
true true
} else { } else {
@@ -349,7 +349,7 @@ macro_rules! handle_table_events {
.app .app
.push_navigation_stack(config.searching_block.expect("Searching block is undefined")); .push_navigation_stack(config.searching_block.expect("Searching block is undefined"));
$table.search = Some($crate::models::HorizontallyScrollableText::default()); $table.search = Some($crate::models::HorizontallyScrollableText::default());
$self.app.should_ignore_quit_key = true; $self.app.ignore_special_keys_for_textbox_input = true;
true true
} else { } else {
+22 -18
View File
@@ -48,6 +48,10 @@ mod tests {
true true
} }
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new( fn new(
key: Key, key: Key,
app: &'a mut App<'b>, app: &'a mut App<'b>,
@@ -648,7 +652,7 @@ mod tests {
TableHandlerUnit::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::FilterMovies, None).handle(); TableHandlerUnit::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::FilterMovies, None).handle();
assert!(app.data.radarr_data.movies.filtered_items.is_some()); assert!(app.data.radarr_data.movies.filtered_items.is_some());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app app
.data .data
@@ -684,7 +688,7 @@ mod tests {
TableHandlerUnit::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::FilterMovies, None).handle(); TableHandlerUnit::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::FilterMovies, None).handle();
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.movies.filtered_items.is_none()); assert!(app.data.radarr_data.movies.filtered_items.is_none());
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
@@ -735,7 +739,7 @@ mod tests {
active_radarr_block: ActiveRadarrBlock, active_radarr_block: ActiveRadarrBlock,
) { ) {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::Movies.into()); app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(active_radarr_block.into()); app.push_navigation_stack(active_radarr_block.into());
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
@@ -744,7 +748,7 @@ mod tests {
TableHandlerUnit::new(ESC_KEY, &mut app, active_radarr_block, None).handle(); TableHandlerUnit::new(ESC_KEY, &mut app, active_radarr_block, None).handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!(app.data.radarr_data.movies.search, None); assert_eq!(app.data.radarr_data.movies.search, None);
} }
@@ -754,7 +758,7 @@ mod tests {
active_radarr_block: ActiveRadarrBlock, active_radarr_block: ActiveRadarrBlock,
) { ) {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::Movies.into()); app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(active_radarr_block.into()); app.push_navigation_stack(active_radarr_block.into());
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
@@ -773,7 +777,7 @@ mod tests {
TableHandlerUnit::new(ESC_KEY, &mut app, active_radarr_block, None).handle(); TableHandlerUnit::new(ESC_KEY, &mut app, active_radarr_block, None).handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!(app.data.radarr_data.movies.filter, None); assert_eq!(app.data.radarr_data.movies.filter, None);
assert_eq!(app.data.radarr_data.movies.filtered_items, None); assert_eq!(app.data.radarr_data.movies.filtered_items, None);
assert_eq!(app.data.radarr_data.movies.filtered_state, None); assert_eq!(app.data.radarr_data.movies.filtered_state, None);
@@ -820,7 +824,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::SearchMovie.into() ActiveRadarrBlock::SearchMovie.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.data.radarr_data.movies.search, app.data.radarr_data.movies.search,
Some(HorizontallyScrollableText::default()) Some(HorizontallyScrollableText::default())
@@ -847,7 +851,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!(app.data.radarr_data.movies.search, None); assert_eq!(app.data.radarr_data.movies.search, None);
} }
@@ -869,7 +873,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!(app.data.radarr_data.movies.search, None); assert_eq!(app.data.radarr_data.movies.search, None);
} }
@@ -894,7 +898,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::FilterMovies.into() ActiveRadarrBlock::FilterMovies.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.movies.filter.is_some()); assert!(app.data.radarr_data.movies.filter.is_some());
} }
@@ -918,14 +922,14 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert!(app.data.radarr_data.movies.filter.is_none()); assert!(app.data.radarr_data.movies.filter.is_none());
} }
#[test] #[test]
fn test_filter_table_key_resets_previous_filter() { fn test_filter_table_key_resets_previous_filter() {
let mut app = App::test_default(); let mut app = App::test_default();
app.should_ignore_quit_key = true; app.ignore_special_keys_for_textbox_input = true;
app.push_navigation_stack(ActiveRadarrBlock::Movies.into()); app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.data.radarr_data = create_test_radarr_data(); app.data.radarr_data = create_test_radarr_data();
app app
@@ -947,7 +951,7 @@ mod tests {
app.get_current_route(), app.get_current_route(),
ActiveRadarrBlock::FilterMovies.into() ActiveRadarrBlock::FilterMovies.into()
); );
assert!(app.should_ignore_quit_key); assert!(app.ignore_special_keys_for_textbox_input);
assert_eq!( assert_eq!(
app.data.radarr_data.movies.filter, app.data.radarr_data.movies.filter,
Some(HorizontallyScrollableText::default()) Some(HorizontallyScrollableText::default())
@@ -974,7 +978,7 @@ mod tests {
.handle(); .handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
assert!(!app.should_ignore_quit_key); assert!(!app.ignore_special_keys_for_textbox_input);
assert_eq!(app.data.radarr_data.movies.filter, None); assert_eq!(app.data.radarr_data.movies.filter, None);
} }
@@ -1040,7 +1044,7 @@ mod tests {
app.data.radarr_data.movies.search = Some(HorizontallyScrollableText::default()); app.data.radarr_data.movies.search = Some(HorizontallyScrollableText::default());
TableHandlerUnit::new( TableHandlerUnit::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::SearchMovie, ActiveRadarrBlock::SearchMovie,
None, None,
@@ -1049,7 +1053,7 @@ mod tests {
assert_str_eq!( assert_str_eq!(
app.data.radarr_data.movies.search.as_ref().unwrap().text, app.data.radarr_data.movies.search.as_ref().unwrap().text,
"h" "a"
); );
} }
@@ -1065,7 +1069,7 @@ mod tests {
app.data.radarr_data.movies.filter = Some(HorizontallyScrollableText::default()); app.data.radarr_data.movies.filter = Some(HorizontallyScrollableText::default());
TableHandlerUnit::new( TableHandlerUnit::new(
Key::Char('h'), Key::Char('a'),
&mut app, &mut app,
ActiveRadarrBlock::FilterMovies, ActiveRadarrBlock::FilterMovies,
None, None,
@@ -1074,7 +1078,7 @@ mod tests {
assert_str_eq!( assert_str_eq!(
app.data.radarr_data.movies.filter.as_ref().unwrap().text, app.data.radarr_data.movies.filter.as_ref().unwrap().text,
"h" "a"
); );
} }
+1 -1
View File
@@ -246,7 +246,7 @@ async fn start_ui(
match input_events.next()? { match input_events.next()? {
InputEvent::KeyEvent(key) => { InputEvent::KeyEvent(key) => {
if key == Key::Char('q') && !app.should_ignore_quit_key { if key == Key::Char('q') && !app.ignore_special_keys_for_textbox_input {
break; break;
} }