feat: Support alternative keymappings for all keys, featuring hjkl movements
This commit is contained in:
+61
-1
@@ -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: None,
|
||||||
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_alt_navigation:expr) => {
|
||||||
|
$crate::app::key_binding::DEFAULT_KEYBINDINGS.$binding.key == $key
|
||||||
|
|| !$ignore_alt_navigation
|
||||||
|
&& ($crate::app::key_binding::DEFAULT_KEYBINDINGS
|
||||||
|
.$binding
|
||||||
|
.alt
|
||||||
|
.is_some()
|
||||||
|
&& $crate::app::key_binding::DEFAULT_KEYBINDINGS
|
||||||
|
.$binding
|
||||||
|
.alt
|
||||||
|
.unwrap()
|
||||||
|
== $key)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ mod test {
|
|||||||
#[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), "sort")]
|
#[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), "sort")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), "edit")]
|
#[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), "edit")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.events, Key::Char('e'), "events")]
|
#[case(DEFAULT_KEYBINDINGS.events, Key::Char('e'), "events")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.logs, Key::Char('l'), "logs")]
|
#[case(DEFAULT_KEYBINDINGS.logs, Key::Char('L'), "logs")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")]
|
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")]
|
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), "test all")]
|
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), "test all")]
|
||||||
|
|||||||
+24
-23
@@ -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_alt_navigation()) => {
|
||||||
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_alt_navigation()) => {
|
||||||
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_alt_navigation())
|
||||||
|
|| matches_key!(right, key, self.ignore_alt_navigation()) =>
|
||||||
|
{
|
||||||
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_alt_navigation(&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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_blocklist_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = BlocklistHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_collection_details_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = CollectionDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_collections_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = CollectionsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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;
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_collection_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = EditCollectionHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_downloads_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = DownloadsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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 {
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = EditIndexerHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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;
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_indexer_settings_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = IndexerSettingsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_indexers_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = IndexersHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_indexer_id() {
|
fn test_extract_indexer_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::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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_test_all_indexers_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = TestAllIndexersHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_add_movie_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = AddMovieHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delete_movie_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = DeleteMovieHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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;
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_movie_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = EditMovieHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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();
|
||||||
|
|||||||
@@ -777,6 +777,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_library_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = LibraryHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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();
|
||||||
|
|||||||
@@ -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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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.should_ignore_quit_key = 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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_movie_details_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = MovieDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_movie_details_handler_is_not_ready_when_loading(
|
fn test_movie_details_handler_is_not_ready_when_loading(
|
||||||
#[values(
|
#[values(
|
||||||
|
|||||||
@@ -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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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.should_ignore_quit_key) => {
|
||||||
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.should_ignore_quit_key) => {
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.should_ignore_quit_key = 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.should_ignore_quit_key = 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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_radarr_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = RadarrHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::Movies,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -195,10 +200,10 @@ 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());
|
||||||
@@ -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;
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_root_folders_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = RootFoldersHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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();
|
||||||
|
|||||||
@@ -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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_system_details_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = SystemDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_system_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = SystemHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_blocklist_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = BlocklistHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_downloads_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = DownloadsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_history_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = HistoryHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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();
|
||||||
|
|||||||
@@ -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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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 {
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = EditIndexerHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_indexer_settings_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = IndexerSettingsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_indexers_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = IndexersHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_indexer_id() {
|
fn test_extract_indexer_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::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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_test_all_indexers_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = TestAllIndexersHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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;
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_add_series_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = AddSeriesHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delete_series_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = DeleteSeriesHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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;
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_series_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = EditSeriesHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_episode_details_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = EpisodeDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_episode_id() {
|
fn test_extract_episode_id() {
|
||||||
let mut app = App::test_default();
|
let mut app = App::test_default();
|
||||||
|
|||||||
@@ -827,6 +827,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_library_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = LibraryHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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();
|
||||||
|
|||||||
@@ -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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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.should_ignore_quit_key = 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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_season_details_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = SeasonDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_series_details_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = SeriesDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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,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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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.should_ignore_quit_key) => {
|
||||||
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.should_ignore_quit_key) => {
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -193,10 +198,10 @@ 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());
|
||||||
@@ -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;
|
||||||
@@ -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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_root_folders_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = RootFoldersHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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.should_ignore_quit_key = true;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(index);
|
||||||
|
|
||||||
|
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.alt.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
block.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), block.into());
|
||||||
|
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(index);
|
||||||
|
|
||||||
|
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.alt.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
block.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), block.into());
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[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,42 @@ 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_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = SonarrHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sonarr_handler_is_ready() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = SonarrHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_system_details_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = SystemDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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,22 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_system_handler_ignore_alt_navigation(
|
||||||
|
#[values(true, false)] should_ignore_quit_key: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.should_ignore_quit_key = should_ignore_quit_key;
|
||||||
|
let handler = SystemHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(handler.ignore_alt_navigation(), should_ignore_quit_key);
|
||||||
|
}
|
||||||
|
|
||||||
#[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();
|
||||||
|
|||||||
@@ -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_alt_navigation()) => $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_alt_navigation()) => $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_alt_navigation())
|
||||||
|| $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.right.key =>
|
|| $crate::matches_key!(right, $self.key, $self.ignore_alt_navigation()) =>
|
||||||
{
|
{
|
||||||
$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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ mod tests {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ignore_alt_navigation(&self) -> bool {
|
||||||
|
self.app.should_ignore_quit_key
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
@@ -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"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user