feat(label): redesign label detail view with Android-style sections

Replace the flat album grid LabelView with a rich detail page featuring:
- Header with label image, name, description, and play button
- Popular Tracks section (5/10/all expand, same UX as ArtistDetailView)
- Releases horizontal scroll row with "See all" → LabelReleasesView
- Critics' Picks section from second releases container
- Playlists, Artists, and More Labels sections

Backend: add /label/page and /label/explore API endpoints with V2
commands (v2_get_label_page, v2_get_label_explore). Models use
serde_json::Value for flexible section parsing.

Old LabelView renamed to LabelReleasesView for the "See all" flow.
i18n keys added to all 4 locales (en, es, de, fr).
This commit is contained in:
vicrodh committed 2026-02-20 02:51:47 -06:00
1 parent 318318a3ab
commit 585053bd42
21 files changed
+2297 -461

No files matched your search

+2 -1
View File
@@ -42,7 +42,8 @@ pub use playback::{PlaybackState, PlaybackStatus, QueueState, QueueTrack, Repeat
pub use traits::{FrontendAdapter, LoggingAdapter, NoOpAdapter};
pub use types::{
Album, AlbumSummary, Artist, ArtistAlbums, ArtistBiography, Favorites, Genre, GenreInfo,
GenreListContainer, GenreListResponse, ImageSet, Label, LabelDetail, Playlist,
GenreListContainer, GenreListResponse, ImageSet, Label, LabelDetail,
LabelExploreResponse, LabelPageContainer, LabelPageData, LabelPageGenericList, Playlist,
PlaylistDuplicateResult, PlaylistGenre, PlaylistOwner, PlaylistWithTrackIds, Quality,
SearchResults, SearchResultsPage, StreamRestriction, StreamUrl, Track, TracksContainer,
UserSession,
+41
View File
@@ -353,6 +353,47 @@ pub struct LabelDetail {
pub albums_count: Option<u32>,
}
// ============ Label Page Types (/label/page) ============
/// Top-level response from /label/page
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabelPageData {
pub id: u64,
pub name: String,
pub description: Option<String>,
#[serde(default)]
pub image: Option<serde_json::Value>,
#[serde(default)]
pub releases: Option<Vec<LabelPageContainer>>,
#[serde(default)]
pub playlists: Option<LabelPageGenericList>,
#[serde(default)]
pub top_tracks: Option<Vec<serde_json::Value>>,
#[serde(default)]
pub top_artists: Option<LabelPageGenericList>,
}
/// A container within label page (e.g. releases category)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabelPageContainer {
pub id: Option<String>,
pub data: Option<LabelPageGenericList>,
}
/// Generic list with has_more and items
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabelPageGenericList {
pub has_more: Option<bool>,
pub items: Option<Vec<serde_json::Value>>,
}
/// Response from /label/explore
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabelExploreResponse {
pub has_more: Option<bool>,
pub items: Option<Vec<serde_json::Value>>,
}
/// Genre model
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Genre {