diff --git a/src/handlers/radarr_handlers/blocklist/mod.rs b/src/handlers/radarr_handlers/blocklist/mod.rs index 11ac0e3..19834f3 100644 --- a/src/handlers/radarr_handlers/blocklist/mod.rs +++ b/src/handlers/radarr_handlers/blocklist/mod.rs @@ -38,7 +38,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a, let blocklist_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::Blocklist.into()) .sorting_block(ActiveRadarrBlock::BlocklistSortPrompt.into()) - .sort_by_fn(|a: &BlocklistItem, b: &BlocklistItem| a.id.cmp(&b.id)) .sort_options(blocklist_sorting_options()); if !self.handle_blocklist_table_events(blocklist_table_handling_config) { diff --git a/src/handlers/radarr_handlers/collections/mod.rs b/src/handlers/radarr_handlers/collections/mod.rs index 19067d3..ffdaf5c 100644 --- a/src/handlers/radarr_handlers/collections/mod.rs +++ b/src/handlers/radarr_handlers/collections/mod.rs @@ -42,7 +42,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<' let collections_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::Collections.into()) .sorting_block(ActiveRadarrBlock::CollectionsSortPrompt.into()) - .sort_by_fn(|a: &Collection, b: &Collection| a.id.cmp(&b.id)) .sort_options(collections_sorting_options()) .searching_block(ActiveRadarrBlock::SearchCollection.into()) .search_error_block(ActiveRadarrBlock::SearchCollectionError.into()) diff --git a/src/handlers/radarr_handlers/library/add_movie_handler.rs b/src/handlers/radarr_handlers/library/add_movie_handler.rs index 246a993..2a6b9da 100644 --- a/src/handlers/radarr_handlers/library/add_movie_handler.rs +++ b/src/handlers/radarr_handlers/library/add_movie_handler.rs @@ -7,7 +7,6 @@ use crate::models::servarr_data::radarr::modals::AddMovieModal; use crate::models::servarr_data::radarr::radarr_data::{ ADD_MOVIE_BLOCKS, ADD_MOVIE_SELECTION_BLOCKS, ActiveRadarrBlock, }; -use crate::models::stateful_table::StatefulTable; use crate::models::{BlockSelectionState, Scrollable}; use crate::network::radarr_network::RadarrEvent; use crate::{ @@ -35,7 +34,7 @@ impl AddMovieHandler<'_, '_> { .radarr_data .add_searched_movies .as_mut() - .unwrap_or(&mut StatefulTable::default()), + .expect("add_searched_movies should be initialized"), AddMovieSearchResult ); diff --git a/src/handlers/radarr_handlers/library/mod.rs b/src/handlers/radarr_handlers/library/mod.rs index 7648db5..1834399 100644 --- a/src/handlers/radarr_handlers/library/mod.rs +++ b/src/handlers/radarr_handlers/library/mod.rs @@ -44,7 +44,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, ' fn handle(&mut self) { let movie_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::Movies.into()) .sorting_block(ActiveRadarrBlock::MoviesSortPrompt.into()) - .sort_by_fn(|a: &Movie, b: &Movie| a.id.cmp(&b.id)) .sort_options(movies_sorting_options()) .searching_block(ActiveRadarrBlock::SearchMovie.into()) .search_error_block(ActiveRadarrBlock::SearchMovieError.into()) diff --git a/src/handlers/sonarr_handlers/blocklist/mod.rs b/src/handlers/sonarr_handlers/blocklist/mod.rs index dff3205..2e66041 100644 --- a/src/handlers/sonarr_handlers/blocklist/mod.rs +++ b/src/handlers/sonarr_handlers/blocklist/mod.rs @@ -38,7 +38,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for BlocklistHandler<'a, let blocklist_table_handling_config = TableHandlingConfig::new(ActiveSonarrBlock::Blocklist.into()) .sorting_block(ActiveSonarrBlock::BlocklistSortPrompt.into()) - .sort_by_fn(|a: &BlocklistItem, b: &BlocklistItem| a.id.cmp(&b.id)) .sort_options(blocklist_sorting_options()); if !self.handle_blocklist_table_events(blocklist_table_handling_config) { diff --git a/src/handlers/sonarr_handlers/history/mod.rs b/src/handlers/sonarr_handlers/history/mod.rs index e29a95f..91942a0 100644 --- a/src/handlers/sonarr_handlers/history/mod.rs +++ b/src/handlers/sonarr_handlers/history/mod.rs @@ -33,7 +33,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for HistoryHandler<'a, ' fn handle(&mut self) { let history_table_handling_config = TableHandlingConfig::new(ActiveSonarrBlock::History.into()) .sorting_block(ActiveSonarrBlock::HistorySortPrompt.into()) - .sort_by_fn(|a: &SonarrHistoryItem, b: &SonarrHistoryItem| a.id.cmp(&b.id)) .sort_options(history_sorting_options()) .searching_block(ActiveSonarrBlock::SearchHistory.into()) .search_error_block(ActiveSonarrBlock::SearchHistoryError.into()) diff --git a/src/handlers/sonarr_handlers/library/add_series_handler.rs b/src/handlers/sonarr_handlers/library/add_series_handler.rs index 233126b..d8ac096 100644 --- a/src/handlers/sonarr_handlers/library/add_series_handler.rs +++ b/src/handlers/sonarr_handlers/library/add_series_handler.rs @@ -5,7 +5,6 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ ADD_SERIES_BLOCKS, ADD_SERIES_SELECTION_BLOCKS, ActiveSonarrBlock, }; use crate::models::sonarr_models::{AddSeriesBody, AddSeriesOptions, AddSeriesSearchResult}; -use crate::models::stateful_table::StatefulTable; use crate::models::{BlockSelectionState, Scrollable}; use crate::network::sonarr_network::SonarrEvent; use crate::{ @@ -33,7 +32,7 @@ impl AddSeriesHandler<'_, '_> { .sonarr_data .add_searched_series .as_mut() - .unwrap_or(&mut StatefulTable::default()), + .expect("add_searched_series should be initialized"), AddSeriesSearchResult ); diff --git a/src/handlers/sonarr_handlers/library/mod.rs b/src/handlers/sonarr_handlers/library/mod.rs index 1131c15..90b5c31 100644 --- a/src/handlers/sonarr_handlers/library/mod.rs +++ b/src/handlers/sonarr_handlers/library/mod.rs @@ -55,7 +55,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for LibraryHandler<'a, ' fn handle(&mut self) { let series_table_handling_config = TableHandlingConfig::new(ActiveSonarrBlock::Series.into()) .sorting_block(ActiveSonarrBlock::SeriesSortPrompt.into()) - .sort_by_fn(|a: &Series, b: &Series| a.id.cmp(&b.id)) .sort_options(series_sorting_options()) .searching_block(ActiveSonarrBlock::SearchSeries.into()) .search_error_block(ActiveSonarrBlock::SearchSeriesError.into()) diff --git a/src/handlers/sonarr_handlers/library/season_details_handler.rs b/src/handlers/sonarr_handlers/library/season_details_handler.rs index 3472996..4ae7fd0 100644 --- a/src/handlers/sonarr_handlers/library/season_details_handler.rs +++ b/src/handlers/sonarr_handlers/library/season_details_handler.rs @@ -115,7 +115,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeasonDetailsHandler TableHandlingConfig::new(ActiveSonarrBlock::SeasonHistory.into()) .sorting_block(ActiveSonarrBlock::SeasonHistorySortPrompt.into()) .sort_options(history_sorting_options()) - .sort_by_fn(|a: &SonarrHistoryItem, b: &SonarrHistoryItem| a.id.cmp(&b.id)) .searching_block(ActiveSonarrBlock::SearchSeasonHistory.into()) .search_error_block(ActiveSonarrBlock::SearchSeasonHistoryError.into()) .search_field_fn(|history_item: &SonarrHistoryItem| &history_item.source_title.text) diff --git a/src/handlers/sonarr_handlers/library/series_details_handler.rs b/src/handlers/sonarr_handlers/library/series_details_handler.rs index ed8ca49..0b6771b 100644 --- a/src/handlers/sonarr_handlers/library/series_details_handler.rs +++ b/src/handlers/sonarr_handlers/library/series_details_handler.rs @@ -71,7 +71,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for SeriesDetailsHandler TableHandlingConfig::new(ActiveSonarrBlock::SeriesHistory.into()) .sorting_block(ActiveSonarrBlock::SeriesHistorySortPrompt.into()) .sort_options(history_sorting_options()) - .sort_by_fn(|a: &SonarrHistoryItem, b: &SonarrHistoryItem| a.id.cmp(&b.id)) .searching_block(ActiveSonarrBlock::SearchSeriesHistory.into()) .search_error_block(ActiveSonarrBlock::SearchSeriesHistoryError.into()) .search_field_fn(|history_item: &SonarrHistoryItem| &history_item.source_title.text) diff --git a/src/handlers/table_handler.rs b/src/handlers/table_handler.rs index 77e32c4..c46320e 100644 --- a/src/handlers/table_handler.rs +++ b/src/handlers/table_handler.rs @@ -1,7 +1,6 @@ use crate::models::Route; use crate::models::stateful_table::SortOption; use derive_setters::Setters; -use std::cmp::Ordering; use std::fmt::Debug; #[cfg(test)] @@ -18,8 +17,6 @@ where #[setters(strip_option)] pub sort_options: Option>>, #[setters(strip_option)] - pub sort_by_fn: Option Ordering>, - #[setters(strip_option)] pub searching_block: Option, #[setters(strip_option)] pub search_error_block: Option, @@ -56,16 +53,12 @@ macro_rules! handle_table_events { _ if $crate::matches_key!(submit, $self.key) => $self.[](config), _ if $crate::matches_key!(esc, $self.key) => $self.[](config), _ if config.searching_block.is_some() - && $self.app.get_current_route() == *config.searching_block - .as_ref() - .expect("searching_block must be configured for this table") => + && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() => { $self.[]() } _ if config.filtering_block.is_some() - && $self.app.get_current_route() == *config.filtering_block - .as_ref() - .expect("filtering_block must be configured for this table") => + && $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap() => { $self.[]() } @@ -91,11 +84,11 @@ macro_rules! handle_table_events { true } _ if config.sorting_block.is_some() - && $self.app.get_current_route() == *config.sorting_block - .as_ref() - .expect("sorting_block must be configured for this table") => + && $self.app.get_current_route() == *config.sorting_block.as_ref().unwrap() => { - $table.sort.as_mut().unwrap().scroll_up(); + if let Some(ref mut sort) = $table.sort { + sort.scroll_up(); + } true } _ => false, @@ -111,27 +104,12 @@ macro_rules! handle_table_events { true } _ if config.sorting_block.is_some() - && $self.app.get_current_route() == *config.sorting_block - .as_ref() - .expect("sorting_block must be configured for this table") => + && $self.app.get_current_route() == *config.sorting_block.as_ref().unwrap() => { - $table - .sort - .as_mut() - .unwrap() - .scroll_down(); - true - } - _ => false, - } - } - - fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { - use $crate::models::Paginated; - - match $self.app.get_current_route() { - _ if config.table_block == $self.app.get_current_route() => { - $table.page_down(); + if let Some(ref mut sort) = $table.sort { + sort + .scroll_down(); + } true } _ => false, @@ -141,12 +119,22 @@ macro_rules! handle_table_events { fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { use $crate::models::Paginated; - match $self.app.get_current_route() { - _ if config.table_block == $self.app.get_current_route() => { - $table.page_up(); - true - } - _ => false, + if config.table_block == $self.app.get_current_route() { + $table.page_up(); + true + } else { + false + } + } + + fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { + use $crate::models::Paginated; + + if config.table_block == $self.app.get_current_route() { + $table.page_down(); + true + } else { + false } } @@ -159,39 +147,27 @@ macro_rules! handle_table_events { true } _ if config.sorting_block.is_some() - && $self.app.get_current_route() == *config.sorting_block - .as_ref() - .expect("sorting_block must be configured for this table") => + && $self.app.get_current_route() == *config.sorting_block.as_ref().unwrap() => { - $table - .sort - .as_mut() - .unwrap() - .scroll_to_top(); + if let Some(ref mut sort) = $table.sort { + sort.scroll_to_top(); + } true } _ if config.searching_block.is_some() - && $self.app.get_current_route() == *config.searching_block - .as_ref() - .expect("searching_block must be configured for this table") => + && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() => { - $table - .search - .as_mut() - .unwrap() - .scroll_home(); + if let Some(ref mut search) = $table.search { + search.scroll_home(); + } true } _ if config.filtering_block.is_some() - && $self.app.get_current_route() == *config.filtering_block - .as_ref() - .expect("filtering_block must be configured for this table") => + && $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap() => { - $table - .filter - .as_mut() - .unwrap() - .scroll_home(); + if let Some(ref mut filter) = $table.filter { + filter.scroll_home(); + } true } _ => false, @@ -207,39 +183,27 @@ macro_rules! handle_table_events { true } _ if config.sorting_block.is_some() - && $self.app.get_current_route() == *config.sorting_block - .as_ref() - .expect("sorting_block must be configured for this table") => + && $self.app.get_current_route() == *config.sorting_block.as_ref().unwrap() => { - $table - .sort - .as_mut() - .unwrap() - .scroll_to_bottom(); + if let Some(ref mut sort) = $table.sort { + sort.scroll_to_bottom(); + } true } _ if config.searching_block.is_some() - && $self.app.get_current_route() == *config.searching_block - .as_ref() - .expect("searching_block must be configured for this table") => + && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() => { - $table - .search - .as_mut() - .unwrap() - .reset_offset(); + if let Some(ref mut search) = $table.search { + search.reset_offset(); + } true } _ if config.filtering_block.is_some() - && $self.app.get_current_route() == *config.filtering_block - .as_ref() - .expect("filtering_block must be configured for this table") => + && $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap() => { - $table - .filter - .as_mut() - .unwrap() - .reset_offset(); + if let Some(ref mut filter) = $table.filter { + filter.reset_offset(); + } true } _ => false, @@ -249,53 +213,36 @@ macro_rules! handle_table_events { fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { match $self.app.get_current_route() { _ if config.searching_block.is_some() - && $self.app.get_current_route() == *config.searching_block - .as_ref() - .expect("searching_block must be configured for this table") => + && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() => { - $crate::handle_text_box_left_right_keys!( - $self, - $self.key, - $table.search.as_mut().unwrap() - ); + if let Some(ref mut search) = $table.search { + $crate::handle_text_box_left_right_keys!($self, $self.key, search); + } true } _ if config.filtering_block.is_some() - && $self.app.get_current_route() == *config.filtering_block - .as_ref() - .expect("filtering_block must be configured for this table") => + && $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap() => { - $crate::handle_text_box_left_right_keys!( - $self, - $self.key, - $table.filter.as_mut().unwrap() - ); + if let Some(ref mut filter) = $table.filter { + $crate::handle_text_box_left_right_keys!($self, $self.key, filter); + } true } _ => false, } } - fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { + fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { match $self.app.get_current_route() { _ if config.sorting_block.is_some() - && $self.app.get_current_route() == *config.sorting_block - .as_ref() - .expect("sorting_block must be configured for this table") => + && $self.app.get_current_route() == *config.sorting_block.as_ref().unwrap() => { - if let Some(sort_by_fn) = config.sort_by_fn { - $table.items.sort_by(sort_by_fn); - } - $table.apply_sorting(); $self.app.pop_navigation_stack(); - true } _ if config.searching_block.is_some() - && $self.app.get_current_route() == *config.searching_block - .as_ref() - .expect("searching_block must be configured for this table") => + && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap() => { $self.app.pop_navigation_stack(); $self.app.ignore_special_keys_for_textbox_input = false; @@ -318,9 +265,7 @@ macro_rules! handle_table_events { true } _ if config.filtering_block.is_some() - && $self.app.get_current_route() == *config.filtering_block - .as_ref() - .expect("filtering_block must be configured for this table") => + && $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap() => { $self.app.pop_navigation_stack(); $self.app.ignore_special_keys_for_textbox_input = false; @@ -349,21 +294,15 @@ macro_rules! handle_table_events { fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { match $self.app.get_current_route() { _ if config.sorting_block.is_some() - && $self.app.get_current_route() == *config.sorting_block - .as_ref() - .expect("sorting_block must be configured for this table") => + && $self.app.get_current_route() == *config.sorting_block.as_ref().unwrap() => { $self.app.pop_navigation_stack(); true } _ if (config.searching_block.is_some() - && $self.app.get_current_route() == *config.searching_block - .as_ref() - .expect("searching_block must be configured for this table")) + && $self.app.get_current_route() == *config.searching_block.as_ref().unwrap()) || (config.search_error_block.is_some() - && $self.app.get_current_route() == *config.search_error_block - .as_ref() - .expect("search_error_block must be configured for this table")) => + && $self.app.get_current_route() == *config.search_error_block.as_ref().unwrap()) => { $self.app.pop_navigation_stack(); $table.reset_search(); @@ -371,13 +310,9 @@ macro_rules! handle_table_events { true } _ if (config.filtering_block.is_some() - && $self.app.get_current_route() == *config.filtering_block - .as_ref() - .expect("filtering_block must be configured for this table")) + && $self.app.get_current_route() == *config.filtering_block.as_ref().unwrap()) || (config.filter_error_block.is_some() - && $self.app.get_current_route() == *config.filter_error_block - .as_ref() - .expect("filter_error_block must be configured for this table")) => + && $self.app.get_current_route() == *config.filter_error_block.as_ref().unwrap()) => { $self.app.pop_navigation_stack(); $table.reset_filter(); @@ -394,68 +329,67 @@ macro_rules! handle_table_events { } } - fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { - if matches!($self.app.get_current_route(), _ if config.table_block == $self.app.get_current_route()) { - $self - .app - .push_navigation_stack(config.filtering_block.expect("Filtering block is undefined").into()); - $table.reset_filter(); - $table.filter = Some($crate::models::HorizontallyScrollableText::default()); - $self.app.ignore_special_keys_for_textbox_input = true; - - true - } else { - false - } - } - - fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { - if matches!($self.app.get_current_route(), _ if config.table_block == $self.app.get_current_route()) { - $self - .app - .push_navigation_stack(config.searching_block.expect("Searching block is undefined")); - $table.search = Some($crate::models::HorizontallyScrollableText::default()); - $self.app.ignore_special_keys_for_textbox_input = true; - - true - } else { - false - } - } - - fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { - if matches!($self.app.get_current_route(), _ if config.table_block == $self.app.get_current_route()) { - $table.sorting( - config - .sort_options - .as_ref() - .expect("Sort options are undefined") - .clone(), - ); - $self - .app - .push_navigation_stack(config.sorting_block.expect("Sorting block is undefined")); - true - } else { - false - } - } - fn [](&mut $self) -> bool { - $crate::handle_text_box_keys!( - $self, - $self.key, - $table.search.as_mut().unwrap() - ); + let Some(ref mut search) = $table.search else { + return false; + }; + + $crate::handle_text_box_keys!($self, $self.key, search); true } fn [](&mut $self) -> bool { - $crate::handle_text_box_keys!( - $self, - $self.key, - $table.filter.as_mut().unwrap() - ); + let Some(ref mut filter) = $table.filter else { + return false; + }; + + $crate::handle_text_box_keys!($self, $self.key, filter); + true + } + + fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { + if $self.app.get_current_route() != config.table_block { + return false; + } + + let Some(ref filtering_block) = config.filtering_block else { + return false; + }; + + let filter = $crate::models::HorizontallyScrollableText::default(); + $table.filter = Some(filter); + $self.app.push_navigation_stack(*filtering_block); + $self.app.ignore_special_keys_for_textbox_input = true; + true + } + + fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { + if $self.app.get_current_route() != config.table_block { + return false; + } + + let Some(ref searching_block) = config.searching_block else { + return false; + }; + + let search = $crate::models::HorizontallyScrollableText::default(); + $table.search = Some(search); + $self.app.push_navigation_stack(*searching_block); + $self.app.ignore_special_keys_for_textbox_input = true; + true + } + + fn [](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool { + if $self.app.get_current_route() != config.table_block { + return false; + } + + let (Some(ref sorting_block), Some(sort_options)) = (config.sorting_block, config.sort_options.as_ref()) else { + return false; + }; + + $table.sorting(sort_options.clone()); + $self.app.push_navigation_stack(*sorting_block); true } } @@ -467,17 +401,16 @@ where T: Clone + PartialEq + Eq + Debug + Default, { pub fn new(table_block: Route) -> Self { - TableHandlingConfig { + Self { + table_block, sorting_block: None, sort_options: None, - sort_by_fn: None, searching_block: None, search_error_block: None, search_field_fn: None, filtering_block: None, filter_error_block: None, filter_field_fn: None, - table_block, } } } diff --git a/src/handlers/table_handler_tests.rs b/src/handlers/table_handler_tests.rs index af61ec2..e419dcd 100644 --- a/src/handlers/table_handler_tests.rs +++ b/src/handlers/table_handler_tests.rs @@ -23,7 +23,6 @@ mod tests { fn handle(&mut self) { let movie_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::Movies.into()) .sorting_block(ActiveRadarrBlock::MoviesSortPrompt.into()) - .sort_by_fn(|a: &Movie, b: &Movie| a.id.cmp(&b.id)) .sort_options(sort_options()) .searching_block(ActiveRadarrBlock::SearchMovie.into()) .search_error_block(ActiveRadarrBlock::SearchMovieError.into()) diff --git a/src/models/stateful_table.rs b/src/models/stateful_table.rs index a38512a..ba90942 100644 --- a/src/models/stateful_table.rs +++ b/src/models/stateful_table.rs @@ -50,151 +50,46 @@ where T: Clone + PartialEq + Eq + Debug, { fn scroll_down(&mut self) { - if let Some(filtered_items) = self.filtered_items.as_ref() { - if filtered_items.is_empty() { - return; - } - - match self - .filtered_state - .as_ref() - .expect("filtered_state must exist when filtered_items exists") - .selected() - { - Some(i) => { - if i >= filtered_items.len() - 1 { - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_first(); - } else { - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_next(); - } - } - None => self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_first(), - }; - + let items_len = self.active_items().len(); + if items_len == 0 { return; } - if self.items.is_empty() { - return; + let state = self.active_state_mut(); + match state.selected() { + Some(i) if i >= items_len - 1 => state.select_first(), + Some(_) => state.select_next(), + None => state.select_first(), } - - match self.state.selected() { - Some(i) => { - if i >= self.items.len() - 1 { - self.state.select_first(); - } else { - self.state.select_next(); - } - } - None => self.state.select_first(), - }; } fn scroll_up(&mut self) { - if let Some(filtered_items) = self.filtered_items.as_ref() { - if filtered_items.is_empty() { - return; - } - - match self - .filtered_state - .as_ref() - .expect("filtered_state must exist when filtered_items exists") - .selected() - { - Some(i) => { - if i == 0 { - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select(Some(filtered_items.len() - 1)); - } else { - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_previous(); - } - } - None => self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_first(), - }; - + let items_len = self.active_items().len(); + if items_len == 0 { return; } - if self.items.is_empty() { - return; + let state = self.active_state_mut(); + match state.selected() { + Some(0) => state.select(Some(items_len - 1)), + Some(_) => state.select_previous(), + None => state.select_first(), } - - match self.state.selected() { - Some(i) => { - if i == 0 { - self.state.select(Some(self.items.len() - 1)); - } else { - self.state.select_previous(); - } - } - None => self.state.select_first(), - }; } fn scroll_to_top(&mut self) { - if let Some(filtered_items) = self.filtered_items.as_ref() { - if filtered_items.is_empty() { - return; - } - - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_first(); + if self.active_items().is_empty() { return; } - - if self.items.is_empty() { - return; - } - - self.state.select_first(); + self.active_state_mut().select_first(); } fn scroll_to_bottom(&mut self) { - if let Some(filtered_items) = self.filtered_items.as_ref() { - if filtered_items.is_empty() { - return; - } - - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select(Some(filtered_items.len() - 1)); + let items_len = self.active_items().len(); + if items_len == 0 { return; } - - if self.items.is_empty() { - return; - } - - self.state.select(Some(self.items.len() - 1)); + self.active_state_mut().select(Some(items_len - 1)); } } @@ -203,89 +98,56 @@ where T: Clone + PartialEq + Eq + Debug, { fn page_down(&mut self) { - if let Some(filtered_items) = self.filtered_items.as_ref() { - if filtered_items.is_empty() { - return; - } - - match self - .filtered_state - .as_ref() - .expect("filtered_state must exist when filtered_items exists") - .selected() - { - Some(i) => { - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select(Some(i.saturating_add(20) % (filtered_items.len() - 1))); - } - None => self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_first(), - }; - + let items_len = self.active_items().len(); + if items_len == 0 { return; } - if self.items.is_empty() { - return; + let state = self.active_state_mut(); + match state.selected() { + Some(i) => state.select(Some(i.saturating_add(20) % (items_len - 1))), + None => state.select_first(), } - - match self.state.selected() { - Some(i) => { - self - .state - .select(Some(i.saturating_add(20) % (self.items.len() - 1))); - } - None => self.state.select_first(), - }; } fn page_up(&mut self) { - if let Some(filtered_items) = self.filtered_items.as_ref() { - if filtered_items.is_empty() { - return; - } - - match self - .filtered_state - .as_ref() - .expect("filtered_state must exist when filtered_items exists") - .selected() - { - Some(i) => { - let len = filtered_items.len() - 1; - self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select(Some((i + len - (20 % len)) % len)); - } - None => self - .filtered_state - .as_mut() - .expect("filtered_state must exist when filtered_items exists") - .select_last(), - }; - + let items_len = self.active_items().len(); + if items_len == 0 { return; } - if self.items.is_empty() { - return; - } - - match self.state.selected() { + let state = self.active_state_mut(); + match state.selected() { Some(i) => { - let len = self.items.len() - 1; - self.state.select(Some((i + len - (20 % len)) % len)); + let len = items_len - 1; + state.select(Some((i + len - (20 % len)) % len)); } - None => self.state.select_last(), - }; + None => state.select_last(), + } + } +} + +impl StatefulTable +where + T: Clone + PartialEq + Eq + Debug, +{ + fn active_items(&self) -> &[T] { + self + .filtered_items + .as_ref() + .map_or(&self.items[..], |items| &items[..]) + } + + fn active_state_mut(&mut self) -> &mut TableState { + if let Some(ref mut filtered_state) = self.filtered_state { + filtered_state + } else { + &mut self.state + } + } + + fn active_state(&self) -> &TableState { + self.filtered_state.as_ref().unwrap_or(&self.state) } } @@ -318,24 +180,13 @@ where } pub fn select_index(&mut self, index: Option) { - if let Some(filtered_state) = &mut self.filtered_state { - filtered_state.select(index); - } else { - self.state.select(index); - } + self.active_state_mut().select(index); } pub fn current_selection(&self) -> &T { - if let Some(filtered_items) = &self.filtered_items { - &filtered_items[self - .filtered_state - .as_ref() - .expect("filtered_state must exist when filtered_items exists") - .selected() - .unwrap_or(0)] - } else { - &self.items[self.state.selected().unwrap_or(0)] - } + let items = self.active_items(); + let index = self.active_state().selected().unwrap_or(0); + &items[index] } pub fn sorting(&mut self, sort_options: Vec>) { diff --git a/src/utils.rs b/src/utils.rs index 3de6810..c157755 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,10 +6,10 @@ use std::sync::Arc; use std::time::Duration; use anyhow::Result; -use anyhow::{anyhow, Context}; +use anyhow::{Context, anyhow}; use colored::Colorize; use indicatif::{ProgressBar, ProgressStyle}; -use log::{error, LevelFilter}; +use log::{LevelFilter, error}; use log4rs::append::file::FileAppender; use log4rs::config::{Appender, Root}; use log4rs::encode::pattern::PatternEncoder; @@ -18,7 +18,7 @@ use reqwest::{Certificate, Client}; use tokio::sync::Mutex; use tokio_util::sync::CancellationToken; -use crate::app::{log_and_print_error, App, AppConfig}; +use crate::app::{App, AppConfig, log_and_print_error}; use crate::cli::{self, Command}; use crate::network::Network; use crate::ui::theme::ThemeDefinitionsWrapper;