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