feat(lidarr): add a scrollable overview popup to artist details
An artist's 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 artist details Albums tab now opens a popup holding the full overview. The popup owns its own ScrollableText, built fresh from the artist's 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 Artist record's overview, which carries no scroll offset, so it cannot scroll along with the popup. Cite the existing view keybinding from the artist 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 artist fixture to a multi-paragraph overview, and the blocklist response fixtures that embed the same artist, so a scrolled popup is distinguishable from an unscrolled one.
This commit is contained in:
59 files changed
+1521
-134
No files matched your search
@@ -1,6 +1,8 @@
|
||||
use serde_json::Number;
|
||||
|
||||
use super::modals::{AddArtistModal, AddRootFolderModal, AlbumDetailsModal, EditArtistModal};
|
||||
use super::modals::{
|
||||
AddArtistModal, AddRootFolderModal, AlbumDetailsModal, ArtistOverviewModal, EditArtistModal,
|
||||
};
|
||||
use crate::app::context_clues::{
|
||||
BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||
@@ -64,6 +66,7 @@ pub struct LidarrData<'a> {
|
||||
pub album_details_modal: Option<AlbumDetailsModal>,
|
||||
pub artist_history: StatefulTable<LidarrHistoryItem>,
|
||||
pub artist_info_tabs: TabState,
|
||||
pub artist_overview_modal: Option<ArtistOverviewModal>,
|
||||
pub artists: StatefulTable<Artist>,
|
||||
pub blocklist: StatefulTable<BlocklistItem>,
|
||||
pub delete_files: bool,
|
||||
@@ -150,6 +153,7 @@ impl<'a> Default for LidarrData<'a> {
|
||||
albums: StatefulTable::default(),
|
||||
album_details_modal: None,
|
||||
artist_history: StatefulTable::default(),
|
||||
artist_overview_modal: None,
|
||||
artists: StatefulTable::default(),
|
||||
blocklist: StatefulTable::default(),
|
||||
delete_files: false,
|
||||
@@ -354,8 +358,13 @@ impl LidarrData<'_> {
|
||||
let mut indexer_test_all_results = StatefulTable::default();
|
||||
indexer_test_all_results.set_items(vec![indexer_test_result()]);
|
||||
|
||||
let artist_overview_modal = ArtistOverviewModal {
|
||||
overview: ScrollableText::with_string(artist().overview.unwrap_or_default()),
|
||||
};
|
||||
|
||||
let mut lidarr_data = LidarrData {
|
||||
album_details_modal: Some(album_details_modal),
|
||||
artist_overview_modal: Some(artist_overview_modal),
|
||||
delete_files: true,
|
||||
disk_space_vec: vec![diskspace()],
|
||||
quality_profile_map: quality_profile_map(),
|
||||
@@ -428,6 +437,7 @@ pub enum ActiveLidarrBlock {
|
||||
ArtistHistory,
|
||||
ArtistHistoryDetails,
|
||||
ArtistHistorySortPrompt,
|
||||
ArtistOverview,
|
||||
ArtistsSortPrompt,
|
||||
AddArtistAlreadyInLibrary,
|
||||
AddArtistConfirmPrompt,
|
||||
@@ -579,6 +589,8 @@ pub static ARTIST_DETAILS_BLOCKS: [ActiveLidarrBlock; 15] = [
|
||||
ActiveLidarrBlock::UpdateAndScanArtistPrompt,
|
||||
];
|
||||
|
||||
pub static ARTIST_OVERVIEW_BLOCKS: [ActiveLidarrBlock; 1] = [ActiveLidarrBlock::ArtistOverview];
|
||||
|
||||
pub static ALBUM_DETAILS_BLOCKS: [ActiveLidarrBlock; 15] = [
|
||||
ActiveLidarrBlock::AlbumDetails,
|
||||
ActiveLidarrBlock::AlbumHistory,
|
||||
|
||||
@@ -11,12 +11,12 @@ mod tests {
|
||||
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ALBUM_DETAILS_BLOCKS,
|
||||
ARTIST_DETAILS_BLOCKS, BLOCKLIST_BLOCKS, DELETE_ALBUM_BLOCKS, DELETE_ALBUM_SELECTION_BLOCKS,
|
||||
DELETE_ARTIST_BLOCKS, DELETE_ARTIST_SELECTION_BLOCKS, DOWNLOADS_BLOCKS, EDIT_ARTIST_BLOCKS,
|
||||
EDIT_ARTIST_SELECTION_BLOCKS, EDIT_INDEXER_BLOCKS, EDIT_INDEXER_NZB_SELECTION_BLOCKS,
|
||||
EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, HISTORY_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
||||
INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS, ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS,
|
||||
TRACK_DETAILS_BLOCKS,
|
||||
ARTIST_DETAILS_BLOCKS, ARTIST_OVERVIEW_BLOCKS, BLOCKLIST_BLOCKS, DELETE_ALBUM_BLOCKS,
|
||||
DELETE_ALBUM_SELECTION_BLOCKS, DELETE_ARTIST_BLOCKS, DELETE_ARTIST_SELECTION_BLOCKS,
|
||||
DOWNLOADS_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS, EDIT_INDEXER_BLOCKS,
|
||||
EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, HISTORY_BLOCKS,
|
||||
INDEXER_SETTINGS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS,
|
||||
ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS, TRACK_DETAILS_BLOCKS,
|
||||
};
|
||||
use crate::models::{
|
||||
BlockSelectionState, Route,
|
||||
@@ -149,6 +149,7 @@ mod tests {
|
||||
assert_none!(lidarr_data.album_details_modal);
|
||||
assert_is_empty!(lidarr_data.artists);
|
||||
assert_is_empty!(lidarr_data.artist_history);
|
||||
assert_none!(lidarr_data.artist_overview_modal);
|
||||
assert_is_empty!(lidarr_data.blocklist);
|
||||
assert!(!lidarr_data.delete_files);
|
||||
assert_is_empty!(lidarr_data.disk_space_vec);
|
||||
@@ -318,6 +319,17 @@ mod tests {
|
||||
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::UpdateAndScanArtistPrompt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_details_blocks_excludes_artist_overview() {
|
||||
assert!(!ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::ArtistOverview));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_overview_blocks_contents() {
|
||||
assert_eq!(ARTIST_OVERVIEW_BLOCKS.len(), 1);
|
||||
assert!(ARTIST_OVERVIEW_BLOCKS.contains(&ActiveLidarrBlock::ArtistOverview));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_album_details_blocks_contents() {
|
||||
assert_eq!(ALBUM_DETAILS_BLOCKS.len(), 15);
|
||||
|
||||
@@ -294,3 +294,9 @@ impl Default for TrackDetailsModal {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub struct ArtistOverviewModal {
|
||||
pub overview: ScrollableText,
|
||||
}
|
||||
@@ -7,7 +7,7 @@ mod tests {
|
||||
use crate::models::lidarr_models::{Artist, MonitorType, NewItemMonitorType};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, LidarrData};
|
||||
use crate::models::servarr_data::lidarr::modals::{
|
||||
AddArtistModal, AlbumDetailsModal, EditArtistModal, TrackDetailsModal,
|
||||
AddArtistModal, AlbumDetailsModal, ArtistOverviewModal, EditArtistModal, TrackDetailsModal,
|
||||
};
|
||||
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||
use crate::models::servarr_models::{Indexer, IndexerField, RootFolder};
|
||||
@@ -307,4 +307,11 @@ mod tests {
|
||||
);
|
||||
assert_eq!(track_details_modal.track_details_tabs.tabs[1].config, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_overview_modal_default() {
|
||||
let artist_overview_modal = ArtistOverviewModal::default();
|
||||
|
||||
assert_is_empty!(artist_overview_modal.overview);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user