feat(qbz-slint): artist detail page

Clicking an artist (from the album page's artist line) opens the
artist detail view: a circular portrait, name, biography, action
buttons, a Popular Tracks list, and a Discography carousel.

- artist.rs: fetches the artist page via QbzCore::get_artist_page and
  maps name, biography (HTML-stripped), portrait URL, top tracks and
  releases; the portrait loads through the shared image cache.
- ArtistPageView.slint reuses AlbumCard for the discography (through
  the Carousel) and AlbumTrackItem for the track list.
- NavState becomes a three-way ContentView (home / album / artist) and
  AppShell routes the content region accordingly. The album page's
  artist line and the artist page's release cards are navigable.

cc
This commit is contained in:
vicrodh committed 2026-05-18 15:59:47 -06:00
1 parent ece878ed49
commit 4e143bbcd5
8 files changed
+580 -18

No files matched your search

+22 -8
View File
@@ -9,7 +9,7 @@ import { Theme } from "../foundation/semantic-colors.slint";
import { Typography } from "../foundation/typography.slint";
import { Radius } from "../foundation/radius.slint";
import { Spacing } from "../foundation/spacing.slint";
import { AlbumState, AlbumTrackItem, NavState } from "../state.slint";
import { AlbumState, AlbumTrackItem, NavState, ContentView } from "../state.slint";
import { QbzIcon } from "../primitives/QbzIcon.slint";
import { ScrollView } from "std-widgets.slint";
@@ -132,6 +132,8 @@ component TrackRow inherits Rectangle {
}
export component AlbumPageView inherits Rectangle {
callback open-artist(string);
background: Theme.surface-main;
ScrollView {
@@ -150,7 +152,7 @@ export component AlbumPageView inherits Rectangle {
height: 28px;
mouse-cursor: pointer;
clicked => {
NavState.showing-album = false;
NavState.view = ContentView.home;
}
back-row := HorizontalLayout {
spacing: 6px;
@@ -210,12 +212,24 @@ export component AlbumPageView inherits Rectangle {
overflow: elide;
}
Rectangle { height: 4px; }
Text {
text: AlbumState.artist;
color: Theme.accent;
font-size: Typography.heading;
font-weight: Typography.medium;
overflow: elide;
HorizontalLayout {
alignment: start;
artist-area := TouchArea {
width: artist-text.preferred-width;
height: artist-text.preferred-height;
mouse-cursor: pointer;
clicked => {
root.open-artist(AlbumState.artist-id);
}
artist-text := Text {
text: AlbumState.artist;
color: artist-area.has-hover
? Theme.accent-hover
: Theme.accent;
font-size: Typography.heading;
font-weight: Typography.medium;
}
}
}
Rectangle { height: 10px; }
Text {