feat(slint): album cards show genre + localized full release date (#469)
Album-card hover overlay now shows the full release date as "MMM D, YYYY" (e.g. "Nov 6, 2025") instead of the year alone. New dates::release_label helper keeps the month/day/year order fixed but localizes the month via chrono format_localized (the app ships 5 languages; current_locale() is the single hook to thread the real UI language once Slint wires translations — English for now). Applied to the Discover and Favorites album mappings. Also fixes Favorites > Albums cards, which hardcoded an empty genre and a year-only label: they now read album.genre and the full date, matching the Discover cards 1:1. The data was already in the getUserFavorites response (qbz-models Album parses genre + release_date_original) — no backend change. cc
This commit is contained in:
6 files changed
+65
-13
No files matched your search
@@ -35,6 +35,7 @@ rfd = { version = "0.15", default-features = false, features = ["xdg-portal", "t
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
dirs = "5"
|
||||
chrono = { workspace = true, features = ["unstable-locales"] }
|
||||
qbz-app = { path = "../qbz-app" }
|
||||
qbz-audio = { path = "../qbz-audio" }
|
||||
qbz-core = { path = "../qbz-core" }
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//! Release-date label formatting for album cards (#469).
|
||||
//!
|
||||
//! Renders a Qobuz release date as a fixed "MMM D, YYYY" structure (e.g.
|
||||
//! "Nov 6, 2025") with a *localized* abbreviated month. We deliberately keep
|
||||
//! the month / day / year order fixed (not the locale-reordered output of a
|
||||
//! `toLocaleDateString`-style call) but localize the month token, because the
|
||||
//! app ships five UI languages (en / es / de / fr / pt). The Slint UI is
|
||||
//! English-only during the migration, so [`current_locale`] returns English
|
||||
//! today — it is the single place to wire the real UI language once Slint
|
||||
//! gets translation support, and no caller needs to change when it does.
|
||||
|
||||
use chrono::{Locale, NaiveDate};
|
||||
|
||||
/// UI language used to render date labels. Slint is English-only for now;
|
||||
/// this is the one hook to thread the persisted UI language through later
|
||||
/// (the app supports en / es / de / fr / pt).
|
||||
pub fn current_locale() -> Locale {
|
||||
Locale::en_US
|
||||
}
|
||||
|
||||
/// Format a Qobuz release date string ("YYYY-MM-DD", possibly with a trailing
|
||||
/// time component) as "MMM D, YYYY" with a localized month. Falls back to the
|
||||
/// bare 4-digit year when only a year is available or the value cannot be
|
||||
/// parsed as a full date, and to an empty string when there is no date.
|
||||
pub fn release_label(date: Option<&str>) -> String {
|
||||
let Some(raw) = date else {
|
||||
return String::new();
|
||||
};
|
||||
let raw = raw.trim();
|
||||
if raw.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
// Only the leading YYYY-MM-DD matters; ignore any trailing time.
|
||||
let head = raw.get(0..10).unwrap_or(raw);
|
||||
if let Ok(parsed) = NaiveDate::parse_from_str(head, "%Y-%m-%d") {
|
||||
// %b = localized abbreviated month, %-d = day without leading zero.
|
||||
return parsed
|
||||
.format_localized("%b %-d, %Y", current_locale())
|
||||
.to_string();
|
||||
}
|
||||
// Year-only fallback (e.g. the source only had "2025").
|
||||
raw.get(0..4).unwrap_or_default().to_string()
|
||||
}
|
||||
@@ -104,6 +104,7 @@ pub struct AlbumCard {
|
||||
pub title: String,
|
||||
pub artist: String,
|
||||
pub artist_id: String,
|
||||
pub genre: String,
|
||||
pub year: String,
|
||||
pub quality_tier: String,
|
||||
pub quality_label: String,
|
||||
@@ -240,11 +241,8 @@ fn map_track(track: Track) -> TrackCard {
|
||||
}
|
||||
|
||||
fn map_album(album: Album) -> AlbumCard {
|
||||
let year = album
|
||||
.release_date_original
|
||||
.as_deref()
|
||||
.and_then(|s| s.get(..4).map(|y| y.to_string()))
|
||||
.unwrap_or_default();
|
||||
let year = crate::dates::release_label(album.release_date_original.as_deref());
|
||||
let genre = album.genre.map(|g| g.name).unwrap_or_default();
|
||||
let quality_label = match (album.maximum_bit_depth, album.maximum_sampling_rate) {
|
||||
(Some(bd), Some(sr)) => format!("{}-bit / {} kHz", bd, sr),
|
||||
_ => String::new(),
|
||||
@@ -254,6 +252,7 @@ fn map_album(album: Album) -> AlbumCard {
|
||||
title: album.title,
|
||||
artist: album.artist.name,
|
||||
artist_id: album.artist.id.to_string(),
|
||||
genre,
|
||||
year,
|
||||
quality_tier: tier(album.maximum_bit_depth).to_string(),
|
||||
quality_label,
|
||||
@@ -338,7 +337,7 @@ pub fn apply_favorites(window: &AppWindow, data: FavData) {
|
||||
title: a.title.into(),
|
||||
artist: a.artist.into(),
|
||||
artist_id: a.artist_id.into(),
|
||||
genre: "".into(),
|
||||
genre: a.genre.into(),
|
||||
year: a.year.into(),
|
||||
quality_tier: a.quality_tier.into(),
|
||||
quality_label: a.quality_label.into(),
|
||||
|
||||
@@ -230,13 +230,13 @@ fn map_album(album: DiscoverAlbum) -> CardData {
|
||||
.map(|a| a.id.to_string())
|
||||
.unwrap_or_default();
|
||||
let genre = album.genre.map(|g| g.name).unwrap_or_default();
|
||||
let year = album
|
||||
.dates
|
||||
.as_ref()
|
||||
.and_then(|d| d.original.as_ref().or(d.download.as_ref()).or(d.stream.as_ref()))
|
||||
.and_then(|date| date.get(0..4))
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
let year = crate::dates::release_label(
|
||||
album
|
||||
.dates
|
||||
.as_ref()
|
||||
.and_then(|d| d.original.as_ref().or(d.download.as_ref()).or(d.stream.as_ref()))
|
||||
.map(|s| s.as_str()),
|
||||
);
|
||||
let (ribbon, ribbon_kind) = pick_ribbon(album.awards.as_deref());
|
||||
let quality_tier = quality_tier(album.audio_info.as_ref()).to_string();
|
||||
let quality_label = quality_label(album.audio_info.as_ref());
|
||||
|
||||
@@ -21,6 +21,7 @@ mod artwork;
|
||||
mod auth;
|
||||
mod commands;
|
||||
mod custom_artwork;
|
||||
mod dates;
|
||||
mod discovery_dismiss;
|
||||
mod favorites;
|
||||
mod foryou;
|
||||
|
||||
Reference in new issue
Block a user