diff --git a/src/app/key_binding.rs b/src/app/key_binding.rs index 860c576..0124769 100644 --- a/src/app/key_binding.rs +++ b/src/app/key_binding.rs @@ -20,6 +20,7 @@ generate_keybindings! { sort, edit, refresh, + update, home, end, delete, @@ -78,6 +79,10 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings { key: Key::Char('r'), desc: "Refresh", }, + update: KeyBinding { + key: Key::Char('u'), + desc: "Update All", + }, home: KeyBinding { key: Key::Home, desc: "Home", diff --git a/src/app/mod.rs b/src/app/mod.rs index 0b7ea69..89cb893 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use anyhow::anyhow; use log::{debug, error}; use reqwest::Client; @@ -28,7 +26,6 @@ pub struct App { pub ticks_until_scroll: u64, pub tick_count: u64, pub last_tick: Instant, - pub network_tick_frequency: Duration, pub is_routing: bool, pub is_loading: bool, pub should_refresh: bool, @@ -137,10 +134,9 @@ impl Default for App { ]), client: Client::new(), title: "Managarr", - tick_until_poll: 50, + tick_until_poll: 400, ticks_until_scroll: 4, tick_count: 0, - network_tick_frequency: Duration::from_secs(20), last_tick: Instant::now(), is_loading: false, is_routing: false, @@ -181,8 +177,6 @@ impl Default for RadarrConfig { #[cfg(test)] mod tests { - use std::time::Duration; - use anyhow::anyhow; use pretty_assertions::{assert_eq, assert_str_eq}; use tokio::sync::mpsc; @@ -220,10 +214,9 @@ mod tests { ] ); assert_str_eq!(app.title, "Managarr"); - assert_eq!(app.tick_until_poll, 50); + assert_eq!(app.tick_until_poll, 400); assert_eq!(app.ticks_until_scroll, 4); assert_eq!(app.tick_count, 0); - assert_eq!(app.network_tick_frequency, Duration::from_secs(20)); assert!(!app.is_loading); assert!(!app.is_routing); assert!(!app.should_refresh); diff --git a/src/app/radarr.rs b/src/app/radarr.rs index af0efec..2129d18 100644 --- a/src/app/radarr.rs +++ b/src/app/radarr.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use bimap::BiMap; use chrono::{DateTime, Utc}; use strum::IntoEnumIterator; @@ -218,7 +216,7 @@ impl Default for RadarrData { title: "Library".to_owned(), route: ActiveRadarrBlock::Movies.into(), help: String::default(), - contextual_help: Some(" add | edit | search | filter | refresh | details | cancel filter | delete" + contextual_help: Some(" add | edit | search | filter | refresh | update all | details | cancel filter | delete" .to_owned()), }, TabRoute { @@ -231,7 +229,7 @@ impl Default for RadarrData { title: "Collections".to_owned(), route: ActiveRadarrBlock::Collections.into(), help: String::default(), - contextual_help: Some(" search | filter | refresh | details | cancel filter" + contextual_help: Some(" search | filter | refresh | update all | details | cancel filter" .to_owned()), }, ]), @@ -239,37 +237,37 @@ impl Default for RadarrData { TabRoute { title: "Details".to_owned(), route: ActiveRadarrBlock::MovieDetails.into(), - help: " refresh | edit | auto search | close".to_owned(), + help: " refresh | update | edit | auto search | close".to_owned(), contextual_help: None }, TabRoute { title: "History".to_owned(), route: ActiveRadarrBlock::MovieHistory.into(), - help: " refresh | edit | auto search | close".to_owned(), + help: " refresh | update | edit | auto search | close".to_owned(), contextual_help: None }, TabRoute { title: "File".to_owned(), route: ActiveRadarrBlock::FileInfo.into(), - help: " refresh | edit | auto search | close".to_owned(), + help: " refresh | update | edit | auto search | close".to_owned(), contextual_help: None, }, TabRoute { title: "Cast".to_owned(), route: ActiveRadarrBlock::Cast.into(), - help: " refresh | edit | auto search | close".to_owned(), + help: " refresh | update | edit | auto search | close".to_owned(), contextual_help: None, }, TabRoute { title: "Crew".to_owned(), route: ActiveRadarrBlock::Crew.into(), - help: " refresh | edit | auto search | close".to_owned(), + help: " refresh | update | edit | auto search | close".to_owned(), contextual_help: None, }, TabRoute { title: "Manual Search".to_owned(), route: ActiveRadarrBlock::ManualSearch.into(), - help: " refresh | edit | sort | auto search | close".to_owned(), + help: " refresh | update | edit | sort | auto search | close".to_owned(), contextual_help: Some(" details".to_owned()) } ]), @@ -313,10 +311,10 @@ pub enum ActiveRadarrBlock { MovieDetails, MovieHistory, Movies, - RefreshAndScanPrompt, - RefreshAllCollectionsPrompt, - RefreshAllMoviesPrompt, - RefreshDownloadsPrompt, + UpdateAndScanPrompt, + UpdateAllCollectionsPrompt, + UpdateAllMoviesPrompt, + UpdateDownloadsPrompt, SearchMovie, SearchCollection, ViewMovieOverview, @@ -349,7 +347,7 @@ pub const MOVIE_DETAILS_BLOCKS: [ActiveRadarrBlock; 10] = [ ActiveRadarrBlock::Cast, ActiveRadarrBlock::Crew, ActiveRadarrBlock::AutomaticallySearchMoviePrompt, - ActiveRadarrBlock::RefreshAndScanPrompt, + ActiveRadarrBlock::UpdateAndScanPrompt, ActiveRadarrBlock::ManualSearch, ActiveRadarrBlock::ManualSearchSortPrompt, ActiveRadarrBlock::ManualSearchConfirmPrompt, @@ -540,13 +538,7 @@ impl App { self.dispatch_by_radarr_block(&active_radarr_block).await; } - if self.is_routing - || self - .network_tick_frequency - .checked_sub(self.last_tick.elapsed()) - .unwrap_or_else(|| Duration::from_secs(0)) - .is_zero() - { + if self.is_routing || self.tick_count % self.tick_until_poll == 0 { self.refresh_metadata().await; self.dispatch_by_radarr_block(&active_radarr_block).await; } @@ -559,6 +551,9 @@ impl App { self .dispatch_network_event(RadarrEvent::GetTags.into()) .await; + self + .dispatch_network_event(RadarrEvent::GetDownloads.into()) + .await; } async fn populate_movie_collection_table(&mut self) { @@ -1019,8 +1014,6 @@ mod tests { } mod radarr_tests { - use std::time::Duration; - use pretty_assertions::assert_eq; use tokio::sync::mpsc; @@ -1456,7 +1449,8 @@ mod tests { #[tokio::test] async fn test_radarr_on_tick_network_tick_frequency() { let (mut app, mut sync_network_rx) = construct_app_unit(); - app.network_tick_frequency = Duration::from_secs(0); + app.tick_count = 2; + app.tick_until_poll = 2; app .radarr_on_tick(ActiveRadarrBlock::Downloads, false) diff --git a/src/handlers/radarr_handlers/mod.rs b/src/handlers/radarr_handlers/mod.rs index 937c393..4650b14 100644 --- a/src/handlers/radarr_handlers/mod.rs +++ b/src/handlers/radarr_handlers/mod.rs @@ -231,9 +231,9 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { } ActiveRadarrBlock::DeleteMoviePrompt | ActiveRadarrBlock::DeleteDownloadPrompt - | ActiveRadarrBlock::RefreshAllMoviesPrompt - | ActiveRadarrBlock::RefreshAllCollectionsPrompt - | ActiveRadarrBlock::RefreshDownloadsPrompt => handle_prompt_toggle(self.app, self.key), + | ActiveRadarrBlock::UpdateAllMoviesPrompt + | ActiveRadarrBlock::UpdateAllCollectionsPrompt + | ActiveRadarrBlock::UpdateDownloadsPrompt => handle_prompt_toggle(self.app, self.key), ActiveRadarrBlock::SearchMovie | ActiveRadarrBlock::SearchCollection => { handle_text_box_left_right_keys!(self, self.key, self.app.data.radarr_data.search) } @@ -256,7 +256,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { if self.app.data.radarr_data.filtered_movies.items.is_empty() { let selected_index = self .search_table(&self.app.data.radarr_data.movies.items.clone(), |movie| { - &movie.title + &movie.title.text }); self .app @@ -267,7 +267,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { } else { let selected_index = self.search_table( &self.app.data.radarr_data.filtered_movies.items.clone(), - |movie| &movie.title, + |movie| &movie.title.text, ); self .app @@ -288,7 +288,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { { let selected_index = self.search_table( &self.app.data.radarr_data.collections.items.clone(), - |collection| &collection.title, + |collection| &collection.title.text, ); self .app @@ -299,7 +299,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { } else { let selected_index = self.search_table( &self.app.data.radarr_data.filtered_collections.items.clone(), - |collection| &collection.title, + |collection| &collection.title.text, ); self .app @@ -312,7 +312,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { ActiveRadarrBlock::FilterMovies => { let filtered_movies = self .filter_table(&self.app.data.radarr_data.movies.items.clone(), |movie| { - &movie.title + &movie.title.text }); if !filtered_movies.is_empty() { @@ -327,7 +327,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { ActiveRadarrBlock::FilterCollections => { let filtered_collections = self.filter_table( &self.app.data.radarr_data.collections.items.clone(), - |collection| &collection.title, + |collection| &collection.title.text, ); if !filtered_collections.is_empty() { @@ -353,23 +353,23 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { self.app.pop_navigation_stack(); } - ActiveRadarrBlock::RefreshAllMoviesPrompt => { + ActiveRadarrBlock::UpdateAllMoviesPrompt => { if self.app.data.radarr_data.prompt_confirm { self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies); } self.app.pop_navigation_stack(); } - ActiveRadarrBlock::RefreshDownloadsPrompt => { + ActiveRadarrBlock::UpdateDownloadsPrompt => { if self.app.data.radarr_data.prompt_confirm { - self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::RefreshDownloads); + self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads); } self.app.pop_navigation_stack(); } - ActiveRadarrBlock::RefreshAllCollectionsPrompt => { + ActiveRadarrBlock::UpdateAllCollectionsPrompt => { if self.app.data.radarr_data.prompt_confirm { - self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::RefreshCollections); + self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections); } self.app.pop_navigation_stack(); @@ -392,9 +392,9 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { } ActiveRadarrBlock::DeleteMoviePrompt | ActiveRadarrBlock::DeleteDownloadPrompt - | ActiveRadarrBlock::RefreshAllMoviesPrompt - | ActiveRadarrBlock::RefreshAllCollectionsPrompt - | ActiveRadarrBlock::RefreshDownloadsPrompt => { + | ActiveRadarrBlock::UpdateAllMoviesPrompt + | ActiveRadarrBlock::UpdateAllCollectionsPrompt + | ActiveRadarrBlock::UpdateDownloadsPrompt => { self.app.pop_navigation_stack(); self.app.data.radarr_data.prompt_confirm = false; } @@ -441,18 +441,28 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { .push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into()); self.app.should_ignore_quit_key = true; } + _ if *key == DEFAULT_KEYBINDINGS.update.key => { + self + .app + .push_navigation_stack(ActiveRadarrBlock::UpdateAllMoviesPrompt.into()); + } _ if *key == DEFAULT_KEYBINDINGS.refresh.key => { self .app - .push_navigation_stack(ActiveRadarrBlock::RefreshAllMoviesPrompt.into()); + .pop_and_push_navigation_stack((*self.active_radarr_block).into()); } _ => (), }, ActiveRadarrBlock::Downloads => match self.key { + _ if *key == DEFAULT_KEYBINDINGS.update.key => { + self + .app + .push_navigation_stack(ActiveRadarrBlock::UpdateDownloadsPrompt.into()); + } _ if *key == DEFAULT_KEYBINDINGS.refresh.key => { self .app - .push_navigation_stack(ActiveRadarrBlock::RefreshDownloadsPrompt.into()); + .pop_and_push_navigation_stack((*self.active_radarr_block).into()); } _ => (), }, @@ -471,10 +481,15 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for RadarrHandler<'a> { self.app.data.radarr_data.is_filtering = true; self.app.should_ignore_quit_key = true; } + _ if *key == DEFAULT_KEYBINDINGS.update.key => { + self + .app + .push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into()); + } _ if *key == DEFAULT_KEYBINDINGS.refresh.key => { self .app - .push_navigation_stack(ActiveRadarrBlock::RefreshAllCollectionsPrompt.into()); + .pop_and_push_navigation_stack((*self.active_radarr_block).into()); } _ => (), }, @@ -614,6 +629,7 @@ mod tests { use crate::handlers::radarr_handlers::RadarrHandler; use crate::handlers::KeyEventHandler; use crate::models::radarr_models::{Collection, Movie}; + use crate::models::HorizontallyScrollableText; use crate::{extended_stateful_iterable_vec, test_handler_delegation}; mod test_handle_scroll_up_and_down { @@ -628,40 +644,44 @@ mod tests { test_collections_scroll, RadarrHandler, collections, - Collection, + simple_stateful_iterable_vec!(Collection, HorizontallyScrollableText), ActiveRadarrBlock::Collections, None, - title + title, + to_string ); test_iterable_scroll!( test_filtered_collections_scroll, RadarrHandler, filtered_collections, - Collection, + simple_stateful_iterable_vec!(Collection, HorizontallyScrollableText), ActiveRadarrBlock::Collections, None, - title + title, + to_string ); test_iterable_scroll!( test_movies_scroll, RadarrHandler, movies, - Movie, + simple_stateful_iterable_vec!(Movie, HorizontallyScrollableText), ActiveRadarrBlock::Movies, None, - title + title, + to_string ); test_iterable_scroll!( test_filtered_movies_scroll, RadarrHandler, filtered_movies, - Movie, + simple_stateful_iterable_vec!(Movie, HorizontallyScrollableText), ActiveRadarrBlock::Movies, None, - title + title, + to_string ); test_iterable_scroll!( @@ -689,40 +709,44 @@ mod tests { test_collections_home_end, RadarrHandler, collections, - Collection, + extended_stateful_iterable_vec!(Collection, HorizontallyScrollableText), ActiveRadarrBlock::Collections, None, - title + title, + to_string ); test_iterable_home_and_end!( test_filtered_collections_home_end, RadarrHandler, filtered_collections, - Collection, + extended_stateful_iterable_vec!(Collection, HorizontallyScrollableText), ActiveRadarrBlock::Collections, None, - title + title, + to_string ); test_iterable_home_and_end!( test_movies_home_end, RadarrHandler, movies, - Movie, + extended_stateful_iterable_vec!(Movie, HorizontallyScrollableText), ActiveRadarrBlock::Movies, None, - title + title, + to_string ); test_iterable_home_and_end!( test_filtered_movies_home_end, RadarrHandler, filtered_movies, - Movie, + extended_stateful_iterable_vec!(Movie, HorizontallyScrollableText), ActiveRadarrBlock::Movies, None, - title + title, + to_string ); test_iterable_home_and_end!( @@ -851,9 +875,9 @@ mod tests { #[values( ActiveRadarrBlock::DeleteMoviePrompt, ActiveRadarrBlock::DeleteDownloadPrompt, - ActiveRadarrBlock::RefreshAllMoviesPrompt, - ActiveRadarrBlock::RefreshAllCollectionsPrompt, - ActiveRadarrBlock::RefreshDownloadsPrompt + ActiveRadarrBlock::UpdateAllMoviesPrompt, + ActiveRadarrBlock::UpdateAllCollectionsPrompt, + ActiveRadarrBlock::UpdateDownloadsPrompt )] active_radarr_block: ActiveRadarrBlock, #[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key, @@ -917,7 +941,10 @@ mod tests { .data .radarr_data .movies - .set_items(extended_stateful_iterable_vec!(Movie)); + .set_items(extended_stateful_iterable_vec!( + Movie, + HorizontallyScrollableText + )); app.data.radarr_data.search = "Test 2".to_owned().into(); RadarrHandler::with( @@ -929,7 +956,7 @@ mod tests { .handle(); assert_str_eq!( - app.data.radarr_data.movies.current_selection().title, + app.data.radarr_data.movies.current_selection().title.text, "Test 2" ); } @@ -941,7 +968,10 @@ mod tests { .data .radarr_data .filtered_movies - .set_items(extended_stateful_iterable_vec!(Movie)); + .set_items(extended_stateful_iterable_vec!( + Movie, + HorizontallyScrollableText + )); app.data.radarr_data.search = "Test 2".to_owned().into(); RadarrHandler::with( @@ -958,7 +988,8 @@ mod tests { .radarr_data .filtered_movies .current_selection() - .title, + .title + .text, "Test 2" ); } @@ -970,7 +1001,10 @@ mod tests { .data .radarr_data .collections - .set_items(extended_stateful_iterable_vec!(Collection)); + .set_items(extended_stateful_iterable_vec!( + Collection, + HorizontallyScrollableText + )); app.data.radarr_data.search = "Test 2".to_owned().into(); RadarrHandler::with( @@ -982,7 +1016,13 @@ mod tests { .handle(); assert_str_eq!( - app.data.radarr_data.collections.current_selection().title, + app + .data + .radarr_data + .collections + .current_selection() + .title + .text, "Test 2" ); } @@ -994,7 +1034,10 @@ mod tests { .data .radarr_data .filtered_collections - .set_items(extended_stateful_iterable_vec!(Collection)); + .set_items(extended_stateful_iterable_vec!( + Collection, + HorizontallyScrollableText + )); app.data.radarr_data.search = "Test 2".to_owned().into(); RadarrHandler::with( @@ -1011,7 +1054,8 @@ mod tests { .radarr_data .filtered_collections .current_selection() - .title, + .title + .text, "Test 2" ); } @@ -1023,7 +1067,10 @@ mod tests { .data .radarr_data .movies - .set_items(extended_stateful_iterable_vec!(Movie)); + .set_items(extended_stateful_iterable_vec!( + Movie, + HorizontallyScrollableText + )); app.data.radarr_data.filter = "Test".to_owned().into(); RadarrHandler::with( @@ -1041,7 +1088,8 @@ mod tests { .radarr_data .filtered_movies .current_selection() - .title, + .title + .text, "Test 1" ); } @@ -1053,7 +1101,10 @@ mod tests { .data .radarr_data .collections - .set_items(extended_stateful_iterable_vec!(Collection)); + .set_items(extended_stateful_iterable_vec!( + Collection, + HorizontallyScrollableText + )); app.data.radarr_data.filter = "Test".to_owned().into(); RadarrHandler::with( @@ -1071,7 +1122,8 @@ mod tests { .radarr_data .filtered_collections .current_selection() - .title, + .title + .text, "Test 1" ); } @@ -1089,18 +1141,18 @@ mod tests { )] #[case( ActiveRadarrBlock::Movies, - ActiveRadarrBlock::RefreshAllMoviesPrompt, + ActiveRadarrBlock::UpdateAllMoviesPrompt, RadarrEvent::UpdateAllMovies )] #[case( ActiveRadarrBlock::Downloads, - ActiveRadarrBlock::RefreshDownloadsPrompt, - RadarrEvent::RefreshDownloads + ActiveRadarrBlock::UpdateDownloadsPrompt, + RadarrEvent::UpdateDownloads )] #[case( ActiveRadarrBlock::Collections, - ActiveRadarrBlock::RefreshAllCollectionsPrompt, - RadarrEvent::RefreshCollections + ActiveRadarrBlock::UpdateAllCollectionsPrompt, + RadarrEvent::UpdateCollections )] fn test_prompt_confirm_submit( #[case] base_route: ActiveRadarrBlock, @@ -1125,14 +1177,11 @@ mod tests { #[rstest] #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::DeleteMoviePrompt)] #[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::DeleteDownloadPrompt)] - #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::RefreshAllMoviesPrompt)] - #[case( - ActiveRadarrBlock::Downloads, - ActiveRadarrBlock::RefreshDownloadsPrompt - )] + #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::UpdateAllMoviesPrompt)] + #[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::UpdateDownloadsPrompt)] #[case( ActiveRadarrBlock::Collections, - ActiveRadarrBlock::RefreshAllCollectionsPrompt + ActiveRadarrBlock::UpdateAllCollectionsPrompt )] fn test_prompt_decline_submit( #[case] base_route: ActiveRadarrBlock, @@ -1203,15 +1252,12 @@ mod tests { #[rstest] #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::DeleteMoviePrompt)] - #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::RefreshAllMoviesPrompt)] + #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::UpdateAllMoviesPrompt)] #[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::DeleteDownloadPrompt)] - #[case( - ActiveRadarrBlock::Downloads, - ActiveRadarrBlock::RefreshDownloadsPrompt - )] + #[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::UpdateDownloadsPrompt)] #[case( ActiveRadarrBlock::Collections, - ActiveRadarrBlock::RefreshAllCollectionsPrompt + ActiveRadarrBlock::UpdateAllCollectionsPrompt )] fn test_prompt_blocks_esc( #[case] base_block: ActiveRadarrBlock, @@ -1337,21 +1383,40 @@ mod tests { } #[rstest] - #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::RefreshAllMoviesPrompt)] - #[case( - ActiveRadarrBlock::Downloads, - ActiveRadarrBlock::RefreshDownloadsPrompt - )] + #[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::UpdateAllMoviesPrompt)] + #[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::UpdateDownloadsPrompt)] #[case( ActiveRadarrBlock::Collections, - ActiveRadarrBlock::RefreshAllCollectionsPrompt + ActiveRadarrBlock::UpdateAllCollectionsPrompt )] - fn test_refresh_key( + fn test_update_key( #[case] active_radarr_block: ActiveRadarrBlock, #[case] expected_radarr_block: ActiveRadarrBlock, ) { let mut app = App::default(); + RadarrHandler::with( + &DEFAULT_KEYBINDINGS.update.key, + &mut app, + &active_radarr_block, + &None, + ) + .handle(); + + assert_eq!(app.get_current_route(), &expected_radarr_block.into()); + } + + #[rstest] + fn test_refresh_key( + #[values( + ActiveRadarrBlock::Movies, + ActiveRadarrBlock::Collections, + ActiveRadarrBlock::Downloads + )] + active_radarr_block: ActiveRadarrBlock, + ) { + let mut app = App::default(); + RadarrHandler::with( &DEFAULT_KEYBINDINGS.refresh.key, &mut app, @@ -1360,7 +1425,8 @@ mod tests { ) .handle(); - assert_eq!(app.get_current_route(), &expected_radarr_block.into()); + assert_eq!(app.get_current_route(), &active_radarr_block.into()); + assert!(app.is_routing); } #[rstest] @@ -1433,7 +1499,10 @@ mod tests { .data .radarr_data .movies - .set_items(extended_stateful_iterable_vec!(Movie)); + .set_items(extended_stateful_iterable_vec!( + Movie, + HorizontallyScrollableText + )); app.data.radarr_data.search = "Test 2".to_owned().into(); app.data.radarr_data.is_searching = true; app.should_ignore_quit_key = true; @@ -1447,7 +1516,7 @@ mod tests { &ActiveRadarrBlock::SearchMovie, &None, ) - .search_table(movies, |movie| &movie.title); + .search_table(movies, |movie| &movie.title.text); assert_eq!(index, Some(1)); assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into()); @@ -1463,7 +1532,10 @@ mod tests { .data .radarr_data .movies - .set_items(extended_stateful_iterable_vec!(Movie)); + .set_items(extended_stateful_iterable_vec!( + Movie, + HorizontallyScrollableText + )); app.data.radarr_data.search = "Test 5".to_owned().into(); app.data.radarr_data.is_searching = true; app.should_ignore_quit_key = true; @@ -1477,7 +1549,7 @@ mod tests { &ActiveRadarrBlock::SearchMovie, &None, ) - .search_table(movies, |movie| &movie.title); + .search_table(movies, |movie| &movie.title.text); assert_eq!(index, None); assert_eq!( @@ -1496,7 +1568,10 @@ mod tests { .data .radarr_data .movies - .set_items(extended_stateful_iterable_vec!(Movie)); + .set_items(extended_stateful_iterable_vec!( + Movie, + HorizontallyScrollableText + )); app.data.radarr_data.filter = "Test 2".to_owned().into(); app.data.radarr_data.is_searching = true; app.should_ignore_quit_key = true; @@ -1510,10 +1585,10 @@ mod tests { &ActiveRadarrBlock::FilterMovies, &None, ) - .filter_table(movies, |movie| &movie.title); + .filter_table(movies, |movie| &movie.title.text); assert_eq!(filter_matches.len(), 1); - assert_str_eq!(filter_matches[0].title, "Test 2"); + assert_str_eq!(filter_matches[0].title.text, "Test 2"); assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into()); assert!(!app.data.radarr_data.is_filtering); assert!(!app.should_ignore_quit_key); @@ -1527,7 +1602,10 @@ mod tests { .data .radarr_data .movies - .set_items(extended_stateful_iterable_vec!(Movie)); + .set_items(extended_stateful_iterable_vec!( + Movie, + HorizontallyScrollableText + )); app.data.radarr_data.filter = "Test 5".to_owned().into(); app.data.radarr_data.is_filtering = true; app.should_ignore_quit_key = true; @@ -1541,7 +1619,7 @@ mod tests { &ActiveRadarrBlock::FilterMovies, &None, ) - .filter_table(movies, |movie| &movie.title); + .filter_table(movies, |movie| &movie.title.text); assert!(filter_matches.is_empty()); assert_eq!( @@ -1590,7 +1668,7 @@ mod tests { ActiveRadarrBlock::Cast, ActiveRadarrBlock::Crew, ActiveRadarrBlock::AutomaticallySearchMoviePrompt, - ActiveRadarrBlock::RefreshAndScanPrompt, + ActiveRadarrBlock::UpdateAndScanPrompt, ActiveRadarrBlock::ManualSearch, ActiveRadarrBlock::ManualSearchConfirmPrompt )] diff --git a/src/handlers/radarr_handlers/movie_details_handler.rs b/src/handlers/radarr_handlers/movie_details_handler.rs index 8cce8dd..68bd0c9 100644 --- a/src/handlers/radarr_handlers/movie_details_handler.rs +++ b/src/handlers/radarr_handlers/movie_details_handler.rs @@ -127,7 +127,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for MovieDetailsHandler<'a> { _ => (), }, ActiveRadarrBlock::AutomaticallySearchMoviePrompt - | ActiveRadarrBlock::RefreshAndScanPrompt + | ActiveRadarrBlock::UpdateAndScanPrompt | ActiveRadarrBlock::ManualSearchConfirmPrompt => handle_prompt_toggle(self.app, self.key), _ => (), } @@ -143,9 +143,9 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for MovieDetailsHandler<'a> { self.app.pop_navigation_stack(); } - ActiveRadarrBlock::RefreshAndScanPrompt => { + ActiveRadarrBlock::UpdateAndScanPrompt => { if self.app.data.radarr_data.prompt_confirm { - self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::RefreshAndScan); + self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAndScan); } self.app.pop_navigation_stack(); @@ -201,7 +201,7 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for MovieDetailsHandler<'a> { self.app.data.radarr_data.reset_movie_info_tabs(); } ActiveRadarrBlock::AutomaticallySearchMoviePrompt - | ActiveRadarrBlock::RefreshAndScanPrompt + | ActiveRadarrBlock::UpdateAndScanPrompt | ActiveRadarrBlock::ManualSearchConfirmPrompt | ActiveRadarrBlock::ManualSearchSortPrompt => { self.app.pop_navigation_stack(); @@ -236,10 +236,15 @@ impl<'a> KeyEventHandler<'a, ActiveRadarrBlock> for MovieDetailsHandler<'a> { self.app.data.radarr_data.populate_edit_movie_fields(); self.app.data.radarr_data.selected_block = ActiveRadarrBlock::EditMovieToggleMonitored; } + _ if *key == DEFAULT_KEYBINDINGS.update.key => { + self + .app + .push_navigation_stack(ActiveRadarrBlock::UpdateAndScanPrompt.into()); + } _ if *key == DEFAULT_KEYBINDINGS.refresh.key => { self .app - .push_navigation_stack(ActiveRadarrBlock::RefreshAndScanPrompt.into()); + .pop_and_push_navigation_stack((*self.active_radarr_block).into()); } _ if *key == DEFAULT_KEYBINDINGS.sort.key => { self @@ -534,7 +539,7 @@ mod tests { fn test_left_right_prompt_toggle( #[values( ActiveRadarrBlock::AutomaticallySearchMoviePrompt, - ActiveRadarrBlock::RefreshAndScanPrompt, + ActiveRadarrBlock::UpdateAndScanPrompt, ActiveRadarrBlock::ManualSearchConfirmPrompt )] active_radarr_block: ActiveRadarrBlock, @@ -628,7 +633,7 @@ mod tests { ActiveRadarrBlock::AutomaticallySearchMoviePrompt, RadarrEvent::TriggerAutomaticSearch )] - #[case(ActiveRadarrBlock::RefreshAndScanPrompt, RadarrEvent::RefreshAndScan)] + #[case(ActiveRadarrBlock::UpdateAndScanPrompt, RadarrEvent::UpdateAndScan)] #[case( ActiveRadarrBlock::ManualSearchConfirmPrompt, RadarrEvent::DownloadRelease @@ -659,7 +664,7 @@ mod tests { fn test_movie_info_prompt_decline_submit( #[values( ActiveRadarrBlock::AutomaticallySearchMoviePrompt, - ActiveRadarrBlock::RefreshAndScanPrompt, + ActiveRadarrBlock::UpdateAndScanPrompt, ActiveRadarrBlock::ManualSearchConfirmPrompt )] prompt_block: ActiveRadarrBlock, @@ -748,7 +753,7 @@ mod tests { fn test_movie_info_prompts_esc( #[values( ActiveRadarrBlock::AutomaticallySearchMoviePrompt, - ActiveRadarrBlock::RefreshAndScanPrompt, + ActiveRadarrBlock::UpdateAndScanPrompt, ActiveRadarrBlock::ManualSearchConfirmPrompt, ActiveRadarrBlock::ManualSearchSortPrompt )] @@ -849,6 +854,34 @@ mod tests { ); } + #[rstest] + fn test_update_key( + #[values( + ActiveRadarrBlock::MovieDetails, + ActiveRadarrBlock::MovieHistory, + ActiveRadarrBlock::FileInfo, + ActiveRadarrBlock::Cast, + ActiveRadarrBlock::Crew, + ActiveRadarrBlock::ManualSearch + )] + active_radarr_block: ActiveRadarrBlock, + ) { + let mut app = App::default(); + + MovieDetailsHandler::with( + &DEFAULT_KEYBINDINGS.update.key, + &mut app, + &active_radarr_block, + &None, + ) + .handle(); + + assert_eq!( + app.get_current_route(), + &ActiveRadarrBlock::UpdateAndScanPrompt.into() + ); + } + #[rstest] fn test_refresh_key( #[values( @@ -871,10 +904,8 @@ mod tests { ) .handle(); - assert_eq!( - app.get_current_route(), - &ActiveRadarrBlock::RefreshAndScanPrompt.into() - ); + assert_eq!(app.get_current_route(), &active_radarr_block.into()); + assert!(app.is_routing); } } diff --git a/src/models/mod.rs b/src/models/mod.rs index bf22b84..ccf27e1 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -219,9 +219,8 @@ impl HorizontallyScrollableText { } pub fn scroll_left_or_reset(&self, width: usize, is_current_selection: bool, can_scroll: bool) { - if can_scroll { - if is_current_selection && self.text.len() >= width && *self.offset.borrow() < self.text.len() - { + if can_scroll && is_current_selection && self.text.len() >= width { + if *self.offset.borrow() < self.text.len() { self.scroll_left(); } else { self.reset_offset(); @@ -563,19 +562,19 @@ mod tests { horizontally_scrollable_text.scroll_left_or_reset(width, false, true); - assert_eq!(*horizontally_scrollable_text.offset.borrow(), 0); + assert_eq!(*horizontally_scrollable_text.offset.borrow(), 1); horizontally_scrollable_text.scroll_left_or_reset(width, true, false); - assert_eq!(*horizontally_scrollable_text.offset.borrow(), 0); + assert_eq!(*horizontally_scrollable_text.offset.borrow(), 1); horizontally_scrollable_text.scroll_left_or_reset(width, true, true); - assert_eq!(*horizontally_scrollable_text.offset.borrow(), 1); + assert_eq!(*horizontally_scrollable_text.offset.borrow(), 2); horizontally_scrollable_text.scroll_left_or_reset(test_text.len(), false, true); - assert_eq!(*horizontally_scrollable_text.offset.borrow(), 0); + assert_eq!(*horizontally_scrollable_text.offset.borrow(), 2); } #[test] diff --git a/src/models/radarr_models.rs b/src/models/radarr_models.rs index cda4329..29717cf 100644 --- a/src/models/radarr_models.rs +++ b/src/models/radarr_models.rs @@ -36,7 +36,7 @@ pub struct RootFolder { pub struct Movie { #[derivative(Default(value = "Number::from(0)"))] pub id: Number, - pub title: String, + pub title: HorizontallyScrollableText, pub original_language: Language, #[derivative(Default(value = "Number::from(0)"))] pub size_on_disk: Number, @@ -84,7 +84,7 @@ pub struct CollectionMovie { #[serde(rename_all = "camelCase")] pub struct Collection { #[serde(default)] - pub title: String, + pub title: HorizontallyScrollableText, pub root_folder_path: Option, pub search_on_add: bool, pub overview: Option, diff --git a/src/network/radarr_network.rs b/src/network/radarr_network.rs index ce68bab..cbdf7eb 100644 --- a/src/network/radarr_network.rs +++ b/src/network/radarr_network.rs @@ -37,12 +37,12 @@ pub enum RadarrEvent { GetStatus, GetTags, HealthCheck, - RefreshAndScan, - RefreshCollections, - RefreshDownloads, SearchNewMovie, TriggerAutomaticSearch, UpdateAllMovies, + UpdateAndScan, + UpdateCollections, + UpdateDownloads, } impl RadarrEvent { @@ -65,10 +65,10 @@ impl RadarrEvent { RadarrEvent::GetStatus => "/system/status", RadarrEvent::GetTags => "/tag", RadarrEvent::TriggerAutomaticSearch - | RadarrEvent::RefreshAndScan + | RadarrEvent::UpdateAndScan | RadarrEvent::UpdateAllMovies - | RadarrEvent::RefreshDownloads - | RadarrEvent::RefreshCollections => "/command", + | RadarrEvent::UpdateDownloads + | RadarrEvent::UpdateCollections => "/command", RadarrEvent::HealthCheck => "/health", } } @@ -101,12 +101,12 @@ impl<'a> Network<'a> { RadarrEvent::GetStatus => self.get_status().await, RadarrEvent::GetTags => self.get_tags().await, RadarrEvent::HealthCheck => self.get_healthcheck().await, - RadarrEvent::RefreshAndScan => self.refresh_and_scan().await, - RadarrEvent::RefreshCollections => self.refresh_collections().await, - RadarrEvent::RefreshDownloads => self.refresh_downloads().await, RadarrEvent::SearchNewMovie => self.search_movie().await, RadarrEvent::TriggerAutomaticSearch => self.trigger_automatic_search().await, RadarrEvent::UpdateAllMovies => self.update_all_movies().await, + RadarrEvent::UpdateAndScan => self.update_and_scan().await, + RadarrEvent::UpdateCollections => self.update_collections().await, + RadarrEvent::UpdateDownloads => self.update_downloads().await, } } @@ -258,9 +258,9 @@ impl<'a> Network<'a> { .await; } - async fn refresh_and_scan(&self) { + async fn update_and_scan(&self) { let movie_id = self.extract_movie_id().await; - info!("Refreshing and scanning movie with id: {}", movie_id); + info!("Updating and scanning movie with id: {}", movie_id); let body = MovieCommandBody { name: "RefreshMovie".to_owned(), movie_ids: vec![movie_id], @@ -268,7 +268,7 @@ impl<'a> Network<'a> { let request_props = self .radarr_request_props_from( - RadarrEvent::RefreshAndScan.resource(), + RadarrEvent::UpdateAndScan.resource(), RequestMethod::Post, Some(body), ) @@ -299,15 +299,15 @@ impl<'a> Network<'a> { .await; } - async fn refresh_downloads(&self) { - info!("Refreshing downloads"); + async fn update_downloads(&self) { + info!("Updating downloads"); let body = CommandBody { name: "RefreshMonitoredDownloads".to_owned(), }; let request_props = self .radarr_request_props_from( - RadarrEvent::RefreshDownloads.resource(), + RadarrEvent::UpdateDownloads.resource(), RequestMethod::Post, Some(body), ) @@ -318,15 +318,15 @@ impl<'a> Network<'a> { .await; } - async fn refresh_collections(&self) { - info!("Refreshing collections"); + async fn update_collections(&self) { + info!("Updating collections"); let body = CommandBody { name: "RefreshCollections".to_owned(), }; let request_props = self .radarr_request_props_from( - RadarrEvent::RefreshCollections.resource(), + RadarrEvent::UpdateCollections.resource(), RequestMethod::Post, Some(body), ) @@ -1176,10 +1176,10 @@ mod test { fn test_resource_command( #[values( RadarrEvent::TriggerAutomaticSearch, - RadarrEvent::RefreshAndScan, + RadarrEvent::UpdateAndScan, RadarrEvent::UpdateAllMovies, - RadarrEvent::RefreshDownloads, - RadarrEvent::RefreshCollections + RadarrEvent::UpdateDownloads, + RadarrEvent::UpdateCollections )] event: RadarrEvent, ) { @@ -1484,7 +1484,7 @@ mod test { } #[tokio::test] - async fn test_handle_refresh_and_scan_event() { + async fn test_handle_update_and_scan_event() { let (async_server, app_arc, _server) = mock_radarr_api( RequestMethod::Post, Some(json!({ @@ -1492,7 +1492,7 @@ mod test { "movieIds": [ 1 ] })), None, - RadarrEvent::RefreshAndScan.resource(), + RadarrEvent::UpdateAndScan.resource(), ) .await; app_arc @@ -1505,7 +1505,7 @@ mod test { let network = Network::new(reqwest::Client::new(), &app_arc); network - .handle_radarr_event(RadarrEvent::RefreshAndScan) + .handle_radarr_event(RadarrEvent::UpdateAndScan) .await; async_server.assert_async().await; @@ -1533,40 +1533,40 @@ mod test { } #[tokio::test] - async fn test_handle_refresh_downloads_event() { + async fn test_handle_update_downloads_event() { let (async_server, app_arc, _server) = mock_radarr_api( RequestMethod::Post, Some(json!({ "name": "RefreshMonitoredDownloads" })), None, - RadarrEvent::RefreshDownloads.resource(), + RadarrEvent::UpdateDownloads.resource(), ) .await; let network = Network::new(reqwest::Client::new(), &app_arc); network - .handle_radarr_event(RadarrEvent::RefreshDownloads) + .handle_radarr_event(RadarrEvent::UpdateDownloads) .await; async_server.assert_async().await; } #[tokio::test] - async fn test_handle_refresh_collections_event() { + async fn test_handle_update_collections_event() { let (async_server, app_arc, _server) = mock_radarr_api( RequestMethod::Post, Some(json!({ "name": "RefreshCollections" })), None, - RadarrEvent::RefreshCollections.resource(), + RadarrEvent::UpdateCollections.resource(), ) .await; let network = Network::new(reqwest::Client::new(), &app_arc); network - .handle_radarr_event(RadarrEvent::RefreshCollections) + .handle_radarr_event(RadarrEvent::UpdateCollections) .await; async_server.assert_async().await; @@ -2562,7 +2562,7 @@ mod test { fn collection() -> Collection { Collection { - title: "Test Collection".to_owned(), + title: "Test Collection".to_owned().into(), root_folder_path: None, search_on_add: true, overview: Some("Collection blah blah blah".to_owned()), @@ -2574,7 +2574,7 @@ mod test { fn movie() -> Movie { Movie { id: Number::from(1), - title: "Test".to_owned(), + title: "Test".to_owned().into(), original_language: language(), size_on_disk: Number::from(3543348019u64), status: "Downloaded".to_owned(), diff --git a/src/ui/mod.rs b/src/ui/mod.rs index e30740c..2c27313 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -92,9 +92,11 @@ fn draw_error(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { .style(style_failure()) .borders(Borders::ALL); - if app.error.text.len() > area.width as usize { - app.error.scroll_left(); - } + app.error.scroll_left_or_reset( + area.width as usize, + true, + app.tick_count % app.ticks_until_scroll == 0, + ); let mut text = Text::from(app.error.to_string()); text.patch_style(style_failure()); diff --git a/src/ui/radarr_ui/collection_details_ui.rs b/src/ui/radarr_ui/collection_details_ui.rs index 56fb106..5bab8a5 100644 --- a/src/ui/radarr_ui/collection_details_ui.rs +++ b/src/ui/radarr_ui/collection_details_ui.rs @@ -108,7 +108,7 @@ pub(super) fn draw_collection_details( .block(borderless_block()) .alignment(Alignment::Center); - f.render_widget(title_block(&collection_selection.title), content_area); + f.render_widget(title_block(&collection_selection.title.text), content_area); f.render_widget(description_paragraph, chunks[0]); f.render_widget(help_paragraph, chunks[2]); diff --git a/src/ui/radarr_ui/mod.rs b/src/ui/radarr_ui/mod.rs index a9529ea..417735f 100644 --- a/src/ui/radarr_ui/mod.rs +++ b/src/ui/radarr_ui/mod.rs @@ -15,7 +15,7 @@ use crate::app::radarr::{ }; use crate::app::App; use crate::logos::RADARR_LOGO; -use crate::models::radarr_models::{DiskSpace, DownloadRecord, Movie}; +use crate::models::radarr_models::{Collection, DiskSpace, DownloadRecord, Movie}; use crate::models::Route; use crate::ui::radarr_ui::add_movie_ui::draw_add_movie_search_popup; use crate::ui::radarr_ui::collection_details_ui::draw_collection_details_popup; @@ -123,26 +123,26 @@ pub(super) fn draw_radarr_ui(f: &mut Frame<'_, B>, app: &mut App, ar draw_downloads, draw_delete_download_prompt, ), - ActiveRadarrBlock::RefreshDownloadsPrompt => draw_prompt_popup_over( + ActiveRadarrBlock::UpdateDownloadsPrompt => draw_prompt_popup_over( f, app, content_rect, draw_downloads, - draw_refresh_downloads_prompt, + draw_update_downloads_prompt, ), - ActiveRadarrBlock::RefreshAllMoviesPrompt => draw_prompt_popup_over( + ActiveRadarrBlock::UpdateAllMoviesPrompt => draw_prompt_popup_over( f, app, content_rect, draw_library, - draw_refresh_all_movies_prompt, + draw_update_all_movies_prompt, ), - ActiveRadarrBlock::RefreshAllCollectionsPrompt => draw_prompt_popup_over( + ActiveRadarrBlock::UpdateAllCollectionsPrompt => draw_prompt_popup_over( f, app, content_rect, draw_collections, - draw_refresh_all_collections_prompt, + draw_update_all_collections_prompt, ), _ => (), } @@ -157,6 +157,18 @@ pub(super) fn draw_radarr_context_row(f: &mut Frame<'_, B>, app: &Ap } fn draw_library(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { + let current_selection = if !app.data.radarr_data.filtered_movies.items.is_empty() { + app + .data + .radarr_data + .filtered_movies + .current_selection() + .clone() + } else if !app.data.radarr_data.movies.items.is_empty() { + app.data.radarr_data.movies.current_selection().clone() + } else { + Movie::default() + }; let quality_profile_map = &app.data.radarr_data.quality_profile_map; let tags_map = &app.data.radarr_data.tags_map; let downloads_vec = &app.data.radarr_data.downloads.items; @@ -205,6 +217,11 @@ fn draw_library(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { .get_active_tab_contextual_help(), }, |movie| { + movie.title.scroll_left_or_reset( + get_width_from_percentage(area, 27), + *movie == current_selection, + app.tick_count % app.ticks_until_scroll == 0, + ); let monitored = if movie.monitored { "🏷" } else { "" }; let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap()); let file_size: f64 = convert_to_gb(movie.size_on_disk.as_u64().unwrap()); @@ -226,7 +243,7 @@ fn draw_library(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { .join(", "); Row::new(vec![ - Cell::from(movie.title.to_owned()), + Cell::from(movie.title.to_string()), Cell::from(movie.year.to_string()), Cell::from(movie.studio.to_string()), Cell::from(format!("{}h {}m", hours, minutes)), @@ -243,7 +260,7 @@ fn draw_library(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { ); } -fn draw_refresh_all_movies_prompt( +fn draw_update_all_movies_prompt( f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect, @@ -251,13 +268,13 @@ fn draw_refresh_all_movies_prompt( draw_prompt_box( f, prompt_area, - "Refresh All Movies", - "Do you want to refresh info and scan your disks for all of your movies?", + "Update All Movies", + "Do you want to update info and scan your disks for all of your movies?", &app.data.radarr_data.prompt_confirm, ); } -fn draw_refresh_downloads_prompt( +fn draw_update_downloads_prompt( f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect, @@ -265,13 +282,13 @@ fn draw_refresh_downloads_prompt( draw_prompt_box( f, prompt_area, - "Refresh Downloads", - "Do you want to refresh your downloads?", + "Update Downloads", + "Do you want to update your downloads?", &app.data.radarr_data.prompt_confirm, ); } -fn draw_refresh_all_collections_prompt( +fn draw_update_all_collections_prompt( f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect, @@ -279,8 +296,8 @@ fn draw_refresh_all_collections_prompt( draw_prompt_box( f, prompt_area, - "Refresh All Collections", - "Do you want to refresh all of your collections?", + "Update All Collections", + "Do you want to update all of your collections?", &app.data.radarr_data.prompt_confirm, ); } @@ -496,6 +513,18 @@ fn draw_downloads(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { } fn draw_collections(f: &mut Frame<'_, B>, app: &mut App, area: Rect) { + let current_selection = if !app.data.radarr_data.filtered_collections.items.is_empty() { + app + .data + .radarr_data + .filtered_collections + .current_selection() + .clone() + } else if !app.data.radarr_data.collections.items.is_empty() { + app.data.radarr_data.collections.current_selection().clone() + } else { + Collection::default() + }; let quality_profile_map = &app.data.radarr_data.quality_profile_map; let content = if !app.data.radarr_data.filtered_collections.items.is_empty() && !app.data.radarr_data.is_filtering @@ -526,9 +555,14 @@ fn draw_collections(f: &mut Frame<'_, B>, app: &mut App, area: Rect) }, |collection| { let number_of_movies = collection.movies.clone().unwrap_or_default().len(); + collection.title.scroll_left_or_reset( + get_width_from_percentage(area, 100 / 5), + *collection == current_selection, + app.tick_count % app.ticks_until_scroll == 0, + ); Row::new(vec![ - Cell::from(collection.title.to_owned()), + Cell::from(collection.title.to_string()), Cell::from(collection.search_on_add.to_string()), Cell::from(number_of_movies.to_string()), Cell::from(collection.root_folder_path.clone().unwrap_or_default()), diff --git a/src/ui/radarr_ui/movie_details_ui.rs b/src/ui/radarr_ui/movie_details_ui.rs index ab27f0f..c3f32c2 100644 --- a/src/ui/radarr_ui/movie_details_ui.rs +++ b/src/ui/radarr_ui/movie_details_ui.rs @@ -39,12 +39,12 @@ pub(super) fn draw_movie_info_popup(f: &mut Frame<'_, B>, app: &mut draw_movie_info, draw_search_movie_prompt, ), - ActiveRadarrBlock::RefreshAndScanPrompt => draw_prompt_popup_over( + ActiveRadarrBlock::UpdateAndScanPrompt => draw_prompt_popup_over( f, app, content_area, draw_movie_info, - draw_refresh_and_scan_prompt, + draw_update_and_scan_prompt, ), ActiveRadarrBlock::ManualSearchSortPrompt => draw_drop_down_popup( f, @@ -102,17 +102,13 @@ fn draw_search_movie_prompt(f: &mut Frame<'_, B>, app: &mut App, pro ); } -fn draw_refresh_and_scan_prompt( - f: &mut Frame<'_, B>, - app: &mut App, - prompt_area: Rect, -) { +fn draw_update_and_scan_prompt(f: &mut Frame<'_, B>, app: &mut App, prompt_area: Rect) { draw_prompt_box( f, prompt_area, - "Refresh and Scan", + "Update and Scan", format!( - "Do you want to trigger a refresh and disk scan for the movie: {}?", + "Do you want to trigger an update and disk scan for the movie: {}?", app.data.radarr_data.movies.current_selection().title ) .as_str(),