fix(cards): carry the Qobuz album version in card titles + tooltip when elided
Every album card producer copied `title` raw although the model carries
`version` ("50th Anniversary", "Deluxe"); the album page, info modal and quick
view already used `format_album_title`. The Artist page listed two identical
"All Things Must Pass" cards for two different editions.
- Route the 8 card producers through `album_qt::format_album_title`
(artist page buckets, album carousels, label grid, Home rails, Library ALL
feed, Artist Scene); search_qt drops its private duplicate of the helper.
- AlbumCard.qml: the title is always the full string, elided at the card
width; when Qt reports `truncated`, hovering shows the whole title in a
Controls ToolTip (QualityBadge pattern, no character counting, no ticker).
Verified: qmllint clean, qbz-qt suite 782/782, release build.
cc
This commit is contained in:
7 files changed
+55
-14
No files matched your search
@@ -921,6 +921,7 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
Text {
|
||||
id: titleText
|
||||
width: parent.width
|
||||
height: 20
|
||||
text: root.title
|
||||
@@ -930,6 +931,48 @@ Rectangle {
|
||||
font.weight: theme.weightMedium
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
// The title is ALWAYS the full one (version included) and
|
||||
// elides at the card's width; when it is cut, hovering shows
|
||||
// the whole text in a small bubble above the line. `truncated`
|
||||
// is Qt's own verdict on the elision, so a title that fits
|
||||
// never raises a tooltip — no character counting. Qt's own
|
||||
// ToolTip, like QualityBadge.qml: a recycled delegate deep
|
||||
// inside a view cannot name the shell's tooltip overlay.
|
||||
ToolTip {
|
||||
id: titleTip
|
||||
visible: titleArea.containsMouse && titleText.truncated
|
||||
&& root.title !== ""
|
||||
text: root.title
|
||||
delay: 350
|
||||
timeout: -1
|
||||
padding: 0
|
||||
x: 0
|
||||
y: -height - 4
|
||||
contentWidth: titleTipText.implicitWidth
|
||||
contentHeight: titleTipText.implicitHeight
|
||||
contentItem: Text {
|
||||
id: titleTipText
|
||||
text: titleTip.text
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: 11
|
||||
font.weight: theme.weightMedium
|
||||
wrapMode: Text.Wrap
|
||||
width: Math.min(implicitWidth, 300)
|
||||
maximumLineCount: 3
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
leftPadding: 9
|
||||
rightPadding: 9
|
||||
topPadding: 5
|
||||
bottomPadding: 5
|
||||
}
|
||||
background: Rectangle {
|
||||
color: theme.surfaceElevated
|
||||
radius: theme.radiusSm
|
||||
border.width: 1
|
||||
border.color: theme.borderSubtle
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: titleArea
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -1086,7 +1086,7 @@ fn map_release_card(release: &qbz_models::PageArtistRelease) -> AlbumCardData {
|
||||
// Heart from the favourite-id cache (see `AlbumCardData::is_favorite`).
|
||||
is_favorite: crate::fav_cache_qt::is_album_favorite(&release.id),
|
||||
id: release.id.clone(),
|
||||
title: release.title.clone(),
|
||||
title: format_album_title(&release.title, release.version.as_deref()),
|
||||
artist,
|
||||
artist_id,
|
||||
genre: release
|
||||
@@ -1213,7 +1213,7 @@ pub async fn load_suggestions(
|
||||
is_pinned: crate::sidebar_qt::is_pinned("album", &a.id),
|
||||
is_favorite: crate::fav_cache_qt::is_album_favorite(&a.id),
|
||||
id: a.id.clone(),
|
||||
title: a.title.clone(),
|
||||
title: format_album_title(&a.title, a.version.as_deref()),
|
||||
artist,
|
||||
artist_id: card_artist_id,
|
||||
genre: a.genre.as_ref().map(|g| g.name.clone()).unwrap_or_default(),
|
||||
|
||||
@@ -442,7 +442,10 @@ pub(crate) fn map_release(release: &PageArtistRelease) -> AlbumCardData {
|
||||
// mounts the same AlbumCard as Home (see `AlbumCardData::is_favorite`).
|
||||
is_favorite: crate::fav_cache_qt::is_album_favorite(&release.id),
|
||||
id: release.id.clone(),
|
||||
title: release.title.clone(),
|
||||
// The Qobuz `version` ("50th Anniversary", "Deluxe") rides the title
|
||||
// everywhere else in the app (`format_album_title`); the card is not
|
||||
// the exception — a title without it points at the wrong edition.
|
||||
title: crate::album_qt::format_album_title(&release.title, release.version.as_deref()),
|
||||
artist,
|
||||
artist_id,
|
||||
genre: release
|
||||
|
||||
@@ -1115,7 +1115,7 @@ fn map_album(album: &Album) -> SceneAlbum {
|
||||
.unwrap_or_default();
|
||||
SceneAlbum {
|
||||
album_id: album.id.clone(),
|
||||
title: album.title.clone(),
|
||||
title: crate::album_qt::format_album_title(&album.title, album.version.as_deref()),
|
||||
artist: album.artist.name.clone(),
|
||||
artist_id: album.artist.id.to_string(),
|
||||
// `image.small || image.large` — Tauri's exact order
|
||||
|
||||
@@ -1797,7 +1797,7 @@ pub(crate) fn map_album(album: DiscoverAlbum) -> HomeCard {
|
||||
is_pinned,
|
||||
is_favorite,
|
||||
id: album.id,
|
||||
title: album.title,
|
||||
title: crate::album_qt::format_album_title(&album.title, album.version.as_deref()),
|
||||
artist,
|
||||
artist_id,
|
||||
blacklist_artist_ids,
|
||||
@@ -1893,7 +1893,7 @@ fn map_slim(index: usize, album: DiscoverAlbum) -> HomeCard {
|
||||
// false. A future SlimCard with a heart inherits a correct row.
|
||||
is_favorite: crate::fav_cache_qt::is_album_favorite(&album.id),
|
||||
id: album.id,
|
||||
title: album.title,
|
||||
title: crate::album_qt::format_album_title(&album.title, album.version.as_deref()),
|
||||
artist: subtitle,
|
||||
artist_id,
|
||||
blacklist_artist_ids,
|
||||
@@ -2101,7 +2101,7 @@ pub(crate) fn map_flat_album(album: Album) -> HomeCard {
|
||||
// DiscoverBrowse, so one stamp covers four surfaces.
|
||||
is_favorite: crate::fav_cache_qt::is_album_favorite(&album.id),
|
||||
id: album.id,
|
||||
title: album.title,
|
||||
title: crate::album_qt::format_album_title(&album.title, album.version.as_deref()),
|
||||
artist: album.artist.name,
|
||||
artist_id: album.artist.id.to_string(),
|
||||
blacklist_artist_ids,
|
||||
|
||||
@@ -651,7 +651,7 @@ fn map_album(album: Album, ready_offline_tracks: usize) -> FeedItem {
|
||||
group: "favorites".into(),
|
||||
source: "qobuz".into(),
|
||||
id: album.id,
|
||||
title: album.title,
|
||||
title: crate::album_qt::format_album_title(&album.title, album.version.as_deref()),
|
||||
subtitle: artist.clone(),
|
||||
artist,
|
||||
artist_id: album.artist.id.to_string(),
|
||||
|
||||
@@ -45,6 +45,7 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use cxx_qt_lib::QString;
|
||||
pub(crate) use qbz_app::settings::search_service::InteractionAction;
|
||||
use crate::album_qt::format_album_title;
|
||||
use qbz_app::settings::search_service::SearchService;
|
||||
use qbz_app::shell::AppRuntime;
|
||||
use qbz_core::LoggingAdapter;
|
||||
@@ -320,12 +321,6 @@ fn year_of(date: Option<&str>) -> String {
|
||||
date.and_then(|d| d.get(0..4)).unwrap_or("").to_string()
|
||||
}
|
||||
|
||||
fn format_album_title(title: &str, version: Option<&str>) -> String {
|
||||
match version.map(str::trim).filter(|v| !v.is_empty()) {
|
||||
Some(v) => format!("{title} ({v})"),
|
||||
None => title.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_album(album: &Album) -> CardRow {
|
||||
CardRow {
|
||||
|
||||
Reference in new issue
Block a user