From 6a7f9fe0da960b31e5a29db0b5b453c463f513ce Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Thu, 3 Sep 2026 17:18:48 -0600 Subject: [PATCH] feat(readarr): add the delete author handler Handles the delete author prompt, toggling whether to delete files on disk and whether to add a list exclusion before confirming. Backing out of the prompt resets both toggles, so preferences from an abandoned delete cannot leak into the next one. --- .../library/delete_author_handler.rs | 151 ++++++ .../library/delete_author_handler_tests.rs | 484 ++++++++++++++++++ .../library/library_handler_tests.rs | 12 +- src/handlers/readarr_handlers/library/mod.rs | 9 +- 4 files changed, 654 insertions(+), 2 deletions(-) create mode 100644 src/handlers/readarr_handlers/library/delete_author_handler.rs create mode 100644 src/handlers/readarr_handlers/library/delete_author_handler_tests.rs diff --git a/src/handlers/readarr_handlers/library/delete_author_handler.rs b/src/handlers/readarr_handlers/library/delete_author_handler.rs new file mode 100644 index 00000000..8f541a4b --- /dev/null +++ b/src/handlers/readarr_handlers/library/delete_author_handler.rs @@ -0,0 +1,151 @@ +use crate::app::App; +use crate::event::Key; +use crate::handlers::{KeyEventHandler, handle_prompt_toggle}; +use crate::matches_key; +use crate::models::Route; +use crate::models::readarr_models::DeleteParams; +use crate::models::servarr_data::readarr::readarr_data::{ + ActiveReadarrBlock, DELETE_AUTHOR_BLOCKS, +}; +use crate::network::readarr_network::ReadarrEvent; + +#[cfg(test)] +#[path = "delete_author_handler_tests.rs"] +mod delete_author_handler_tests; + +pub(in crate::handlers::readarr_handlers) struct DeleteAuthorHandler<'a, 'b> { + key: Key, + app: &'a mut App<'b>, + active_readarr_block: ActiveReadarrBlock, + _context: Option, +} + +impl DeleteAuthorHandler<'_, '_> { + fn build_delete_author_params(&mut self) -> DeleteParams { + let id = self.app.data.readarr_data.authors.current_selection().id; + let delete_files = self.app.data.readarr_data.delete_files; + let add_import_list_exclusion = self.app.data.readarr_data.add_import_list_exclusion; + self.app.data.readarr_data.reset_delete_preferences(); + + DeleteParams { + id, + delete_files, + add_import_list_exclusion, + } + } +} + +impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveReadarrBlock> for DeleteAuthorHandler<'a, 'b> { + fn accepts(active_block: ActiveReadarrBlock) -> bool { + DELETE_AUTHOR_BLOCKS.contains(&active_block) + } + + fn ignore_special_keys(&self) -> bool { + self.app.ignore_special_keys_for_textbox_input + } + + fn new( + key: Key, + app: &'a mut App<'b>, + active_block: ActiveReadarrBlock, + _context: Option, + ) -> DeleteAuthorHandler<'a, 'b> { + DeleteAuthorHandler { + key, + app, + active_readarr_block: active_block, + _context, + } + } + + fn get_key(&self) -> Key { + self.key + } + + fn is_ready(&self) -> bool { + !self.app.is_loading + } + + fn handle_scroll_up(&mut self) { + if self.active_readarr_block == ActiveReadarrBlock::DeleteAuthorPrompt { + self.app.data.readarr_data.selected_block.up(); + } + } + + fn handle_scroll_down(&mut self) { + if self.active_readarr_block == ActiveReadarrBlock::DeleteAuthorPrompt { + self.app.data.readarr_data.selected_block.down(); + } + } + + fn handle_home(&mut self) {} + + fn handle_end(&mut self) {} + + fn handle_delete(&mut self) {} + + fn handle_left_right_action(&mut self) { + if self.active_readarr_block == ActiveReadarrBlock::DeleteAuthorPrompt { + handle_prompt_toggle(self.app, self.key); + } + } + + fn handle_submit(&mut self) { + if self.active_readarr_block == ActiveReadarrBlock::DeleteAuthorPrompt { + match self.app.data.readarr_data.selected_block.get_active_block() { + ActiveReadarrBlock::DeleteAuthorConfirmPrompt => { + if self.app.data.readarr_data.prompt_confirm { + self.app.data.readarr_data.prompt_confirm_action = Some(ReadarrEvent::DeleteAuthor( + self.build_delete_author_params(), + )); + self.app.should_refresh = true; + } else { + self.app.data.readarr_data.reset_delete_preferences(); + } + + self.app.pop_navigation_stack(); + } + ActiveReadarrBlock::DeleteAuthorToggleDeleteFile => { + self.app.data.readarr_data.delete_files = !self.app.data.readarr_data.delete_files; + } + ActiveReadarrBlock::DeleteAuthorToggleAddListExclusion => { + self.app.data.readarr_data.add_import_list_exclusion = + !self.app.data.readarr_data.add_import_list_exclusion; + } + _ => (), + } + } + } + + fn handle_esc(&mut self) { + if self.active_readarr_block == ActiveReadarrBlock::DeleteAuthorPrompt { + self.app.pop_navigation_stack(); + self.app.data.readarr_data.reset_delete_preferences(); + self.app.data.readarr_data.prompt_confirm = false; + } + } + + fn handle_char_key_event(&mut self) { + if self.active_readarr_block == ActiveReadarrBlock::DeleteAuthorPrompt + && self.app.data.readarr_data.selected_block.get_active_block() + == ActiveReadarrBlock::DeleteAuthorConfirmPrompt + && matches_key!(confirm, self.key) + { + self.app.data.readarr_data.prompt_confirm = true; + self.app.data.readarr_data.prompt_confirm_action = Some(ReadarrEvent::DeleteAuthor( + self.build_delete_author_params(), + )); + self.app.should_refresh = true; + + self.app.pop_navigation_stack(); + } + } + + fn app_mut(&mut self) -> &mut App<'b> { + self.app + } + + fn current_route(&self) -> Route { + self.app.get_current_route() + } +} diff --git a/src/handlers/readarr_handlers/library/delete_author_handler_tests.rs b/src/handlers/readarr_handlers/library/delete_author_handler_tests.rs new file mode 100644 index 00000000..ef7d7c7a --- /dev/null +++ b/src/handlers/readarr_handlers/library/delete_author_handler_tests.rs @@ -0,0 +1,484 @@ +#[cfg(test)] +mod tests { + use pretty_assertions::assert_eq; + use rstest::rstest; + use strum::IntoEnumIterator; + + use crate::app::App; + use crate::app::key_binding::DEFAULT_KEYBINDINGS; + use crate::event::Key; + use crate::handlers::KeyEventHandler; + use crate::handlers::readarr_handlers::library::delete_author_handler::DeleteAuthorHandler; + use crate::models::readarr_models::{Author, DeleteParams}; + use crate::models::servarr_data::readarr::readarr_data::{ + ActiveReadarrBlock, DELETE_AUTHOR_BLOCKS, + }; + + mod test_handle_scroll_up_and_down { + use pretty_assertions::assert_eq; + use rstest::rstest; + + use crate::models::BlockSelectionState; + use crate::models::servarr_data::readarr::readarr_data::DELETE_AUTHOR_SELECTION_BLOCKS; + + use super::*; + + #[rstest] + fn test_delete_author_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) { + let mut app = App::test_default(); + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app.data.readarr_data.selected_block.down(); + + DeleteAuthorHandler::new(key, &mut app, ActiveReadarrBlock::DeleteAuthorPrompt, None) + .handle(); + + if key == Key::Up { + assert_eq!( + app.data.readarr_data.selected_block.get_active_block(), + ActiveReadarrBlock::DeleteAuthorToggleDeleteFile + ); + } else { + assert_eq!( + app.data.readarr_data.selected_block.get_active_block(), + ActiveReadarrBlock::DeleteAuthorConfirmPrompt + ); + } + } + + #[rstest] + fn test_delete_author_prompt_scroll_no_op_when_not_ready( + #[values(Key::Up, Key::Down)] key: Key, + ) { + let mut app = App::test_default(); + app.is_loading = true; + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app.data.readarr_data.selected_block.down(); + + DeleteAuthorHandler::new(key, &mut app, ActiveReadarrBlock::DeleteAuthorPrompt, None) + .handle(); + + assert_eq!( + app.data.readarr_data.selected_block.get_active_block(), + ActiveReadarrBlock::DeleteAuthorToggleAddListExclusion + ); + } + } + + mod test_handle_left_right_action { + use rstest::rstest; + + use super::*; + + #[rstest] + fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) { + let mut app = App::test_default(); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + + DeleteAuthorHandler::new(key, &mut app, ActiveReadarrBlock::DeleteAuthorPrompt, None) + .handle(); + + assert!(app.data.readarr_data.prompt_confirm); + + DeleteAuthorHandler::new(key, &mut app, ActiveReadarrBlock::DeleteAuthorPrompt, None) + .handle(); + + assert!(!app.data.readarr_data.prompt_confirm); + } + } + + mod test_handle_submit { + use pretty_assertions::assert_eq; + + use crate::assert_navigation_popped; + use crate::models::BlockSelectionState; + use crate::models::servarr_data::readarr::readarr_data::DELETE_AUTHOR_SELECTION_BLOCKS; + use crate::network::readarr_network::ReadarrEvent; + + use super::*; + + const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key; + + #[test] + fn test_delete_author_prompt_prompt_decline_submit() { + let mut app = App::test_default(); + app.push_navigation_stack(ActiveReadarrBlock::Authors.into()); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app + .data + .readarr_data + .selected_block + .set_index(0, DELETE_AUTHOR_SELECTION_BLOCKS.len() - 1); + app.data.readarr_data.delete_files = true; + app.data.readarr_data.add_import_list_exclusion = true; + + DeleteAuthorHandler::new( + SUBMIT_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_navigation_popped!(app, ActiveReadarrBlock::Authors.into()); + assert_none!(app.data.readarr_data.prompt_confirm_action); + assert!(!app.data.readarr_data.prompt_confirm); + assert!(!app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + } + + #[test] + fn test_delete_author_confirm_prompt_prompt_confirmation_submit() { + let mut app = App::test_default(); + app.push_navigation_stack(ActiveReadarrBlock::Authors.into()); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + app.data.readarr_data.prompt_confirm = true; + app.data.readarr_data.delete_files = false; + app.data.readarr_data.add_import_list_exclusion = true; + app.data.readarr_data.authors.set_items(vec![author()]); + let expected_delete_author_params = DeleteParams { + id: 42, + delete_files: false, + add_import_list_exclusion: true, + }; + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app + .data + .readarr_data + .selected_block + .set_index(0, DELETE_AUTHOR_SELECTION_BLOCKS.len() - 1); + + DeleteAuthorHandler::new( + SUBMIT_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_navigation_popped!(app, ActiveReadarrBlock::Authors.into()); + assert_eq!( + app.data.readarr_data.prompt_confirm_action, + Some(ReadarrEvent::DeleteAuthor(expected_delete_author_params)) + ); + assert!(app.should_refresh); + assert!(app.data.readarr_data.prompt_confirm); + assert!(!app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + } + + #[test] + fn test_delete_author_confirm_prompt_prompt_confirmation_submit_no_op_when_not_ready() { + let mut app = App::test_default(); + app.is_loading = true; + app.push_navigation_stack(ActiveReadarrBlock::Authors.into()); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + app.data.readarr_data.prompt_confirm = true; + app.data.readarr_data.delete_files = true; + app.data.readarr_data.add_import_list_exclusion = false; + + DeleteAuthorHandler::new( + SUBMIT_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_eq!( + app.get_current_route(), + ActiveReadarrBlock::DeleteAuthorPrompt.into() + ); + assert_none!(app.data.readarr_data.prompt_confirm_action); + assert!(!app.should_refresh); + assert!(app.data.readarr_data.prompt_confirm); + assert!(app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + } + + #[test] + fn test_delete_author_toggle_delete_files_submit() { + let current_route = ActiveReadarrBlock::DeleteAuthorPrompt.into(); + let mut app = App::test_default(); + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + + DeleteAuthorHandler::new( + SUBMIT_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_eq!(app.get_current_route(), current_route); + assert!(app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + + DeleteAuthorHandler::new( + SUBMIT_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_eq!(app.get_current_route(), current_route); + assert!(!app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + } + + #[test] + fn test_delete_author_toggle_add_list_exclusion_submit() { + let current_route = ActiveReadarrBlock::DeleteAuthorPrompt.into(); + let mut app = App::test_default(); + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app.data.readarr_data.selected_block.down(); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + + DeleteAuthorHandler::new( + SUBMIT_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_eq!(app.get_current_route(), current_route); + assert!(app.data.readarr_data.add_import_list_exclusion); + assert!(!app.data.readarr_data.delete_files); + + DeleteAuthorHandler::new( + SUBMIT_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_eq!(app.get_current_route(), current_route); + assert!(!app.data.readarr_data.add_import_list_exclusion); + assert!(!app.data.readarr_data.delete_files); + } + } + + mod test_handle_esc { + use rstest::rstest; + + use crate::assert_navigation_popped; + + use super::*; + + const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key; + + #[rstest] + fn test_delete_author_prompt_esc(#[values(true, false)] is_loading: bool) { + let mut app = App::test_default(); + app.is_loading = is_loading; + app.push_navigation_stack(ActiveReadarrBlock::Authors.into()); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + app.data.readarr_data.prompt_confirm = true; + app.data.readarr_data.delete_files = true; + app.data.readarr_data.add_import_list_exclusion = true; + + DeleteAuthorHandler::new( + ESC_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_navigation_popped!(app, ActiveReadarrBlock::Authors.into()); + assert!(!app.data.readarr_data.prompt_confirm); + assert!(!app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + } + } + + mod test_handle_key_char { + use pretty_assertions::assert_eq; + + use crate::assert_navigation_popped; + use crate::models::BlockSelectionState; + use crate::models::servarr_data::readarr::readarr_data::DELETE_AUTHOR_SELECTION_BLOCKS; + use crate::network::readarr_network::ReadarrEvent; + + use super::*; + + const CONFIRM_KEY: Key = DEFAULT_KEYBINDINGS.confirm.key; + + #[test] + fn test_delete_author_confirm_prompt_prompt_confirm() { + let mut app = App::test_default(); + app.push_navigation_stack(ActiveReadarrBlock::Authors.into()); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + app.data.readarr_data.delete_files = true; + app.data.readarr_data.add_import_list_exclusion = false; + app.data.readarr_data.authors.set_items(vec![author()]); + let expected_delete_author_params = DeleteParams { + id: 42, + delete_files: true, + add_import_list_exclusion: false, + }; + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app + .data + .readarr_data + .selected_block + .set_index(0, DELETE_AUTHOR_SELECTION_BLOCKS.len() - 1); + + DeleteAuthorHandler::new( + CONFIRM_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_navigation_popped!(app, ActiveReadarrBlock::Authors.into()); + assert_eq!( + app.data.readarr_data.prompt_confirm_action, + Some(ReadarrEvent::DeleteAuthor(expected_delete_author_params)) + ); + assert!(app.should_refresh); + assert!(app.data.readarr_data.prompt_confirm); + assert!(!app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + } + + #[test] + fn test_delete_author_confirm_prompt_prompt_confirm_no_op_when_not_ready() { + let mut app = App::test_default(); + app.is_loading = true; + app.push_navigation_stack(ActiveReadarrBlock::Authors.into()); + app.push_navigation_stack(ActiveReadarrBlock::DeleteAuthorPrompt.into()); + app.data.readarr_data.delete_files = true; + app.data.readarr_data.add_import_list_exclusion = false; + app.data.readarr_data.authors.set_items(vec![author()]); + app.data.readarr_data.selected_block = + BlockSelectionState::new(DELETE_AUTHOR_SELECTION_BLOCKS); + app + .data + .readarr_data + .selected_block + .set_index(0, DELETE_AUTHOR_SELECTION_BLOCKS.len() - 1); + + DeleteAuthorHandler::new( + CONFIRM_KEY, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .handle(); + + assert_eq!( + app.get_current_route(), + ActiveReadarrBlock::DeleteAuthorPrompt.into() + ); + assert_none!(app.data.readarr_data.prompt_confirm_action); + assert!(!app.should_refresh); + assert!(!app.data.readarr_data.prompt_confirm); + assert!(app.data.readarr_data.delete_files); + } + } + + #[test] + fn test_delete_author_handler_accepts() { + ActiveReadarrBlock::iter().for_each(|active_readarr_block| { + if DELETE_AUTHOR_BLOCKS.contains(&active_readarr_block) { + assert!(DeleteAuthorHandler::accepts(active_readarr_block)); + } else { + assert!(!DeleteAuthorHandler::accepts(active_readarr_block)); + } + }); + } + + #[rstest] + fn test_delete_author_handler_ignore_special_keys( + #[values(true, false)] ignore_special_keys_for_textbox_input: bool, + ) { + let mut app = App::test_default(); + app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input; + let handler = DeleteAuthorHandler::new( + DEFAULT_KEYBINDINGS.esc.key, + &mut app, + ActiveReadarrBlock::default(), + None, + ); + + assert_eq!( + handler.ignore_special_keys(), + ignore_special_keys_for_textbox_input + ); + } + + #[test] + fn test_build_delete_author_params() { + let mut app = App::test_default(); + app.data.readarr_data.authors.set_items(vec![author()]); + app.data.readarr_data.delete_files = true; + app.data.readarr_data.add_import_list_exclusion = false; + let expected_delete_author_params = DeleteParams { + id: 42, + delete_files: true, + add_import_list_exclusion: false, + }; + + let delete_author_params = DeleteAuthorHandler::new( + DEFAULT_KEYBINDINGS.esc.key, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ) + .build_delete_author_params(); + + assert_eq!(delete_author_params, expected_delete_author_params); + assert!(!app.data.readarr_data.delete_files); + assert!(!app.data.readarr_data.add_import_list_exclusion); + } + + #[test] + fn test_delete_author_handler_not_ready_when_loading() { + let mut app = App::test_default(); + app.is_loading = true; + + let handler = DeleteAuthorHandler::new( + DEFAULT_KEYBINDINGS.esc.key, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ); + + assert!(!handler.is_ready()); + } + + #[test] + fn test_delete_author_handler_ready_when_not_loading() { + let mut app = App::test_default(); + app.is_loading = false; + + let handler = DeleteAuthorHandler::new( + DEFAULT_KEYBINDINGS.esc.key, + &mut app, + ActiveReadarrBlock::DeleteAuthorPrompt, + None, + ); + + assert!(handler.is_ready()); + } + + fn author() -> Author { + Author { + id: 42, + ..Author::default() + } + } +} diff --git a/src/handlers/readarr_handlers/library/library_handler_tests.rs b/src/handlers/readarr_handlers/library/library_handler_tests.rs index 8bc0d5f2..a6906059 100644 --- a/src/handlers/readarr_handlers/library/library_handler_tests.rs +++ b/src/handlers/readarr_handlers/library/library_handler_tests.rs @@ -15,7 +15,7 @@ mod tests { use crate::models::readarr_models::{Author, AuthorStatistics, AuthorStatus}; use crate::models::servarr_data::readarr::readarr_data::{ ADD_AUTHOR_BLOCKS, AUTHOR_DETAILS_BLOCKS, ActiveReadarrBlock, BOOK_DETAILS_BLOCKS, - EDIT_AUTHOR_BLOCKS, EDITION_DETAILS_BLOCKS, LIBRARY_BLOCKS, + DELETE_AUTHOR_BLOCKS, EDIT_AUTHOR_BLOCKS, EDITION_DETAILS_BLOCKS, LIBRARY_BLOCKS, }; use crate::test_handler_delegation; @@ -898,6 +898,15 @@ mod tests { ); } + #[test] + fn test_delegates_delete_author_blocks_to_delete_author_handler() { + test_handler_delegation!( + LibraryHandler, + ActiveReadarrBlock::Authors, + ActiveReadarrBlock::DeleteAuthorPrompt + ); + } + #[test] fn test_delegates_edit_author_blocks_to_edit_author_handler() { test_handler_delegation!( @@ -915,6 +924,7 @@ mod tests { library_handler_blocks.extend(BOOK_DETAILS_BLOCKS); library_handler_blocks.extend(EDITION_DETAILS_BLOCKS); library_handler_blocks.extend(ADD_AUTHOR_BLOCKS); + library_handler_blocks.extend(DELETE_AUTHOR_BLOCKS); library_handler_blocks.extend(EDIT_AUTHOR_BLOCKS); ActiveReadarrBlock::iter().for_each(|readarr_block| { diff --git a/src/handlers/readarr_handlers/library/mod.rs b/src/handlers/readarr_handlers/library/mod.rs index bce88861..b2b96c4f 100644 --- a/src/handlers/readarr_handlers/library/mod.rs +++ b/src/handlers/readarr_handlers/library/mod.rs @@ -22,12 +22,14 @@ use crate::models::Route; mod add_author_handler; mod author_details_handler; mod book_details_handler; +mod delete_author_handler; mod edit_author_handler; mod edition_details_handler; pub(in crate::handlers::readarr_handlers) use { add_author_handler::AddAuthorHandler, author_details_handler::AuthorDetailsHandler, - book_details_handler::BookDetailsHandler, edit_author_handler::EditAuthorHandler, + book_details_handler::BookDetailsHandler, delete_author_handler::DeleteAuthorHandler, + edit_author_handler::EditAuthorHandler, }; #[cfg(test)] @@ -70,6 +72,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveReadarrBlock> for LibraryHandler<'a, AddAuthorHandler::new(self.key, self.app, self.active_readarr_block, self.context) .handle(); } + _ if DeleteAuthorHandler::accepts(self.active_readarr_block) => { + DeleteAuthorHandler::new(self.key, self.app, self.active_readarr_block, self.context) + .handle(); + } _ if EditAuthorHandler::accepts(self.active_readarr_block) => { EditAuthorHandler::new(self.key, self.app, self.active_readarr_block, self.context) .handle(); @@ -89,6 +95,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveReadarrBlock> for LibraryHandler<'a, fn accepts(active_block: ActiveReadarrBlock) -> bool { AddAuthorHandler::accepts(active_block) + || DeleteAuthorHandler::accepts(active_block) || EditAuthorHandler::accepts(active_block) || AuthorDetailsHandler::accepts(active_block) || BookDetailsHandler::accepts(active_block)