Lidarr support #1
@@ -36,15 +36,16 @@ pub static ADD_ARTIST_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
||||
];
|
||||
|
||||
pub static ARTIST_DETAILS_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||
pub static ARTIST_DETAILS_CONTEXT_CLUES: [ContextClue; 8] = [
|
||||
(
|
||||
DEFAULT_KEYBINDINGS.refresh,
|
||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||
),
|
||||
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||
(DEFAULT_KEYBINDINGS.edit, "edit artist"),
|
||||
(DEFAULT_KEYBINDINGS.delete, "delete album"),
|
||||
(
|
||||
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
|
||||
"toggle album monitoring",
|
||||
),
|
||||
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
||||
|
||||
@@ -81,13 +81,17 @@ mod tests {
|
||||
);
|
||||
assert_some_eq_x!(
|
||||
artist_details_context_clues_iter.next(),
|
||||
&(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc)
|
||||
&(DEFAULT_KEYBINDINGS.edit, "edit artist")
|
||||
);
|
||||
assert_some_eq_x!(
|
||||
artist_details_context_clues_iter.next(),
|
||||
&(DEFAULT_KEYBINDINGS.delete, "delete album")
|
||||
);
|
||||
assert_some_eq_x!(
|
||||
artist_details_context_clues_iter.next(),
|
||||
&(
|
||||
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
|
||||
"toggle album monitoring",
|
||||
)
|
||||
);
|
||||
assert_some_eq_x!(
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use crate::app::App;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::lidarr_handlers::library::delete_album_handler::DeleteAlbumHandler;
|
||||
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||
use crate::handlers::{KeyEventHandler, handle_prompt_toggle};
|
||||
use crate::matches_key;
|
||||
use crate::models::lidarr_models::Album;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, EDIT_ARTIST_SELECTION_BLOCKS,
|
||||
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_SELECTION_BLOCKS,
|
||||
EDIT_ARTIST_SELECTION_BLOCKS,
|
||||
};
|
||||
use crate::models::{BlockSelectionState, Route};
|
||||
use crate::network::lidarr_network::LidarrEvent;
|
||||
@@ -18,7 +20,7 @@ pub struct ArtistDetailsHandler<'a, 'b> {
|
||||
key: Key,
|
||||
app: &'a mut App<'b>,
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
_context: Option<ActiveLidarrBlock>,
|
||||
context: Option<ActiveLidarrBlock>,
|
||||
}
|
||||
|
||||
impl ArtistDetailsHandler<'_, '_> {
|
||||
@@ -44,12 +46,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler
|
||||
|app| &mut app.data.lidarr_data.albums,
|
||||
albums_table_handling_config,
|
||||
) {
|
||||
self.handle_key_event();
|
||||
match self.active_lidarr_block {
|
||||
_ if DeleteAlbumHandler::accepts(self.active_lidarr_block) => {
|
||||
DeleteAlbumHandler::new(self.key, self.app, self.active_lidarr_block, self.context)
|
||||
.handle();
|
||||
}
|
||||
_ => self.handle_key_event(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn accepts(active_block: ActiveLidarrBlock) -> bool {
|
||||
ARTIST_DETAILS_BLOCKS.contains(&active_block)
|
||||
DeleteAlbumHandler::accepts(active_block) || ARTIST_DETAILS_BLOCKS.contains(&active_block)
|
||||
}
|
||||
|
||||
fn ignore_special_keys(&self) -> bool {
|
||||
@@ -60,13 +68,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler
|
||||
key: Key,
|
||||
app: &'a mut App<'b>,
|
||||
active_block: ActiveLidarrBlock,
|
||||
_context: Option<ActiveLidarrBlock>,
|
||||
context: Option<ActiveLidarrBlock>,
|
||||
) -> ArtistDetailsHandler<'a, 'b> {
|
||||
ArtistDetailsHandler {
|
||||
key,
|
||||
app,
|
||||
active_lidarr_block: active_block,
|
||||
_context,
|
||||
context,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +94,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler
|
||||
|
||||
fn handle_end(&mut self) {}
|
||||
|
||||
fn handle_delete(&mut self) {}
|
||||
fn handle_delete(&mut self) {
|
||||
if self.active_lidarr_block == ActiveLidarrBlock::ArtistDetails {
|
||||
self
|
||||
.app
|
||||
.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
self.app.data.lidarr_data.selected_block =
|
||||
BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_left_right_action(&mut self) {
|
||||
match self.active_lidarr_block {
|
||||
|
||||
@@ -9,9 +9,42 @@ mod tests {
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::lidarr_handlers::library::artist_details_handler::ArtistDetailsHandler;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock,
|
||||
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
|
||||
};
|
||||
|
||||
mod test_handle_delete {
|
||||
use super::*;
|
||||
use crate::assert_delete_prompt;
|
||||
use crate::event::Key;
|
||||
use crate::models::lidarr_models::Album;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::DELETE_ALBUM_SELECTION_BLOCKS;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
const DELETE_KEY: Key = DEFAULT_KEYBINDINGS.delete.key;
|
||||
|
||||
#[test]
|
||||
fn test_album_delete() {
|
||||
let mut app = App::test_default();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.albums
|
||||
.set_items(vec![Album::default()]);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
|
||||
assert_delete_prompt!(
|
||||
ArtistDetailsHandler,
|
||||
app,
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt
|
||||
);
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.selected_block.blocks,
|
||||
DELETE_ALBUM_SELECTION_BLOCKS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_left_right_action {
|
||||
use rstest::rstest;
|
||||
|
||||
@@ -436,8 +469,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_artist_details_handler_accepts() {
|
||||
let mut artist_details_blocks = ARTIST_DETAILS_BLOCKS.clone().to_vec();
|
||||
artist_details_blocks.extend(DELETE_ALBUM_BLOCKS);
|
||||
|
||||
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
|
||||
if ARTIST_DETAILS_BLOCKS.contains(&active_lidarr_block) {
|
||||
if artist_details_blocks.contains(&active_lidarr_block) {
|
||||
assert!(ArtistDetailsHandler::accepts(active_lidarr_block));
|
||||
} else {
|
||||
assert!(!ArtistDetailsHandler::accepts(active_lidarr_block));
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
use crate::models::Route;
|
||||
use crate::models::lidarr_models::DeleteParams;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::DELETE_ALBUM_BLOCKS;
|
||||
use crate::network::lidarr_network::LidarrEvent;
|
||||
use crate::{
|
||||
app::App,
|
||||
event::Key,
|
||||
handlers::{KeyEventHandler, handle_prompt_toggle},
|
||||
matches_key,
|
||||
models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "delete_album_handler_tests.rs"]
|
||||
mod delete_album_handler_tests;
|
||||
|
||||
pub(in crate::handlers::lidarr_handlers) struct DeleteAlbumHandler<'a, 'b> {
|
||||
key: Key,
|
||||
app: &'a mut App<'b>,
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
_context: Option<ActiveLidarrBlock>,
|
||||
}
|
||||
|
||||
impl DeleteAlbumHandler<'_, '_> {
|
||||
fn build_delete_album_params(&mut self) -> DeleteParams {
|
||||
let id = self.app.data.lidarr_data.albums.current_selection().id;
|
||||
let delete_files = self.app.data.lidarr_data.delete_files;
|
||||
let add_import_list_exclusion = self.app.data.lidarr_data.add_import_list_exclusion;
|
||||
self.app.data.lidarr_data.reset_delete_preferences();
|
||||
|
||||
DeleteParams {
|
||||
id,
|
||||
delete_files,
|
||||
add_import_list_exclusion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for DeleteAlbumHandler<'a, 'b> {
|
||||
fn accepts(active_block: ActiveLidarrBlock) -> bool {
|
||||
DELETE_ALBUM_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: ActiveLidarrBlock,
|
||||
_context: Option<ActiveLidarrBlock>,
|
||||
) -> Self {
|
||||
DeleteAlbumHandler {
|
||||
key,
|
||||
app,
|
||||
active_lidarr_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_lidarr_block == ActiveLidarrBlock::DeleteAlbumPrompt {
|
||||
self.app.data.lidarr_data.selected_block.up();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_scroll_down(&mut self) {
|
||||
if self.active_lidarr_block == ActiveLidarrBlock::DeleteAlbumPrompt {
|
||||
self.app.data.lidarr_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_lidarr_block == ActiveLidarrBlock::DeleteAlbumPrompt {
|
||||
handle_prompt_toggle(self.app, self.key);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_submit(&mut self) {
|
||||
if self.active_lidarr_block == ActiveLidarrBlock::DeleteAlbumPrompt {
|
||||
match self.app.data.lidarr_data.selected_block.get_active_block() {
|
||||
ActiveLidarrBlock::DeleteAlbumConfirmPrompt => {
|
||||
if self.app.data.lidarr_data.prompt_confirm {
|
||||
self.app.data.lidarr_data.prompt_confirm_action =
|
||||
Some(LidarrEvent::DeleteAlbum(self.build_delete_album_params()));
|
||||
self.app.should_refresh = true;
|
||||
} else {
|
||||
self.app.data.lidarr_data.reset_delete_preferences();
|
||||
}
|
||||
|
||||
self.app.pop_navigation_stack();
|
||||
}
|
||||
ActiveLidarrBlock::DeleteAlbumToggleDeleteFile => {
|
||||
self.app.data.lidarr_data.delete_files = !self.app.data.lidarr_data.delete_files;
|
||||
}
|
||||
ActiveLidarrBlock::DeleteAlbumToggleAddListExclusion => {
|
||||
self.app.data.lidarr_data.add_import_list_exclusion =
|
||||
!self.app.data.lidarr_data.add_import_list_exclusion;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_esc(&mut self) {
|
||||
if self.active_lidarr_block == ActiveLidarrBlock::DeleteAlbumPrompt {
|
||||
self.app.pop_navigation_stack();
|
||||
self.app.data.lidarr_data.reset_delete_preferences();
|
||||
self.app.data.lidarr_data.prompt_confirm = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_char_key_event(&mut self) {
|
||||
if self.active_lidarr_block == ActiveLidarrBlock::DeleteAlbumPrompt
|
||||
&& self.app.data.lidarr_data.selected_block.get_active_block()
|
||||
== ActiveLidarrBlock::DeleteAlbumConfirmPrompt
|
||||
&& matches_key!(confirm, self.key)
|
||||
{
|
||||
self.app.data.lidarr_data.prompt_confirm = true;
|
||||
self.app.data.lidarr_data.prompt_confirm_action =
|
||||
Some(LidarrEvent::DeleteAlbum(self.build_delete_album_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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
#[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::lidarr_handlers::library::delete_album_handler::DeleteAlbumHandler;
|
||||
use crate::models::lidarr_models::{Album, DeleteParams};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, DELETE_ALBUM_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::lidarr::lidarr_data::DELETE_ALBUM_SELECTION_BLOCKS;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[rstest]
|
||||
fn test_delete_album_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||
let mut app = App::test_default();
|
||||
app.data.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
app.data.lidarr_data.selected_block.down();
|
||||
|
||||
DeleteAlbumHandler::new(key, &mut app, ActiveLidarrBlock::DeleteAlbumPrompt, None).handle();
|
||||
|
||||
if key == Key::Up {
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.selected_block.get_active_block(),
|
||||
ActiveLidarrBlock::DeleteAlbumToggleDeleteFile
|
||||
);
|
||||
} else {
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.selected_block.get_active_block(),
|
||||
ActiveLidarrBlock::DeleteAlbumConfirmPrompt
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_delete_album_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.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
app.data.lidarr_data.selected_block.down();
|
||||
|
||||
DeleteAlbumHandler::new(key, &mut app, ActiveLidarrBlock::DeleteAlbumPrompt, None).handle();
|
||||
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.selected_block.get_active_block(),
|
||||
ActiveLidarrBlock::DeleteAlbumToggleAddListExclusion
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
|
||||
DeleteAlbumHandler::new(key, &mut app, ActiveLidarrBlock::DeleteAlbumPrompt, None).handle();
|
||||
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
|
||||
DeleteAlbumHandler::new(key, &mut app, ActiveLidarrBlock::DeleteAlbumPrompt, None).handle();
|
||||
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_submit {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::models::BlockSelectionState;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::DELETE_ALBUM_SELECTION_BLOCKS;
|
||||
use crate::network::lidarr_network::LidarrEvent;
|
||||
|
||||
use super::*;
|
||||
use crate::assert_navigation_popped;
|
||||
|
||||
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_prompt_prompt_decline_submit() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
app.data.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.selected_block
|
||||
.set_index(0, DELETE_ALBUM_SELECTION_BLOCKS.len() - 1);
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
|
||||
DeleteAlbumHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ArtistDetails.into());
|
||||
assert_none!(app.data.lidarr_data.prompt_confirm_action);
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_confirm_prompt_prompt_confirmation_submit() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
app.data.lidarr_data.prompt_confirm = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.albums
|
||||
.set_items(vec![Album::default()]);
|
||||
let expected_delete_album_params = DeleteParams {
|
||||
id: 0,
|
||||
delete_files: true,
|
||||
add_import_list_exclusion: true,
|
||||
};
|
||||
app.data.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.selected_block
|
||||
.set_index(0, DELETE_ALBUM_SELECTION_BLOCKS.len() - 1);
|
||||
|
||||
DeleteAlbumHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ArtistDetails.into());
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.prompt_confirm_action,
|
||||
Some(LidarrEvent::DeleteAlbum(expected_delete_album_params))
|
||||
);
|
||||
assert!(app.should_refresh);
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_confirm_prompt_prompt_confirmation_submit_no_op_when_not_ready() {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = true;
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
app.data.lidarr_data.prompt_confirm = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
|
||||
DeleteAlbumHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt.into()
|
||||
);
|
||||
assert_none!(app.data.lidarr_data.prompt_confirm_action);
|
||||
assert!(!app.should_refresh);
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert!(app.data.lidarr_data.delete_files);
|
||||
assert!(app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_toggle_delete_files_submit() {
|
||||
let current_route = ActiveLidarrBlock::DeleteAlbumPrompt.into();
|
||||
let mut app = App::test_default();
|
||||
app.data.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
|
||||
DeleteAlbumHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), current_route);
|
||||
assert_eq!(app.data.lidarr_data.delete_files, true);
|
||||
|
||||
DeleteAlbumHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), current_route);
|
||||
assert_eq!(app.data.lidarr_data.delete_files, false);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_esc {
|
||||
use super::*;
|
||||
use crate::assert_navigation_popped;
|
||||
use rstest::rstest;
|
||||
|
||||
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||
|
||||
#[rstest]
|
||||
fn test_delete_album_prompt_esc(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
app.data.lidarr_data.prompt_confirm = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
|
||||
DeleteAlbumHandler::new(
|
||||
ESC_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ArtistDetails.into());
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_key_char {
|
||||
use crate::{
|
||||
assert_navigation_popped,
|
||||
models::{
|
||||
BlockSelectionState, servarr_data::lidarr::lidarr_data::DELETE_ALBUM_SELECTION_BLOCKS,
|
||||
},
|
||||
network::lidarr_network::LidarrEvent,
|
||||
};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_confirm_prompt_prompt_confirm() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.albums
|
||||
.set_items(vec![Album::default()]);
|
||||
let expected_delete_album_params = DeleteParams {
|
||||
id: 0,
|
||||
delete_files: true,
|
||||
add_import_list_exclusion: true,
|
||||
};
|
||||
app.data.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.selected_block
|
||||
.set_index(0, DELETE_ALBUM_SELECTION_BLOCKS.len() - 1);
|
||||
|
||||
DeleteAlbumHandler::new(
|
||||
DEFAULT_KEYBINDINGS.confirm.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ArtistDetails.into());
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.prompt_confirm_action,
|
||||
Some(LidarrEvent::DeleteAlbum(expected_delete_album_params))
|
||||
);
|
||||
assert!(app.should_refresh);
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_handler_accepts() {
|
||||
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
|
||||
if DELETE_ALBUM_BLOCKS.contains(&active_lidarr_block) {
|
||||
assert!(DeleteAlbumHandler::accepts(active_lidarr_block));
|
||||
} else {
|
||||
assert!(!DeleteAlbumHandler::accepts(active_lidarr_block));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_delete_album_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 = DeleteAlbumHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::default(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
handler.ignore_special_keys(),
|
||||
ignore_special_keys_for_textbox_input
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_delete_album_params() {
|
||||
let mut app = App::test_default();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.albums
|
||||
.set_items(vec![Album::default()]);
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
let expected_delete_album_params = DeleteParams {
|
||||
id: 0,
|
||||
delete_files: true,
|
||||
add_import_list_exclusion: true,
|
||||
};
|
||||
|
||||
let delete_album_params = DeleteAlbumHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.build_delete_album_params();
|
||||
|
||||
assert_eq!(delete_album_params, expected_delete_album_params);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_handler_not_ready_when_loading() {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = true;
|
||||
|
||||
let handler = DeleteAlbumHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(!handler.is_ready());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_handler_ready_when_not_loading() {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = false;
|
||||
|
||||
let handler = DeleteAlbumHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(handler.is_ready());
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,9 @@ pub(in crate::handlers::lidarr_handlers) struct DeleteArtistHandler<'a, 'b> {
|
||||
impl DeleteArtistHandler<'_, '_> {
|
||||
fn build_delete_artist_params(&mut self) -> DeleteParams {
|
||||
let id = self.app.data.lidarr_data.artists.current_selection().id;
|
||||
let delete_files = self.app.data.lidarr_data.delete_artist_files;
|
||||
let delete_files = self.app.data.lidarr_data.delete_files;
|
||||
let add_import_list_exclusion = self.app.data.lidarr_data.add_import_list_exclusion;
|
||||
self.app.data.lidarr_data.reset_delete_artist_preferences();
|
||||
self.app.data.lidarr_data.reset_delete_preferences();
|
||||
|
||||
DeleteParams {
|
||||
id,
|
||||
@@ -99,14 +99,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for DeleteArtistHandler<
|
||||
Some(LidarrEvent::DeleteArtist(self.build_delete_artist_params()));
|
||||
self.app.should_refresh = true;
|
||||
} else {
|
||||
self.app.data.lidarr_data.reset_delete_artist_preferences();
|
||||
self.app.data.lidarr_data.reset_delete_preferences();
|
||||
}
|
||||
|
||||
self.app.pop_navigation_stack();
|
||||
}
|
||||
ActiveLidarrBlock::DeleteArtistToggleDeleteFile => {
|
||||
self.app.data.lidarr_data.delete_artist_files =
|
||||
!self.app.data.lidarr_data.delete_artist_files;
|
||||
self.app.data.lidarr_data.delete_files = !self.app.data.lidarr_data.delete_files;
|
||||
}
|
||||
ActiveLidarrBlock::DeleteArtistToggleAddListExclusion => {
|
||||
self.app.data.lidarr_data.add_import_list_exclusion =
|
||||
@@ -120,7 +119,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for DeleteArtistHandler<
|
||||
fn handle_esc(&mut self) {
|
||||
if self.active_lidarr_block == ActiveLidarrBlock::DeleteArtistPrompt {
|
||||
self.app.pop_navigation_stack();
|
||||
self.app.data.lidarr_data.reset_delete_artist_preferences();
|
||||
self.app.data.lidarr_data.reset_delete_preferences();
|
||||
self.app.data.lidarr_data.prompt_confirm = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ mod tests {
|
||||
.lidarr_data
|
||||
.selected_block
|
||||
.set_index(0, DELETE_ARTIST_SELECTION_BLOCKS.len() - 1);
|
||||
app.data.lidarr_data.delete_artist_files = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
|
||||
DeleteArtistHandler::new(
|
||||
@@ -120,7 +120,7 @@ mod tests {
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::Artists.into());
|
||||
assert_none!(app.data.lidarr_data.prompt_confirm_action);
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_artist_files);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ mod tests {
|
||||
app.push_navigation_stack(ActiveLidarrBlock::Artists.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteArtistPrompt.into());
|
||||
app.data.lidarr_data.prompt_confirm = true;
|
||||
app.data.lidarr_data.delete_artist_files = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
app
|
||||
.data
|
||||
@@ -165,7 +165,7 @@ mod tests {
|
||||
);
|
||||
assert!(app.should_refresh);
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_artist_files);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ mod tests {
|
||||
app.push_navigation_stack(ActiveLidarrBlock::Artists.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteArtistPrompt.into());
|
||||
app.data.lidarr_data.prompt_confirm = true;
|
||||
app.data.lidarr_data.delete_artist_files = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
|
||||
DeleteArtistHandler::new(
|
||||
@@ -194,7 +194,7 @@ mod tests {
|
||||
assert_none!(app.data.lidarr_data.prompt_confirm_action);
|
||||
assert!(!app.should_refresh);
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert!(app.data.lidarr_data.delete_artist_files);
|
||||
assert!(app.data.lidarr_data.delete_files);
|
||||
assert!(app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ mod tests {
|
||||
.handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), current_route);
|
||||
assert_eq!(app.data.lidarr_data.delete_artist_files, true);
|
||||
assert_eq!(app.data.lidarr_data.delete_files, true);
|
||||
|
||||
DeleteArtistHandler::new(
|
||||
SUBMIT_KEY,
|
||||
@@ -226,7 +226,7 @@ mod tests {
|
||||
.handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), current_route);
|
||||
assert_eq!(app.data.lidarr_data.delete_artist_files, false);
|
||||
assert_eq!(app.data.lidarr_data.delete_files, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ mod tests {
|
||||
app.push_navigation_stack(ActiveLidarrBlock::Artists.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteArtistPrompt.into());
|
||||
app.data.lidarr_data.prompt_confirm = true;
|
||||
app.data.lidarr_data.delete_artist_files = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
|
||||
DeleteArtistHandler::new(
|
||||
@@ -257,7 +257,7 @@ mod tests {
|
||||
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::Artists.into());
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_artist_files);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
}
|
||||
@@ -279,7 +279,7 @@ mod tests {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::Artists.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteArtistPrompt.into());
|
||||
app.data.lidarr_data.delete_artist_files = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
app
|
||||
.data
|
||||
@@ -314,7 +314,7 @@ mod tests {
|
||||
);
|
||||
assert!(app.should_refresh);
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert!(!app.data.lidarr_data.delete_artist_files);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
}
|
||||
@@ -357,7 +357,7 @@ mod tests {
|
||||
.lidarr_data
|
||||
.artists
|
||||
.set_items(vec![Artist::default()]);
|
||||
app.data.lidarr_data.delete_artist_files = true;
|
||||
app.data.lidarr_data.delete_files = true;
|
||||
app.data.lidarr_data.add_import_list_exclusion = true;
|
||||
let expected_delete_artist_params = DeleteParams {
|
||||
id: 0,
|
||||
@@ -374,7 +374,7 @@ mod tests {
|
||||
.build_delete_artist_params();
|
||||
|
||||
assert_eq!(delete_artist_params, expected_delete_artist_params);
|
||||
assert!(!app.data.lidarr_data.delete_artist_files);
|
||||
assert!(!app.data.lidarr_data.delete_files);
|
||||
assert!(!app.data.lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ mod tests {
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::lidarr_handlers::library::{LibraryHandler, artists_sorting_options};
|
||||
use crate::models::lidarr_models::{Artist, ArtistStatistics, ArtistStatus};
|
||||
use crate::models::lidarr_models::{Album, Artist, ArtistStatistics, ArtistStatus};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ARTIST_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ARTIST_BLOCKS,
|
||||
EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS, LIBRARY_BLOCKS,
|
||||
ADD_ARTIST_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
|
||||
DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS, LIBRARY_BLOCKS,
|
||||
};
|
||||
use crate::models::servarr_data::lidarr::modals::EditArtistModal;
|
||||
use crate::network::lidarr_network::LidarrEvent;
|
||||
@@ -28,6 +28,7 @@ mod tests {
|
||||
library_handler_blocks.extend(LIBRARY_BLOCKS);
|
||||
library_handler_blocks.extend(ARTIST_DETAILS_BLOCKS);
|
||||
library_handler_blocks.extend(DELETE_ARTIST_BLOCKS);
|
||||
library_handler_blocks.extend(DELETE_ALBUM_BLOCKS);
|
||||
library_handler_blocks.extend(EDIT_ARTIST_BLOCKS);
|
||||
library_handler_blocks.extend(ADD_ARTIST_BLOCKS);
|
||||
|
||||
@@ -533,6 +534,31 @@ mod tests {
|
||||
assert_eq!(app.get_current_route(), ActiveLidarrBlock::Artists.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delegates_delete_album_blocks_to_delete_album_handler() {
|
||||
let mut app = App::test_default();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.albums
|
||||
.set_items(vec![Album::default()]);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
|
||||
LibraryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
ActiveLidarrBlock::ArtistDetails.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delegates_delete_artist_blocks_to_delete_artist_handler() {
|
||||
let mut app = App::test_default();
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||
|
||||
mod add_artist_handler;
|
||||
mod artist_details_handler;
|
||||
mod delete_album_handler;
|
||||
mod delete_artist_handler;
|
||||
mod edit_artist_handler;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ pub struct LidarrData<'a> {
|
||||
pub albums: StatefulTable<Album>,
|
||||
pub artist_info_tabs: TabState,
|
||||
pub artists: StatefulTable<Artist>,
|
||||
pub delete_artist_files: bool,
|
||||
pub delete_files: bool,
|
||||
pub disk_space_vec: Vec<DiskSpace>,
|
||||
pub downloads: StatefulTable<DownloadRecord>,
|
||||
pub edit_artist_modal: Option<EditArtistModal>,
|
||||
@@ -57,8 +57,8 @@ pub struct LidarrData<'a> {
|
||||
}
|
||||
|
||||
impl LidarrData<'_> {
|
||||
pub fn reset_delete_artist_preferences(&mut self) {
|
||||
self.delete_artist_files = false;
|
||||
pub fn reset_delete_preferences(&mut self) {
|
||||
self.delete_files = false;
|
||||
self.add_import_list_exclusion = false;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ impl<'a> Default for LidarrData<'a> {
|
||||
add_searched_artists: None,
|
||||
albums: StatefulTable::default(),
|
||||
artists: StatefulTable::default(),
|
||||
delete_artist_files: false,
|
||||
delete_files: false,
|
||||
disk_space_vec: Vec::new(),
|
||||
downloads: StatefulTable::default(),
|
||||
edit_artist_modal: None,
|
||||
@@ -176,7 +176,7 @@ impl LidarrData<'_> {
|
||||
.set_items(vec![metadata_profile().name]);
|
||||
|
||||
let mut lidarr_data = LidarrData {
|
||||
delete_artist_files: true,
|
||||
delete_files: true,
|
||||
disk_space_vec: vec![diskspace()],
|
||||
quality_profile_map: quality_profile_map(),
|
||||
metadata_profile_map: metadata_profile_map(),
|
||||
@@ -226,6 +226,10 @@ pub enum ActiveLidarrBlock {
|
||||
AddArtistSelectRootFolder,
|
||||
AddArtistTagsInput,
|
||||
AutomaticallySearchArtistPrompt,
|
||||
DeleteAlbumPrompt,
|
||||
DeleteAlbumConfirmPrompt,
|
||||
DeleteAlbumToggleDeleteFile,
|
||||
DeleteAlbumToggleAddListExclusion,
|
||||
DeleteArtistPrompt,
|
||||
DeleteArtistConfirmPrompt,
|
||||
DeleteArtistToggleDeleteFile,
|
||||
@@ -304,6 +308,19 @@ pub const DELETE_ARTIST_SELECTION_BLOCKS: &[&[ActiveLidarrBlock]] = &[
|
||||
&[ActiveLidarrBlock::DeleteArtistConfirmPrompt],
|
||||
];
|
||||
|
||||
pub static DELETE_ALBUM_BLOCKS: [ActiveLidarrBlock; 4] = [
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
ActiveLidarrBlock::DeleteAlbumConfirmPrompt,
|
||||
ActiveLidarrBlock::DeleteAlbumToggleDeleteFile,
|
||||
ActiveLidarrBlock::DeleteAlbumToggleAddListExclusion,
|
||||
];
|
||||
|
||||
pub const DELETE_ALBUM_SELECTION_BLOCKS: &[&[ActiveLidarrBlock]] = &[
|
||||
&[ActiveLidarrBlock::DeleteAlbumToggleDeleteFile],
|
||||
&[ActiveLidarrBlock::DeleteAlbumToggleAddListExclusion],
|
||||
&[ActiveLidarrBlock::DeleteAlbumConfirmPrompt],
|
||||
];
|
||||
|
||||
pub static EDIT_ARTIST_BLOCKS: [ActiveLidarrBlock; 8] = [
|
||||
ActiveLidarrBlock::EditArtistPrompt,
|
||||
ActiveLidarrBlock::EditArtistConfirmPrompt,
|
||||
|
||||
@@ -5,8 +5,9 @@ mod tests {
|
||||
};
|
||||
use crate::models::lidarr_models::Album;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ARTIST_DETAILS_BLOCKS, DELETE_ARTIST_BLOCKS,
|
||||
DELETE_ARTIST_SELECTION_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS,
|
||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ARTIST_DETAILS_BLOCKS, DELETE_ALBUM_BLOCKS,
|
||||
DELETE_ALBUM_SELECTION_BLOCKS, DELETE_ARTIST_BLOCKS, DELETE_ARTIST_SELECTION_BLOCKS,
|
||||
EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS,
|
||||
};
|
||||
use crate::models::{
|
||||
BlockSelectionState, Route,
|
||||
@@ -34,16 +35,16 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reset_delete_artist_preferences() {
|
||||
fn test_reset_delete_preferences() {
|
||||
let mut lidarr_data = LidarrData {
|
||||
delete_artist_files: true,
|
||||
delete_files: true,
|
||||
add_import_list_exclusion: true,
|
||||
..LidarrData::default()
|
||||
};
|
||||
|
||||
lidarr_data.reset_delete_artist_preferences();
|
||||
lidarr_data.reset_delete_preferences();
|
||||
|
||||
assert!(!lidarr_data.delete_artist_files);
|
||||
assert!(!lidarr_data.delete_files);
|
||||
assert!(!lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
@@ -129,7 +130,7 @@ mod tests {
|
||||
assert_none!(lidarr_data.add_searched_artists);
|
||||
assert_is_empty!(lidarr_data.albums);
|
||||
assert_is_empty!(lidarr_data.artists);
|
||||
assert!(!lidarr_data.delete_artist_files);
|
||||
assert!(!lidarr_data.delete_files);
|
||||
assert_is_empty!(lidarr_data.disk_space_vec);
|
||||
assert_is_empty!(lidarr_data.downloads);
|
||||
assert_none!(lidarr_data.edit_artist_modal);
|
||||
@@ -271,6 +272,34 @@ mod tests {
|
||||
assert_none!(delete_artist_block_iter.next());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_blocks_contents() {
|
||||
assert_eq!(DELETE_ALBUM_BLOCKS.len(), 4);
|
||||
assert!(DELETE_ALBUM_BLOCKS.contains(&ActiveLidarrBlock::DeleteAlbumPrompt));
|
||||
assert!(DELETE_ALBUM_BLOCKS.contains(&ActiveLidarrBlock::DeleteAlbumConfirmPrompt));
|
||||
assert!(DELETE_ALBUM_BLOCKS.contains(&ActiveLidarrBlock::DeleteAlbumToggleDeleteFile));
|
||||
assert!(DELETE_ALBUM_BLOCKS.contains(&ActiveLidarrBlock::DeleteAlbumToggleAddListExclusion));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_selection_blocks_ordering() {
|
||||
let mut delete_album_block_iter = DELETE_ALBUM_SELECTION_BLOCKS.iter();
|
||||
|
||||
assert_eq!(
|
||||
delete_album_block_iter.next().unwrap(),
|
||||
&[ActiveLidarrBlock::DeleteAlbumToggleDeleteFile]
|
||||
);
|
||||
assert_eq!(
|
||||
delete_album_block_iter.next().unwrap(),
|
||||
&[ActiveLidarrBlock::DeleteAlbumToggleAddListExclusion]
|
||||
);
|
||||
assert_eq!(
|
||||
delete_album_block_iter.next().unwrap(),
|
||||
&[ActiveLidarrBlock::DeleteAlbumConfirmPrompt]
|
||||
);
|
||||
assert_none!(delete_album_block_iter.next());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edit_artist_blocks() {
|
||||
assert_eq!(EDIT_ARTIST_BLOCKS.len(), 8);
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::app::App;
|
||||
use crate::models::Route;
|
||||
use crate::models::lidarr_models::Album;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock};
|
||||
use crate::ui::lidarr_ui::library::delete_album_ui::DeleteAlbumUi;
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::utils::{
|
||||
borderless_block, get_width_from_percentage, layout_block_top_border, title_block,
|
||||
@@ -32,10 +33,10 @@ impl DrawUi for ArtistDetailsUi {
|
||||
let Route::Lidarr(active_lidarr_block, _) = route else {
|
||||
return false;
|
||||
};
|
||||
ARTIST_DETAILS_BLOCKS.contains(&active_lidarr_block)
|
||||
DeleteAlbumUi::accepts(route) || ARTIST_DETAILS_BLOCKS.contains(&active_lidarr_block)
|
||||
}
|
||||
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let route = app.get_current_route();
|
||||
if let Route::Lidarr(active_lidarr_block, _) = route {
|
||||
let draw_artist_details_popup = |f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect| {
|
||||
@@ -65,6 +66,7 @@ impl DrawUi for ArtistDetailsUi {
|
||||
draw_artist_details(f, app, content_area);
|
||||
|
||||
match active_lidarr_block {
|
||||
_ if DeleteAlbumUi::accepts(route) => DeleteAlbumUi::draw(f, app, area),
|
||||
ActiveLidarrBlock::AutomaticallySearchArtistPrompt => {
|
||||
let prompt = format!(
|
||||
"Do you want to trigger an automatic search of your indexers for all monitored album(s) for the artist: {}?",
|
||||
|
||||
@@ -3,7 +3,7 @@ mod tests {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock,
|
||||
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
|
||||
};
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::lidarr_ui::library::artist_details_ui::ArtistDetailsUi;
|
||||
@@ -11,6 +11,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_artist_details_ui_accepts() {
|
||||
let mut blocks = ARTIST_DETAILS_BLOCKS.clone().to_vec();
|
||||
blocks.extend(DELETE_ALBUM_BLOCKS);
|
||||
|
||||
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
|
||||
if blocks.contains(&active_lidarr_block) {
|
||||
assert!(ArtistDetailsUi::accepts(active_lidarr_block.into()));
|
||||
@@ -24,7 +26,10 @@ mod tests {
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock;
|
||||
use crate::models::BlockSelectionState;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ActiveLidarrBlock, DELETE_ALBUM_SELECTION_BLOCKS,
|
||||
};
|
||||
use crate::models::stateful_table::StatefulTable;
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::lidarr_ui::library::artist_details_ui::ArtistDetailsUi;
|
||||
@@ -96,6 +101,20 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_details_ui_renders_delete_album_prompt_over_artist_details() {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
app.data.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
|
||||
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
|
||||
ArtistDetailsUi::draw(f, app, f.area());
|
||||
});
|
||||
|
||||
insta::assert_snapshot!(output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_details_ui_renders_update_and_scan_prompt_over_artist_details() {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::Rect;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::Route;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, DELETE_ALBUM_BLOCKS};
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::widgets::checkbox::Checkbox;
|
||||
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
|
||||
use crate::ui::widgets::popup::{Popup, Size};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "delete_album_ui_tests.rs"]
|
||||
mod delete_album_ui_tests;
|
||||
|
||||
pub(in crate::ui::lidarr_ui) struct DeleteAlbumUi;
|
||||
|
||||
impl DrawUi for DeleteAlbumUi {
|
||||
fn accepts(route: Route) -> bool {
|
||||
let Route::Lidarr(active_lidarr_block, _) = route else {
|
||||
return false;
|
||||
};
|
||||
DELETE_ALBUM_BLOCKS.contains(&active_lidarr_block)
|
||||
}
|
||||
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
|
||||
if matches!(
|
||||
app.get_current_route(),
|
||||
Route::Lidarr(ActiveLidarrBlock::DeleteAlbumPrompt, _)
|
||||
) {
|
||||
let selected_block = app.data.lidarr_data.selected_block.get_active_block();
|
||||
let prompt = format!(
|
||||
"Do you really want to delete the album: \n{}?",
|
||||
app.data.lidarr_data.albums.current_selection().title.text
|
||||
);
|
||||
let checkboxes = vec![
|
||||
Checkbox::new("Delete Album Files")
|
||||
.checked(app.data.lidarr_data.delete_files)
|
||||
.highlighted(selected_block == ActiveLidarrBlock::DeleteAlbumToggleDeleteFile),
|
||||
Checkbox::new("Add List Exclusion")
|
||||
.checked(app.data.lidarr_data.add_import_list_exclusion)
|
||||
.highlighted(selected_block == ActiveLidarrBlock::DeleteAlbumToggleAddListExclusion),
|
||||
];
|
||||
let confirmation_prompt = ConfirmationPrompt::new()
|
||||
.title("Delete Album")
|
||||
.prompt(&prompt)
|
||||
.checkboxes(checkboxes)
|
||||
.yes_no_highlighted(selected_block == ActiveLidarrBlock::DeleteAlbumConfirmPrompt)
|
||||
.yes_no_value(app.data.lidarr_data.prompt_confirm);
|
||||
|
||||
f.render_widget(
|
||||
Popup::new(confirmation_prompt).size(Size::MediumPrompt),
|
||||
f.area(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::BlockSelectionState;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ActiveLidarrBlock, DELETE_ALBUM_BLOCKS, DELETE_ALBUM_SELECTION_BLOCKS,
|
||||
};
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::lidarr_ui::library::delete_album_ui::DeleteAlbumUi;
|
||||
use crate::ui::ui_test_utils::test_utils::render_to_string_with_app;
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_ui_accepts() {
|
||||
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
|
||||
if DELETE_ALBUM_BLOCKS.contains(&active_lidarr_block) {
|
||||
assert!(DeleteAlbumUi::accepts(active_lidarr_block.into()));
|
||||
} else {
|
||||
assert!(!DeleteAlbumUi::accepts(active_lidarr_block.into()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mod snapshot_tests {
|
||||
use crate::ui::ui_test_utils::test_utils::TerminalSize;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_delete_album_ui_renders_delete_album() {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
app.data.lidarr_data.selected_block = BlockSelectionState::new(DELETE_ALBUM_SELECTION_BLOCKS);
|
||||
|
||||
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
|
||||
DeleteAlbumUi::draw(f, app, f.area());
|
||||
});
|
||||
|
||||
insta::assert_snapshot!(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ impl DrawUi for DeleteArtistUi {
|
||||
);
|
||||
let checkboxes = vec![
|
||||
Checkbox::new("Delete Artist Files")
|
||||
.checked(app.data.lidarr_data.delete_artist_files)
|
||||
.checked(app.data.lidarr_data.delete_files)
|
||||
.highlighted(selected_block == ActiveLidarrBlock::DeleteArtistToggleDeleteFile),
|
||||
Checkbox::new("Add List Exclusion")
|
||||
.checked(app.data.lidarr_data.add_import_list_exclusion)
|
||||
|
||||
@@ -4,8 +4,8 @@ mod tests {
|
||||
|
||||
use crate::models::lidarr_models::{Artist, ArtistStatistics, ArtistStatus};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ARTIST_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ARTIST_BLOCKS,
|
||||
EDIT_ARTIST_BLOCKS, LIBRARY_BLOCKS,
|
||||
ADD_ARTIST_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
|
||||
DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS, LIBRARY_BLOCKS,
|
||||
};
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::lidarr_ui::library::{LibraryUi, decorate_artist_row_with_style};
|
||||
@@ -18,6 +18,7 @@ mod tests {
|
||||
let mut library_ui_blocks = Vec::new();
|
||||
library_ui_blocks.extend(LIBRARY_BLOCKS);
|
||||
library_ui_blocks.extend(DELETE_ARTIST_BLOCKS);
|
||||
library_ui_blocks.extend(DELETE_ALBUM_BLOCKS);
|
||||
library_ui_blocks.extend(EDIT_ARTIST_BLOCKS);
|
||||
library_ui_blocks.extend(ADD_ARTIST_BLOCKS);
|
||||
library_ui_blocks.extend(ARTIST_DETAILS_BLOCKS);
|
||||
|
||||
@@ -33,6 +33,7 @@ mod artist_details_ui;
|
||||
mod delete_artist_ui;
|
||||
mod edit_artist_ui;
|
||||
|
||||
mod delete_album_ui;
|
||||
#[cfg(test)]
|
||||
#[path = "library_ui_tests.rs"]
|
||||
mod library_ui_tests;
|
||||
@@ -59,8 +60,8 @@ impl DrawUi for LibraryUi {
|
||||
match route {
|
||||
_ if AddArtistUi::accepts(route) => AddArtistUi::draw(f, app, area),
|
||||
_ if DeleteArtistUi::accepts(route) => DeleteArtistUi::draw(f, app, area),
|
||||
_ if EditArtistUi::accepts(route) => EditArtistUi::draw(f, app, area),
|
||||
_ if ArtistDetailsUi::accepts(route) => ArtistDetailsUi::draw(f, app, area),
|
||||
_ if EditArtistUi::accepts(route) => EditArtistUi::draw(f, app, area),
|
||||
Route::Lidarr(ActiveLidarrBlock::UpdateAllArtistsPrompt, _) => {
|
||||
let confirmation_prompt = ConfirmationPrompt::new()
|
||||
.title("Update All Artists")
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
---
|
||||
source: src/ui/lidarr_ui/library/artist_details_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
|
||||
|
||||
|
||||
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│Artist: Alex │
|
||||
│Overview: some interesting description of the artist │
|
||||
│Disambiguation: American pianist │
|
||||
│Type: Person │
|
||||
│Status: Continuing │
|
||||
│Genres: soundtrack │
|
||||
│Rating: 84% │
|
||||
│Path: /nfs/music/test-artist │
|
||||
│Quality Profile: Lossless │
|
||||
│Metadata Profile: Standard │
|
||||
│Monitored: Yes │
|
||||
│Albums: 1 │
|
||||
│Tracks: 15/15 ╭───────────────────── Delete Album ──────────────────────╮ │
|
||||
│Size on Disk: 0.00 GB │ Do you really want to delete the album: │ │
|
||||
│ │ Test Album? │ │
|
||||
│ │ │ │
|
||||
│╭ Artist Details ───────────────────────│ │───────────────────────────────────────────╮│
|
||||
││ Albums │ ╭───╮ │ ││
|
||||
││─────────────────────────────────────────│ Delete Album Files: │ ✔ │ │───────────────────────────────────────────││
|
||||
││ Monitored Title │ ╰───╯ │ Release Date Size ││
|
||||
││=> 🏷 Test Album │ ╭───╮ │ 2023-01-01 0.00 GB ││
|
||||
││ │ Add List Exclusion: │ │ │ ││
|
||||
││ │ ╰───╯ │ ││
|
||||
││ │ │ ││
|
||||
││ │ │ ││
|
||||
││ │ │ ││
|
||||
││ │╭────────────────────────────╮╭───────────────────────────╮│ ││
|
||||
││ ││ Yes ││ No ││ ││
|
||||
││ │╰────────────────────────────╯╰───────────────────────────╯│ ││
|
||||
││ ╰───────────────────────────────────────────────────────────╯ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
││ ││
|
||||
│╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯│
|
||||
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
---
|
||||
source: src/ui/lidarr_ui/library/delete_album_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭───────────────────── Delete Album ──────────────────────╮
|
||||
│ Do you really want to delete the album: │
|
||||
│ Test Album? │
|
||||
│ │
|
||||
│ │
|
||||
│ ╭───╮ │
|
||||
│ Delete Album Files: │ ✔ │ │
|
||||
│ ╰───╯ │
|
||||
│ ╭───╮ │
|
||||
│ Add List Exclusion: │ │ │
|
||||
│ ╰───╯ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│╭────────────────────────────╮╭───────────────────────────╮│
|
||||
││ Yes ││ No ││
|
||||
│╰────────────────────────────╯╰───────────────────────────╯│
|
||||
╰───────────────────────────────────────────────────────────╯
|
||||
Reference in New Issue
Block a user