refactor(ui): Simplified the popup delegation so all future UI is easier to implement

This commit is contained in:
2024-12-11 15:08:52 -07:00
parent e9a30382a3
commit c09950d0af
59 changed files with 488 additions and 660 deletions
+8
View File
@@ -223,6 +223,14 @@ mod tests {
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetStatus.into() RadarrEvent::GetStatus.into()
); );
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetQualityProfiles.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetTags.into()
);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetMovies.into() RadarrEvent::GetMovies.into()
+21
View File
@@ -17,11 +17,23 @@ impl<'a> App<'a> {
.await; .await;
} }
ActiveRadarrBlock::Collections => { ActiveRadarrBlock::Collections => {
self
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
.await;
self self
.dispatch_network_event(RadarrEvent::GetCollections.into()) .dispatch_network_event(RadarrEvent::GetCollections.into())
.await; .await;
self
.dispatch_network_event(RadarrEvent::GetMovies.into())
.await;
} }
ActiveRadarrBlock::CollectionDetails => { ActiveRadarrBlock::CollectionDetails => {
self
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
.await;
self
.dispatch_network_event(RadarrEvent::GetTags.into())
.await;
self.is_loading = true; self.is_loading = true;
self.populate_movie_collection_table().await; self.populate_movie_collection_table().await;
self.is_loading = false; self.is_loading = false;
@@ -37,6 +49,12 @@ impl<'a> App<'a> {
.await; .await;
} }
ActiveRadarrBlock::Movies => { ActiveRadarrBlock::Movies => {
self
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
.await;
self
.dispatch_network_event(RadarrEvent::GetTags.into())
.await;
self self
.dispatch_network_event(RadarrEvent::GetMovies.into()) .dispatch_network_event(RadarrEvent::GetMovies.into())
.await; .await;
@@ -45,6 +63,9 @@ impl<'a> App<'a> {
.await; .await;
} }
ActiveRadarrBlock::Indexers => { ActiveRadarrBlock::Indexers => {
self
.dispatch_network_event(RadarrEvent::GetTags.into())
.await;
self self
.dispatch_network_event(RadarrEvent::GetIndexers.into()) .dispatch_network_event(RadarrEvent::GetIndexers.into())
.await; .await;
+2 -1
View File
@@ -77,7 +77,8 @@ pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
]; ];
pub static COLLECTION_DETAILS_CONTEXT_CLUES: [ContextClue; 2] = [ pub static COLLECTION_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [
(DEFAULT_KEYBINDINGS.submit, "show overview/add movie"), (DEFAULT_KEYBINDINGS.submit, "show overview/add movie"),
(DEFAULT_KEYBINDINGS.edit, "edit collection"),
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
]; ];
@@ -240,6 +240,11 @@ mod tests {
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap(); let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
assert_str_eq!(*description, "edit collection");
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc); assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc); assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
assert_eq!(collection_details_context_clues_iter.next(), None); assert_eq!(collection_details_context_clues_iter.next(), None);
+37 -1
View File
@@ -38,17 +38,25 @@ mod tests {
.await; .await;
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetQualityProfiles.into()
);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetCollections.into() RadarrEvent::GetCollections.into()
); );
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetMovies.into()
);
assert!(!app.data.radarr_data.prompt_confirm); assert!(!app.data.radarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0); assert_eq!(app.tick_count, 0);
} }
#[tokio::test] #[tokio::test]
async fn test_dispatch_by_collection_details_block() { async fn test_dispatch_by_collection_details_block() {
let (mut app, _) = construct_app_unit(); let (mut app, mut sync_network_rx) = construct_app_unit();
app.data.radarr_data.collections.set_items(vec![Collection { app.data.radarr_data.collections.set_items(vec![Collection {
movies: Some(vec![CollectionMovie::default()]), movies: Some(vec![CollectionMovie::default()]),
@@ -60,6 +68,14 @@ mod tests {
.await; .await;
assert!(!app.is_loading); assert!(!app.is_loading);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetQualityProfiles.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetTags.into()
);
assert!(!app.data.radarr_data.collection_movies.items.is_empty()); assert!(!app.data.radarr_data.collection_movies.items.is_empty());
assert_eq!(app.tick_count, 0); assert_eq!(app.tick_count, 0);
assert!(!app.data.radarr_data.prompt_confirm); assert!(!app.data.radarr_data.prompt_confirm);
@@ -80,6 +96,14 @@ mod tests {
.await; .await;
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetQualityProfiles.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetTags.into()
);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
RadarrEvent::AddMovie(None).into() RadarrEvent::AddMovie(None).into()
@@ -132,6 +156,14 @@ mod tests {
.await; .await;
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetQualityProfiles.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetTags.into()
);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetMovies.into() RadarrEvent::GetMovies.into()
@@ -153,6 +185,10 @@ mod tests {
.await; .await;
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetTags.into()
);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
RadarrEvent::GetIndexers.into() RadarrEvent::GetIndexers.into()
+12
View File
@@ -15,6 +15,15 @@ impl<'a> App<'a> {
pub(super) async fn dispatch_by_sonarr_block(&mut self, active_sonarr_block: &ActiveSonarrBlock) { pub(super) async fn dispatch_by_sonarr_block(&mut self, active_sonarr_block: &ActiveSonarrBlock) {
match active_sonarr_block { match active_sonarr_block {
ActiveSonarrBlock::Series => { ActiveSonarrBlock::Series => {
self
.dispatch_network_event(SonarrEvent::GetQualityProfiles.into())
.await;
self
.dispatch_network_event(SonarrEvent::GetLanguageProfiles.into())
.await;
self
.dispatch_network_event(SonarrEvent::GetTags.into())
.await;
self self
.dispatch_network_event(SonarrEvent::ListSeries.into()) .dispatch_network_event(SonarrEvent::ListSeries.into())
.await; .await;
@@ -89,6 +98,9 @@ impl<'a> App<'a> {
.await; .await;
} }
ActiveSonarrBlock::Indexers => { ActiveSonarrBlock::Indexers => {
self
.dispatch_network_event(SonarrEvent::GetTags.into())
.await;
self self
.dispatch_network_event(SonarrEvent::GetIndexers.into()) .dispatch_network_event(SonarrEvent::GetIndexers.into())
.await; .await;
+16
View File
@@ -257,6 +257,18 @@ mod tests {
.await; .await;
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetQualityProfiles.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetLanguageProfiles.into()
);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetTags.into()
);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::ListSeries.into() SonarrEvent::ListSeries.into()
@@ -274,6 +286,10 @@ mod tests {
.await; .await;
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!(
sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetTags.into()
);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetIndexers.into() SonarrEvent::GetIndexers.into()
@@ -369,7 +369,7 @@ mod tests {
test_edit_collection_key!( test_edit_collection_key!(
CollectionDetailsHandler, CollectionDetailsHandler,
ActiveRadarrBlock::CollectionDetails, ActiveRadarrBlock::CollectionDetails,
ActiveRadarrBlock::CollectionDetails Some(ActiveRadarrBlock::CollectionDetails)
); );
} }
@@ -449,7 +449,11 @@ mod tests {
#[test] #[test]
fn test_collection_search_box_left_right_keys() { fn test_collection_search_box_left_right_keys() {
let mut app = App::default(); let mut app = App::default();
app.data.radarr_data.collections.set_items(vec![Collection::default()]); app
.data
.radarr_data
.collections
.set_items(vec![Collection::default()]);
app.push_navigation_stack(ActiveRadarrBlock::SearchCollection.into()); app.push_navigation_stack(ActiveRadarrBlock::SearchCollection.into());
app.data.radarr_data.collections.search = Some("Test".into()); app.data.radarr_data.collections.search = Some("Test".into());
@@ -499,7 +503,11 @@ mod tests {
#[test] #[test]
fn test_collection_filter_box_left_right_keys() { fn test_collection_filter_box_left_right_keys() {
let mut app = App::default(); let mut app = App::default();
app.data.radarr_data.collections.set_items(vec![Collection::default()]); app
.data
.radarr_data
.collections
.set_items(vec![Collection::default()]);
app.push_navigation_stack(ActiveRadarrBlock::FilterCollections.into()); app.push_navigation_stack(ActiveRadarrBlock::FilterCollections.into());
app.data.radarr_data.collections.filter = Some("Test".into()); app.data.radarr_data.collections.filter = Some("Test".into());
@@ -938,7 +946,11 @@ mod tests {
filtered_state: Some(TableState::default()), filtered_state: Some(TableState::default()),
..StatefulTable::default() ..StatefulTable::default()
}; };
app.data.radarr_data.collections.set_items(vec![Collection::default()]); app
.data
.radarr_data
.collections
.set_items(vec![Collection::default()]);
CollectionsHandler::with(ESC_KEY, &mut app, active_radarr_block, None).handle(); CollectionsHandler::with(ESC_KEY, &mut app, active_radarr_block, None).handle();
@@ -977,7 +989,11 @@ mod tests {
#[test] #[test]
fn test_collections_sort_prompt_block_esc() { fn test_collections_sort_prompt_block_esc() {
let mut app = App::default(); let mut app = App::default();
app.data.radarr_data.collections.set_items(vec![Collection::default()]); app
.data
.radarr_data
.collections
.set_items(vec![Collection::default()]);
app.push_navigation_stack(ActiveRadarrBlock::Collections.into()); app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
app.push_navigation_stack(ActiveRadarrBlock::CollectionsSortPrompt.into()); app.push_navigation_stack(ActiveRadarrBlock::CollectionsSortPrompt.into());
@@ -1174,11 +1190,7 @@ mod tests {
#[test] #[test]
fn test_collection_edit_key() { fn test_collection_edit_key() {
test_edit_collection_key!( test_edit_collection_key!(CollectionsHandler, ActiveRadarrBlock::Collections, None);
CollectionsHandler,
ActiveRadarrBlock::Collections,
ActiveRadarrBlock::Collections
);
} }
#[test] #[test]
@@ -151,13 +151,9 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
match self.active_radarr_block { match self.active_radarr_block {
ActiveRadarrBlock::Collections => match self.key { ActiveRadarrBlock::Collections => match self.key {
_ if key == DEFAULT_KEYBINDINGS.edit.key => { _ if key == DEFAULT_KEYBINDINGS.edit.key => {
self.app.push_navigation_stack( self
( .app
ActiveRadarrBlock::EditCollectionPrompt, .push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
Some(ActiveRadarrBlock::Collections),
)
.into(),
);
self.app.data.radarr_data.edit_collection_modal = self.app.data.radarr_data.edit_collection_modal =
Some((&self.app.data.radarr_data).into()); Some((&self.app.data.radarr_data).into());
self.app.data.radarr_data.selected_block = self.app.data.radarr_data.selected_block =
@@ -424,14 +424,14 @@ mod tests {
fn test_test_indexer_esc(#[values(true, false)] is_ready: bool) { fn test_test_indexer_esc(#[values(true, false)] is_ready: bool) {
let mut app = App::default(); let mut app = App::default();
app.is_loading = is_ready; app.is_loading = is_ready;
app.data.radarr_data.indexer_test_error = Some("test result".to_owned()); app.data.radarr_data.indexer_test_errors = Some("test result".to_owned());
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into()); app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into()); app.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
IndexersHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::TestIndexer, None).handle(); IndexersHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::TestIndexer, None).handle();
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into()); assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
assert_eq!(app.data.radarr_data.indexer_test_error, None); assert_eq!(app.data.radarr_data.indexer_test_errors, None);
} }
#[rstest] #[rstest]
+1 -1
View File
@@ -154,7 +154,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
} }
ActiveRadarrBlock::TestIndexer => { ActiveRadarrBlock::TestIndexer => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.radarr_data.indexer_test_error = None; self.app.data.radarr_data.indexer_test_errors = None;
} }
_ => handle_clear_errors(self.app), _ => handle_clear_errors(self.app),
} }
@@ -141,7 +141,7 @@ mod utils {
assert_eq!( assert_eq!(
app.get_current_route(), app.get_current_route(),
(ActiveRadarrBlock::EditCollectionPrompt, Some($context)).into() (ActiveRadarrBlock::EditCollectionPrompt, $context).into()
); );
assert_eq!( assert_eq!(
app.data.radarr_data.selected_block.get_active_block(), app.data.radarr_data.selected_block.get_active_block(),
@@ -432,14 +432,14 @@ mod tests {
fn test_test_indexer_esc(#[values(true, false)] is_ready: bool) { fn test_test_indexer_esc(#[values(true, false)] is_ready: bool) {
let mut app = App::default(); let mut app = App::default();
app.is_loading = is_ready; app.is_loading = is_ready;
app.data.sonarr_data.indexer_test_error = Some("test result".to_owned()); app.data.sonarr_data.indexer_test_errors = Some("test result".to_owned());
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into()); app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
app.push_navigation_stack(ActiveSonarrBlock::TestIndexer.into()); app.push_navigation_stack(ActiveSonarrBlock::TestIndexer.into());
IndexersHandler::with(ESC_KEY, &mut app, ActiveSonarrBlock::TestIndexer, None).handle(); IndexersHandler::with(ESC_KEY, &mut app, ActiveSonarrBlock::TestIndexer, None).handle();
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into()); assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
assert_eq!(app.data.sonarr_data.indexer_test_error, None); assert_eq!(app.data.sonarr_data.indexer_test_errors, None);
} }
#[rstest] #[rstest]
+1 -1
View File
@@ -154,7 +154,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexersHandler<'a,
} }
ActiveSonarrBlock::TestIndexer => { ActiveSonarrBlock::TestIndexer => {
self.app.pop_navigation_stack(); self.app.pop_navigation_stack();
self.app.data.sonarr_data.indexer_test_error = None; self.app.data.sonarr_data.indexer_test_errors = None;
} }
_ => handle_clear_errors(self.app), _ => handle_clear_errors(self.app),
} }
+6 -3
View File
@@ -59,9 +59,12 @@ macro_rules! handle_table_events {
{ {
$self.[<handle_ $name _table_filter_box_input>]() $self.[<handle_ $name _table_filter_box_input>]()
} }
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.filter.key => $self.[<handle_ $name _table_filter_key>](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.filter.key
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.search.key => $self.[<handle_ $name _table_search_key>](props), && props.filtering_block.is_some() => $self.[<handle_ $name _table_filter_key>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.sort.key => $self.[<handle_ $name _table_sort_key>](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.search.key
&& props.searching_block.is_some() => $self.[<handle_ $name _table_search_key>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.sort.key
&& props.sorting_block.is_some() => $self.[<handle_ $name _table_sort_key>](props),
_ => false, _ => false,
} }
} else { } else {
@@ -62,7 +62,7 @@ pub struct RadarrData<'a> {
pub edit_indexer_modal: Option<EditIndexerModal>, pub edit_indexer_modal: Option<EditIndexerModal>,
pub edit_root_folder: Option<HorizontallyScrollableText>, pub edit_root_folder: Option<HorizontallyScrollableText>,
pub indexer_settings: Option<IndexerSettings>, pub indexer_settings: Option<IndexerSettings>,
pub indexer_test_error: Option<String>, pub indexer_test_errors: Option<String>,
pub indexer_test_all_results: Option<StatefulTable<IndexerTestResultModalItem>>, pub indexer_test_all_results: Option<StatefulTable<IndexerTestResultModalItem>>,
pub movie_details_modal: Option<MovieDetailsModal>, pub movie_details_modal: Option<MovieDetailsModal>,
pub prompt_confirm: bool, pub prompt_confirm: bool,
@@ -112,7 +112,7 @@ impl<'a> Default for RadarrData<'a> {
edit_indexer_modal: None, edit_indexer_modal: None,
edit_root_folder: None, edit_root_folder: None,
indexer_settings: None, indexer_settings: None,
indexer_test_error: None, indexer_test_errors: None,
indexer_test_all_results: None, indexer_test_all_results: None,
movie_details_modal: None, movie_details_modal: None,
prompt_confirm: false, prompt_confirm: false,
@@ -92,7 +92,7 @@ mod tests {
assert!(radarr_data.edit_root_folder.is_none()); assert!(radarr_data.edit_root_folder.is_none());
assert!(radarr_data.edit_indexer_modal.is_none()); assert!(radarr_data.edit_indexer_modal.is_none());
assert!(radarr_data.indexer_settings.is_none()); assert!(radarr_data.indexer_settings.is_none());
assert!(radarr_data.indexer_test_error.is_none()); assert!(radarr_data.indexer_test_errors.is_none());
assert!(radarr_data.indexer_test_all_results.is_none()); assert!(radarr_data.indexer_test_all_results.is_none());
assert!(radarr_data.movie_details_modal.is_none()); assert!(radarr_data.movie_details_modal.is_none());
assert!(radarr_data.prompt_confirm_action.is_none()); assert!(radarr_data.prompt_confirm_action.is_none());
@@ -53,7 +53,7 @@ pub struct SonarrData<'a> {
pub indexers: StatefulTable<Indexer>, pub indexers: StatefulTable<Indexer>,
pub indexer_settings: Option<IndexerSettings>, pub indexer_settings: Option<IndexerSettings>,
pub indexer_test_all_results: Option<StatefulTable<IndexerTestResultModalItem>>, pub indexer_test_all_results: Option<StatefulTable<IndexerTestResultModalItem>>,
pub indexer_test_error: Option<String>, pub indexer_test_errors: Option<String>,
pub language_profiles_map: BiMap<i64, String>, pub language_profiles_map: BiMap<i64, String>,
pub logs: StatefulList<HorizontallyScrollableText>, pub logs: StatefulList<HorizontallyScrollableText>,
pub log_details: StatefulList<HorizontallyScrollableText>, pub log_details: StatefulList<HorizontallyScrollableText>,
@@ -106,7 +106,7 @@ impl<'a> Default for SonarrData<'a> {
history: StatefulTable::default(), history: StatefulTable::default(),
indexers: StatefulTable::default(), indexers: StatefulTable::default(),
indexer_settings: None, indexer_settings: None,
indexer_test_error: None, indexer_test_errors: None,
indexer_test_all_results: None, indexer_test_all_results: None,
language_profiles_map: BiMap::new(), language_profiles_map: BiMap::new(),
logs: StatefulList::default(), logs: StatefulList::default(),
@@ -95,7 +95,7 @@ mod tests {
assert!(sonarr_data.history.is_empty()); assert!(sonarr_data.history.is_empty());
assert!(sonarr_data.indexers.is_empty()); assert!(sonarr_data.indexers.is_empty());
assert!(sonarr_data.indexer_settings.is_none()); assert!(sonarr_data.indexer_settings.is_none());
assert!(sonarr_data.indexer_test_error.is_none()); assert!(sonarr_data.indexer_test_errors.is_none());
assert!(sonarr_data.indexer_test_all_results.is_none()); assert!(sonarr_data.indexer_test_all_results.is_none());
assert!(sonarr_data.language_profiles_map.is_empty()); assert!(sonarr_data.language_profiles_map.is_empty());
assert!(sonarr_data.logs.is_empty()); assert!(sonarr_data.logs.is_empty());
+7 -3
View File
@@ -2102,12 +2102,16 @@ impl<'a, 'b> Network<'a, 'b> {
self self
.handle_request::<Value, Value>(request_props, |test_results, mut app| { .handle_request::<Value, Value>(request_props, |test_results, mut app| {
if test_results.as_object().is_none() { if test_results.as_object().is_none() {
app.data.radarr_data.indexer_test_error = Some( app.data.radarr_data.indexer_test_errors = Some(
test_results.as_array().unwrap()[0] test_results
.as_array()
.unwrap()[0]
.get("errorMessage") .get("errorMessage")
.unwrap() .unwrap()
.to_string(), .to_string()
); );
} else {
app.data.radarr_data.indexer_test_errors = Some(String::new());
}; };
}) })
.await .await
+3 -3
View File
@@ -931,7 +931,7 @@ mod test {
async_details_server.assert_async().await; async_details_server.assert_async().await;
async_test_server.assert_async().await; async_test_server.assert_async().await;
assert_eq!( assert_eq!(
app_arc.lock().await.data.radarr_data.indexer_test_error, app_arc.lock().await.data.radarr_data.indexer_test_errors,
Some("\"test failure\"".to_owned()) Some("\"test failure\"".to_owned())
); );
assert_eq!(value, response_json) assert_eq!(value, response_json)
@@ -1000,8 +1000,8 @@ mod test {
async_details_server.assert_async().await; async_details_server.assert_async().await;
async_test_server.assert_async().await; async_test_server.assert_async().await;
assert_eq!( assert_eq!(
app_arc.lock().await.data.radarr_data.indexer_test_error, app_arc.lock().await.data.radarr_data.indexer_test_errors,
None Some(String::new())
); );
assert_eq!(value, json!({})); assert_eq!(value, json!({}));
} }
+3 -1
View File
@@ -2368,12 +2368,14 @@ impl<'a, 'b> Network<'a, 'b> {
self self
.handle_request::<Value, Value>(request_props, |test_results, mut app| { .handle_request::<Value, Value>(request_props, |test_results, mut app| {
if test_results.as_object().is_none() { if test_results.as_object().is_none() {
app.data.sonarr_data.indexer_test_error = Some( app.data.sonarr_data.indexer_test_errors = Some(
test_results.as_array().unwrap()[0] test_results.as_array().unwrap()[0]
.get("errorMessage") .get("errorMessage")
.unwrap() .unwrap()
.to_string(), .to_string(),
); );
} else {
app.data.sonarr_data.indexer_test_errors = Some(String::new());
}; };
}) })
.await .await
+3 -3
View File
@@ -6302,7 +6302,7 @@ mod test {
async_details_server.assert_async().await; async_details_server.assert_async().await;
async_test_server.assert_async().await; async_test_server.assert_async().await;
assert_eq!( assert_eq!(
app_arc.lock().await.data.sonarr_data.indexer_test_error, app_arc.lock().await.data.sonarr_data.indexer_test_errors,
Some("\"test failure\"".to_owned()) Some("\"test failure\"".to_owned())
); );
assert_eq!(value, response_json) assert_eq!(value, response_json)
@@ -6371,8 +6371,8 @@ mod test {
async_details_server.assert_async().await; async_details_server.assert_async().await;
async_test_server.assert_async().await; async_test_server.assert_async().await;
assert_eq!( assert_eq!(
app_arc.lock().await.data.sonarr_data.indexer_test_error, app_arc.lock().await.data.sonarr_data.indexer_test_errors,
None Some(String::new())
); );
assert_eq!(value, json!({})); assert_eq!(value, json!({}));
} }
-33
View File
@@ -128,39 +128,6 @@ pub fn draw_popup(
popup_fn(f, app, popup_area); popup_fn(f, app, popup_area);
} }
fn draw_popup_ui<T: DrawUi>(f: &mut Frame<'_>, app: &mut App<'_>, size: Size) {
let (percent_x, percent_y) = size.to_percent();
let popup_area = centered_rect(percent_x, percent_y, f.area());
f.render_widget(Clear, popup_area);
f.render_widget(background_block(), popup_area);
T::draw(f, app, popup_area);
}
pub fn draw_popup_over(
f: &mut Frame<'_>,
app: &mut App<'_>,
area: Rect,
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
popup_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
size: Size,
) {
background_fn(f, app, area);
draw_popup(f, app, popup_fn, size);
}
pub fn draw_popup_over_ui<T: DrawUi>(
f: &mut Frame<'_>,
app: &mut App<'_>,
area: Rect,
background_fn: impl Fn(&mut Frame<'_>, &mut App<'_>, Rect),
size: Size,
) {
background_fn(f, app, area);
draw_popup_ui::<T>(f, app, size);
}
fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -> Rect { fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -> Rect {
if title.is_empty() { if title.is_empty() {
f.render_widget(layout_block(), area); f.render_widget(layout_block(), area);
+3 -7
View File
@@ -32,12 +32,10 @@ impl DrawUi for BlocklistUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() { if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
match active_radarr_block {
ActiveRadarrBlock::Blocklist | ActiveRadarrBlock::BlocklistSortPrompt => {
draw_blocklist_table(f, app, area)
}
ActiveRadarrBlock::BlocklistItemDetails => {
draw_blocklist_table(f, app, area); draw_blocklist_table(f, app, area);
match active_radarr_block {
ActiveRadarrBlock::BlocklistItemDetails => {
draw_blocklist_item_details_popup(f, app); draw_blocklist_item_details_popup(f, app);
} }
ActiveRadarrBlock::DeleteBlocklistItemPrompt => { ActiveRadarrBlock::DeleteBlocklistItemPrompt => {
@@ -55,7 +53,6 @@ impl DrawUi for BlocklistUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_blocklist_table(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
@@ -67,7 +64,6 @@ impl DrawUi for BlocklistUi {
.prompt("Do you want to clear your blocklist?") .prompt("Do you want to clear your blocklist?")
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_blocklist_table(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::SmallPrompt), Popup::new(confirmation_prompt).size(Size::SmallPrompt),
f.area(), f.area(),
@@ -12,7 +12,6 @@ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS,
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::{EnumDisplayStyle, Route};
use crate::ui::radarr_ui::collections::draw_collections;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block_top_border_with_title, title_block, borderless_block, get_width_from_percentage, layout_block_top_border_with_title, title_block,
@@ -20,7 +19,7 @@ use crate::ui::utils::{
}; };
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use crate::utils::convert_runtime; use crate::utils::convert_runtime;
#[cfg(test)] #[cfg(test)]
@@ -31,41 +30,25 @@ pub(super) struct CollectionDetailsUi;
impl DrawUi for CollectionDetailsUi { impl DrawUi for CollectionDetailsUi {
fn accepts(route: Route) -> bool { fn accepts(route: Route) -> bool {
if let Route::Radarr(active_radarr_block, _) = route { if let Route::Radarr(active_radarr_block, context_option) = route {
if let Some(context) = context_option {
return COLLECTION_DETAILS_BLOCKS.contains(&active_radarr_block)
&& context == ActiveRadarrBlock::CollectionDetails;
}
return COLLECTION_DETAILS_BLOCKS.contains(&active_radarr_block); return COLLECTION_DETAILS_BLOCKS.contains(&active_radarr_block);
} }
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() { if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() {
let draw_collection_details_popup = draw_popup(f, app, draw_collection_details, Size::Large);
|f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect| match context_option
.unwrap_or(active_radarr_block)
{
ActiveRadarrBlock::ViewMovieOverview => {
draw_popup_over(
f,
app,
popup_area,
draw_collection_details,
draw_movie_overview,
Size::Small,
);
}
ActiveRadarrBlock::CollectionDetails => draw_collection_details(f, app, popup_area),
_ => (),
};
draw_popup_over( if context_option.unwrap_or(active_radarr_block) == ActiveRadarrBlock::ViewMovieOverview {
f, draw_popup(f, app, draw_movie_overview, Size::Small);
app, }
area,
draw_collections,
draw_collection_details_popup,
Size::Large,
);
} }
} }
} }
@@ -17,5 +17,7 @@ mod tests {
assert!(!CollectionDetailsUi::accepts(active_radarr_block.into())); assert!(!CollectionDetailsUi::accepts(active_radarr_block.into()));
} }
}); });
assert!(CollectionDetailsUi::accepts((ActiveRadarrBlock::CollectionDetails, Some(ActiveRadarrBlock::CollectionDetails)).into()));
} }
} }
@@ -1,9 +1,8 @@
use std::sync::atomic::Ordering;
use ratatui::layout::{Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{ListItem, Paragraph}; use ratatui::widgets::{ListItem, Paragraph};
use ratatui::Frame; use ratatui::Frame;
use std::sync::atomic::Ordering;
use crate::app::context_clues::{build_context_clue_string, CONFIRMATION_PROMPT_CONTEXT_CLUES}; use crate::app::context_clues::{build_context_clue_string, CONFIRMATION_PROMPT_CONTEXT_CLUES};
use crate::app::App; use crate::app::App;
@@ -14,7 +13,6 @@ use crate::models::servarr_data::radarr::radarr_data::{
use crate::models::{EnumDisplayStyle, Route}; use crate::models::{EnumDisplayStyle, Route};
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi; use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi;
use crate::ui::radarr_ui::collections::draw_collections;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered}; use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
@@ -22,7 +20,7 @@ use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use crate::ui::{draw_popup, draw_popup_over, draw_popup_over_ui, DrawUi}; use crate::ui::{draw_popup, DrawUi};
#[cfg(test)] #[cfg(test)]
#[path = "edit_collection_ui_tests.rs"] #[path = "edit_collection_ui_tests.rs"]
@@ -32,51 +30,42 @@ pub(super) struct EditCollectionUi;
impl DrawUi for EditCollectionUi { impl DrawUi for EditCollectionUi {
fn accepts(route: Route) -> bool { fn accepts(route: Route) -> bool {
if let Route::Radarr(active_radarr_block, _) = route { if let Route::Radarr(active_radarr_block, context_option) = route {
if let Some(context) = context_option {
return EDIT_COLLECTION_BLOCKS.contains(&active_radarr_block)
&& context == ActiveRadarrBlock::CollectionDetails;
}
return EDIT_COLLECTION_BLOCKS.contains(&active_radarr_block); return EDIT_COLLECTION_BLOCKS.contains(&active_radarr_block);
} }
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() { if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() {
let draw_edit_collection_prompt = if let Some(context) = context_option {
|f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect| match active_radarr_block { if COLLECTION_DETAILS_BLOCKS.contains(&context) {
draw_popup(f, app, CollectionDetailsUi::draw, Size::Large);
}
}
draw_popup(
f,
app,
draw_edit_collection_confirmation_prompt,
Size::Medium,
);
match active_radarr_block {
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability => { ActiveRadarrBlock::EditCollectionSelectMinimumAvailability => {
draw_edit_collection_confirmation_prompt(f, app, prompt_area);
draw_edit_collection_select_minimum_availability_popup(f, app); draw_edit_collection_select_minimum_availability_popup(f, app);
} }
ActiveRadarrBlock::EditCollectionSelectQualityProfile => { ActiveRadarrBlock::EditCollectionSelectQualityProfile => {
draw_edit_collection_confirmation_prompt(f, app, prompt_area);
draw_edit_collection_select_quality_profile_popup(f, app); draw_edit_collection_select_quality_profile_popup(f, app);
} }
ActiveRadarrBlock::EditCollectionPrompt
| ActiveRadarrBlock::EditCollectionToggleMonitored
| ActiveRadarrBlock::EditCollectionRootFolderPathInput
| ActiveRadarrBlock::EditCollectionToggleSearchOnAdd => {
draw_edit_collection_confirmation_prompt(f, app, prompt_area)
}
_ => (), _ => (),
}; };
if let Some(context) = context_option {
match context {
ActiveRadarrBlock::Collections => draw_popup_over(
f,
app,
area,
draw_collections,
draw_edit_collection_prompt,
Size::Medium,
),
_ if COLLECTION_DETAILS_BLOCKS.contains(&context) => {
draw_popup_over_ui::<CollectionDetailsUi>(f, app, area, draw_collections, Size::Large);
draw_popup(f, app, draw_edit_collection_prompt, Size::Medium);
}
_ => (),
}
}
} }
} }
} }
@@ -16,6 +16,8 @@ mod tests {
} else { } else {
assert!(!EditCollectionUi::accepts(active_radarr_block.into())); assert!(!EditCollectionUi::accepts(active_radarr_block.into()));
} }
}) });
assert!(EditCollectionUi::accepts((ActiveRadarrBlock::EditCollectionPrompt, Some(ActiveRadarrBlock::CollectionDetails)).into()));
} }
} }
+11 -23
View File
@@ -2,8 +2,6 @@ use ratatui::layout::{Constraint, Rect};
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
use ratatui::Frame; use ratatui::Frame;
pub(super) use collection_details_ui::draw_collection_details;
use crate::app::App; use crate::app::App;
use crate::models::radarr_models::Collection; use crate::models::radarr_models::Collection;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, COLLECTIONS_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, COLLECTIONS_BLOCKS};
@@ -38,37 +36,23 @@ impl DrawUi for CollectionsUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let route = app.get_current_route(); let route = app.get_current_route();
let mut collections_ui_matcher = |active_radarr_block| match active_radarr_block { draw_collections(f, app, area);
ActiveRadarrBlock::Collections
| ActiveRadarrBlock::CollectionsSortPrompt match route {
| ActiveRadarrBlock::SearchCollection _ if CollectionDetailsUi::accepts(route) => CollectionDetailsUi::draw(f, app, area),
| ActiveRadarrBlock::SearchCollectionError _ if EditCollectionUi::accepts(route) => EditCollectionUi::draw(f, app, area),
| ActiveRadarrBlock::FilterCollections Route::Radarr(ActiveRadarrBlock::UpdateAllCollectionsPrompt, _) => {
| ActiveRadarrBlock::FilterCollectionsError => draw_collections(f, app, area),
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
let confirmation_prompt = ConfirmationPrompt::new() let confirmation_prompt = ConfirmationPrompt::new()
.title("Update All Collections") .title("Update All Collections")
.prompt("Do you want to update all of your collections?") .prompt("Do you want to update all of your collections?")
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_collections(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
); );
} }
_ => (), _ => (),
};
match route {
_ if CollectionDetailsUi::accepts(route) => CollectionDetailsUi::draw(f, app, area),
_ if EditCollectionUi::accepts(route) => EditCollectionUi::draw(f, app, area),
Route::Radarr(active_radarr_block, _)
if COLLECTIONS_BLOCKS.contains(&active_radarr_block) =>
{
collections_ui_matcher(active_radarr_block)
}
_ => (),
} }
} }
} }
@@ -123,7 +107,11 @@ pub(super) fn draw_collections(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
.primary() .primary()
}; };
let collections_table = ManagarrTable::new(content, collection_row_mapping) let collections_table = ManagarrTable::new(content, collection_row_mapping)
.loading(app.is_loading) .loading(
app.is_loading
|| app.data.radarr_data.movies.is_empty()
|| app.data.radarr_data.quality_profile_map.is_empty(),
)
.footer(collections_table_footer) .footer(collections_table_footer)
.block(layout_block_top_border()) .block(layout_block_top_border())
.sorting(active_radarr_block == ActiveRadarrBlock::CollectionsSortPrompt) .sorting(active_radarr_block == ActiveRadarrBlock::CollectionsSortPrompt)
+2 -3
View File
@@ -31,8 +31,9 @@ impl DrawUi for DownloadsUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() { if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
draw_downloads(f, app, area);
match active_radarr_block { match active_radarr_block {
ActiveRadarrBlock::Downloads => draw_downloads(f, app, area),
ActiveRadarrBlock::DeleteDownloadPrompt => { ActiveRadarrBlock::DeleteDownloadPrompt => {
let prompt = format!( let prompt = format!(
"Do you really want to delete this download: \n{}?", "Do you really want to delete this download: \n{}?",
@@ -43,7 +44,6 @@ impl DrawUi for DownloadsUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_downloads(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
@@ -55,7 +55,6 @@ impl DrawUi for DownloadsUi {
.prompt("Do you want to update your downloads?") .prompt("Do you want to update your downloads?")
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_downloads(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
+3 -6
View File
@@ -5,7 +5,6 @@ use crate::app::App;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::Route; use crate::models::Route;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
@@ -13,7 +12,7 @@ use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use crate::ui::widgets::loading_block::LoadingBlock; use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use ratatui::layout::{Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::Paragraph; use ratatui::widgets::Paragraph;
@@ -34,12 +33,10 @@ impl DrawUi for EditIndexerUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_indexers,
draw_edit_indexer_prompt, draw_edit_indexer_prompt,
Size::WideLargePrompt, Size::WideLargePrompt,
); );
@@ -12,7 +12,6 @@ use crate::models::servarr_data::radarr::radarr_data::{
}; };
use crate::models::Route; use crate::models::Route;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
@@ -20,7 +19,7 @@ use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use crate::ui::widgets::loading_block::LoadingBlock; use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
#[cfg(test)] #[cfg(test)]
#[path = "indexer_settings_ui_tests.rs"] #[path = "indexer_settings_ui_tests.rs"]
@@ -37,12 +36,10 @@ impl DrawUi for IndexerSettingsUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_indexers,
draw_edit_indexer_settings_prompt, draw_edit_indexer_settings_prompt,
Size::WideLargePrompt, Size::WideLargePrompt,
); );
+15 -16
View File
@@ -44,25 +44,33 @@ impl DrawUi for IndexersUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let route = app.get_current_route(); let route = app.get_current_route();
let mut indexers_matchers = |active_radarr_block| match active_radarr_block {
ActiveRadarrBlock::Indexers => draw_indexers(f, app, area),
ActiveRadarrBlock::TestIndexer => {
draw_indexers(f, app, area); draw_indexers(f, app, area);
if app.is_loading {
match route {
_ if EditIndexerUi::accepts(route) => EditIndexerUi::draw(f, app, area),
_ if IndexerSettingsUi::accepts(route) => IndexerSettingsUi::draw(f, app, area),
_ if TestAllIndexersUi::accepts(route) => TestAllIndexersUi::draw(f, app, area),
Route::Radarr(active_radarr_block, _) => match active_radarr_block {
ActiveRadarrBlock::TestIndexer => {
if app.is_loading || app.data.radarr_data.indexer_test_errors.is_none() {
let loading_popup = Popup::new(LoadingBlock::new( let loading_popup = Popup::new(LoadingBlock::new(
app.is_loading, app.is_loading || app.data.radarr_data.indexer_test_errors.is_none(),
title_block("Testing Indexer"), title_block("Testing Indexer"),
)) ))
.size(Size::LargeMessage); .size(Size::LargeMessage);
f.render_widget(loading_popup, f.area()); f.render_widget(loading_popup, f.area());
} else { } else {
let popup = if let Some(result) = app.data.radarr_data.indexer_test_error.as_ref() { let popup = {
let result = app.data.radarr_data.indexer_test_errors.as_ref().expect("Test result is unpopulated");
if !result.is_empty() {
Popup::new(Message::new(result.clone())).size(Size::LargeMessage) Popup::new(Message::new(result.clone())).size(Size::LargeMessage)
} else { } else {
let message = Message::new("Indexer test succeeded!") let message = Message::new("Indexer test succeeded!")
.title("Success") .title("Success")
.style(Style::new().success().bold()); .style(Style::new().success().bold());
Popup::new(message).size(Size::Message) Popup::new(message).size(Size::Message)
}
}; };
f.render_widget(popup, f.area()); f.render_widget(popup, f.area());
@@ -85,22 +93,13 @@ impl DrawUi for IndexersUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_indexers(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
); );
} }
_ => (), _ => (),
}; },
match route {
_ if EditIndexerUi::accepts(route) => EditIndexerUi::draw(f, app, area),
_ if IndexerSettingsUi::accepts(route) => IndexerSettingsUi::draw(f, app, area),
_ if TestAllIndexersUi::accepts(route) => TestAllIndexersUi::draw(f, app, area),
Route::Radarr(active_radarr_block, _) if INDEXERS_BLOCKS.contains(&active_radarr_block) => {
indexers_matchers(active_radarr_block)
}
_ => (), _ => (),
} }
} }
@@ -3,12 +3,11 @@ use crate::app::App;
use crate::models::servarr_data::modals::IndexerTestResultModalItem; use crate::models::servarr_data::modals::IndexerTestResultModalItem;
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::models::Route; use crate::models::Route;
use crate::ui::radarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{borderless_block, get_width_from_percentage, title_block}; use crate::ui::utils::{borderless_block, get_width_from_percentage, title_block};
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use ratatui::layout::{Alignment, Constraint, Rect}; use ratatui::layout::{Alignment, Constraint, Rect};
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
use ratatui::Frame; use ratatui::Frame;
@@ -28,26 +27,22 @@ impl DrawUi for TestAllIndexersUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
draw_popup_over( draw_popup(f, app, draw_test_all_indexers_test_results, Size::Large);
f,
app,
area,
draw_indexers,
draw_test_all_indexers_test_results,
Size::Large,
);
} }
} }
fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let is_loading = app.is_loading || app.data.radarr_data.indexer_test_all_results.is_none();
let block = title_block("Test All Indexers");
let current_selection = let current_selection =
if let Some(test_all_results) = app.data.radarr_data.indexer_test_all_results.as_ref() { if let Some(test_all_results) = app.data.radarr_data.indexer_test_all_results.as_ref() {
test_all_results.current_selection().clone() test_all_results.current_selection().clone()
} else { } else {
IndexerTestResultModalItem::default() IndexerTestResultModalItem::default()
}; };
f.render_widget(title_block("Test All Indexers"), area); f.render_widget(block, area);
let help_footer = format!( let help_footer = format!(
"<↑↓> scroll | {}", "<↑↓> scroll | {}",
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES) build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
@@ -77,7 +72,7 @@ fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, are
test_results_row_mapping, test_results_row_mapping,
) )
.block(borderless_block()) .block(borderless_block())
.loading(app.is_loading) .loading(is_loading)
.footer(Some(help_footer)) .footer(Some(help_footer))
.footer_alignment(Alignment::Center) .footer_alignment(Alignment::Center)
.margin(1) .margin(1)
+12 -56
View File
@@ -13,8 +13,6 @@ use crate::models::radarr_models::AddMovieSearchResult;
use crate::models::servarr_data::radarr::modals::AddMovieModal; use crate::models::servarr_data::radarr::modals::AddMovieModal;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS};
use crate::models::{EnumDisplayStyle, Route}; use crate::models::{EnumDisplayStyle, Route};
use crate::ui::radarr_ui::collections::{draw_collection_details, draw_collections};
use crate::ui::radarr_ui::library::draw_library;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless, borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless,
@@ -26,9 +24,10 @@ use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::message::Message; use crate::ui::widgets::message::Message;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use crate::utils::convert_runtime; use crate::utils::convert_runtime;
use crate::{render_selectable_input_box, App}; use crate::{render_selectable_input_box, App};
use crate::ui::radarr_ui::collections::CollectionsUi;
#[cfg(test)] #[cfg(test)]
#[path = "add_movie_ui_tests.rs"] #[path = "add_movie_ui_tests.rs"]
@@ -47,73 +46,35 @@ impl DrawUi for AddMovieUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() { if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() {
let draw_add_movie_search_popup = if context_option.is_some() {
|f: &mut Frame<'_>, app: &mut App<'_>, area: Rect| match active_radarr_block { CollectionsUi::draw(f, app, area);
ActiveRadarrBlock::AddMovieSearchInput draw_popup(f, app, draw_confirmation_popup, Size::Medium);
| ActiveRadarrBlock::AddMovieSearchResults } else {
| ActiveRadarrBlock::AddMovieEmptySearchResults => { draw_popup(f, app, draw_add_movie_search, Size::Large);
draw_add_movie_search(f, app, area);
} match active_radarr_block {
ActiveRadarrBlock::AddMoviePrompt ActiveRadarrBlock::AddMoviePrompt
| ActiveRadarrBlock::AddMovieSelectMonitor | ActiveRadarrBlock::AddMovieSelectMonitor
| ActiveRadarrBlock::AddMovieSelectMinimumAvailability | ActiveRadarrBlock::AddMovieSelectMinimumAvailability
| ActiveRadarrBlock::AddMovieSelectQualityProfile | ActiveRadarrBlock::AddMovieSelectQualityProfile
| ActiveRadarrBlock::AddMovieSelectRootFolder | ActiveRadarrBlock::AddMovieSelectRootFolder
| ActiveRadarrBlock::AddMovieTagsInput => { | ActiveRadarrBlock::AddMovieTagsInput => {
if context_option.is_some() { draw_popup(
draw_popup_over(
f, f,
app, app,
area,
draw_collection_details,
draw_confirmation_popup, draw_confirmation_popup,
Size::Medium, Size::Medium,
); );
} else {
draw_popup_over(
f,
app,
area,
draw_add_movie_search,
draw_confirmation_popup,
Size::Medium,
);
}
} }
ActiveRadarrBlock::AddMovieAlreadyInLibrary => { ActiveRadarrBlock::AddMovieAlreadyInLibrary => {
draw_add_movie_search(f, app, area);
f.render_widget( f.render_widget(
Popup::new(Message::new("This film is already in your library")).size(Size::Message), Popup::new(Message::new("This film is already in your library")).size(Size::Message),
f.area(), f.area(),
); );
} }
_ => (), _ => (),
};
match active_radarr_block {
_ if ADD_MOVIE_BLOCKS.contains(&active_radarr_block) => {
if context_option.is_some() {
draw_popup_over(
f,
app,
area,
draw_collections,
draw_add_movie_search_popup,
Size::Large,
)
} else {
draw_popup_over(
f,
app,
area,
draw_library,
draw_add_movie_search_popup,
Size::Large,
)
} }
} }
_ => (),
}
} }
} }
} }
@@ -285,26 +246,21 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
fn draw_confirmation_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_confirmation_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() { if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
draw_confirmation_prompt(f, app, area);
match active_radarr_block { match active_radarr_block {
ActiveRadarrBlock::AddMovieSelectMonitor => { ActiveRadarrBlock::AddMovieSelectMonitor => {
draw_confirmation_prompt(f, app, area);
draw_add_movie_select_monitor_popup(f, app); draw_add_movie_select_monitor_popup(f, app);
} }
ActiveRadarrBlock::AddMovieSelectMinimumAvailability => { ActiveRadarrBlock::AddMovieSelectMinimumAvailability => {
draw_confirmation_prompt(f, app, area);
draw_add_movie_select_minimum_availability_popup(f, app); draw_add_movie_select_minimum_availability_popup(f, app);
} }
ActiveRadarrBlock::AddMovieSelectQualityProfile => { ActiveRadarrBlock::AddMovieSelectQualityProfile => {
draw_confirmation_prompt(f, app, area);
draw_add_movie_select_quality_profile_popup(f, app); draw_add_movie_select_quality_profile_popup(f, app);
} }
ActiveRadarrBlock::AddMovieSelectRootFolder => { ActiveRadarrBlock::AddMovieSelectRootFolder => {
draw_confirmation_prompt(f, app, area);
draw_add_movie_select_root_folder_popup(f, app); draw_add_movie_select_root_folder_popup(f, app);
} }
ActiveRadarrBlock::AddMoviePrompt | ActiveRadarrBlock::AddMovieTagsInput => {
draw_confirmation_prompt(f, app, area)
}
_ => (), _ => (),
} }
} }
+1 -3
View File
@@ -4,7 +4,6 @@ use ratatui::Frame;
use crate::app::App; use crate::app::App;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DELETE_MOVIE_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DELETE_MOVIE_BLOCKS};
use crate::models::Route; use crate::models::Route;
use crate::ui::radarr_ui::library::draw_library;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
@@ -25,7 +24,7 @@ impl DrawUi for DeleteMovieUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if matches!( if matches!(
app.get_current_route(), app.get_current_route(),
Route::Radarr(ActiveRadarrBlock::DeleteMoviePrompt, _) Route::Radarr(ActiveRadarrBlock::DeleteMoviePrompt, _)
@@ -50,7 +49,6 @@ impl DrawUi for DeleteMovieUi {
.yes_no_highlighted(selected_block == ActiveRadarrBlock::DeleteMovieConfirmPrompt) .yes_no_highlighted(selected_block == ActiveRadarrBlock::DeleteMovieConfirmPrompt)
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_library(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
+11 -33
View File
@@ -14,7 +14,6 @@ use crate::models::servarr_data::radarr::radarr_data::{
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::{EnumDisplayStyle, Route};
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::library::draw_library;
use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi; use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
@@ -24,7 +23,7 @@ use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use crate::ui::{draw_popup, draw_popup_over, draw_popup_over_ui, DrawUi}; use crate::ui::{draw_popup, DrawUi};
#[cfg(test)] #[cfg(test)]
#[path = "edit_movie_ui_tests.rs"] #[path = "edit_movie_ui_tests.rs"]
@@ -41,45 +40,24 @@ impl DrawUi for EditMovieUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() { if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() {
let draw_edit_movie_prompt = if let Some(context) = context_option {
|f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect| match active_radarr_block { if MOVIE_DETAILS_BLOCKS.contains(&context) {
draw_popup(f, app, MovieDetailsUi::draw, Size::Large);
}
}
draw_popup(f, app, draw_edit_movie_confirmation_prompt, Size::Medium);
match active_radarr_block {
ActiveRadarrBlock::EditMovieSelectMinimumAvailability => { ActiveRadarrBlock::EditMovieSelectMinimumAvailability => {
draw_edit_movie_confirmation_prompt(f, app, prompt_area);
draw_edit_movie_select_minimum_availability_popup(f, app); draw_edit_movie_select_minimum_availability_popup(f, app);
} }
ActiveRadarrBlock::EditMovieSelectQualityProfile => { ActiveRadarrBlock::EditMovieSelectQualityProfile => {
draw_edit_movie_confirmation_prompt(f, app, prompt_area);
draw_edit_movie_select_quality_profile_popup(f, app); draw_edit_movie_select_quality_profile_popup(f, app);
} }
ActiveRadarrBlock::EditMoviePrompt
| ActiveRadarrBlock::EditMovieToggleMonitored
| ActiveRadarrBlock::EditMoviePathInput
| ActiveRadarrBlock::EditMovieTagsInput => {
draw_edit_movie_confirmation_prompt(f, app, prompt_area)
}
_ => (), _ => (),
};
if let Some(context) = context_option {
match context {
ActiveRadarrBlock::Movies => {
draw_popup_over(
f,
app,
area,
draw_library,
draw_edit_movie_prompt,
Size::Medium,
);
}
_ if MOVIE_DETAILS_BLOCKS.contains(&context) => {
draw_popup_over_ui::<MovieDetailsUi>(f, app, area, draw_library, Size::Large);
draw_popup(f, app, draw_edit_movie_prompt, Size::Medium);
}
_ => (),
}
} }
} }
} }
+12 -23
View File
@@ -44,43 +44,32 @@ impl DrawUi for LibraryUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let route = app.get_current_route(); let route = app.get_current_route();
let mut library_ui_matchers = |active_radarr_block: ActiveRadarrBlock| match active_radarr_block if !matches!(route, Route::Radarr(_, Some(_))) {
{
ActiveRadarrBlock::Movies
| ActiveRadarrBlock::MoviesSortPrompt
| ActiveRadarrBlock::SearchMovie
| ActiveRadarrBlock::SearchMovieError
| ActiveRadarrBlock::FilterMovies
| ActiveRadarrBlock::FilterMoviesError => draw_library(f, app, area),
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
let confirmation_prompt = ConfirmationPrompt::new()
.title("Update All Movies")
.prompt("Do you want to update info and scan your disks for all of your movies?")
.yes_no_value(app.data.radarr_data.prompt_confirm);
draw_library(f, app, area); draw_library(f, app, area);
f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(),
);
} }
_ => (),
};
match route { match route {
_ if MovieDetailsUi::accepts(route) => MovieDetailsUi::draw(f, app, area), _ if MovieDetailsUi::accepts(route) => MovieDetailsUi::draw(f, app, area),
_ if AddMovieUi::accepts(route) => AddMovieUi::draw(f, app, area), _ if AddMovieUi::accepts(route) => AddMovieUi::draw(f, app, area),
_ if EditMovieUi::accepts(route) => EditMovieUi::draw(f, app, area), _ if EditMovieUi::accepts(route) => EditMovieUi::draw(f, app, area),
_ if DeleteMovieUi::accepts(route) => DeleteMovieUi::draw(f, app, area), _ if DeleteMovieUi::accepts(route) => DeleteMovieUi::draw(f, app, area),
Route::Radarr(active_radarr_block, _) if LIBRARY_BLOCKS.contains(&active_radarr_block) => { Route::Radarr(ActiveRadarrBlock::UpdateAllMoviesPrompt, _) => {
library_ui_matchers(active_radarr_block) let confirmation_prompt = ConfirmationPrompt::new()
.title("Update All Movies")
.prompt("Do you want to update info and scan your disks for all of your movies?")
.yes_no_value(app.data.radarr_data.prompt_confirm);
f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(),
);
} }
_ => (), _ => (),
} }
} }
} }
pub(super) fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() { if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
let current_selection = if !app.data.radarr_data.movies.items.is_empty() { let current_selection = if !app.data.radarr_data.movies.items.is_empty() {
app.data.radarr_data.movies.current_selection().clone() app.data.radarr_data.movies.current_selection().clone()
+3 -6
View File
@@ -11,14 +11,13 @@ use crate::models::radarr_models::{Credit, MovieHistoryItem, RadarrRelease};
use crate::models::servarr_data::radarr::modals::MovieDetailsModal; use crate::models::servarr_data::radarr::modals::MovieDetailsModal;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, MOVIE_DETAILS_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, MOVIE_DETAILS_BLOCKS};
use crate::models::Route; use crate::models::Route;
use crate::ui::radarr_ui::library::draw_library;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{borderless_block, decorate_peer_style, get_width_from_percentage, layout_block_bottom_border, layout_block_top_border}; use crate::ui::utils::{borderless_block, decorate_peer_style, get_width_from_percentage, layout_block_bottom_border, layout_block_top_border};
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::loading_block::LoadingBlock; use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::{draw_popup_over, draw_tabs, DrawUi}; use crate::ui::{draw_popup, draw_tabs, DrawUi};
use crate::utils::convert_to_gb; use crate::utils::convert_to_gb;
#[cfg(test)] #[cfg(test)]
@@ -36,7 +35,7 @@ impl DrawUi for MovieDetailsUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() { if let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() {
let draw_movie_info_popup = |f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect| { let draw_movie_info_popup = |f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect| {
let content_area = draw_tabs( let content_area = draw_tabs(
@@ -85,11 +84,9 @@ impl DrawUi for MovieDetailsUi {
} }
}; };
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_library,
draw_movie_info_popup, draw_movie_info_popup,
Size::Large, Size::Large,
); );
+4 -6
View File
@@ -11,7 +11,7 @@ use crate::ui::utils::layout_block_top_border;
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::{draw_input_box_popup, draw_popup_over, DrawUi}; use crate::ui::{draw_input_box_popup, draw_popup, DrawUi};
use crate::utils::convert_to_gb; use crate::utils::convert_to_gb;
#[cfg(test)] #[cfg(test)]
@@ -31,13 +31,12 @@ impl DrawUi for RootFoldersUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() { if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
draw_root_folders(f, app, area);
match active_radarr_block { match active_radarr_block {
ActiveRadarrBlock::RootFolders => draw_root_folders(f, app, area), ActiveRadarrBlock::AddRootFolderPrompt => draw_popup(
ActiveRadarrBlock::AddRootFolderPrompt => draw_popup_over(
f, f,
app, app,
area,
draw_root_folders,
draw_add_root_folder_prompt_box, draw_add_root_folder_prompt_box,
Size::InputBox, Size::InputBox,
), ),
@@ -51,7 +50,6 @@ impl DrawUi for RootFoldersUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.radarr_data.prompt_confirm); .yes_no_value(app.data.radarr_data.prompt_confirm);
draw_root_folders(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
+4 -7
View File
@@ -63,18 +63,15 @@ impl DrawUi for SystemUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let route = app.get_current_route(); let route = app.get_current_route();
draw_system_ui_layout(f, app, area);
match route { if SystemDetailsUi::accepts(route) {
_ if SystemDetailsUi::accepts(route) => SystemDetailsUi::draw(f, app, area), SystemDetailsUi::draw(f, app, area);
_ if matches!(route, Route::Radarr(ActiveRadarrBlock::System, _)) => {
draw_system_ui_layout(f, app, area)
}
_ => (),
} }
} }
} }
pub(super) fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let [activities_area, logs_area, help_area] = Layout::vertical([ let [activities_area, logs_area, help_area] = Layout::vertical([
Constraint::Ratio(1, 2), Constraint::Ratio(1, 2),
Constraint::Ratio(1, 2), Constraint::Ratio(1, 2),
+5 -11
View File
@@ -10,7 +10,7 @@ use crate::models::radarr_models::RadarrTask;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS};
use crate::models::Route; use crate::models::Route;
use crate::ui::radarr_ui::system::{ use crate::ui::radarr_ui::system::{
draw_queued_events, draw_system_ui_layout, extract_task_props, TASK_TABLE_CONSTRAINTS, draw_queued_events, extract_task_props, TASK_TABLE_CONSTRAINTS,
TASK_TABLE_HEADERS, TASK_TABLE_HEADERS,
}; };
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
@@ -20,7 +20,7 @@ use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
#[cfg(test)] #[cfg(test)]
#[path = "system_details_ui_tests.rs"] #[path = "system_details_ui_tests.rs"]
@@ -37,33 +37,27 @@ impl DrawUi for SystemDetailsUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() { if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
match active_radarr_block { match active_radarr_block {
ActiveRadarrBlock::SystemLogs => { ActiveRadarrBlock::SystemLogs => {
draw_system_ui_layout(f, app, area);
draw_logs_popup(f, app); draw_logs_popup(f, app);
} }
ActiveRadarrBlock::SystemTasks | ActiveRadarrBlock::SystemTaskStartConfirmPrompt => { ActiveRadarrBlock::SystemTasks | ActiveRadarrBlock::SystemTaskStartConfirmPrompt => {
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_system_ui_layout,
draw_tasks_popup, draw_tasks_popup,
Size::Large, Size::Large,
) )
} }
ActiveRadarrBlock::SystemQueuedEvents => draw_popup_over( ActiveRadarrBlock::SystemQueuedEvents => draw_popup(
f, f,
app, app,
area,
draw_system_ui_layout,
draw_queued_events, draw_queued_events,
Size::Medium, Size::Medium,
), ),
ActiveRadarrBlock::SystemUpdates => { ActiveRadarrBlock::SystemUpdates => {
draw_system_ui_layout(f, app, area);
draw_updates_popup(f, app); draw_updates_popup(f, app);
} }
_ => (), _ => (),
+3 -7
View File
@@ -32,12 +32,10 @@ impl DrawUi for BlocklistUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
match active_sonarr_block {
ActiveSonarrBlock::Blocklist | ActiveSonarrBlock::BlocklistSortPrompt => {
draw_blocklist_table(f, app, area)
}
ActiveSonarrBlock::BlocklistItemDetails => {
draw_blocklist_table(f, app, area); draw_blocklist_table(f, app, area);
match active_sonarr_block {
ActiveSonarrBlock::BlocklistItemDetails => {
draw_blocklist_item_details_popup(f, app); draw_blocklist_item_details_popup(f, app);
} }
ActiveSonarrBlock::DeleteBlocklistItemPrompt => { ActiveSonarrBlock::DeleteBlocklistItemPrompt => {
@@ -55,7 +53,6 @@ impl DrawUi for BlocklistUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_blocklist_table(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
@@ -67,7 +64,6 @@ impl DrawUi for BlocklistUi {
.prompt("Do you want to clear your blocklist?") .prompt("Do you want to clear your blocklist?")
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_blocklist_table(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::SmallPrompt), Popup::new(confirmation_prompt).size(Size::SmallPrompt),
f.area(), f.area(),
+2 -3
View File
@@ -31,8 +31,9 @@ impl DrawUi for DownloadsUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
draw_downloads(f, app, area);
match active_sonarr_block { match active_sonarr_block {
ActiveSonarrBlock::Downloads => draw_downloads(f, app, area),
ActiveSonarrBlock::DeleteDownloadPrompt => { ActiveSonarrBlock::DeleteDownloadPrompt => {
let prompt = format!( let prompt = format!(
"Do you really want to delete this download: \n{}?", "Do you really want to delete this download: \n{}?",
@@ -43,7 +44,6 @@ impl DrawUi for DownloadsUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_downloads(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
@@ -55,7 +55,6 @@ impl DrawUi for DownloadsUi {
.prompt("Do you want to update your downloads?") .prompt("Do you want to update your downloads?")
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_downloads(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
+2 -10
View File
@@ -39,19 +39,11 @@ impl DrawUi for HistoryUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
match active_sonarr_block {
ActiveSonarrBlock::History
| ActiveSonarrBlock::HistorySortPrompt
| ActiveSonarrBlock::SearchHistory
| ActiveSonarrBlock::SearchHistoryError
| ActiveSonarrBlock::FilterHistory
| ActiveSonarrBlock::FilterHistoryError => draw_history_table(f, app, area),
ActiveSonarrBlock::HistoryItemDetails => {
draw_history_table(f, app, area); draw_history_table(f, app, area);
if active_sonarr_block == ActiveSonarrBlock::HistoryItemDetails {
draw_history_item_details_popup(f, app); draw_history_item_details_popup(f, app);
} }
_ => (),
}
} }
} }
} }
+3 -6
View File
@@ -5,7 +5,6 @@ use crate::app::App;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::Route; use crate::models::Route;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::sonarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
@@ -13,7 +12,7 @@ use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use crate::ui::widgets::loading_block::LoadingBlock; use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use ratatui::layout::{Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::Paragraph; use ratatui::widgets::Paragraph;
@@ -34,12 +33,10 @@ impl DrawUi for EditIndexerUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_indexers,
draw_edit_indexer_prompt, draw_edit_indexer_prompt,
Size::WideLargePrompt, Size::WideLargePrompt,
); );
@@ -10,14 +10,13 @@ use crate::models::servarr_data::sonarr::sonarr_data::{
}; };
use crate::models::Route; use crate::models::Route;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::sonarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::title_block_centered; use crate::ui::utils::title_block_centered;
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use crate::ui::widgets::loading_block::LoadingBlock; use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
#[cfg(test)] #[cfg(test)]
#[path = "indexer_settings_ui_tests.rs"] #[path = "indexer_settings_ui_tests.rs"]
@@ -34,12 +33,10 @@ impl DrawUi for IndexerSettingsUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_indexers,
draw_edit_indexer_settings_prompt, draw_edit_indexer_settings_prompt,
Size::LargePrompt, Size::LargePrompt,
); );
+14 -15
View File
@@ -44,25 +44,33 @@ impl DrawUi for IndexersUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let route = app.get_current_route(); let route = app.get_current_route();
let mut indexers_matchers = |active_sonarr_block| match active_sonarr_block {
ActiveSonarrBlock::Indexers => draw_indexers(f, app, area),
ActiveSonarrBlock::TestIndexer => {
draw_indexers(f, app, area); draw_indexers(f, app, area);
if app.is_loading || app.is_routing {
match route {
_ if EditIndexerUi::accepts(route) => EditIndexerUi::draw(f, app, area),
_ if IndexerSettingsUi::accepts(route) => IndexerSettingsUi::draw(f, app, area),
_ if TestAllIndexersUi::accepts(route) => TestAllIndexersUi::draw(f, app, area),
Route::Sonarr(active_sonarr_block, _) => match active_sonarr_block {
ActiveSonarrBlock::TestIndexer => {
if app.is_loading || app.data.sonarr_data.indexer_test_errors.is_none() {
let loading_popup = Popup::new(LoadingBlock::new( let loading_popup = Popup::new(LoadingBlock::new(
app.is_loading, app.is_loading || app.data.sonarr_data.indexer_test_errors.is_none(),
title_block("Testing Indexer"), title_block("Testing Indexer"),
)) ))
.size(Size::LargeMessage); .size(Size::LargeMessage);
f.render_widget(loading_popup, f.area()); f.render_widget(loading_popup, f.area());
} else { } else {
let popup = if let Some(result) = app.data.sonarr_data.indexer_test_error.as_ref() { let popup = {
let result = app.data.sonarr_data.indexer_test_errors.as_ref().expect("Test result is unpopulated");
if !result.is_empty() {
Popup::new(Message::new(result.clone())).size(Size::LargeMessage) Popup::new(Message::new(result.clone())).size(Size::LargeMessage)
} else { } else {
let message = Message::new("Indexer test succeeded!") let message = Message::new("Indexer test succeeded!")
.title("Success") .title("Success")
.style(Style::new().success().bold()); .style(Style::new().success().bold());
Popup::new(message).size(Size::Message) Popup::new(message).size(Size::Message)
}
}; };
f.render_widget(popup, f.area()); f.render_widget(popup, f.area());
@@ -85,21 +93,12 @@ impl DrawUi for IndexersUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_indexers(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
); );
} }
_ => (), _ => (),
};
match route {
_ if EditIndexerUi::accepts(route) => EditIndexerUi::draw(f, app, area),
_ if IndexerSettingsUi::accepts(route) => IndexerSettingsUi::draw(f, app, area),
_ if TestAllIndexersUi::accepts(route) => TestAllIndexersUi::draw(f, app, area),
Route::Sonarr(active_sonarr_block, _) if INDEXERS_BLOCKS.contains(&active_sonarr_block) => {
indexers_matchers(active_sonarr_block)
} }
_ => (), _ => (),
} }
@@ -3,12 +3,11 @@ use crate::app::App;
use crate::models::servarr_data::modals::IndexerTestResultModalItem; use crate::models::servarr_data::modals::IndexerTestResultModalItem;
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock; use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::Route; use crate::models::Route;
use crate::ui::sonarr_ui::indexers::draw_indexers;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{borderless_block, get_width_from_percentage, title_block}; use crate::ui::utils::{borderless_block, get_width_from_percentage, title_block};
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use ratatui::layout::{Alignment, Constraint, Rect}; use ratatui::layout::{Alignment, Constraint, Rect};
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
use ratatui::Frame; use ratatui::Frame;
@@ -28,12 +27,10 @@ impl DrawUi for TestAllIndexersUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_indexers,
draw_test_all_indexers_test_results, draw_test_all_indexers_test_results,
Size::Large, Size::Large,
); );
@@ -41,6 +38,7 @@ impl DrawUi for TestAllIndexersUi {
} }
fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let is_loading = app.is_loading || app.data.sonarr_data.indexer_test_all_results.is_none();
let current_selection = let current_selection =
if let Some(test_all_results) = app.data.sonarr_data.indexer_test_all_results.as_ref() { if let Some(test_all_results) = app.data.sonarr_data.indexer_test_all_results.as_ref() {
test_all_results.current_selection().clone() test_all_results.current_selection().clone()
@@ -77,7 +75,7 @@ fn draw_test_all_indexers_test_results(f: &mut Frame<'_>, app: &mut App<'_>, are
test_results_row_mapping, test_results_row_mapping,
) )
.block(borderless_block()) .block(borderless_block())
.loading(app.is_loading) .loading(is_loading)
.footer(Some(help_footer)) .footer(Some(help_footer))
.footer_alignment(Alignment::Center) .footer_alignment(Alignment::Center)
.margin(1) .margin(1)
+7 -32
View File
@@ -13,7 +13,6 @@ use crate::models::servarr_data::sonarr::modals::AddSeriesModal;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, ADD_SERIES_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, ADD_SERIES_BLOCKS};
use crate::models::sonarr_models::AddSeriesSearchResult; use crate::models::sonarr_models::AddSeriesSearchResult;
use crate::models::{EnumDisplayStyle, Route}; use crate::models::{EnumDisplayStyle, Route};
use crate::ui::sonarr_ui::library::draw_library;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless, borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless,
@@ -26,7 +25,7 @@ use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::message::Message; use crate::ui::widgets::message::Message;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use crate::{render_selectable_input_box, App}; use crate::{render_selectable_input_box, App};
#[cfg(test)] #[cfg(test)]
@@ -44,15 +43,11 @@ impl DrawUi for AddSeriesUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
let draw_add_series_search_popup = draw_popup(f, app, draw_add_series_search, Size::Large);
|f: &mut Frame<'_>, app: &mut App<'_>, area: Rect| match active_sonarr_block {
ActiveSonarrBlock::AddSeriesSearchInput match active_sonarr_block {
| ActiveSonarrBlock::AddSeriesSearchResults
| ActiveSonarrBlock::AddSeriesEmptySearchResults => {
draw_add_series_search(f, app, area);
}
ActiveSonarrBlock::AddSeriesPrompt ActiveSonarrBlock::AddSeriesPrompt
| ActiveSonarrBlock::AddSeriesSelectMonitor | ActiveSonarrBlock::AddSeriesSelectMonitor
| ActiveSonarrBlock::AddSeriesSelectSeriesType | ActiveSonarrBlock::AddSeriesSelectSeriesType
@@ -60,35 +55,15 @@ impl DrawUi for AddSeriesUi {
| ActiveSonarrBlock::AddSeriesSelectLanguageProfile | ActiveSonarrBlock::AddSeriesSelectLanguageProfile
| ActiveSonarrBlock::AddSeriesSelectRootFolder | ActiveSonarrBlock::AddSeriesSelectRootFolder
| ActiveSonarrBlock::AddSeriesTagsInput => { | ActiveSonarrBlock::AddSeriesTagsInput => {
draw_popup_over( draw_popup(f, app, draw_confirmation_popup, Size::Long);
f,
app,
area,
draw_add_series_search,
draw_confirmation_popup,
Size::Long,
);
} }
ActiveSonarrBlock::AddSeriesAlreadyInLibrary => { ActiveSonarrBlock::AddSeriesAlreadyInLibrary => {
draw_add_series_search(f, app, area);
f.render_widget( f.render_widget(
Popup::new(Message::new("This film is already in your library")).size(Size::Message), Popup::new(Message::new("This series is already in your library")).size(Size::Message),
f.area(), f.area(),
); );
} }
_ => (), _ => (),
};
match active_sonarr_block {
_ if ADD_SERIES_BLOCKS.contains(&active_sonarr_block) => draw_popup_over(
f,
app,
area,
draw_library,
draw_add_series_search_popup,
Size::Large,
),
_ => (),
} }
} }
} }
+2 -4
View File
@@ -4,7 +4,6 @@ use ratatui::Frame;
use crate::app::App; use crate::app::App;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DELETE_SERIES_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DELETE_SERIES_BLOCKS};
use crate::models::Route; use crate::models::Route;
use crate::ui::sonarr_ui::library::draw_library;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
@@ -25,14 +24,14 @@ impl DrawUi for DeleteSeriesUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if matches!( if matches!(
app.get_current_route(), app.get_current_route(),
Route::Sonarr(ActiveSonarrBlock::DeleteSeriesPrompt, _) Route::Sonarr(ActiveSonarrBlock::DeleteSeriesPrompt, _)
) { ) {
let selected_block = app.data.sonarr_data.selected_block.get_active_block(); let selected_block = app.data.sonarr_data.selected_block.get_active_block();
let prompt = format!( let prompt = format!(
"Do you really want to delete: \n{}?", "Do you really want to delete the series: \n{}?",
app.data.sonarr_data.series.current_selection().title.text app.data.sonarr_data.series.current_selection().title.text
); );
let checkboxes = vec![ let checkboxes = vec![
@@ -50,7 +49,6 @@ impl DrawUi for DeleteSeriesUi {
.yes_no_highlighted(selected_block == ActiveSonarrBlock::DeleteSeriesConfirmPrompt) .yes_no_highlighted(selected_block == ActiveSonarrBlock::DeleteSeriesConfirmPrompt)
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_library(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
+13 -32
View File
@@ -14,7 +14,6 @@ use crate::models::servarr_data::sonarr::sonarr_data::{
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::{EnumDisplayStyle, Route};
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::sonarr_ui::library::draw_library;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered}; use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
@@ -23,7 +22,7 @@ use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::input_box::InputBox; use crate::ui::widgets::input_box::InputBox;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use crate::ui::{draw_popup, draw_popup_over, draw_popup_over_ui, DrawUi}; use crate::ui::{draw_popup, DrawUi};
use super::series_details_ui::SeriesDetailsUi; use super::series_details_ui::SeriesDetailsUi;
@@ -42,52 +41,34 @@ impl DrawUi for EditSeriesUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Sonarr(active_sonarr_block, context_option) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, context_option) = app.get_current_route() {
if let Some(context) = context_option {
if SERIES_DETAILS_BLOCKS.contains(&context) {
draw_popup(f, app, SeriesDetailsUi::draw, Size::Large);
}
}
let draw_edit_series_prompt = let draw_edit_series_prompt =
|f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect| match active_sonarr_block { |f: &mut Frame<'_>, app: &mut App<'_>, prompt_area: Rect| {
ActiveSonarrBlock::EditSeriesSelectSeriesType => {
draw_edit_series_confirmation_prompt(f, app, prompt_area); draw_edit_series_confirmation_prompt(f, app, prompt_area);
match active_sonarr_block {
ActiveSonarrBlock::EditSeriesSelectSeriesType => {
draw_edit_series_select_series_type_popup(f, app); draw_edit_series_select_series_type_popup(f, app);
} }
ActiveSonarrBlock::EditSeriesSelectQualityProfile => { ActiveSonarrBlock::EditSeriesSelectQualityProfile => {
draw_edit_series_confirmation_prompt(f, app, prompt_area);
draw_edit_series_select_quality_profile_popup(f, app); draw_edit_series_select_quality_profile_popup(f, app);
} }
ActiveSonarrBlock::EditSeriesSelectLanguageProfile => { ActiveSonarrBlock::EditSeriesSelectLanguageProfile => {
draw_edit_series_confirmation_prompt(f, app, prompt_area);
draw_edit_series_select_language_profile_popup(f, app); draw_edit_series_select_language_profile_popup(f, app);
} }
ActiveSonarrBlock::EditSeriesPrompt
| ActiveSonarrBlock::EditSeriesToggleMonitored
| ActiveSonarrBlock::EditSeriesToggleSeasonFolder
| ActiveSonarrBlock::EditSeriesPathInput
| ActiveSonarrBlock::EditSeriesTagsInput => {
draw_edit_series_confirmation_prompt(f, app, prompt_area)
}
_ => (), _ => (),
}
}; };
if let Some(context) = context_option {
match context {
ActiveSonarrBlock::Series => {
draw_popup_over(
f,
app,
area,
draw_library,
draw_edit_series_prompt,
Size::Long,
);
}
_ if SERIES_DETAILS_BLOCKS.contains(&context) => {
draw_popup_over_ui::<SeriesDetailsUi>(f, app, area, draw_library, Size::Large);
draw_popup(f, app, draw_edit_series_prompt, Size::Long); draw_popup(f, app, draw_edit_series_prompt, Size::Long);
} }
_ => (),
}
}
}
} }
} }
+9 -25
View File
@@ -54,46 +54,30 @@ impl DrawUi for LibraryUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let route = app.get_current_route(); let route = app.get_current_route();
let mut series_ui_matchers = |active_sonarr_block: ActiveSonarrBlock| match active_sonarr_block draw_library(f, app, area);
{
ActiveSonarrBlock::Series match route {
| ActiveSonarrBlock::SeriesSortPrompt _ if AddSeriesUi::accepts(route) => AddSeriesUi::draw(f, app, area),
| ActiveSonarrBlock::SearchSeries _ if DeleteSeriesUi::accepts(route) => DeleteSeriesUi::draw(f, app, area),
| ActiveSonarrBlock::SearchSeriesError _ if EditSeriesUi::accepts(route) => EditSeriesUi::draw(f, app, area),
| ActiveSonarrBlock::FilterSeries _ if SeriesDetailsUi::accepts(route) => SeriesDetailsUi::draw(f, app, area),
| ActiveSonarrBlock::FilterSeriesError => draw_library(f, app, area), Route::Sonarr(ActiveSonarrBlock::UpdateAllSeriesPrompt, _) => {
ActiveSonarrBlock::UpdateAllSeriesPrompt => {
let confirmation_prompt = ConfirmationPrompt::new() let confirmation_prompt = ConfirmationPrompt::new()
.title("Update All Series") .title("Update All Series")
.prompt("Do you want to update info and scan your disks for all of your series?") .prompt("Do you want to update info and scan your disks for all of your series?")
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_library(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
); );
} }
_ => (), _ => (),
};
match route {
_ if AddSeriesUi::accepts(route) => AddSeriesUi::draw(f, app, area),
_ if DeleteSeriesUi::accepts(route) => DeleteSeriesUi::draw(f, app, area),
_ if EditSeriesUi::accepts(route) => EditSeriesUi::draw(f, app, area),
_ if SeriesDetailsUi::accepts(route) => {
draw_library(f, app, area);
SeriesDetailsUi::draw(f, app, area)
},
Route::Sonarr(active_sonarr_block, _) if LIBRARY_BLOCKS.contains(&active_sonarr_block) => {
series_ui_matchers(active_sonarr_block)
}
_ => (),
} }
} }
} }
pub(super) fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
let current_selection = if !app.data.sonarr_data.series.items.is_empty() { let current_selection = if !app.data.sonarr_data.series.items.is_empty() {
app.data.sonarr_data.series.current_selection().clone() app.data.sonarr_data.series.current_selection().clone()
+5 -19
View File
@@ -12,6 +12,7 @@ use crate::models::sonarr_models::{
Season, SeasonStatistics, SonarrHistoryEventType, SonarrHistoryItem, Season, SeasonStatistics, SonarrHistoryEventType, SonarrHistoryItem,
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::{EnumDisplayStyle, Route};
use crate::ui::sonarr_ui::library::season_details_ui::SeasonDetailsUi;
use crate::ui::sonarr_ui::sonarr_ui_utils::{ use crate::ui::sonarr_ui::sonarr_ui_utils::{
create_download_failed_history_event_details, create_download_failed_history_event_details,
create_download_folder_imported_history_event_details, create_download_folder_imported_history_event_details,
@@ -28,12 +29,9 @@ use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::message::Message; use crate::ui::widgets::message::Message;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::{draw_popup, draw_popup_over, draw_tabs, DrawUi}; use crate::ui::{draw_popup, draw_tabs, DrawUi};
use crate::ui::sonarr_ui::library::season_details_ui::SeasonDetailsUi;
use crate::utils::convert_to_gb; use crate::utils::convert_to_gb;
use super::draw_library;
#[cfg(test)] #[cfg(test)]
#[path = "series_details_ui_tests.rs"] #[path = "series_details_ui_tests.rs"]
mod series_details_ui_tests; mod series_details_ui_tests;
@@ -107,28 +105,16 @@ impl DrawUi for SeriesDetailsUi {
}; };
}; };
match route {
_ if SeasonDetailsUi::accepts(route) => {
draw_popup(f, app, draw_series_details_popup, Size::XXLarge); draw_popup(f, app, draw_series_details_popup, Size::XXLarge);
if SeasonDetailsUi::accepts(route) {
SeasonDetailsUi::draw(f, app, area); SeasonDetailsUi::draw(f, app, area);
},
Route::Sonarr(active_sonarr_block, _) if SERIES_DETAILS_BLOCKS.contains(&active_sonarr_block) => {
draw_popup_over(
f,
app,
area,
draw_library,
draw_series_details_popup,
Size::XXLarge,
);
}
_ => (),
} }
} }
} }
} }
pub fn draw_series_description(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_series_description(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let current_selection = app.data.sonarr_data.series.current_selection(); let current_selection = app.data.sonarr_data.series.current_selection();
let monitored = if current_selection.monitored { let monitored = if current_selection.monitored {
"Yes" "Yes"
+4 -6
View File
@@ -11,7 +11,7 @@ use crate::ui::utils::layout_block_top_border;
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::{draw_input_box_popup, draw_popup_over, DrawUi}; use crate::ui::{draw_input_box_popup, draw_popup, DrawUi};
use crate::utils::convert_to_gb; use crate::utils::convert_to_gb;
#[cfg(test)] #[cfg(test)]
@@ -31,13 +31,12 @@ impl DrawUi for RootFoldersUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
draw_root_folders(f, app, area);
match active_sonarr_block { match active_sonarr_block {
ActiveSonarrBlock::RootFolders => draw_root_folders(f, app, area), ActiveSonarrBlock::AddRootFolderPrompt => draw_popup(
ActiveSonarrBlock::AddRootFolderPrompt => draw_popup_over(
f, f,
app, app,
area,
draw_root_folders,
draw_add_root_folder_prompt_box, draw_add_root_folder_prompt_box,
Size::InputBox, Size::InputBox,
), ),
@@ -51,7 +50,6 @@ impl DrawUi for RootFoldersUi {
.prompt(&prompt) .prompt(&prompt)
.yes_no_value(app.data.sonarr_data.prompt_confirm); .yes_no_value(app.data.sonarr_data.prompt_confirm);
draw_root_folders(f, app, area);
f.render_widget( f.render_widget(
Popup::new(confirmation_prompt).size(Size::MediumPrompt), Popup::new(confirmation_prompt).size(Size::MediumPrompt),
f.area(), f.area(),
+4 -7
View File
@@ -57,18 +57,15 @@ impl DrawUi for SystemUi {
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let route = app.get_current_route(); let route = app.get_current_route();
draw_system_ui_layout(f, app, area);
match route { if SystemDetailsUi::accepts(route) {
_ if SystemDetailsUi::accepts(route) => SystemDetailsUi::draw(f, app, area), SystemDetailsUi::draw(f, app, area);
_ if matches!(route, Route::Sonarr(ActiveSonarrBlock::System, _)) => {
draw_system_ui_layout(f, app, area)
}
_ => (),
} }
} }
} }
pub(super) fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let [activities_area, logs_area, help_area] = Layout::vertical([ let [activities_area, logs_area, help_area] = Layout::vertical([
Constraint::Ratio(1, 2), Constraint::Ratio(1, 2),
Constraint::Ratio(1, 2), Constraint::Ratio(1, 2),
+6 -12
View File
@@ -10,7 +10,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SYSTEM
use crate::models::sonarr_models::SonarrTask; use crate::models::sonarr_models::SonarrTask;
use crate::models::Route; use crate::models::Route;
use crate::ui::sonarr_ui::system::{ use crate::ui::sonarr_ui::system::{
draw_queued_events, draw_system_ui_layout, extract_task_props, TASK_TABLE_CONSTRAINTS, draw_queued_events, extract_task_props, TASK_TABLE_CONSTRAINTS,
TASK_TABLE_HEADERS, TASK_TABLE_HEADERS,
}; };
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
@@ -20,7 +20,7 @@ use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::managarr_table::ManagarrTable; use crate::ui::widgets::managarr_table::ManagarrTable;
use crate::ui::widgets::popup::{Popup, Size}; use crate::ui::widgets::popup::{Popup, Size};
use crate::ui::widgets::selectable_list::SelectableList; use crate::ui::widgets::selectable_list::SelectableList;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup, DrawUi};
#[cfg(test)] #[cfg(test)]
#[path = "system_details_ui_tests.rs"] #[path = "system_details_ui_tests.rs"]
@@ -37,33 +37,27 @@ impl DrawUi for SystemDetailsUi {
false false
} }
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
match active_sonarr_block { match active_sonarr_block {
ActiveSonarrBlock::SystemLogs => { ActiveSonarrBlock::SystemLogs => {
draw_system_ui_layout(f, app, area);
draw_logs_popup(f, app); draw_logs_popup(f, app);
} }
ActiveSonarrBlock::SystemTasks | ActiveSonarrBlock::SystemTaskStartConfirmPrompt => { ActiveSonarrBlock::SystemTasks | ActiveSonarrBlock::SystemTaskStartConfirmPrompt => {
draw_popup_over( draw_popup(
f, f,
app, app,
area,
draw_system_ui_layout,
draw_tasks_popup, draw_tasks_popup,
Size::Large, Size::Large,
) )
} }
ActiveSonarrBlock::SystemQueuedEvents => draw_popup_over( ActiveSonarrBlock::SystemQueuedEvents => draw_popup(
f, f,
app, app,
area,
draw_system_ui_layout,
draw_queued_events, draw_queued_events,
Size::Medium, Size::Medium,
), ),
ActiveSonarrBlock::SystemUpdates => { ActiveSonarrBlock::SystemUpdates => {
draw_system_ui_layout(f, app, area);
draw_updates_popup(f, app); draw_updates_popup(f, app);
} }
_ => (), _ => (),
@@ -158,7 +152,7 @@ fn draw_updates_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
let updates = app.data.sonarr_data.updates.get_text(); let updates = app.data.sonarr_data.updates.get_text();
let block = title_block("Updates"); let block = title_block("Updates");
if !updates.is_empty() { if !updates.is_empty() && !app.is_loading {
let updates_paragraph = Paragraph::new(Text::from(updates)) let updates_paragraph = Paragraph::new(Text::from(updates))
.block(borderless_block()) .block(borderless_block())
.scroll((app.data.sonarr_data.updates.offset, 0)); .scroll((app.data.sonarr_data.updates.offset, 0));