feat(sonarr): add a scrollable overview popup to series details
A series' overview renders as one line of a description box that does not scroll, so a long overview overflows with no way to read the rest. Pressing v on the series details Seasons tab now opens a popup holding the full overview. The popup owns its own ScrollableText, built fresh from the series' overview when it opens and torn down on Esc so a reopened popup starts at the top. Scrolling mutates only that owned state. The background paragraph renders the Series record's overview, which carries no scroll offset, so it cannot scroll along with the popup. Cite the existing view keybinding from the series details context clues and give the popup its own clue set so it does not inherit the hints of the view underneath. Enrich the shared series fixture to a multi-paragraph overview, and the raw response fixture that encodes the same series, so a scrolled popup is distinguishable from an unscrolled one.
This commit is contained in:
57 files changed
+1454
-62
No files matched your search
@@ -303,3 +303,9 @@ impl Default for SeasonDetailsModal {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub struct SeriesOverviewModal {
|
||||
pub overview: ScrollableText,
|
||||
}
|
||||
@@ -11,7 +11,7 @@ mod tests {
|
||||
SELECTABLE_EPISODE_DETAILS_CONTEXT_CLUES,
|
||||
};
|
||||
use crate::models::servarr_data::sonarr::modals::{
|
||||
EditSeriesModal, EpisodeDetailsModal, SeasonDetailsModal,
|
||||
EditSeriesModal, EpisodeDetailsModal, SeasonDetailsModal, SeriesOverviewModal,
|
||||
};
|
||||
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||
use crate::models::servarr_models::{Indexer, IndexerField};
|
||||
@@ -428,4 +428,11 @@ mod tests {
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_series_overview_modal_default() {
|
||||
let series_overview_modal = SeriesOverviewModal::default();
|
||||
|
||||
assert_is_empty!(series_overview_modal.overview);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::modals::{AddSeriesModal, EditSeriesModal, SeasonDetailsModal};
|
||||
use super::modals::{AddSeriesModal, EditSeriesModal, SeasonDetailsModal, SeriesOverviewModal};
|
||||
use crate::{
|
||||
app::{
|
||||
context_clues::{
|
||||
@@ -89,6 +89,7 @@ pub struct SonarrData<'a> {
|
||||
pub series: StatefulTable<Series>,
|
||||
pub series_history: Option<StatefulTable<SonarrHistoryItem>>,
|
||||
pub series_info_tabs: TabState,
|
||||
pub series_overview_modal: Option<SeriesOverviewModal>,
|
||||
pub start_time: DateTime<Utc>,
|
||||
pub tags_map: BiMap<i64, String>,
|
||||
pub tasks: StatefulTable<SonarrTask>,
|
||||
@@ -172,6 +173,7 @@ impl<'a> Default for SonarrData<'a> {
|
||||
selected_block: BlockSelectionState::default(),
|
||||
series: StatefulTable::default(),
|
||||
series_history: None,
|
||||
series_overview_modal: None,
|
||||
start_time: DateTime::default(),
|
||||
tags_map: BiMap::default(),
|
||||
tasks: StatefulTable::default(),
|
||||
@@ -347,6 +349,10 @@ impl SonarrData<'_> {
|
||||
series_history.search = Some("series history search".into());
|
||||
series_history.filter = Some("series history filter".into());
|
||||
|
||||
let series_overview_modal = SeriesOverviewModal {
|
||||
overview: ScrollableText::with_string(series().overview.clone().unwrap_or_default()),
|
||||
};
|
||||
|
||||
let mut sonarr_data = SonarrData {
|
||||
add_list_exclusion: true,
|
||||
add_searched_series: Some(add_searched_series),
|
||||
@@ -364,6 +370,7 @@ impl SonarrData<'_> {
|
||||
quality_profile_map: quality_profile_map(),
|
||||
season_details_modal: Some(season_details_modal),
|
||||
series_history: Some(series_history),
|
||||
series_overview_modal: Some(series_overview_modal),
|
||||
start_time: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap()),
|
||||
tags_map: tags_map(),
|
||||
updates: updates(),
|
||||
@@ -503,6 +510,7 @@ pub enum ActiveSonarrBlock {
|
||||
SeriesHistory,
|
||||
SeriesHistoryDetails,
|
||||
SeriesHistorySortPrompt,
|
||||
SeriesOverview,
|
||||
SeriesSortPrompt,
|
||||
System,
|
||||
SystemLogs,
|
||||
@@ -542,6 +550,8 @@ pub static SERIES_DETAILS_BLOCKS: [ActiveSonarrBlock; 12] = [
|
||||
ActiveSonarrBlock::SeriesHistoryDetails,
|
||||
];
|
||||
|
||||
pub static SERIES_OVERVIEW_BLOCKS: [ActiveSonarrBlock; 1] = [ActiveSonarrBlock::SeriesOverview];
|
||||
|
||||
pub static SEASON_DETAILS_BLOCKS: [ActiveSonarrBlock; 15] = [
|
||||
ActiveSonarrBlock::SeasonDetails,
|
||||
ActiveSonarrBlock::SeasonHistory,
|
||||
|
||||
@@ -171,6 +171,7 @@ mod tests {
|
||||
assert_eq!(sonarr_data.selected_block, BlockSelectionState::default());
|
||||
assert_is_empty!(sonarr_data.series);
|
||||
assert_none!(sonarr_data.series_history);
|
||||
assert_none!(sonarr_data.series_overview_modal);
|
||||
assert_eq!(sonarr_data.start_time, <DateTime<Utc>>::default());
|
||||
assert_is_empty!(sonarr_data.tags_map);
|
||||
assert_is_empty!(sonarr_data.tasks);
|
||||
@@ -289,7 +290,8 @@ mod tests {
|
||||
EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, EDIT_SERIES_BLOCKS,
|
||||
EDIT_SERIES_SELECTION_BLOCKS, EPISODE_DETAILS_BLOCKS, HISTORY_BLOCKS,
|
||||
INDEXER_SETTINGS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS, LIBRARY_BLOCKS,
|
||||
ROOT_FOLDERS_BLOCKS, SEASON_DETAILS_BLOCKS, SERIES_DETAILS_BLOCKS, SYSTEM_DETAILS_BLOCKS,
|
||||
ROOT_FOLDERS_BLOCKS, SEASON_DETAILS_BLOCKS, SERIES_DETAILS_BLOCKS, SERIES_OVERVIEW_BLOCKS,
|
||||
SYSTEM_DETAILS_BLOCKS,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -671,6 +673,17 @@ mod tests {
|
||||
assert!(SERIES_DETAILS_BLOCKS.contains(&ActiveSonarrBlock::SeriesHistoryDetails));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_series_details_blocks_excludes_series_overview() {
|
||||
assert!(!SERIES_DETAILS_BLOCKS.contains(&ActiveSonarrBlock::SeriesOverview));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_series_overview_blocks_contents() {
|
||||
assert_eq!(SERIES_OVERVIEW_BLOCKS.len(), 1);
|
||||
assert!(SERIES_OVERVIEW_BLOCKS.contains(&ActiveSonarrBlock::SeriesOverview));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_season_details_blocks_contents() {
|
||||
assert_eq!(SEASON_DETAILS_BLOCKS.len(), 15);
|
||||
|
||||
Reference in new issue
Block a user