refactor(slint): mix rows reuse SearchTrackRow; For You uses HomeSkeleton

Track row reuse: the mix views had a bespoke MixTrackRow with a dead
favorite/more controls (no context menu), while search / favorites /
artist already share SearchTrackRow (which has the TrackContextMenu).
Consolidated:
  - SearchTrackRow gains optional show-album (album column) +
    show-favorite (standalone heart) — off by default, so search /
    favorites rows are unchanged. SearchTrackItem gains an `album`
    field.
  - MixView drops MixTrackRow/MixTrackItem and renders SearchTrackRow
    with show-album + show-favorite. A row "play" starts the mix from
    that track; the context-menu actions (play next / queue / favorite
    / view album / view artist / ...) now bubble through media-action
    and work in the mix views too.

For You skeleton: the For You tab showed a bare spinner during its
lazy load; it now shows the same pulsing HomeSkeleton as Home (the
static Qobuz Mixes tiles stay visible above it). Editor's Picks is
served from the shared discover-index cache (Tauri parity) and shows
the skeleton during the initial load via the existing HomeView guard.

cc
This commit is contained in:
vicrodh committed 2026-05-21 23:46:13 -06:00
1 parent 61882166f7
commit 469c2495bf
8 files changed
+83 -193

No files matched your search

@@ -17,6 +17,11 @@ export component SearchTrackRow inherits Rectangle {
in property <SearchTrackItem> track;
in property <int> index;
in property <bool> show-artwork: true;
// Optional extra columns (mix / playlist-style rows): an album
// column and a standalone favorite button. Off by default so the
// search / favorites rows are unchanged.
in property <bool> show-album: false;
in property <bool> show-favorite: false;
// kind ("track"), track id, action ("play" | "play-next" | "queue" | "favorite").
callback media-action(string, string, string);
@@ -110,6 +115,16 @@ export component SearchTrackRow inherits Rectangle {
}
}
// Optional album column (mix / playlist rows).
if root.show-album: Text {
text: root.track.album;
width: 220px;
color: Theme.text-muted;
font-size: Typography.legal;
vertical-alignment: center;
overflow: elide;
}
Text {
text: root.track.duration;
width: 70px;
@@ -129,6 +144,31 @@ export component SearchTrackRow inherits Rectangle {
vertical-alignment: center;
}
// Optional standalone favorite button.
if root.show-favorite: VerticalLayout {
alignment: center;
Rectangle {
width: 28px;
height: 28px;
border-radius: Radius.sm;
background: fav-ta.has-hover ? Theme.surface-elevated : transparent;
QbzIcon {
source: @image-url("../assets/icons/heart.svg");
width: 16px;
height: 16px;
x: (parent.width - self.width) / 2;
y: (parent.height - self.height) / 2;
tint: fav-ta.has-hover ? Theme.text-primary : Theme.text-muted;
}
fav-ta := TouchArea {
mouse-cursor: pointer;
clicked => {
root.media-action("track", root.track.id, "favorite");
}
}
}
}
VerticalLayout {
alignment: center;
Rectangle {