Lidarr support #1

Merged
Dark-Alex-17 merged 61 commits from lidarr into main 2026-01-21 21:30:47 +00:00
21 changed files with 953 additions and 57 deletions
Showing only changes of commit f31810e48a - Show all commits
+4 -3
View File
@@ -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),
+6 -2
View File
@@ -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;
+22 -5
View File
@@ -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);
}
}
}
+1 -1
View File
@@ -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)
+3 -2
View File
@@ -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);
+2 -1
View File
@@ -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")
@@ -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 ││ ││
││ │╰────────────────────────────╯╰───────────────────────────╯│ ││
││ ╰───────────────────────────────────────────────────────────╯ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
│╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -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 ││
│╰────────────────────────────╯╰───────────────────────────╯│
╰───────────────────────────────────────────────────────────╯