Cleaned up the block selection logic to use the new BlockSelectionState struct

This commit is contained in:
2023-08-08 10:50:06 -06:00
parent 2561e7e9b2
commit 4fb83c114a
23 changed files with 840 additions and 882 deletions
+15 -15
View File
@@ -14,7 +14,7 @@ pub(crate) mod radarr;
const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies, None);
pub struct App {
pub struct App<'a> {
navigation_stack: Vec<Route>,
network_tx: Option<Sender<NetworkEvent>>,
pub server_tabs: TabState,
@@ -31,10 +31,10 @@ pub struct App {
pub should_refresh: bool,
pub should_ignore_quit_key: bool,
pub config: AppConfig,
pub data: Data,
pub data: Data<'a>,
}
impl App {
impl<'a> App<'a> {
pub fn new(network_tx: Sender<NetworkEvent>, config: AppConfig) -> Self {
App {
network_tx: Some(network_tx),
@@ -106,12 +106,12 @@ impl App {
self.push_navigation_stack(route);
}
pub fn get_current_route(&self) -> &Route {
pub fn get_current_route(&'a self) -> &'a Route {
self.navigation_stack.last().unwrap_or(&DEFAULT_ROUTE)
}
}
impl Default for App {
impl<'a> Default for App<'a> {
fn default() -> Self {
App {
navigation_stack: vec![DEFAULT_ROUTE],
@@ -120,15 +120,15 @@ impl Default for App {
response: String::default(),
server_tabs: TabState::new(vec![
TabRoute {
title: "Radarr".to_owned(),
title: "Radarr",
route: ActiveRadarrBlock::Movies.into(),
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <q> quit ".to_owned(),
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <q> quit ",
contextual_help: None,
},
TabRoute {
title: "Sonarr".to_owned(),
title: "Sonarr",
route: Route::Sonarr,
help: "<tab> change servarr | <q> quit ".to_owned(),
help: "<tab> change servarr | <q> quit ",
contextual_help: None,
},
]),
@@ -149,8 +149,8 @@ impl Default for App {
}
#[derive(Default)]
pub struct Data {
pub radarr_data: RadarrData,
pub struct Data<'a> {
pub radarr_data: RadarrData<'a>,
}
#[derive(Debug, Deserialize, Serialize, Default)]
@@ -200,15 +200,15 @@ mod tests {
app.server_tabs.tabs,
vec![
TabRoute {
title: "Radarr".to_owned(),
title: "Radarr",
route: ActiveRadarrBlock::Movies.into(),
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <q> quit ".to_owned(),
help: "<↑↓> scroll | ←→ change tab | <tab> change servarr | <q> quit ",
contextual_help: None,
},
TabRoute {
title: "Sonarr".to_owned(),
title: "Sonarr",
route: Route::Sonarr,
help: "<tab> change servarr | <q> quit ".to_owned(),
help: "<tab> change servarr | <q> quit ",
contextual_help: None,
}
]
+165 -404
View File
@@ -8,11 +8,12 @@ use crate::models::radarr_models::{
MinimumAvailability, Monitor, Movie, MovieHistoryItem, Release, ReleaseField, RootFolder,
};
use crate::models::{
HorizontallyScrollableText, ScrollableText, StatefulList, StatefulTable, TabRoute, TabState,
BlockSelectionState, HorizontallyScrollableText, ScrollableText, StatefulList, StatefulTable,
TabRoute, TabState,
};
use crate::network::radarr_network::RadarrEvent;
pub struct RadarrData {
pub struct RadarrData<'a> {
pub root_folders: StatefulTable<RootFolder>,
pub disk_space_vec: Vec<DiskSpace>,
pub version: String,
@@ -24,7 +25,7 @@ pub struct RadarrData {
pub minimum_availability_list: StatefulList<MinimumAvailability>,
pub quality_profile_list: StatefulList<String>,
pub root_folder_list: StatefulList<RootFolder>,
pub selected_block: ActiveRadarrBlock,
pub selected_block: BlockSelectionState<'a, ActiveRadarrBlock>,
pub downloads: StatefulTable<DownloadRecord>,
pub quality_profile_map: BiMap<u64, String>,
pub tags_map: BiMap<u64, String>,
@@ -57,7 +58,7 @@ pub struct RadarrData {
pub is_filtering: bool,
}
impl RadarrData {
impl<'a> RadarrData<'a> {
pub fn reset_movie_collection_table(&mut self) {
self.collection_movies = StatefulTable::default();
}
@@ -226,8 +227,8 @@ impl RadarrData {
}
}
impl Default for RadarrData {
fn default() -> RadarrData {
impl<'a> Default for RadarrData<'a> {
fn default() -> RadarrData<'a> {
RadarrData {
root_folders: StatefulTable::default(),
disk_space_vec: Vec::new(),
@@ -239,7 +240,7 @@ impl Default for RadarrData {
minimum_availability_list: StatefulList::default(),
quality_profile_list: StatefulList::default(),
root_folder_list: StatefulList::default(),
selected_block: ActiveRadarrBlock::AddMovieSelectRootFolder,
selected_block: BlockSelectionState::default(),
filtered_movies: StatefulTable::default(),
downloads: StatefulTable::default(),
quality_profile_map: BiMap::default(),
@@ -271,75 +272,79 @@ impl Default for RadarrData {
add_list_exclusion: false,
main_tabs: TabState::new(vec![
TabRoute {
title: "Library".to_owned(),
title: "Library",
route: ActiveRadarrBlock::Movies.into(),
help: String::default(),
contextual_help: Some("<a> add | <e> edit | <del> delete | <s> search | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"
.to_owned()),
help: "",
contextual_help: Some("<a> add | <e> edit | <del> delete | <s> search | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"),
},
TabRoute {
title: "Downloads".to_owned(),
title: "Downloads",
route: ActiveRadarrBlock::Downloads.into(),
help: String::default(),
contextual_help: Some("<r> refresh | <del> delete".to_owned()),
help: "",
contextual_help: Some("<r> refresh | <del> delete"),
},
TabRoute {
title: "Collections".to_owned(),
title: "Collections",
route: ActiveRadarrBlock::Collections.into(),
help: String::default(),
contextual_help: Some("<s> search | <e> edit | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"
.to_owned()),
help: "",
contextual_help: Some("<s> search | <e> edit | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"),
},
TabRoute {
title: "Root Folders".to_owned(),
title: "Root Folders",
route: ActiveRadarrBlock::RootFolders.into(),
help: String::default(),
contextual_help: Some("<a> add | <del> delete | <r> refresh".to_owned()),
help: "",
contextual_help: Some("<a> add | <del> delete | <r> refresh"),
},
TabRoute {
title: "System",
route: ActiveRadarrBlock::System.into(),
help: "",
contextual_help: Some("<enter> select menu item | <esc> go back to menu selection")
}
]),
movie_info_tabs: TabState::new(vec![
TabRoute {
title: "Details".to_owned(),
title: "Details",
route: ActiveRadarrBlock::MovieDetails.into(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close".to_owned(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
contextual_help: None
},
TabRoute {
title: "History".to_owned(),
title: "History",
route: ActiveRadarrBlock::MovieHistory.into(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close".to_owned(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
contextual_help: None
},
TabRoute {
title: "File".to_owned(),
title: "File",
route: ActiveRadarrBlock::FileInfo.into(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close".to_owned(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
contextual_help: None,
},
TabRoute {
title: "Cast".to_owned(),
title: "Cast",
route: ActiveRadarrBlock::Cast.into(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close".to_owned(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
contextual_help: None,
},
TabRoute {
title: "Crew".to_owned(),
title: "Crew",
route: ActiveRadarrBlock::Crew.into(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close".to_owned(),
help: "<r> refresh | <u> update | <e> edit | <s> auto search | <esc> close",
contextual_help: None,
},
TabRoute {
title: "Manual Search".to_owned(),
title: "Manual Search",
route: ActiveRadarrBlock::ManualSearch.into(),
help: "<r> refresh | <u> update | <e> edit | <o> sort | <s> auto search | <esc> close".to_owned(),
contextual_help: Some("<enter> details".to_owned())
help: "<r> refresh | <u> update | <e> edit | <o> sort | <s> auto search | <esc> close",
contextual_help: Some("<enter> details")
}
]),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum ActiveRadarrBlock {
AddMovieAlreadyInLibrary,
AddMovieSearchInput,
@@ -387,8 +392,10 @@ pub enum ActiveRadarrBlock {
ManualSearchConfirmPrompt,
MovieDetails,
MovieHistory,
#[default]
Movies,
RootFolders,
System,
UpdateAndScanPrompt,
UpdateAllCollectionsPrompt,
UpdateAllMoviesPrompt,
@@ -410,6 +417,14 @@ pub const ADD_MOVIE_BLOCKS: [ActiveRadarrBlock; 10] = [
ActiveRadarrBlock::AddMovieAlreadyInLibrary,
ActiveRadarrBlock::AddMovieTagsInput,
];
pub const ADD_MOVIE_SELECTION_BLOCKS: [ActiveRadarrBlock; 6] = [
ActiveRadarrBlock::AddMovieSelectRootFolder,
ActiveRadarrBlock::AddMovieSelectMonitor,
ActiveRadarrBlock::AddMovieSelectMinimumAvailability,
ActiveRadarrBlock::AddMovieSelectQualityProfile,
ActiveRadarrBlock::AddMovieTagsInput,
ActiveRadarrBlock::AddMovieConfirmPrompt,
];
pub const EDIT_COLLECTION_BLOCKS: [ActiveRadarrBlock; 7] = [
ActiveRadarrBlock::EditCollectionPrompt,
ActiveRadarrBlock::EditCollectionConfirmPrompt,
@@ -419,6 +434,14 @@ pub const EDIT_COLLECTION_BLOCKS: [ActiveRadarrBlock; 7] = [
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd,
ActiveRadarrBlock::EditCollectionToggleMonitored,
];
pub const EDIT_COLLECTION_SELECTION_BLOCKS: [ActiveRadarrBlock; 6] = [
ActiveRadarrBlock::EditCollectionToggleMonitored,
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd,
ActiveRadarrBlock::EditCollectionConfirmPrompt,
];
pub const EDIT_MOVIE_BLOCKS: [ActiveRadarrBlock; 7] = [
ActiveRadarrBlock::EditMoviePrompt,
ActiveRadarrBlock::EditMovieConfirmPrompt,
@@ -428,6 +451,14 @@ pub const EDIT_MOVIE_BLOCKS: [ActiveRadarrBlock; 7] = [
ActiveRadarrBlock::EditMovieTagsInput,
ActiveRadarrBlock::EditMovieToggleMonitored,
];
pub const EDIT_MOVIE_SELECTION_BLOCKS: [ActiveRadarrBlock; 6] = [
ActiveRadarrBlock::EditMovieToggleMonitored,
ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
ActiveRadarrBlock::EditMovieSelectQualityProfile,
ActiveRadarrBlock::EditMoviePathInput,
ActiveRadarrBlock::EditMovieTagsInput,
ActiveRadarrBlock::EditMovieConfirmPrompt,
];
pub const MOVIE_DETAILS_BLOCKS: [ActiveRadarrBlock; 10] = [
ActiveRadarrBlock::MovieDetails,
ActiveRadarrBlock::MovieHistory,
@@ -458,141 +489,11 @@ pub const DELETE_MOVIE_BLOCKS: [ActiveRadarrBlock; 4] = [
ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
];
impl ActiveRadarrBlock {
pub fn next_add_movie_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::AddMovieSelectRootFolder => ActiveRadarrBlock::AddMovieSelectMonitor,
ActiveRadarrBlock::AddMovieSelectMonitor => {
ActiveRadarrBlock::AddMovieSelectMinimumAvailability
}
ActiveRadarrBlock::AddMovieSelectMinimumAvailability => {
ActiveRadarrBlock::AddMovieSelectQualityProfile
}
ActiveRadarrBlock::AddMovieSelectQualityProfile => ActiveRadarrBlock::AddMovieTagsInput,
ActiveRadarrBlock::AddMovieTagsInput => ActiveRadarrBlock::AddMovieConfirmPrompt,
_ => ActiveRadarrBlock::AddMovieSelectRootFolder,
}
}
pub fn next_edit_movie_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::EditMovieToggleMonitored => {
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
}
ActiveRadarrBlock::EditMovieSelectMinimumAvailability => {
ActiveRadarrBlock::EditMovieSelectQualityProfile
}
ActiveRadarrBlock::EditMovieSelectQualityProfile => ActiveRadarrBlock::EditMoviePathInput,
ActiveRadarrBlock::EditMoviePathInput => ActiveRadarrBlock::EditMovieTagsInput,
ActiveRadarrBlock::EditMovieTagsInput => ActiveRadarrBlock::EditMovieConfirmPrompt,
_ => ActiveRadarrBlock::EditMovieToggleMonitored,
}
}
pub fn next_edit_collection_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::EditCollectionToggleMonitored => {
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
}
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability => {
ActiveRadarrBlock::EditCollectionSelectQualityProfile
}
ActiveRadarrBlock::EditCollectionSelectQualityProfile => {
ActiveRadarrBlock::EditCollectionRootFolderPathInput
}
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd
}
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd => {
ActiveRadarrBlock::EditCollectionConfirmPrompt
}
_ => ActiveRadarrBlock::EditCollectionToggleMonitored,
}
}
pub fn next_delete_movie_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::DeleteMovieToggleDeleteFile => {
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion
}
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion => {
ActiveRadarrBlock::DeleteMovieConfirmPrompt
}
ActiveRadarrBlock::DeleteMovieConfirmPrompt => ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
_ => ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
}
}
pub fn previous_add_movie_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::AddMovieSelectRootFolder => ActiveRadarrBlock::AddMovieConfirmPrompt,
ActiveRadarrBlock::AddMovieSelectMonitor => ActiveRadarrBlock::AddMovieSelectRootFolder,
ActiveRadarrBlock::AddMovieSelectMinimumAvailability => {
ActiveRadarrBlock::AddMovieSelectMonitor
}
ActiveRadarrBlock::AddMovieSelectQualityProfile => {
ActiveRadarrBlock::AddMovieSelectMinimumAvailability
}
ActiveRadarrBlock::AddMovieTagsInput => ActiveRadarrBlock::AddMovieSelectQualityProfile,
ActiveRadarrBlock::AddMovieConfirmPrompt => ActiveRadarrBlock::AddMovieTagsInput,
_ => ActiveRadarrBlock::AddMovieSelectRootFolder,
}
}
pub fn previous_edit_movie_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::EditMovieToggleMonitored => ActiveRadarrBlock::EditMovieConfirmPrompt,
ActiveRadarrBlock::EditMovieSelectMinimumAvailability => {
ActiveRadarrBlock::EditMovieToggleMonitored
}
ActiveRadarrBlock::EditMovieSelectQualityProfile => {
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
}
ActiveRadarrBlock::EditMoviePathInput => ActiveRadarrBlock::EditMovieSelectQualityProfile,
ActiveRadarrBlock::EditMovieTagsInput => ActiveRadarrBlock::EditMoviePathInput,
ActiveRadarrBlock::EditMovieConfirmPrompt => ActiveRadarrBlock::EditMovieTagsInput,
_ => ActiveRadarrBlock::EditMovieToggleMonitored,
}
}
pub fn previous_edit_collection_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::EditCollectionToggleMonitored => {
ActiveRadarrBlock::EditCollectionConfirmPrompt
}
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability => {
ActiveRadarrBlock::EditCollectionToggleMonitored
}
ActiveRadarrBlock::EditCollectionSelectQualityProfile => {
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
}
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
ActiveRadarrBlock::EditCollectionSelectQualityProfile
}
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd => {
ActiveRadarrBlock::EditCollectionRootFolderPathInput
}
ActiveRadarrBlock::EditCollectionConfirmPrompt => {
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd
}
_ => ActiveRadarrBlock::EditCollectionToggleMonitored,
}
}
pub fn previous_delete_movie_prompt_block(&self) -> Self {
match self {
ActiveRadarrBlock::DeleteMovieToggleDeleteFile => ActiveRadarrBlock::DeleteMovieConfirmPrompt,
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion => {
ActiveRadarrBlock::DeleteMovieToggleDeleteFile
}
ActiveRadarrBlock::DeleteMovieConfirmPrompt => {
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion
}
_ => ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
}
}
}
pub const DELETE_MOVIE_SELECTION_BLOCKS: [ActiveRadarrBlock; 3] = [
ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
ActiveRadarrBlock::DeleteMovieConfirmPrompt,
];
impl From<ActiveRadarrBlock> for Route {
fn from(active_radarr_block: ActiveRadarrBlock) -> Route {
@@ -606,7 +507,7 @@ impl From<(ActiveRadarrBlock, Option<ActiveRadarrBlock>)> for Route {
}
}
impl App {
impl<'a> App<'a> {
pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: &ActiveRadarrBlock) {
match active_radarr_block {
ActiveRadarrBlock::Collections => {
@@ -773,7 +674,7 @@ pub mod radarr_test_utils {
};
use crate::models::ScrollableText;
pub fn create_test_radarr_data() -> RadarrData {
pub fn create_test_radarr_data<'a>() -> RadarrData<'a> {
let mut radarr_data = RadarrData {
is_searching: true,
is_filtering: true,
@@ -905,9 +806,9 @@ mod tests {
use crate::models::radarr_models::{
Collection, MinimumAvailability, Monitor, Movie, RootFolder,
};
use crate::models::HorizontallyScrollableText;
use crate::models::Route;
use crate::models::StatefulTable;
use crate::models::{BlockSelectionState, HorizontallyScrollableText};
#[test]
fn test_from_tuple_to_route_with_context() {
@@ -1149,10 +1050,7 @@ mod tests {
assert!(radarr_data.minimum_availability_list.items.is_empty());
assert!(radarr_data.quality_profile_list.items.is_empty());
assert!(radarr_data.root_folder_list.items.is_empty());
assert_eq!(
radarr_data.selected_block,
ActiveRadarrBlock::AddMovieSelectRootFolder
);
assert_eq!(radarr_data.selected_block, BlockSelectionState::default());
assert!(radarr_data.filtered_movies.items.is_empty());
assert!(radarr_data.downloads.items.is_empty());
assert!(radarr_data.quality_profile_map.is_empty());
@@ -1183,7 +1081,7 @@ mod tests {
assert!(!radarr_data.delete_movie_files);
assert!(!radarr_data.add_list_exclusion);
assert_eq!(radarr_data.main_tabs.tabs.len(), 4);
assert_eq!(radarr_data.main_tabs.tabs.len(), 5);
assert_str_eq!(radarr_data.main_tabs.tabs[0].title, "Library");
assert_eq!(
@@ -1192,7 +1090,7 @@ mod tests {
);
assert!(radarr_data.main_tabs.tabs[0].help.is_empty());
assert_eq!(radarr_data.main_tabs.tabs[0].contextual_help,
Some("<a> add | <e> edit | <del> delete | <s> search | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter".to_owned()));
Some("<a> add | <e> edit | <del> delete | <s> search | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"));
assert_str_eq!(radarr_data.main_tabs.tabs[1].title, "Downloads");
assert_eq!(
@@ -1202,7 +1100,7 @@ mod tests {
assert!(radarr_data.main_tabs.tabs[1].help.is_empty());
assert_eq!(
radarr_data.main_tabs.tabs[1].contextual_help,
Some("<r> refresh | <del> delete".to_owned())
Some("<r> refresh | <del> delete")
);
assert_str_eq!(radarr_data.main_tabs.tabs[2].title, "Collections");
@@ -1212,7 +1110,7 @@ mod tests {
);
assert!(radarr_data.main_tabs.tabs[2].help.is_empty());
assert_eq!(radarr_data.main_tabs.tabs[2].contextual_help,
Some("<s> search | <e> edit | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter".to_owned()));
Some("<s> search | <e> edit | <f> filter | <r> refresh | <u> update all | <enter> details | <esc> cancel filter"));
assert_str_eq!(radarr_data.main_tabs.tabs[3].title, "Root Folders");
assert_eq!(
@@ -1222,7 +1120,18 @@ mod tests {
assert!(radarr_data.main_tabs.tabs[3].help.is_empty());
assert_eq!(
radarr_data.main_tabs.tabs[3].contextual_help,
Some("<a> add | <del> delete | <r> refresh".to_owned())
Some("<a> add | <del> delete | <r> refresh")
);
assert_str_eq!(radarr_data.main_tabs.tabs[4].title, "System");
assert_eq!(
radarr_data.main_tabs.tabs[4].route,
ActiveRadarrBlock::System.into()
);
assert!(radarr_data.main_tabs.tabs[4].help.is_empty());
assert_eq!(
radarr_data.main_tabs.tabs[4].contextual_help,
Some("<enter> select menu item | <esc> go back to menu selection")
);
assert_eq!(radarr_data.movie_info_tabs.tabs.len(), 6);
@@ -1303,7 +1212,7 @@ mod tests {
);
assert_eq!(
radarr_data.movie_info_tabs.tabs[5].contextual_help,
Some("<enter> details".to_owned())
Some("<enter> details")
);
}
}
@@ -1311,264 +1220,116 @@ mod tests {
mod active_radarr_block_tests {
use pretty_assertions::assert_eq;
use crate::app::radarr::ActiveRadarrBlock;
use crate::app::radarr::{
ActiveRadarrBlock, ADD_MOVIE_SELECTION_BLOCKS, DELETE_MOVIE_SELECTION_BLOCKS,
EDIT_COLLECTION_SELECTION_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS,
};
#[test]
fn test_next_add_movie_prompt_block() {
let active_block = ActiveRadarrBlock::AddMovieSelectRootFolder.next_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieSelectMonitor);
let active_block = active_block.next_add_movie_prompt_block();
fn test_add_movie_prompt_block_order() {
let mut add_movie_block_iter = ADD_MOVIE_SELECTION_BLOCKS.iter();
assert_eq!(
active_block,
ActiveRadarrBlock::AddMovieSelectMinimumAvailability
add_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::AddMovieSelectRootFolder
);
let active_block = active_block.next_add_movie_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::AddMovieSelectQualityProfile
add_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::AddMovieSelectMonitor
);
let active_block = active_block.next_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieTagsInput);
let active_block = active_block.next_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieConfirmPrompt);
let active_block = active_block.next_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieSelectRootFolder);
}
#[test]
fn test_next_edit_movie_prompt_block() {
let active_block = ActiveRadarrBlock::EditMovieToggleMonitored.next_edit_movie_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
add_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::AddMovieSelectMinimumAvailability
);
let active_block = active_block.next_edit_movie_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditMovieSelectQualityProfile
add_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::AddMovieSelectQualityProfile
);
let active_block = active_block.next_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMoviePathInput);
let active_block = active_block.next_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMovieTagsInput);
let active_block = active_block.next_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMovieConfirmPrompt);
let active_block = active_block.next_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMovieToggleMonitored);
}
#[test]
fn test_next_edit_collection_prompt_block() {
let active_block =
ActiveRadarrBlock::EditCollectionToggleMonitored.next_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
add_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::AddMovieTagsInput
);
let active_block = active_block.next_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionSelectQualityProfile
);
let active_block = active_block.next_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionRootFolderPathInput
);
let active_block = active_block.next_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd
);
let active_block = active_block.next_edit_collection_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditCollectionConfirmPrompt);
let active_block = active_block.next_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionToggleMonitored
add_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::AddMovieConfirmPrompt
);
}
#[test]
fn test_next_delete_movie_prompt_block() {
let active_block =
ActiveRadarrBlock::DeleteMovieToggleDeleteFile.next_delete_movie_prompt_block();
fn test_edit_movie_prompt_block_order() {
let mut edit_movie_block_iter = EDIT_MOVIE_SELECTION_BLOCKS.iter();
assert_eq!(
active_block,
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion
edit_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditMovieToggleMonitored
);
let active_block = active_block.next_delete_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::DeleteMovieConfirmPrompt);
let active_block = active_block.next_delete_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::DeleteMovieToggleDeleteFile);
}
#[test]
fn test_previous_add_movie_prompt_block() {
let active_block =
ActiveRadarrBlock::AddMovieSelectRootFolder.previous_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieConfirmPrompt);
let active_block = active_block.previous_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieTagsInput);
let active_block = active_block.previous_add_movie_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::AddMovieSelectQualityProfile
edit_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditMovieSelectMinimumAvailability
);
let active_block = active_block.previous_add_movie_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::AddMovieSelectMinimumAvailability
edit_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditMovieSelectQualityProfile
);
let active_block = active_block.previous_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieSelectMonitor);
let active_block = active_block.previous_add_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::AddMovieSelectRootFolder);
}
#[test]
fn test_previous_edit_movie_prompt_block() {
let active_block =
ActiveRadarrBlock::EditMovieToggleMonitored.previous_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMovieConfirmPrompt);
let active_block = active_block.previous_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMovieTagsInput);
let active_block = active_block.previous_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMoviePathInput);
let active_block = active_block.previous_edit_movie_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditMovieSelectQualityProfile
edit_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditMoviePathInput
);
let active_block = active_block.previous_edit_movie_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
edit_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditMovieTagsInput
);
let active_block = active_block.previous_edit_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditMovieToggleMonitored);
}
#[test]
fn test_previous_edit_collection_prompt_block() {
let active_block =
ActiveRadarrBlock::EditCollectionToggleMonitored.previous_edit_collection_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::EditCollectionConfirmPrompt);
let active_block = active_block.previous_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd
);
let active_block = active_block.previous_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionRootFolderPathInput
);
let active_block = active_block.previous_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionSelectQualityProfile
);
let active_block = active_block.previous_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
);
let active_block = active_block.previous_edit_collection_prompt_block();
assert_eq!(
active_block,
ActiveRadarrBlock::EditCollectionToggleMonitored
edit_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditMovieConfirmPrompt
);
}
#[test]
fn test_previous_delete_movie_prompt_block() {
let active_block =
ActiveRadarrBlock::DeleteMovieToggleDeleteFile.previous_delete_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::DeleteMovieConfirmPrompt);
let active_block = active_block.previous_delete_movie_prompt_block();
fn test_edit_collection_prompt_block_order() {
let mut edit_collection_block_iter = EDIT_COLLECTION_SELECTION_BLOCKS.iter();
assert_eq!(
active_block,
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion
edit_collection_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditCollectionToggleMonitored
);
assert_eq!(
edit_collection_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
);
assert_eq!(
edit_collection_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditCollectionSelectQualityProfile
);
assert_eq!(
edit_collection_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditCollectionRootFolderPathInput
);
assert_eq!(
edit_collection_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditCollectionToggleSearchOnAdd
);
assert_eq!(
edit_collection_block_iter.next().unwrap(),
&ActiveRadarrBlock::EditCollectionConfirmPrompt
);
}
let active_block = active_block.previous_delete_movie_prompt_block();
assert_eq!(active_block, ActiveRadarrBlock::DeleteMovieToggleDeleteFile);
#[test]
fn test_delete_movie_prompt_block_order() {
let mut delete_movie_block_iter = DELETE_MOVIE_SELECTION_BLOCKS.iter();
assert_eq!(
delete_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::DeleteMovieToggleDeleteFile
);
assert_eq!(
delete_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::DeleteMovieToggleAddListExclusion
);
assert_eq!(
delete_movie_block_iter.next().unwrap(),
&ActiveRadarrBlock::DeleteMovieConfirmPrompt
);
}
}
@@ -2120,7 +1881,7 @@ mod tests {
assert!(!app.data.radarr_data.collection_movies.items.is_empty());
}
fn construct_app_unit() -> (App, mpsc::Receiver<NetworkEvent>) {
fn construct_app_unit<'a>() -> (App<'a>, mpsc::Receiver<NetworkEvent>) {
let (sync_network_tx, sync_network_rx) = mpsc::channel::<NetworkEvent>(500);
let mut app = App {
network_tx: Some(sync_network_tx),
+5 -5
View File
@@ -7,7 +7,7 @@ use crate::models::{HorizontallyScrollableText, Route};
mod radarr_handlers;
pub trait KeyEventHandler<'a, T: Into<Route>> {
pub trait KeyEventHandler<'a, 'b, T: Into<Route>> {
fn handle_key_event(&mut self) {
let key = self.get_key();
match key {
@@ -29,7 +29,7 @@ pub trait KeyEventHandler<'a, T: Into<Route>> {
self.handle_key_event();
}
fn with(key: &'a Key, app: &'a mut App, active_block: &'a T, context: &'a Option<T>) -> Self;
fn with(key: &'a Key, app: &'a mut App<'b>, active_block: &'a T, context: &'a Option<T>) -> Self;
fn get_key(&self) -> &Key;
fn handle_scroll_up(&mut self);
fn handle_scroll_down(&mut self);
@@ -42,19 +42,19 @@ pub trait KeyEventHandler<'a, T: Into<Route>> {
fn handle_char_key_event(&mut self);
}
pub fn handle_events(key: Key, app: &mut App) {
pub fn handle_events(key: Key, app: &mut App<'_>) {
if let Route::Radarr(active_radarr_block, context) = *app.get_current_route() {
RadarrHandler::with(&key, app, &active_radarr_block, &context).handle()
}
}
fn handle_clear_errors(app: &mut App) {
fn handle_clear_errors(app: &mut App<'_>) {
if !app.error.text.is_empty() {
app.error = HorizontallyScrollableText::default();
}
}
fn handle_prompt_toggle(app: &mut App, key: &Key) {
fn handle_prompt_toggle(app: &mut App<'_>, key: &Key) {
match key {
_ if *key == DEFAULT_KEYBINDINGS.left.key || *key == DEFAULT_KEYBINDINGS.right.key => {
if let Route::Radarr(_, _) = *app.get_current_route() {
@@ -1,24 +1,24 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::radarr::ActiveRadarrBlock;
use crate::app::radarr::{ActiveRadarrBlock, ADD_MOVIE_SELECTION_BLOCKS};
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::{Scrollable, StatefulTable};
use crate::models::{BlockSelectionState, Scrollable, StatefulTable};
use crate::network::radarr_network::RadarrEvent;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys, App, Key};
pub(super) struct AddMovieHandler<'a> {
pub(super) struct AddMovieHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
}
impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for AddMovieHandler<'a> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a, 'b> {
fn with(
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
) -> AddMovieHandler<'a> {
) -> AddMovieHandler<'a, 'b> {
AddMovieHandler {
key,
app,
@@ -51,14 +51,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for AddMovieHandler<'a> {
ActiveRadarrBlock::AddMovieSelectRootFolder => {
self.app.data.radarr_data.root_folder_list.scroll_up()
}
ActiveRadarrBlock::AddMoviePrompt => {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.previous_add_movie_prompt_block()
}
ActiveRadarrBlock::AddMoviePrompt => self.app.data.radarr_data.selected_block.previous(),
_ => (),
}
}
@@ -83,14 +76,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for AddMovieHandler<'a> {
ActiveRadarrBlock::AddMovieSelectRootFolder => {
self.app.data.radarr_data.root_folder_list.scroll_down()
}
ActiveRadarrBlock::AddMoviePrompt => {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.next_add_movie_prompt_block()
}
ActiveRadarrBlock::AddMoviePrompt => self.app.data.radarr_data.selected_block.next(),
_ => (),
}
}
@@ -220,31 +206,42 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for AddMovieHandler<'a> {
.app
.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
self.app.data.radarr_data.populate_preferences_lists();
self.app.data.radarr_data.selected_block = ActiveRadarrBlock::AddMovieSelectRootFolder;
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
}
}
ActiveRadarrBlock::AddMoviePrompt => match self.app.data.radarr_data.selected_block {
ActiveRadarrBlock::AddMovieConfirmPrompt => {
if self.app.data.radarr_data.prompt_confirm {
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::AddMovie);
}
ActiveRadarrBlock::AddMoviePrompt => {
match self.app.data.radarr_data.selected_block.get_active_block() {
ActiveRadarrBlock::AddMovieConfirmPrompt => {
if self.app.data.radarr_data.prompt_confirm {
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::AddMovie);
}
self.app.pop_navigation_stack();
self.app.pop_navigation_stack();
}
ActiveRadarrBlock::AddMovieSelectMonitor
| ActiveRadarrBlock::AddMovieSelectMinimumAvailability
| ActiveRadarrBlock::AddMovieSelectQualityProfile
| ActiveRadarrBlock::AddMovieSelectRootFolder => self.app.push_navigation_stack(
(
*self.app.data.radarr_data.selected_block.get_active_block(),
*self.context,
)
.into(),
),
ActiveRadarrBlock::AddMovieTagsInput => {
self.app.push_navigation_stack(
(
*self.app.data.radarr_data.selected_block.get_active_block(),
*self.context,
)
.into(),
);
self.app.should_ignore_quit_key = true;
}
_ => (),
}
ActiveRadarrBlock::AddMovieSelectMonitor
| ActiveRadarrBlock::AddMovieSelectMinimumAvailability
| ActiveRadarrBlock::AddMovieSelectQualityProfile
| ActiveRadarrBlock::AddMovieSelectRootFolder => self
.app
.push_navigation_stack((self.app.data.radarr_data.selected_block, *self.context).into()),
ActiveRadarrBlock::AddMovieTagsInput => {
self.app.push_navigation_stack(
(self.app.data.radarr_data.selected_block, *self.context).into(),
);
self.app.should_ignore_quit_key = true;
}
_ => (),
},
}
ActiveRadarrBlock::AddMovieSelectMonitor
| ActiveRadarrBlock::AddMovieSelectMinimumAvailability
| ActiveRadarrBlock::AddMovieSelectQualityProfile
@@ -321,6 +318,8 @@ mod tests {
use rstest::rstest;
use strum::IntoEnumIterator;
use crate::app::radarr::ADD_MOVIE_SELECTION_BLOCKS;
use crate::models::BlockSelectionState;
use crate::{simple_stateful_iterable_vec, test_enum_scroll, test_iterable_scroll};
use super::*;
@@ -375,19 +374,20 @@ mod tests {
#[rstest]
fn test_add_movie_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
let mut app = App::default();
app.data.radarr_data.selected_block = ActiveRadarrBlock::AddMovieSelectMinimumAvailability;
app.data.radarr_data.selected_block = BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
app.data.radarr_data.selected_block.next();
AddMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::AddMoviePrompt, &None).handle();
if key == Key::Up {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::AddMovieSelectMonitor
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::AddMovieSelectRootFolder
);
} else {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::AddMovieSelectQualityProfile
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::AddMovieSelectMinimumAvailability
);
}
}
@@ -513,7 +513,9 @@ mod tests {
use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
use crate::app::radarr::ADD_MOVIE_SELECTION_BLOCKS;
use crate::models::radarr_models::Movie;
use crate::models::BlockSelectionState;
use crate::network::radarr_network::RadarrEvent;
use super::*;
@@ -564,8 +566,8 @@ mod tests {
&ActiveRadarrBlock::AddMoviePrompt.into()
);
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::AddMovieSelectRootFolder
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::AddMovieSelectRootFolder
);
assert!(!app.data.radarr_data.monitor_list.items.is_empty());
assert!(!app
@@ -636,7 +638,12 @@ mod tests {
let mut app = App::default();
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
app.data.radarr_data.selected_block = ActiveRadarrBlock::AddMovieConfirmPrompt;
app.data.radarr_data.selected_block = BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
AddMovieHandler::with(
&SUBMIT_KEY,
@@ -656,7 +663,12 @@ mod tests {
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
app.data.radarr_data.prompt_confirm = true;
app.data.radarr_data.selected_block = ActiveRadarrBlock::AddMovieConfirmPrompt;
app.data.radarr_data.selected_block = BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
AddMovieHandler::with(
&SUBMIT_KEY,
@@ -674,15 +686,14 @@ mod tests {
}
#[rstest]
#[case(ActiveRadarrBlock::AddMovieSelectRootFolder, 0)]
#[case(ActiveRadarrBlock::AddMovieSelectMonitor, 1)]
#[case(ActiveRadarrBlock::AddMovieSelectMinimumAvailability, 2)]
#[case(ActiveRadarrBlock::AddMovieSelectQualityProfile, 3)]
#[case(ActiveRadarrBlock::AddMovieTagsInput, 4)]
fn test_add_movie_prompt_selected_block_submit(
#[values(
ActiveRadarrBlock::AddMovieSelectMonitor,
ActiveRadarrBlock::AddMovieSelectMinimumAvailability,
ActiveRadarrBlock::AddMovieSelectQualityProfile,
ActiveRadarrBlock::AddMovieSelectRootFolder,
ActiveRadarrBlock::AddMovieTagsInput
)]
selected_block: ActiveRadarrBlock,
#[case] selected_block: ActiveRadarrBlock,
#[case] index: usize,
) {
let mut app = App::default();
app.push_navigation_stack(
@@ -692,7 +703,8 @@ mod tests {
)
.into(),
);
app.data.radarr_data.selected_block = selected_block;
app.data.radarr_data.selected_block = BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
app.data.radarr_data.selected_block.set_index(index);
AddMovieHandler::with(
&SUBMIT_KEY,
@@ -1,24 +1,26 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::radarr::ActiveRadarrBlock;
use crate::app::radarr::{
ActiveRadarrBlock, ADD_MOVIE_SELECTION_BLOCKS, EDIT_COLLECTION_SELECTION_BLOCKS,
};
use crate::app::App;
use crate::event::Key;
use crate::handlers::KeyEventHandler;
use crate::models::Scrollable;
use crate::models::{BlockSelectionState, Scrollable};
pub(super) struct CollectionDetailsHandler<'a> {
pub(super) struct CollectionDetailsHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
}
impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for CollectionDetailsHandler<'a> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHandler<'a, 'b> {
fn with(
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
) -> CollectionDetailsHandler<'a> {
) -> CollectionDetailsHandler<'a, 'b> {
CollectionDetailsHandler {
key,
app,
@@ -95,7 +97,8 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for CollectionDetailsHandler<'a>
)
.into(),
);
self.app.data.radarr_data.selected_block = ActiveRadarrBlock::AddMovieSelectRootFolder;
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
self.app.data.radarr_data.populate_preferences_lists();
}
}
@@ -124,7 +127,8 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for CollectionDetailsHandler<'a>
.into(),
);
self.app.data.radarr_data.populate_edit_collection_fields();
self.app.data.radarr_data.selected_block = ActiveRadarrBlock::EditCollectionToggleMonitored;
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
}
}
}
@@ -182,7 +186,9 @@ mod tests {
use bimap::BiMap;
use pretty_assertions::assert_eq;
use crate::app::radarr::ADD_MOVIE_SELECTION_BLOCKS;
use crate::models::radarr_models::Movie;
use crate::models::BlockSelectionState;
use super::*;
@@ -198,7 +204,12 @@ mod tests {
.set_items(vec![CollectionMovie::default()]);
app.data.radarr_data.quality_profile_map =
BiMap::from_iter([(1, "B - Test 2".to_owned()), (0, "A - Test 1".to_owned())]);
app.data.radarr_data.selected_block = ActiveRadarrBlock::AddMovieConfirmPrompt;
app.data.radarr_data.selected_block = BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
CollectionDetailsHandler::with(
&SUBMIT_KEY,
@@ -218,8 +229,8 @@ mod tests {
);
assert!(!app.data.radarr_data.monitor_list.items.is_empty());
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::AddMovieSelectRootFolder
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::AddMovieSelectRootFolder
);
assert!(!app
.data
@@ -329,7 +340,9 @@ mod tests {
use crate::app::radarr::radarr_test_utils::create_test_radarr_data;
use crate::app::radarr::RadarrData;
use crate::app::radarr::EDIT_COLLECTION_SELECTION_BLOCKS;
use crate::models::radarr_models::{Collection, MinimumAvailability};
use crate::models::BlockSelectionState;
use crate::models::HorizontallyScrollableText;
use crate::models::StatefulTable;
use crate::test_edit_collection_key;
@@ -4,17 +4,17 @@ use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::network::radarr_network::RadarrEvent;
pub(super) struct DeleteMovieHandler<'a> {
pub(super) struct DeleteMovieHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
}
impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for DeleteMovieHandler<'a> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'a, 'b> {
fn with(
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
) -> Self {
@@ -32,23 +32,13 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for DeleteMovieHandler<'a> {
fn handle_scroll_up(&mut self) {
if *self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.previous_delete_movie_prompt_block();
self.app.data.radarr_data.selected_block.previous();
}
}
fn handle_scroll_down(&mut self) {
if *self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.next_delete_movie_prompt_block();
self.app.data.radarr_data.selected_block.next();
}
}
@@ -66,7 +56,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for DeleteMovieHandler<'a> {
fn handle_submit(&mut self) {
if self.active_radarr_block == &ActiveRadarrBlock::DeleteMoviePrompt {
match self.app.data.radarr_data.selected_block {
match self.app.data.radarr_data.selected_block.get_active_block() {
ActiveRadarrBlock::DeleteMovieConfirmPrompt => {
if self.app.data.radarr_data.prompt_confirm {
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteMovie);
@@ -114,25 +104,30 @@ mod tests {
use pretty_assertions::assert_eq;
use rstest::rstest;
use crate::app::radarr::DELETE_MOVIE_SELECTION_BLOCKS;
use crate::models::BlockSelectionState;
use super::*;
#[rstest]
fn test_delete_movie_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
let mut app = App::default();
app.data.radarr_data.selected_block = ActiveRadarrBlock::DeleteMovieToggleAddListExclusion;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
app.data.radarr_data.selected_block.next();
DeleteMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::DeleteMoviePrompt, &None)
.handle();
if key == Key::Up {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::DeleteMovieToggleDeleteFile
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::DeleteMovieToggleDeleteFile
);
} else {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::DeleteMovieConfirmPrompt
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::DeleteMovieConfirmPrompt
);
}
}
@@ -162,6 +157,8 @@ mod tests {
mod test_handle_submit {
use pretty_assertions::assert_eq;
use crate::app::radarr::DELETE_MOVIE_SELECTION_BLOCKS;
use crate::models::BlockSelectionState;
use crate::network::radarr_network::RadarrEvent;
use super::*;
@@ -173,7 +170,13 @@ mod tests {
let mut app = App::default();
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
app.data.radarr_data.selected_block = ActiveRadarrBlock::DeleteMovieConfirmPrompt;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
app.data.radarr_data.delete_movie_files = true;
app.data.radarr_data.add_list_exclusion = true;
@@ -200,7 +203,13 @@ mod tests {
app.data.radarr_data.prompt_confirm = true;
app.data.radarr_data.delete_movie_files = true;
app.data.radarr_data.add_list_exclusion = true;
app.data.radarr_data.selected_block = ActiveRadarrBlock::DeleteMovieConfirmPrompt;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
DeleteMovieHandler::with(
&SUBMIT_KEY,
@@ -225,7 +234,8 @@ mod tests {
fn test_delete_movie_toggle_delete_files_submit() {
let current_route = ActiveRadarrBlock::DeleteMoviePrompt.into();
let mut app = App::default();
app.data.radarr_data.selected_block = ActiveRadarrBlock::DeleteMovieToggleDeleteFile;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
DeleteMovieHandler::with(
@@ -7,20 +7,20 @@ use crate::models::Scrollable;
use crate::network::radarr_network::RadarrEvent;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
pub(super) struct EditCollectionHandler<'a> {
pub(super) struct EditCollectionHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
}
impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditCollectionHandler<'a> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandler<'a, 'b> {
fn with(
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
) -> EditCollectionHandler<'a> {
) -> EditCollectionHandler<'a, 'b> {
EditCollectionHandler {
key,
app,
@@ -45,12 +45,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditCollectionHandler<'a> {
self.app.data.radarr_data.quality_profile_list.scroll_up()
}
ActiveRadarrBlock::EditCollectionPrompt => {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.previous_edit_collection_prompt_block()
self.app.data.radarr_data.selected_block.previous()
}
_ => (),
}
@@ -67,14 +62,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditCollectionHandler<'a> {
ActiveRadarrBlock::EditCollectionSelectQualityProfile => {
self.app.data.radarr_data.quality_profile_list.scroll_down()
}
ActiveRadarrBlock::EditCollectionPrompt => {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.next_edit_collection_prompt_block()
}
ActiveRadarrBlock::EditCollectionPrompt => self.app.data.radarr_data.selected_block.next(),
_ => (),
}
}
@@ -135,41 +123,53 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditCollectionHandler<'a> {
fn handle_submit(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditCollectionPrompt => match self.app.data.radarr_data.selected_block {
ActiveRadarrBlock::EditCollectionConfirmPrompt => {
if self.app.data.radarr_data.prompt_confirm {
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection);
self.app.should_refresh = true;
}
ActiveRadarrBlock::EditCollectionPrompt => {
match self.app.data.radarr_data.selected_block.get_active_block() {
ActiveRadarrBlock::EditCollectionConfirmPrompt => {
if self.app.data.radarr_data.prompt_confirm {
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection);
self.app.should_refresh = true;
}
self.app.pop_navigation_stack();
self.app.pop_navigation_stack();
}
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => {
self.app.push_navigation_stack(
(
*self.app.data.radarr_data.selected_block.get_active_block(),
*self.context,
)
.into(),
)
}
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
self.app.push_navigation_stack(
(
*self.app.data.radarr_data.selected_block.get_active_block(),
*self.context,
)
.into(),
);
self.app.should_ignore_quit_key = true;
}
ActiveRadarrBlock::EditCollectionToggleMonitored => {
self.app.data.radarr_data.edit_monitored =
Some(!self.app.data.radarr_data.edit_monitored.unwrap_or_default())
}
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd => {
self.app.data.radarr_data.edit_search_on_add = Some(
!self
.app
.data
.radarr_data
.edit_search_on_add
.unwrap_or_default(),
)
}
_ => (),
}
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => self
.app
.push_navigation_stack((self.app.data.radarr_data.selected_block, *self.context).into()),
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
self.app.push_navigation_stack(
(self.app.data.radarr_data.selected_block, *self.context).into(),
);
self.app.should_ignore_quit_key = true;
}
ActiveRadarrBlock::EditCollectionToggleMonitored => {
self.app.data.radarr_data.edit_monitored =
Some(!self.app.data.radarr_data.edit_monitored.unwrap_or_default())
}
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd => {
self.app.data.radarr_data.edit_search_on_add = Some(
!self
.app
.data
.radarr_data
.edit_search_on_add
.unwrap_or_default(),
)
}
_ => (),
},
}
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => self.app.pop_navigation_stack(),
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
@@ -222,6 +222,8 @@ mod tests {
use rstest::rstest;
use strum::IntoEnumIterator;
use crate::app::radarr::EDIT_COLLECTION_SELECTION_BLOCKS;
use crate::models::BlockSelectionState;
use crate::{test_enum_scroll, test_iterable_scroll};
use super::*;
@@ -247,7 +249,8 @@ mod tests {
fn test_edit_collection_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
let mut app = App::default();
app.data.radarr_data.selected_block =
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability;
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app.data.radarr_data.selected_block.next();
EditCollectionHandler::with(
&key,
@@ -259,13 +262,13 @@ mod tests {
if key == Key::Up {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::EditCollectionToggleMonitored
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::EditCollectionToggleMonitored
);
} else {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::EditCollectionSelectQualityProfile
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::EditCollectionSelectQualityProfile
);
}
}
@@ -351,7 +354,8 @@ mod tests {
use pretty_assertions::assert_eq;
use rstest::rstest;
use crate::models::Route;
use crate::app::radarr::EDIT_COLLECTION_SELECTION_BLOCKS;
use crate::models::{BlockSelectionState, Route};
use crate::network::radarr_network::RadarrEvent;
use super::*;
@@ -387,7 +391,13 @@ mod tests {
let mut app = App::default();
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditCollectionConfirmPrompt;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
EditCollectionHandler::with(
&SUBMIT_KEY,
@@ -410,7 +420,13 @@ mod tests {
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
app.data.radarr_data.prompt_confirm = true;
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditCollectionConfirmPrompt;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
EditCollectionHandler::with(
&SUBMIT_KEY,
@@ -438,7 +454,8 @@ mod tests {
Some(ActiveRadarrBlock::Collections),
));
let mut app = App::default();
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditCollectionToggleMonitored;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app.push_navigation_stack(current_route);
EditCollectionHandler::with(
@@ -471,7 +488,13 @@ mod tests {
Some(ActiveRadarrBlock::Collections),
));
let mut app = App::default();
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditCollectionToggleSearchOnAdd;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 2);
app.push_navigation_stack(current_route);
EditCollectionHandler::with(
@@ -498,13 +521,12 @@ mod tests {
}
#[rstest]
#[case(ActiveRadarrBlock::EditCollectionSelectMinimumAvailability, 1)]
#[case(ActiveRadarrBlock::EditCollectionSelectQualityProfile, 2)]
#[case(ActiveRadarrBlock::EditCollectionRootFolderPathInput, 3)]
fn test_edit_collection_prompt_selected_block_submit(
#[values(
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
ActiveRadarrBlock::EditCollectionRootFolderPathInput
)]
selected_block: ActiveRadarrBlock,
#[case] selected_block: ActiveRadarrBlock,
#[case] index: usize,
) {
let mut app = App::default();
app.push_navigation_stack(
@@ -514,7 +536,9 @@ mod tests {
)
.into(),
);
app.data.radarr_data.selected_block = selected_block;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app.data.radarr_data.selected_block.set_index(index);
EditCollectionHandler::with(
&SUBMIT_KEY,
@@ -7,20 +7,20 @@ use crate::models::Scrollable;
use crate::network::radarr_network::RadarrEvent;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
pub(super) struct EditMovieHandler<'a> {
pub(super) struct EditMovieHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
}
impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditMovieHandler<'a> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a, 'b> {
fn with(
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
) -> EditMovieHandler<'a> {
) -> EditMovieHandler<'a, 'b> {
EditMovieHandler {
key,
app,
@@ -44,14 +44,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditMovieHandler<'a> {
ActiveRadarrBlock::EditMovieSelectQualityProfile => {
self.app.data.radarr_data.quality_profile_list.scroll_up()
}
ActiveRadarrBlock::EditMoviePrompt => {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.previous_edit_movie_prompt_block()
}
ActiveRadarrBlock::EditMoviePrompt => self.app.data.radarr_data.selected_block.previous(),
_ => (),
}
}
@@ -67,14 +60,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditMovieHandler<'a> {
ActiveRadarrBlock::EditMovieSelectQualityProfile => {
self.app.data.radarr_data.quality_profile_list.scroll_down()
}
ActiveRadarrBlock::EditMoviePrompt => {
self.app.data.radarr_data.selected_block = self
.app
.data
.radarr_data
.selected_block
.next_edit_movie_prompt_block()
}
ActiveRadarrBlock::EditMoviePrompt => self.app.data.radarr_data.selected_block.next(),
_ => (),
}
}
@@ -136,31 +122,41 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for EditMovieHandler<'a> {
fn handle_submit(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditMoviePrompt => match self.app.data.radarr_data.selected_block {
ActiveRadarrBlock::EditMovieConfirmPrompt => {
if self.app.data.radarr_data.prompt_confirm {
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditMovie);
self.app.should_refresh = true;
}
ActiveRadarrBlock::EditMoviePrompt => {
match self.app.data.radarr_data.selected_block.get_active_block() {
ActiveRadarrBlock::EditMovieConfirmPrompt => {
if self.app.data.radarr_data.prompt_confirm {
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditMovie);
self.app.should_refresh = true;
}
self.app.pop_navigation_stack();
self.app.pop_navigation_stack();
}
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
| ActiveRadarrBlock::EditMovieSelectQualityProfile => self.app.push_navigation_stack(
(
*self.app.data.radarr_data.selected_block.get_active_block(),
*self.context,
)
.into(),
),
ActiveRadarrBlock::EditMoviePathInput | ActiveRadarrBlock::EditMovieTagsInput => {
self.app.push_navigation_stack(
(
*self.app.data.radarr_data.selected_block.get_active_block(),
*self.context,
)
.into(),
);
self.app.should_ignore_quit_key = true;
}
ActiveRadarrBlock::EditMovieToggleMonitored => {
self.app.data.radarr_data.edit_monitored =
Some(!self.app.data.radarr_data.edit_monitored.unwrap_or_default())
}
_ => (),
}
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
| ActiveRadarrBlock::EditMovieSelectQualityProfile => self
.app
.push_navigation_stack((self.app.data.radarr_data.selected_block, *self.context).into()),
ActiveRadarrBlock::EditMoviePathInput | ActiveRadarrBlock::EditMovieTagsInput => {
self.app.push_navigation_stack(
(self.app.data.radarr_data.selected_block, *self.context).into(),
);
self.app.should_ignore_quit_key = true;
}
ActiveRadarrBlock::EditMovieToggleMonitored => {
self.app.data.radarr_data.edit_monitored =
Some(!self.app.data.radarr_data.edit_monitored.unwrap_or_default())
}
_ => (),
},
}
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
| ActiveRadarrBlock::EditMovieSelectQualityProfile => self.app.pop_navigation_stack(),
ActiveRadarrBlock::EditMoviePathInput | ActiveRadarrBlock::EditMovieTagsInput => {
@@ -219,6 +215,8 @@ mod tests {
use rstest::rstest;
use strum::IntoEnumIterator;
use crate::app::radarr::EDIT_MOVIE_SELECTION_BLOCKS;
use crate::models::BlockSelectionState;
use crate::{test_enum_scroll, test_iterable_scroll};
use super::*;
@@ -243,19 +241,20 @@ mod tests {
#[rstest]
fn test_edit_movie_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
let mut app = App::default();
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditMovieSelectMinimumAvailability;
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
app.data.radarr_data.selected_block.next();
EditMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::EditMoviePrompt, &None).handle();
if key == Key::Up {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::EditMovieToggleMonitored
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::EditMovieToggleMonitored
);
} else {
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::EditMovieSelectQualityProfile
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::EditMovieSelectQualityProfile
);
}
}
@@ -347,7 +346,8 @@ mod tests {
use pretty_assertions::assert_eq;
use rstest::rstest;
use crate::models::Route;
use crate::app::radarr::{EDIT_COLLECTION_SELECTION_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS};
use crate::models::{BlockSelectionState, Route};
use crate::network::radarr_network::RadarrEvent;
use super::*;
@@ -407,7 +407,12 @@ mod tests {
let mut app = App::default();
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditMovieConfirmPrompt;
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
EditMovieHandler::with(
&SUBMIT_KEY,
@@ -427,7 +432,12 @@ mod tests {
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
app.data.radarr_data.prompt_confirm = true;
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditMovieConfirmPrompt;
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
EditMovieHandler::with(
&SUBMIT_KEY,
@@ -452,7 +462,7 @@ mod tests {
Some(ActiveRadarrBlock::Movies),
));
let mut app = App::default();
app.data.radarr_data.selected_block = ActiveRadarrBlock::EditMovieToggleMonitored;
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
app.push_navigation_stack(current_route);
EditMovieHandler::with(
@@ -479,14 +489,13 @@ mod tests {
}
#[rstest]
#[case(ActiveRadarrBlock::EditMovieSelectMinimumAvailability, 1)]
#[case(ActiveRadarrBlock::EditMovieSelectQualityProfile, 2)]
#[case(ActiveRadarrBlock::EditMoviePathInput, 3)]
#[case(ActiveRadarrBlock::EditMovieTagsInput, 4)]
fn test_edit_movie_prompt_selected_block_submit(
#[values(
ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
ActiveRadarrBlock::EditMovieSelectQualityProfile,
ActiveRadarrBlock::EditMoviePathInput,
ActiveRadarrBlock::EditMovieTagsInput
)]
selected_block: ActiveRadarrBlock,
#[case] selected_block: ActiveRadarrBlock,
#[case] index: usize,
) {
let mut app = App::default();
app.push_navigation_stack(
@@ -496,7 +505,8 @@ mod tests {
)
.into(),
);
app.data.radarr_data.selected_block = selected_block;
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
app.data.radarr_data.selected_block.set_index(index);
EditMovieHandler::with(
&SUBMIT_KEY,
+34 -22
View File
@@ -1,7 +1,9 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::radarr::{
ActiveRadarrBlock, ADD_MOVIE_BLOCKS, COLLECTION_DETAILS_BLOCKS, DELETE_MOVIE_BLOCKS,
EDIT_COLLECTION_BLOCKS, EDIT_MOVIE_BLOCKS, FILTER_BLOCKS, MOVIE_DETAILS_BLOCKS, SEARCH_BLOCKS,
DELETE_MOVIE_SELECTION_BLOCKS, EDIT_COLLECTION_BLOCKS, EDIT_COLLECTION_SELECTION_BLOCKS,
EDIT_MOVIE_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS, FILTER_BLOCKS, MOVIE_DETAILS_BLOCKS,
SEARCH_BLOCKS,
};
use crate::handlers::radarr_handlers::add_movie_handler::AddMovieHandler;
use crate::handlers::radarr_handlers::collection_details_handler::CollectionDetailsHandler;
@@ -10,7 +12,7 @@ use crate::handlers::radarr_handlers::edit_collection_handler::EditCollectionHan
use crate::handlers::radarr_handlers::edit_movie_handler::EditMovieHandler;
use crate::handlers::radarr_handlers::movie_details_handler::MovieDetailsHandler;
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
use crate::models::{HorizontallyScrollableText, Scrollable};
use crate::models::{BlockSelectionState, HorizontallyScrollableText, Scrollable};
use crate::network::radarr_network::RadarrEvent;
use crate::utils::strip_non_search_characters;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys, App, Key};
@@ -22,14 +24,14 @@ mod edit_collection_handler;
mod edit_movie_handler;
mod movie_details_handler;
pub(super) struct RadarrHandler<'a> {
pub(super) struct RadarrHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
}
impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b> {
fn handle(&mut self) {
match self.active_radarr_block {
_ if MOVIE_DETAILS_BLOCKS.contains(self.active_radarr_block) => {
@@ -60,10 +62,10 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> {
fn with(
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
context: &'a Option<ActiveRadarrBlock>,
) -> RadarrHandler<'a> {
) -> RadarrHandler<'a, 'b> {
RadarrHandler {
key,
app,
@@ -222,7 +224,8 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> {
self
.app
.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
self.app.data.radarr_data.selected_block = ActiveRadarrBlock::DeleteMovieToggleDeleteFile;
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
}
ActiveRadarrBlock::Downloads => self
.app
@@ -239,7 +242,8 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> {
ActiveRadarrBlock::Movies
| ActiveRadarrBlock::Downloads
| ActiveRadarrBlock::Collections
| ActiveRadarrBlock::RootFolders => match self.key {
| ActiveRadarrBlock::RootFolders
| ActiveRadarrBlock::System => match self.key {
_ if *self.key == DEFAULT_KEYBINDINGS.left.key => {
self.app.data.radarr_data.main_tabs.previous();
self
@@ -473,7 +477,8 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> {
.into(),
);
self.app.data.radarr_data.populate_edit_movie_fields();
self.app.data.radarr_data.selected_block = ActiveRadarrBlock::EditMovieToggleMonitored;
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
}
_ if *key == DEFAULT_KEYBINDINGS.add.key => {
self
@@ -527,7 +532,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> {
);
self.app.data.radarr_data.populate_edit_collection_fields();
self.app.data.radarr_data.selected_block =
ActiveRadarrBlock::EditCollectionToggleMonitored;
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
}
_ if *key == DEFAULT_KEYBINDINGS.update.key => {
self
@@ -565,7 +570,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> {
}
}
impl RadarrHandler<'_> {
impl<'a, 'b> RadarrHandler<'a, 'b> {
fn search_table<T, F>(&mut self, rows: &[T], field_selection_fn: F) -> Option<usize>
where
F: Fn(&T) -> &str,
@@ -636,6 +641,7 @@ mod radarr_handler_test_utils {
tags: vec![Number::from(1)],
..Movie::default()
}]);
radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
app.data.radarr_data = radarr_data;
$handler::with(&DEFAULT_KEYBINDINGS.edit.key, &mut app, &$block, &None).handle();
@@ -645,8 +651,8 @@ mod radarr_handler_test_utils {
&(ActiveRadarrBlock::EditMoviePrompt, Some($context)).into()
);
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::EditMovieToggleMonitored
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::EditMovieToggleMonitored
);
assert_eq!(
app.data.radarr_data.minimum_availability_list.items,
@@ -702,6 +708,7 @@ mod radarr_handler_test_utils {
minimum_availability: MinimumAvailability::Released,
..Collection::default()
}]);
radarr_data.selected_block = BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app.data.radarr_data = radarr_data;
$handler::with(&DEFAULT_KEYBINDINGS.edit.key, &mut app, &$block, &None).handle();
@@ -711,8 +718,8 @@ mod radarr_handler_test_utils {
&(ActiveRadarrBlock::EditCollectionPrompt, Some($context)).into()
);
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::EditCollectionToggleMonitored
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::EditCollectionToggleMonitored
);
assert_eq!(
app.data.radarr_data.minimum_availability_list.items,
@@ -951,8 +958,8 @@ mod tests {
&ActiveRadarrBlock::DeleteMoviePrompt.into()
);
assert_eq!(
app.data.radarr_data.selected_block,
ActiveRadarrBlock::DeleteMovieToggleDeleteFile
app.data.radarr_data.selected_block.get_active_block(),
&ActiveRadarrBlock::DeleteMovieToggleDeleteFile
);
}
@@ -996,10 +1003,11 @@ mod tests {
use super::*;
#[rstest]
#[case(ActiveRadarrBlock::Movies, 0, ActiveRadarrBlock::RootFolders)]
#[case(ActiveRadarrBlock::Downloads, 1, ActiveRadarrBlock::Movies)]
#[case(ActiveRadarrBlock::Collections, 2, ActiveRadarrBlock::Downloads)]
#[case(ActiveRadarrBlock::Movies, 0, ActiveRadarrBlock::System)]
#[case(ActiveRadarrBlock::System, 4, ActiveRadarrBlock::RootFolders)]
#[case(ActiveRadarrBlock::RootFolders, 3, ActiveRadarrBlock::Collections)]
#[case(ActiveRadarrBlock::Collections, 2, ActiveRadarrBlock::Downloads)]
#[case(ActiveRadarrBlock::Downloads, 1, ActiveRadarrBlock::Movies)]
fn test_radarr_tab_left(
#[case] active_radarr_block: ActiveRadarrBlock,
#[case] index: usize,
@@ -1027,7 +1035,8 @@ mod tests {
#[case(ActiveRadarrBlock::Movies, 0, ActiveRadarrBlock::Downloads)]
#[case(ActiveRadarrBlock::Downloads, 1, ActiveRadarrBlock::Collections)]
#[case(ActiveRadarrBlock::Collections, 2, ActiveRadarrBlock::RootFolders)]
#[case(ActiveRadarrBlock::RootFolders, 3, ActiveRadarrBlock::Movies)]
#[case(ActiveRadarrBlock::RootFolders, 3, ActiveRadarrBlock::System)]
#[case(ActiveRadarrBlock::System, 4, ActiveRadarrBlock::Movies)]
fn test_radarr_tab_right(
#[case] active_radarr_block: ActiveRadarrBlock,
#[case] index: usize,
@@ -1549,7 +1558,10 @@ mod tests {
use crate::app::radarr::radarr_test_utils::create_test_radarr_data;
use crate::app::radarr::RadarrData;
use crate::app::radarr::EDIT_COLLECTION_SELECTION_BLOCKS;
use crate::app::radarr::EDIT_MOVIE_SELECTION_BLOCKS;
use crate::models::radarr_models::MinimumAvailability;
use crate::models::BlockSelectionState;
use crate::models::HorizontallyScrollableText;
use crate::models::StatefulTable;
@@ -4,28 +4,28 @@ use serde_json::Number;
use strum::IntoEnumIterator;
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::radarr::ActiveRadarrBlock;
use crate::app::radarr::{ActiveRadarrBlock, EDIT_MOVIE_SELECTION_BLOCKS};
use crate::app::App;
use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::radarr_models::{Language, Release, ReleaseField};
use crate::models::Scrollable;
use crate::models::{BlockSelectionState, Scrollable};
use crate::network::radarr_network::RadarrEvent;
pub(super) struct MovieDetailsHandler<'a> {
pub(super) struct MovieDetailsHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
}
impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for MovieDetailsHandler<'a> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<'a, 'b> {
fn with(
key: &'a Key,
app: &'a mut App,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
) -> MovieDetailsHandler<'a> {
) -> MovieDetailsHandler<'a, 'b> {
MovieDetailsHandler {
key,
app,
@@ -234,7 +234,8 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for MovieDetailsHandler<'a> {
.into(),
);
self.app.data.radarr_data.populate_edit_movie_fields();
self.app.data.radarr_data.selected_block = ActiveRadarrBlock::EditMovieToggleMonitored;
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
}
_ if *key == DEFAULT_KEYBINDINGS.update.key => {
self
@@ -779,7 +780,9 @@ mod tests {
use crate::app::radarr::radarr_test_utils::create_test_radarr_data;
use crate::app::radarr::RadarrData;
use crate::app::radarr::EDIT_MOVIE_SELECTION_BLOCKS;
use crate::models::radarr_models::{MinimumAvailability, Movie};
use crate::models::BlockSelectionState;
use crate::models::HorizontallyScrollableText;
use crate::models::StatefulTable;
use crate::test_edit_movie_key;
+2 -2
View File
@@ -57,7 +57,7 @@ async fn main() -> Result<()> {
}
#[tokio::main]
async fn start_networking(mut network_rx: Receiver<NetworkEvent>, app: &Arc<Mutex<App>>) {
async fn start_networking(mut network_rx: Receiver<NetworkEvent>, app: &Arc<Mutex<App<'_>>>) {
let network = Network::new(reqwest::Client::new(), app);
while let Some(network_event) = network_rx.recv().await {
@@ -65,7 +65,7 @@ async fn start_networking(mut network_rx: Receiver<NetworkEvent>, app: &Arc<Mute
}
}
async fn start_ui(app: &Arc<Mutex<App>>) -> Result<()> {
async fn start_ui(app: &Arc<Mutex<App<'_>>>) -> Result<()> {
let mut stdout = io::stdout();
enable_raw_mode()?;
+136 -30
View File
@@ -250,12 +250,12 @@ impl HorizontallyScrollableText {
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct TabRoute {
pub title: String,
pub title: &'static str,
pub route: Route,
pub help: String,
pub contextual_help: Option<String>,
pub help: &'static str,
pub contextual_help: Option<&'static str>,
}
pub struct TabState {
@@ -279,12 +279,12 @@ impl TabState {
&self.tabs[self.index].route
}
pub fn get_active_tab_help(&self) -> String {
self.tabs[self.index].help.clone()
pub fn get_active_tab_help(&self) -> &'static str {
self.tabs[self.index].help
}
pub fn get_active_tab_contextual_help(&self) -> Option<String> {
self.tabs[self.index].contextual_help.clone()
pub fn get_active_tab_contextual_help(&self) -> Option<&'static str> {
self.tabs[self.index].contextual_help
}
pub fn next(&mut self) {
@@ -300,6 +300,50 @@ impl TabState {
}
}
#[derive(Default, Eq, PartialEq, Debug)]
pub struct BlockSelectionState<'a, T>
where
T: Sized + Clone + Copy + Default,
{
pub blocks: &'a [T],
pub index: usize,
}
impl<'a, T> BlockSelectionState<'a, T>
where
T: Sized + Clone + Copy + Default,
{
pub fn new(blocks: &'a [T]) -> BlockSelectionState<'a, T> {
BlockSelectionState { blocks, index: 0 }
}
pub fn get_active_block(&self) -> &T {
&self.blocks[self.index]
}
pub fn next(&mut self) {
self.index = (self.index + 1) % self.blocks.len();
}
pub fn previous(&mut self) {
if self.index > 0 {
self.index -= 1;
} else {
self.index = self.blocks.len() - 1;
}
}
}
#[cfg(test)]
impl<'a, T> BlockSelectionState<'a, T>
where
T: Sized + Clone + Copy + Default,
{
pub fn set_index(&mut self, index: usize) {
self.index = index;
}
}
#[cfg(test)]
mod tests {
use std::cell::RefCell;
@@ -308,9 +352,19 @@ mod tests {
use crate::app::radarr::ActiveRadarrBlock;
use crate::models::{
HorizontallyScrollableText, Scrollable, ScrollableText, StatefulTable, TabRoute, TabState,
BlockSelectionState, HorizontallyScrollableText, Scrollable, ScrollableText, StatefulTable,
TabRoute, TabState,
};
const BLOCKS: [ActiveRadarrBlock; 6] = [
ActiveRadarrBlock::AddMovieSelectRootFolder,
ActiveRadarrBlock::AddMovieSelectMonitor,
ActiveRadarrBlock::AddMovieSelectMinimumAvailability,
ActiveRadarrBlock::AddMovieSelectQualityProfile,
ActiveRadarrBlock::AddMovieTagsInput,
ActiveRadarrBlock::AddMovieConfirmPrompt,
];
#[test]
fn test_stateful_table_scroll() {
let mut stateful_table = create_test_stateful_table();
@@ -672,11 +726,9 @@ mod tests {
#[test]
fn test_tab_state_get_active_route() {
let second_tab = create_test_tab_routes()[1].clone().route;
let tab_state = TabState {
tabs: create_test_tab_routes(),
index: 1,
};
let tabs = create_test_tab_routes();
let second_tab = tabs[1].route;
let tab_state = TabState { tabs, index: 1 };
let active_route = tab_state.get_active_route();
@@ -685,11 +737,9 @@ mod tests {
#[test]
fn test_tab_state_get_active_tab_help() {
let second_tab_help = create_test_tab_routes()[1].clone().help;
let tab_state = TabState {
tabs: create_test_tab_routes(),
index: 1,
};
let tabs = create_test_tab_routes();
let second_tab_help = tabs[1].help;
let tab_state = TabState { tabs, index: 1 };
let tab_help = tab_state.get_active_tab_help();
@@ -698,11 +748,9 @@ mod tests {
#[test]
fn test_tab_state_get_active_tab_contextual_help() {
let second_tab_contextual_help = create_test_tab_routes()[1].clone().contextual_help.unwrap();
let tab_state = TabState {
tabs: create_test_tab_routes(),
index: 1,
};
let tabs = create_test_tab_routes();
let second_tab_contextual_help = tabs[1].contextual_help.unwrap();
let tab_state = TabState { tabs, index: 1 };
let tab_contextual_help = tab_state.get_active_tab_contextual_help();
@@ -742,19 +790,77 @@ mod tests {
assert_eq!(tab_state.get_active_route(), &tab_routes[0].route);
}
#[test]
fn test_block_selection_state_new() {
let block_selection_state = BlockSelectionState::new(&BLOCKS);
assert_eq!(block_selection_state.index, 0);
}
#[test]
fn test_block_selection_state_get_active_block() {
let second_block = BLOCKS[1];
let block_selection_state = BlockSelectionState {
blocks: &BLOCKS,
index: 1,
};
let active_block = block_selection_state.get_active_block();
assert_eq!(active_block, &second_block);
}
#[test]
fn test_block_selection_state_next() {
let blocks = [
ActiveRadarrBlock::AddMovieSelectRootFolder,
ActiveRadarrBlock::AddMovieSelectMonitor,
];
let mut block_selection_state = BlockSelectionState::new(&blocks);
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
block_selection_state.next();
assert_eq!(block_selection_state.get_active_block(), &blocks[1]);
block_selection_state.next();
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
}
#[test]
fn test_block_selection_state_previous() {
let blocks = [
ActiveRadarrBlock::AddMovieSelectRootFolder,
ActiveRadarrBlock::AddMovieSelectMonitor,
];
let mut block_selection_state = BlockSelectionState::new(&blocks);
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
block_selection_state.previous();
assert_eq!(block_selection_state.get_active_block(), &blocks[1]);
block_selection_state.previous();
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
}
fn create_test_tab_routes() -> Vec<TabRoute> {
vec![
TabRoute {
title: "Test 1".to_owned(),
title: "Test 1",
route: ActiveRadarrBlock::Movies.into(),
help: "Help for Test 1".to_owned(),
contextual_help: Some("Contextual Help for Test 1".to_owned()),
help: "Help for Test 1",
contextual_help: Some("Contextual Help for Test 1"),
},
TabRoute {
title: "Test 2".to_owned(),
title: "Test 2",
route: ActiveRadarrBlock::Collections.into(),
help: "Help for Test 2".to_owned(),
contextual_help: Some("Contextual Help for Test 2".to_owned()),
help: "Help for Test 2",
contextual_help: Some("Contextual Help for Test 2"),
},
]
}
+7 -7
View File
@@ -21,13 +21,13 @@ pub enum NetworkEvent {
Radarr(RadarrEvent),
}
pub struct Network<'a> {
pub struct Network<'a, 'b> {
pub client: Client,
pub app: &'a Arc<Mutex<App>>,
pub app: &'a Arc<Mutex<App<'b>>>,
}
impl<'a> Network<'a> {
pub fn new(client: Client, app: &'a Arc<Mutex<App>>) -> Self {
impl<'a, 'b> Network<'a, 'b> {
pub fn new(client: Client, app: &'a Arc<Mutex<App<'b>>>) -> Self {
Network { client, app }
}
@@ -43,7 +43,7 @@ impl<'a> Network<'a> {
pub async fn handle_request<B, R>(
&self,
request_props: RequestProps<B>,
mut app_update_fn: impl FnMut(R, MutexGuard<'_, App>),
mut app_update_fn: impl FnMut(R, MutexGuard<'_, App<'_>>),
) where
B: Serialize + Default + Debug,
R: DeserializeOwned,
@@ -427,11 +427,11 @@ mod tests {
pub value: String,
}
async fn mock_api(
async fn mock_api<'a>(
method: RequestMethod,
response_status: usize,
has_response_body: bool,
) -> (Mock, Arc<Mutex<App>>, ServerGuard) {
) -> (Mock, Arc<Mutex<App<'a>>>, ServerGuard) {
let mut server = Server::new_async().await;
let mut async_server = server
.mock(&method.to_string().to_uppercase(), "/test")
+41 -62
View File
@@ -86,7 +86,7 @@ impl From<RadarrEvent> for NetworkEvent {
}
}
impl<'a> Network<'a> {
impl<'a, 'b> Network<'a, 'b> {
pub async fn handle_radarr_event(&self, radarr_event: RadarrEvent) {
match radarr_event {
RadarrEvent::AddMovie => self.add_movie().await,
@@ -1533,13 +1533,9 @@ mod test {
"languages": [ { "name": "English" } ],
"quality": { "quality": { "name": "HD - 1080p" }}
}]);
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(release_json),
format!("{}?movieId=1", RadarrEvent::GetReleases.resource()).as_str(),
)
.await;
let resource = format!("{}?movieId=1", RadarrEvent::GetReleases.resource());
let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Get, None, Some(release_json), &resource).await;
app_arc
.lock()
.await
@@ -1581,15 +1577,15 @@ mod test {
}
}
}]);
let resource = format!(
"{}?term=test%20term",
RadarrEvent::SearchNewMovie.resource()
);
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(add_movie_search_result_json),
format!(
"{}?term=test%20term",
RadarrEvent::SearchNewMovie.resource()
)
.as_str(),
&resource,
)
.await;
app_arc.lock().await.data.radarr_data.search = "test term".to_owned().into();
@@ -1614,17 +1610,12 @@ mod test {
#[tokio::test]
async fn test_handle_search_new_movie_event_no_results() {
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(json!([])),
format!(
"{}?term=test%20term",
RadarrEvent::SearchNewMovie.resource()
)
.as_str(),
)
.await;
let resource = format!(
"{}?term=test%20term",
RadarrEvent::SearchNewMovie.resource()
);
let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Get, None, Some(json!([])), &resource).await;
app_arc.lock().await.data.radarr_data.search = "test term".to_owned().into();
let network = Network::new(reqwest::Client::new(), &app_arc);
@@ -1766,11 +1757,12 @@ mod test {
#[tokio::test]
async fn test_handle_get_movie_details_event() {
let resource = format!("{}/1", RadarrEvent::GetMovieDetails.resource());
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(serde_json::from_str(MOVIE_JSON).unwrap()),
format!("{}/1", RadarrEvent::GetMovieDetails.resource()).as_str(),
&resource,
)
.await;
app_arc
@@ -1872,11 +1864,12 @@ mod test {
"minimumAvailability": "released",
"ratings": {}
});
let resource = format!("{}/1", RadarrEvent::GetMovieDetails.resource());
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(movie_json_with_missing_fields),
format!("{}/1", RadarrEvent::GetMovieDetails.resource()).as_str(),
&resource,
)
.await;
app_arc
@@ -1953,11 +1946,12 @@ mod test {
"date": "2022-12-30T07:37:56Z",
"eventType": "grabbed"
}]);
let resource = format!("{}?movieId=1", RadarrEvent::GetMovieHistory.resource());
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(movie_history_item_json),
format!("{}?movieId=1", RadarrEvent::GetMovieHistory.resource()).as_str(),
&resource,
)
.await;
app_arc
@@ -2183,13 +2177,9 @@ mod test {
"type": "crew",
}
]);
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(credits_json),
format!("{}?movieId=1", RadarrEvent::GetMovieCredits.resource()).as_str(),
)
.await;
let resource = format!("{}?movieId=1", RadarrEvent::GetMovieCredits.resource());
let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Get, None, Some(credits_json), &resource).await;
app_arc
.lock()
.await
@@ -2216,17 +2206,12 @@ mod test {
#[tokio::test]
async fn test_handle_delete_movie_event() {
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Delete,
None,
None,
format!(
"{}/1?deleteFiles=true&addImportExclusion=true",
RadarrEvent::DeleteMovie.resource()
)
.as_str(),
)
.await;
let resource = format!(
"{}/1?deleteFiles=true&addImportExclusion=true",
RadarrEvent::DeleteMovie.resource()
);
let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
{
let mut app = app_arc.lock().await;
app.data.radarr_data.movies.set_items(vec![movie()]);
@@ -2244,13 +2229,9 @@ mod test {
#[tokio::test]
async fn test_handle_delete_download_event() {
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Delete,
None,
None,
format!("{}/1", RadarrEvent::DeleteDownload.resource()).as_str(),
)
.await;
let resource = format!("{}/1", RadarrEvent::DeleteDownload.resource());
let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
app_arc
.lock()
.await
@@ -2269,13 +2250,9 @@ mod test {
#[tokio::test]
async fn test_handle_delete_root_folder_event() {
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Delete,
None,
None,
format!("{}/1", RadarrEvent::DeleteRootFolder.resource()).as_str(),
)
.await;
let resource = format!("{}/1", RadarrEvent::DeleteRootFolder.resource());
let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
app_arc
.lock()
.await
@@ -2415,11 +2392,12 @@ mod test {
*expected_body.get_mut("path").unwrap() = json!("/nfs/Test Path");
*expected_body.get_mut("tags").unwrap() = json!([1, 2]);
let resource = format!("{}/1", RadarrEvent::GetMovieDetails.resource());
let (async_details_server, app_arc, mut server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(serde_json::from_str(MOVIE_JSON).unwrap()),
format!("{}/1", RadarrEvent::GetMovieDetails.resource()).as_str(),
&resource,
)
.await;
let async_edit_server = server
@@ -2510,11 +2488,12 @@ mod test {
*expected_body.get_mut("rootFolderPath").unwrap() = json!("/nfs/Test Path");
*expected_body.get_mut("searchOnAdd").unwrap() = json!(false);
let resource = format!("{}/123", RadarrEvent::GetCollections.resource());
let (async_details_server, app_arc, mut server) = mock_radarr_api(
RequestMethod::Get,
None,
Some(detailed_collection_body),
format!("{}/123", RadarrEvent::GetCollections.resource()).as_str(),
&resource,
)
.await;
let async_edit_server = server
@@ -2854,7 +2833,7 @@ mod test {
request_body: Option<Value>,
response_body: Option<Value>,
resource: &str,
) -> (Mock, Arc<Mutex<App>>, ServerGuard) {
) -> (Mock, Arc<Mutex<App<'_>>>, ServerGuard) {
let mut server = Server::new_async().await;
let mut async_server = server
.mock(
+29 -29
View File
@@ -29,7 +29,7 @@ mod utils;
static HIGHLIGHT_SYMBOL: &str = "=> ";
pub fn ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) {
pub fn ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>) {
f.render_widget(background_block(), f.size());
let main_chunks = if !app.error.text.is_empty() {
let chunks = vertical_chunks_with_margin(
@@ -65,7 +65,7 @@ pub fn ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App) {
}
}
fn draw_header_row<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_header_row<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let chunks =
horizontal_chunks_with_margin(vec![Constraint::Length(75), Constraint::Min(0)], area, 1);
let help_text = Text::from(app.server_tabs.get_active_tab_help());
@@ -74,7 +74,7 @@ fn draw_header_row<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect)
.server_tabs
.tabs
.iter()
.map(|tab| Spans::from(Span::styled(&tab.title, style_default_bold())))
.map(|tab| Spans::from(Span::styled(tab.title, style_default_bold())))
.collect();
let tabs = Tabs::new(titles)
.block(logo_block())
@@ -89,7 +89,7 @@ fn draw_header_row<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect)
f.render_widget(help, chunks[1]);
}
fn draw_error<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_error<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let block =
title_block("Error | <esc> to close").style(style_failure().add_modifier(Modifier::BOLD));
@@ -112,8 +112,8 @@ fn draw_error<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
pub fn draw_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
popup_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
app: &mut App<'_>,
popup_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
percent_x: u16,
percent_y: u16,
) {
@@ -125,10 +125,10 @@ pub fn draw_popup<B: Backend>(
pub fn draw_popup_over<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
percent_x: u16,
percent_y: u16,
) {
@@ -139,55 +139,55 @@ pub fn draw_popup_over<B: Backend>(
pub fn draw_prompt_popup_over<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
) {
draw_popup_over(f, app, area, background_fn, popup_fn, 35, 35);
}
pub fn draw_small_popup_over<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
) {
draw_popup_over(f, app, area, background_fn, popup_fn, 40, 40);
}
pub fn draw_medium_popup_over<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
) {
draw_popup_over(f, app, area, background_fn, popup_fn, 60, 60);
}
pub fn draw_large_popup_over<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
popup_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
) {
draw_popup_over(f, app, area, background_fn, popup_fn, 75, 75);
}
pub fn draw_drop_down_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
drop_down_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
drop_down_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
) {
draw_popup_over(f, app, area, background_fn, drop_down_fn, 20, 30);
}
fn draw_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
fn draw_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rect) {
if let Route::Radarr(_, _) = app.get_current_route() {
radarr_ui::draw_radarr_context_row(f, app, area)
}
@@ -195,10 +195,10 @@ fn draw_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
pub fn draw_error_popup_over<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
message: &str,
background_fn: fn(&mut Frame<'_, B>, &mut App, Rect),
background_fn: fn(&mut Frame<'_, B>, &mut App<'_>, Rect),
) {
background_fn(f, app, area);
draw_error_popup(f, message);
@@ -238,7 +238,7 @@ fn draw_tabs<'a, B: Backend>(
let titles = tab_state
.tabs
.iter()
.map(|tab_route| Spans::from(Span::styled(&tab_route.title, style_default_bold())))
.map(|tab_route| Spans::from(Span::styled(tab_route.title, style_default_bold())))
.collect();
let tabs = Tabs::new(titles)
.block(block)
@@ -258,7 +258,7 @@ pub struct TableProps<'a, T> {
pub content: &'a mut StatefulTable<T>,
pub table_headers: Vec<&'a str>,
pub constraints: Vec<Constraint>,
pub help: Option<String>,
pub help: Option<&'static str>,
}
fn draw_table<'a, B, T, F>(
+20 -12
View File
@@ -27,7 +27,7 @@ use crate::App;
pub(super) fn draw_add_movie_search_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
area: Rect,
) {
if let Route::Radarr(active_radarr_block, context_option) = *app.get_current_route() {
@@ -67,7 +67,7 @@ pub(super) fn draw_add_movie_search_popup<B: Backend>(
}
}
fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let current_selection = if app.data.radarr_data.add_searched_movies.items.is_empty() {
AddMovieSearchResult::default()
} else {
@@ -233,7 +233,7 @@ fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area:
);
}
fn draw_confirmation_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect) {
fn draw_confirmation_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, prompt_area: Rect) {
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
match active_radarr_block {
ActiveRadarrBlock::AddMovieSelectMonitor => {
@@ -280,7 +280,11 @@ fn draw_confirmation_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, prom
}
}
fn draw_select_monitor_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, popup_area: Rect) {
fn draw_select_monitor_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App<'_>,
popup_area: Rect,
) {
draw_drop_down_list(
f,
popup_area,
@@ -289,7 +293,11 @@ fn draw_select_monitor_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, po
);
}
fn draw_confirmation_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect) {
fn draw_confirmation_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App<'_>,
prompt_area: Rect,
) {
let (movie_title, movie_overview) = if let Route::Radarr(_, Some(_)) = app.get_current_route() {
(
&app
@@ -328,8 +336,8 @@ fn draw_confirmation_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, pro
let title = format!("Add Movie - {}", movie_title);
let prompt = movie_overview;
let yes_no_value = app.data.radarr_data.prompt_confirm;
let selected_block = app.data.radarr_data.selected_block;
let highlight_yes_no = selected_block == ActiveRadarrBlock::AddMovieConfirmPrompt;
let selected_block = app.data.radarr_data.selected_block.get_active_block();
let highlight_yes_no = selected_block == &ActiveRadarrBlock::AddMovieConfirmPrompt;
let selected_monitor = app.data.radarr_data.monitor_list.current_selection();
let selected_minimum_availability = app
@@ -374,7 +382,7 @@ fn draw_confirmation_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, pro
chunks[1],
"Root Folder",
&selected_root_folder.path,
selected_block == ActiveRadarrBlock::AddMovieSelectRootFolder,
selected_block == &ActiveRadarrBlock::AddMovieSelectRootFolder,
);
draw_drop_down_menu_button(
@@ -382,7 +390,7 @@ fn draw_confirmation_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, pro
chunks[2],
"Monitor",
selected_monitor.to_display_str(),
selected_block == ActiveRadarrBlock::AddMovieSelectMonitor,
selected_block == &ActiveRadarrBlock::AddMovieSelectMonitor,
);
draw_drop_down_menu_button(
@@ -390,14 +398,14 @@ fn draw_confirmation_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, pro
chunks[3],
"Minimum Availability",
selected_minimum_availability.to_display_str(),
selected_block == ActiveRadarrBlock::AddMovieSelectMinimumAvailability,
selected_block == &ActiveRadarrBlock::AddMovieSelectMinimumAvailability,
);
draw_drop_down_menu_button(
f,
chunks[4],
"Quality Profile",
selected_quality_profile,
selected_block == ActiveRadarrBlock::AddMovieSelectQualityProfile,
selected_block == &ActiveRadarrBlock::AddMovieSelectQualityProfile,
);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
@@ -407,7 +415,7 @@ fn draw_confirmation_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, pro
"Tags",
&app.data.radarr_data.edit_tags.text,
*app.data.radarr_data.edit_tags.offset.borrow(),
selected_block == ActiveRadarrBlock::AddMovieTagsInput,
selected_block == &ActiveRadarrBlock::AddMovieTagsInput,
active_radarr_block == ActiveRadarrBlock::AddMovieTagsInput,
);
}
+3 -3
View File
@@ -18,7 +18,7 @@ use crate::utils::convert_runtime;
pub(super) fn draw_collection_details_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
content_area: Rect,
) {
if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() {
@@ -40,7 +40,7 @@ pub(super) fn draw_collection_details_popup<B: Backend>(
pub(super) fn draw_collection_details<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
content_area: Rect,
) {
let chunks = vertical_chunks_with_margin(
@@ -213,7 +213,7 @@ pub(super) fn draw_collection_details<B: Backend>(
);
}
fn draw_movie_overview<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area: Rect) {
fn draw_movie_overview<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
let title_block = title_block("Overview");
f.render_widget(title_block, content_area);
+5 -5
View File
@@ -9,14 +9,14 @@ use crate::ui::draw_prompt_box_with_checkboxes;
pub(super) fn draw_delete_movie_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
if matches!(
*app.get_current_route(),
Route::Radarr(ActiveRadarrBlock::DeleteMoviePrompt, _)
) {
let selected_block = app.data.radarr_data.selected_block;
let selected_block = app.data.radarr_data.selected_block.get_active_block();
draw_prompt_box_with_checkboxes(
f,
prompt_area,
@@ -30,15 +30,15 @@ pub(super) fn draw_delete_movie_prompt<B: Backend>(
(
"Delete Movie Files",
app.data.radarr_data.delete_movie_files,
selected_block == ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
selected_block == &ActiveRadarrBlock::DeleteMovieToggleDeleteFile,
),
(
"Add List Exclusion",
app.data.radarr_data.add_list_exclusion,
selected_block == ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
selected_block == &ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
),
],
selected_block == ActiveRadarrBlock::DeleteMovieConfirmPrompt,
selected_block == &ActiveRadarrBlock::DeleteMovieConfirmPrompt,
app.data.radarr_data.prompt_confirm,
)
}
+9 -9
View File
@@ -18,7 +18,7 @@ use crate::ui::{
pub(super) fn draw_edit_collection_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
@@ -54,7 +54,7 @@ pub(super) fn draw_edit_collection_prompt<B: Backend>(
fn draw_edit_collection_confirmation_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
let (collection_title, collection_overview) =
@@ -97,8 +97,8 @@ fn draw_edit_collection_confirmation_prompt<B: Backend>(
};
let title = format!("Edit - {}", collection_title);
let yes_no_value = app.data.radarr_data.prompt_confirm;
let selected_block = app.data.radarr_data.selected_block;
let highlight_yes_no = selected_block == ActiveRadarrBlock::EditCollectionConfirmPrompt;
let selected_block = app.data.radarr_data.selected_block.get_active_block();
let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditCollectionConfirmPrompt;
let selected_minimum_availability = app
.data
@@ -141,7 +141,7 @@ fn draw_edit_collection_confirmation_prompt<B: Backend>(
chunks[1],
"Monitored",
app.data.radarr_data.edit_monitored.unwrap_or_default(),
selected_block == ActiveRadarrBlock::EditCollectionToggleMonitored,
selected_block == &ActiveRadarrBlock::EditCollectionToggleMonitored,
);
draw_drop_down_menu_button(
@@ -149,14 +149,14 @@ fn draw_edit_collection_confirmation_prompt<B: Backend>(
chunks[2],
"Minimum Availability",
selected_minimum_availability.to_display_str(),
selected_block == ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
selected_block == &ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
);
draw_drop_down_menu_button(
f,
chunks[3],
"Quality Profile",
selected_quality_profile,
selected_block == ActiveRadarrBlock::EditCollectionSelectQualityProfile,
selected_block == &ActiveRadarrBlock::EditCollectionSelectQualityProfile,
);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
@@ -166,7 +166,7 @@ fn draw_edit_collection_confirmation_prompt<B: Backend>(
"Root Folder",
&app.data.radarr_data.edit_path.text,
*app.data.radarr_data.edit_path.offset.borrow(),
selected_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput,
selected_block == &ActiveRadarrBlock::EditCollectionRootFolderPathInput,
active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput,
);
}
@@ -176,7 +176,7 @@ fn draw_edit_collection_confirmation_prompt<B: Backend>(
chunks[5],
"Search on Add",
app.data.radarr_data.edit_search_on_add.unwrap_or_default(),
selected_block == ActiveRadarrBlock::EditCollectionToggleSearchOnAdd,
selected_block == &ActiveRadarrBlock::EditCollectionToggleSearchOnAdd,
);
draw_button(
+9 -9
View File
@@ -18,7 +18,7 @@ use crate::ui::{
pub(super) fn draw_edit_movie_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
@@ -54,7 +54,7 @@ pub(super) fn draw_edit_movie_prompt<B: Backend>(
fn draw_edit_movie_confirmation_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
let (movie_title, movie_overview) = if app.data.radarr_data.filtered_movies.items.is_empty() {
@@ -94,8 +94,8 @@ fn draw_edit_movie_confirmation_prompt<B: Backend>(
};
let title = format!("Edit - {}", movie_title);
let yes_no_value = app.data.radarr_data.prompt_confirm;
let selected_block = app.data.radarr_data.selected_block;
let highlight_yes_no = selected_block == ActiveRadarrBlock::EditMovieConfirmPrompt;
let selected_block = app.data.radarr_data.selected_block.get_active_block();
let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditMovieConfirmPrompt;
let selected_minimum_availability = app
.data
@@ -138,7 +138,7 @@ fn draw_edit_movie_confirmation_prompt<B: Backend>(
chunks[1],
"Monitored",
app.data.radarr_data.edit_monitored.unwrap_or_default(),
selected_block == ActiveRadarrBlock::EditMovieToggleMonitored,
selected_block == &ActiveRadarrBlock::EditMovieToggleMonitored,
);
draw_drop_down_menu_button(
@@ -146,14 +146,14 @@ fn draw_edit_movie_confirmation_prompt<B: Backend>(
chunks[2],
"Minimum Availability",
selected_minimum_availability.to_display_str(),
selected_block == ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
selected_block == &ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
);
draw_drop_down_menu_button(
f,
chunks[3],
"Quality Profile",
selected_quality_profile,
selected_block == ActiveRadarrBlock::EditMovieSelectQualityProfile,
selected_block == &ActiveRadarrBlock::EditMovieSelectQualityProfile,
);
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
@@ -163,7 +163,7 @@ fn draw_edit_movie_confirmation_prompt<B: Backend>(
"Path",
&app.data.radarr_data.edit_path.text,
*app.data.radarr_data.edit_path.offset.borrow(),
selected_block == ActiveRadarrBlock::EditMoviePathInput,
selected_block == &ActiveRadarrBlock::EditMoviePathInput,
active_radarr_block == ActiveRadarrBlock::EditMoviePathInput,
);
draw_text_box_with_label(
@@ -172,7 +172,7 @@ fn draw_edit_movie_confirmation_prompt<B: Backend>(
"Tags",
&app.data.radarr_data.edit_tags.text,
*app.data.radarr_data.edit_tags.offset.borrow(),
selected_block == ActiveRadarrBlock::EditMovieTagsInput,
selected_block == &ActiveRadarrBlock::EditMovieTagsInput,
active_radarr_block == ActiveRadarrBlock::EditMovieTagsInput,
);
}
+27 -19
View File
@@ -43,7 +43,7 @@ mod edit_collection_ui;
mod edit_movie_ui;
mod movie_details_ui;
pub(super) fn draw_radarr_ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
pub(super) fn draw_radarr_ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let (content_rect, _) = draw_tabs(f, area, "Movies", &app.data.radarr_data.main_tabs);
if let Route::Radarr(active_radarr_block, context_option) = *app.get_current_route() {
@@ -195,7 +195,7 @@ pub(super) fn draw_radarr_ui<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, ar
}
}
pub(super) fn draw_radarr_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
pub(super) fn draw_radarr_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rect) {
let chunks = horizontal_chunks(vec![Constraint::Min(0), Constraint::Length(20)], area);
let context_chunks = horizontal_chunks(
@@ -208,7 +208,7 @@ pub(super) fn draw_radarr_context_row<B: Backend>(f: &mut Frame<'_, B>, app: &Ap
draw_radarr_logo(f, chunks[1]);
}
fn draw_library<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_library<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let current_selection = if !app.data.radarr_data.filtered_movies.items.is_empty() {
app
.data
@@ -314,7 +314,7 @@ fn draw_library<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_update_all_movies_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
draw_prompt_box(
@@ -328,7 +328,7 @@ fn draw_update_all_movies_prompt<B: Backend>(
fn draw_update_downloads_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
draw_prompt_box(
@@ -342,7 +342,7 @@ fn draw_update_downloads_prompt<B: Backend>(
fn draw_update_all_collections_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
draw_prompt_box(
@@ -354,7 +354,11 @@ fn draw_update_all_collections_prompt<B: Backend>(
);
}
fn draw_delete_download_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect) {
fn draw_delete_download_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App<'_>,
prompt_area: Rect,
) {
draw_prompt_box(
f,
prompt_area,
@@ -370,7 +374,7 @@ fn draw_delete_download_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App,
fn draw_delete_root_folder_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
draw_prompt_box(
@@ -386,7 +390,11 @@ fn draw_delete_root_folder_prompt<B: Backend>(
);
}
fn draw_add_root_folder_prompt_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_add_root_folder_prompt_box<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App<'_>,
area: Rect,
) {
let chunks = vertical_chunks_with_margin(
vec![
Constraint::Length(3),
@@ -413,7 +421,7 @@ fn draw_add_root_folder_prompt_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut A
f.render_widget(help, chunks[1]);
}
fn draw_search_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_search_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let chunks =
vertical_chunks_with_margin(vec![Constraint::Length(3), Constraint::Min(0)], area, 1);
if !app.data.radarr_data.is_searching {
@@ -454,7 +462,7 @@ fn draw_search_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect)
}
}
fn draw_filter_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_filter_box<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let chunks =
vertical_chunks_with_margin(vec![Constraint::Length(3), Constraint::Min(0)], area, 1);
if !app.data.radarr_data.is_filtering {
@@ -504,7 +512,7 @@ fn draw_radarr_logo<B: Backend>(f: &mut Frame<'_, B>, area: Rect) {
f.render_widget(logo, area);
}
fn draw_stats_context<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
fn draw_stats_context<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rect) {
let block = title_block("Stats");
if !app.data.radarr_data.version.is_empty() {
@@ -602,7 +610,7 @@ fn draw_stats_context<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
}
}
fn draw_downloads_context<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rect) {
fn draw_downloads_context<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rect) {
let block = title_block("Downloads");
let downloads_vec = &app.data.radarr_data.downloads.items;
@@ -632,7 +640,7 @@ fn draw_downloads_context<B: Backend>(f: &mut Frame<'_, B>, app: &App, area: Rec
}
}
fn draw_downloads<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_downloads<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let current_selection = if app.data.radarr_data.downloads.items.is_empty() {
DownloadRecord::default()
} else {
@@ -708,7 +716,7 @@ fn draw_downloads<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
);
}
fn draw_collections<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_collections<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
let current_selection = if !app.data.radarr_data.filtered_collections.items.is_empty() {
app
.data
@@ -790,7 +798,7 @@ fn draw_collections<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect)
);
}
fn draw_root_folders<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_root_folders<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
draw_table(
f,
area,
@@ -863,7 +871,7 @@ fn determine_row_style(downloads_vec: &[DownloadRecord], movie: &Movie) -> Style
fn draw_select_minimum_availability_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
popup_area: Rect,
) {
draw_drop_down_list(
@@ -876,7 +884,7 @@ fn draw_select_minimum_availability_popup<B: Backend>(
fn draw_select_quality_profile_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
popup_area: Rect,
) {
draw_drop_down_list(
@@ -889,7 +897,7 @@ fn draw_select_quality_profile_popup<B: Backend>(
fn draw_select_root_folder_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
popup_area: Rect,
) {
draw_drop_down_list(
+23 -11
View File
@@ -22,7 +22,11 @@ use crate::ui::{
};
use crate::utils::convert_to_gb;
pub(super) fn draw_movie_info_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
pub(super) fn draw_movie_info_popup<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App<'_>,
area: Rect,
) {
let (content_area, _) = draw_tabs(f, area, "Movie Info", &app.data.radarr_data.movie_info_tabs);
if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() {
@@ -67,7 +71,7 @@ pub(super) fn draw_movie_info_popup<B: Backend>(f: &mut Frame<'_, B>, app: &mut
}
}
fn draw_movie_info<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect) {
fn draw_movie_info<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, _) =
app.data.radarr_data.movie_info_tabs.get_active_route()
{
@@ -83,7 +87,11 @@ fn draw_movie_info<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, area: Rect)
}
}
fn draw_search_movie_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect) {
fn draw_search_movie_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App<'_>,
prompt_area: Rect,
) {
draw_prompt_box(
f,
prompt_area,
@@ -97,7 +105,11 @@ fn draw_search_movie_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, pro
);
}
fn draw_update_and_scan_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect) {
fn draw_update_and_scan_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App<'_>,
prompt_area: Rect,
) {
draw_prompt_box(
f,
prompt_area,
@@ -111,7 +123,7 @@ fn draw_update_and_scan_prompt<B: Backend>(f: &mut Frame<'_, B>, app: &mut App,
);
}
fn draw_file_info<B: Backend>(f: &mut Frame<'_, B>, app: &App, content_area: Rect) {
fn draw_file_info<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, content_area: Rect) {
let file_info = app.data.radarr_data.file_details.to_owned();
if !file_info.is_empty() {
@@ -167,7 +179,7 @@ fn draw_file_info<B: Backend>(f: &mut Frame<'_, B>, app: &App, content_area: Rec
}
}
fn draw_movie_details<B: Backend>(f: &mut Frame<'_, B>, app: &App, content_area: Rect) {
fn draw_movie_details<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, content_area: Rect) {
let movie_details = app.data.radarr_data.movie_details.get_text();
let block = layout_block_top_border();
@@ -210,7 +222,7 @@ fn draw_movie_details<B: Backend>(f: &mut Frame<'_, B>, app: &App, content_area:
}
}
fn draw_movie_history<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area: Rect) {
fn draw_movie_history<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
let current_selection = if app.data.radarr_data.movie_history.items.is_empty() {
MovieHistoryItem::default()
} else {
@@ -285,7 +297,7 @@ fn draw_movie_history<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_a
}
}
fn draw_movie_cast<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area: Rect) {
fn draw_movie_cast<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
draw_table(
f,
content_area,
@@ -317,7 +329,7 @@ fn draw_movie_cast<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area
);
}
fn draw_movie_crew<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area: Rect) {
fn draw_movie_crew<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
draw_table(
f,
content_area,
@@ -351,7 +363,7 @@ fn draw_movie_crew<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area
);
}
fn draw_movie_releases<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_area: Rect) {
fn draw_movie_releases<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_area: Rect) {
let current_selection = if app.data.radarr_data.movie_releases.items.is_empty() {
Release::default()
} else {
@@ -475,7 +487,7 @@ fn draw_movie_releases<B: Backend>(f: &mut Frame<'_, B>, app: &mut App, content_
fn draw_manual_search_confirm_prompt<B: Backend>(
f: &mut Frame<'_, B>,
app: &mut App,
app: &mut App<'_>,
prompt_area: Rect,
) {
let current_selection = app.data.radarr_data.movie_releases.current_selection();