refactor(slint): one shared TrackRow + TrackItem across all surfaces

Collapses the three near-identical track rows (AlbumView's inline
TrackRow, ArtistPage's inline TrackRow with multi-select, and the
shared SearchTrackRow) into a single primitives/TrackRow driven by
flags, backed by one TrackItem (superset). Foundation for the
upcoming playlist module, which renders the artwork variant heavily.

  - New primitives/TrackRow.slint with: show-artwork (cover+number vs
    number cell), show-album, show-favorite, show-download,
    multi-select-mode (selection checkbox). One media-action wires
    play / play-next / queue / favorite / download / toggle-select +
    the TrackContextMenu.
  - TrackItem is the unified model (superset of the old AlbumTrackItem
    + SearchTrackItem: number, album, selected, artwork all present;
    unused fields stay empty per surface).
  - Migrated AlbumView (show-artwork:false, show-download:true),
    ArtistPage Popular (show-artwork:false, multi-select-mode),
    Search, Favorites, Mix (show-artwork:true, +album/+favorite).
    Deleted SearchTrackRow.slint and both inline TrackRows.
  - Rust: AlbumTrackItem + SearchTrackItem -> TrackItem across
    album/artist/search/favorites/mix/main; search's internal row
    struct renamed TrackRow -> TrackRowData to free the TrackRow name
    for the Slint component. 46 tests pass.

cc
This commit is contained in:
vicrodh committed 2026-05-22 00:31:42 -06:00
1 parent 469c2495bf
commit 1ebec6cbc1
14 files changed
+207 -464

No files matched your search

@@ -8,7 +8,7 @@
// per-type tabs show the full loaded set as a card grid or row list with
// a load-more button.
import { SearchState, SearchActions, SearchTrackItem, SearchPlaylistItem, AlbumCardItem, SlimItem } from "../state.slint";
import { SearchState, SearchActions, TrackItem, SearchPlaylistItem, AlbumCardItem, SlimItem } from "../state.slint";
import { Theme } from "../foundation/semantic-colors.slint";
import { Typography } from "../foundation/typography.slint";
import { Radius } from "../foundation/radius.slint";
@@ -18,7 +18,7 @@ import { PlaylistCarousel } from "../discover/PlaylistCarousel.slint";
import { AlbumCard } from "../discover/AlbumCard.slint";
import { ArtistCard } from "../discover/ArtistCard.slint";
import { PlaylistCard } from "../discover/PlaylistCard.slint";
import { SearchTrackRow } from "SearchTrackRow.slint";
import { TrackRow } from "../primitives/TrackRow.slint";
import { NavButtons } from "../shell/NavButtons.slint";
import { QbzIcon } from "../primitives/QbzIcon.slint";
import { LoadingSpinner } from "../primitives/LoadingSpinner.slint";
@@ -480,7 +480,7 @@ export component SearchResultsView inherits Rectangle {
if SearchState.most-popular-kind == "track": Rectangle {
width: 320px;
height: 56px;
SearchTrackRow {
TrackRow {
width: 320px;
track: SearchState.most-popular-track;
index: 0;
@@ -542,7 +542,7 @@ export component SearchResultsView inherits Rectangle {
show-more: SearchState.tab == 0 && SearchState.tracks-total > root.preview-cap;
more-clicked => { SearchActions.tab-changed(2); }
}
for track[idx] in SearchState.tracks: SearchTrackRow {
for track[idx] in SearchState.tracks: TrackRow {
visible: SearchState.tab == 2 || idx < root.preview-cap;
height: self.visible ? 56px : 0px;
track: track;