feat(qt): Open containing album on cortinilla track rows

CortRow gains an albumId — the Qobuz album id for catalog tracks, the
album group key for local ones (both are what crate::open_album routes),
empty elsewhere. The track menu gates its new entry on the field, the
action funnels through cortinillaMenuAction like its siblings, and the
new msgid ships in the seven non-English locales.

cc
This commit is contained in:
vicrodh committed 2026-08-31 11:26:17 -06:00
1 parent 7f702f118d
commit 5e6daf0e81
10 files changed
+67 -10

No files matched your search

@@ -446,6 +446,9 @@ msgstr "Entdecken Sie neue Musik aus Ihren meistgespielten Playlists."
msgid "Open album" msgid "Open album"
msgstr "Album öffnen" msgstr "Album öffnen"
msgid "Open containing album"
msgstr "Zugehöriges Album öffnen"
msgid "Play" msgid "Play"
msgstr "Abspielen" msgstr "Abspielen"
@@ -449,6 +449,9 @@ msgstr "Descubre música nueva a partir de tus listas más reproducidas."
msgid "Open album" msgid "Open album"
msgstr "Abrir álbum" msgstr "Abrir álbum"
msgid "Open containing album"
msgstr "Abrir el álbum contenedor"
msgid "Play" msgid "Play"
msgstr "Reproducir" msgstr "Reproducir"
@@ -446,6 +446,9 @@ msgstr "Découvrez de nouvelles musiques à partir de vos playlists les plus éc
msgid "Open album" msgid "Open album"
msgstr "Ouvrir l'album" msgstr "Ouvrir l'album"
msgid "Open containing album"
msgstr "Ouvrir l'album d'origine"
msgid "Play" msgid "Play"
msgstr "Lecture" msgstr "Lecture"
@@ -445,6 +445,9 @@ msgstr "よく再生するプレイリストから新しい音楽を見つけま
msgid "Open album" msgid "Open album"
msgstr "アルバムを開く" msgstr "アルバムを開く"
msgid "Open containing album"
msgstr "収録アルバムを開く"
msgid "Play" msgid "Play"
msgstr "再生" msgstr "再生"
@@ -446,6 +446,9 @@ msgstr "Ontdek nieuwe muziek op basis van je meest afgespeelde afspeellijsten."
msgid "Open album" msgid "Open album"
msgstr "Album openen" msgstr "Album openen"
msgid "Open containing album"
msgstr "Bijbehorend album openen"
msgid "Play" msgid "Play"
msgstr "Afspelen" msgstr "Afspelen"
@@ -446,6 +446,9 @@ msgstr "Descubra novas músicas a partir das suas playlists mais reproduzidas."
msgid "Open album" msgid "Open album"
msgstr "Abrir álbum" msgstr "Abrir álbum"
msgid "Open containing album"
msgstr "Abrir o álbum de origem"
msgid "Play" msgid "Play"
msgstr "Reproduzir" msgstr "Reproduzir"
@@ -445,6 +445,9 @@ msgstr "Откройте новую музыку из ваших любимых
msgid "Open album" msgid "Open album"
msgstr "Открыть альбом" msgstr "Открыть альбом"
msgid "Open containing album"
msgstr "Открыть альбом трека"
msgid "Play" msgid "Play"
msgstr "Воспроизвести" msgstr "Воспроизвести"
+16 -9
View File
@@ -102,13 +102,20 @@ Item {
artistRows.push({ "label": t("Play", r), "icon": "play-fill", "action": "play" }) artistRows.push({ "label": t("Play", r), "icon": "play-fill", "action": "play" })
return artistRows return artistRows
} }
if (row.kind === "track") return [ if (row.kind === "track") {
{ "label": t("Play", r), "icon": "play-fill", "action": "play" }, var trackRows = [
{ "label": t("Play next", r), "icon": "list-start", "action": "next" }, { "label": t("Play", r), "icon": "play-fill", "action": "play" },
{ "label": t("Play later", r), "icon": "list-plus", "action": "later" }, { "label": t("Play next", r), "icon": "list-start", "action": "next" },
{ "label": t("Add to queue", r), "icon": "list-end", "action": "queue" }, { "label": t("Play later", r), "icon": "list-plus", "action": "later" },
{ "label": t("Add to playlist", r), "icon": "list-music", "action": "add-to-playlist" } { "label": t("Add to queue", r), "icon": "list-end", "action": "queue" },
] { "label": t("Add to playlist", r), "icon": "list-music", "action": "add-to-playlist" }
]
// QoL round: gated on the payload actually carrying the album
// (a Qobuz id or a local group key — search_qt::CortRow.albumId).
if ((row.albumId || "") !== "")
trackRows.push({ "label": t("Open containing album", r), "icon": "disc-3", "action": "open-album" })
return trackRows
}
if (row.kind === "playlist") return [ if (row.kind === "playlist") return [
{ "label": t("Open playlist", r), "icon": "list-music", "action": "open" }, { "label": t("Open playlist", r), "icon": "list-music", "action": "open" },
{ "label": t("Play", r), "icon": "play-fill", "action": "play" }, { "label": t("Play", r), "icon": "play-fill", "action": "play" },
@@ -124,8 +131,8 @@ Item {
if (fi === undefined || fi === null) if (fi === undefined || fi === null)
return return
QbzSearch.cortinillaMenuAction(fi, action) QbzSearch.cortinillaMenuAction(fi, action)
if ((action === "open" || action === "play" || action === "add-to-playlist") if ((action === "open" || action === "open-album" || action === "play"
&& root.headerBar) || action === "add-to-playlist") && root.headerBar)
root.headerBar.clearSearch() root.headerBar.clearSearch()
} }
+5
View File
@@ -206,6 +206,7 @@ pub(crate) fn derive_local_album_rows(
quality_detail: local_quality_detail(t), quality_detail: local_quality_detail(t),
art_url, art_url,
art_path, art_path,
album_id: String::new(),
flat_index: 0, flat_index: 0,
}); });
} }
@@ -259,6 +260,7 @@ pub(crate) fn derive_local_artist_rows(
quality_detail: String::new(), quality_detail: String::new(),
art_url, art_url,
art_path, art_path,
album_id: String::new(),
flat_index: 0, flat_index: 0,
}); });
} }
@@ -291,6 +293,9 @@ pub(crate) fn map_local_track_to_cort_row(t: &qbz_library::LocalTrack) -> CortRo
quality_detail: local_quality_detail(t), quality_detail: local_quality_detail(t),
art_url, art_url,
art_path, art_path,
// The same group key the local Albums section uses as its row id —
// what "Open containing album" hands to `crate::open_album`.
album_id: t.album_group_key.clone(),
flat_index: 0, flat_index: 0,
} }
} }
+25 -1
View File
@@ -566,6 +566,12 @@ pub struct CortRow {
pub art_url: String, pub art_url: String,
#[serde(rename = "artPath")] #[serde(rename = "artPath")]
pub art_path: String, pub art_path: String,
/// TRACK rows only ("Open containing album"): the containing album — a
/// Qobuz album id or a local album group key (both are what
/// `crate::open_album` routes). Empty when unknown; the QML menu gates
/// its entry on that.
#[serde(rename = "albumId")]
pub album_id: String,
#[serde(rename = "flatIndex")] #[serde(rename = "flatIndex")]
pub flat_index: i32, pub flat_index: i32,
} }
@@ -673,6 +679,7 @@ fn map_search_all_to_cortinilla(query: &str, results: &SearchAllResults) -> Cort
subtitle: m.artist, subtitle: m.artist,
quality_detail, quality_detail,
art_url: m.art_url, art_url: m.art_url,
album_id: m.album_id,
..Default::default() ..Default::default()
} }
}; };
@@ -1270,7 +1277,7 @@ pub fn row_menu_action(flat_index: i32, action: &str) {
} }
if !matches!( if !matches!(
action, action,
"play" | "next" | "later" | "queue" | "add-to-playlist" "play" | "next" | "later" | "queue" | "add-to-playlist" | "open-album"
) { ) {
log::warn!("[qbz-qt] cortinilla menu: unknown action {action:?}"); log::warn!("[qbz-qt] cortinilla menu: unknown action {action:?}");
return; return;
@@ -1298,6 +1305,23 @@ pub fn row_menu_action(flat_index: i32, action: &str) {
row.source, row.source,
row.id, row.id,
); );
if action == "open-album" {
set_cortinilla_open(false);
// `open_album` routes BOTH id spaces (its is_local_feed_id arm
// recognises local group keys), so no source split here. The QML
// entry is gated on a non-empty albumId; an empty one is a stale
// snapshot, not a user path.
if row.kind != "track" || row.album_id.is_empty() {
log::warn!(
"[qbz-qt] cortinilla menu open-album: kind={} albumId empty={}",
row.kind,
row.album_id.is_empty()
);
return;
}
crate::open_album(row.album_id);
return;
}
if action == "add-to-playlist" { if action == "add-to-playlist" {
set_cortinilla_open(false); set_cortinilla_open(false);
if row.kind != "track" { if row.kind != "track" {