feat(ui): add explicit content badge across entire app

Display parental_warning badge (E icon) next to track titles in all
views: TrackRow, QueuePanel, NowPlayingBar, ImmersivePlayer with all
13 visualizer panels, MiniPlayer surfaces, and AlbumDetailView.

Propagate parental_warning field through the full data chain from
Rust backend (qbz-models, queue, commands_v2, session_store, API
server) to frontend stores, adapters, and UI components. Badge uses
CSS mask technique with explicit.svg for theme compatibility.
This commit is contained in:
vicrodh committed 2026-03-06 08:48:51 -06:00
1 parent 6685566091
commit 5b9f5a75c2
39 files changed
+538 -36

No files matched your search

+1
View File
@@ -979,6 +979,7 @@ async fn play_album(
artist_id: t.performer.as_ref().map(|p| p.id),
streamable: t.streamable,
source: Some("qobuz".to_string()),
parental_warning: t.parental_warning,
}
})
.collect()
+7
View File
@@ -5477,6 +5477,7 @@ fn track_to_queue_track_from_api(track: &crate::api::Track) -> CoreQueueTrack {
artist_id,
streamable: track.streamable,
source: Some("qobuz".to_string()),
parental_warning: track.parental_warning,
}
}
@@ -5604,6 +5605,8 @@ pub struct V2QueueTrack {
/// Source type: "qobuz", "local", "plex"
#[serde(default)]
pub source: Option<String>,
#[serde(default)]
pub parental_warning: bool,
}
fn default_streamable() -> bool {
@@ -5627,6 +5630,7 @@ impl From<V2QueueTrack> for crate::queue::QueueTrack {
artist_id: t.artist_id,
streamable: t.streamable,
source: t.source,
parental_warning: t.parental_warning,
}
}
}
@@ -5648,6 +5652,7 @@ impl From<crate::queue::QueueTrack> for V2QueueTrack {
artist_id: t.artist_id,
streamable: t.streamable,
source: t.source,
parental_warning: t.parental_warning,
}
}
}
@@ -5670,6 +5675,7 @@ impl From<V2QueueTrack> for CoreQueueTrack {
artist_id: t.artist_id,
streamable: t.streamable,
source: t.source,
parental_warning: t.parental_warning,
}
}
}
@@ -5691,6 +5697,7 @@ impl From<CoreQueueTrack> for V2QueueTrack {
artist_id: t.artist_id,
streamable: t.streamable,
source: t.source,
parental_warning: t.parental_warning,
}
}
}
+4
View File
@@ -54,6 +54,9 @@ pub struct QueueTrack {
/// Optional origin source (e.g. "qobuz", "local", "plex")
#[serde(default)]
pub source: Option<String>,
/// Parental advisory / explicit content
#[serde(default)]
pub parental_warning: bool,
}
fn default_streamable() -> bool {
@@ -759,6 +762,7 @@ mod tests {
artist_id: None,
streamable: true,
source: Some("test".to_string()),
parental_warning: false,
}
}
+3
View File
@@ -29,6 +29,8 @@ pub struct PersistedQueueTrack {
pub streamable: bool,
#[serde(default)]
pub source: Option<String>,
#[serde(default)]
pub parental_warning: bool,
}
/// Represents the full persisted session state
@@ -345,6 +347,7 @@ impl SessionStore {
artist_id: row.get::<_, Option<i64>>(11)?.map(|v| v as u64),
streamable: true, // Default to true for persisted tracks
source: row.get(12)?,
parental_warning: false, // Not persisted in DB
})
})
.map_err(|e| format!("Failed to query queue tracks: {}", e))?