Ports Tauri's SpotlightLite — one favorite artist highlighted with a
hero and a content row. Backed by get_artist_page.
- Spotlight component: header (title + "Shine a light…" subtitle),
hero (round portrait + ARTIST label + name + play-top-tracks /
open-artist circle buttons), and a draggable Flickable row
mixing a TOP TRACKS card, a RADIO card, and the artist's albums.
- New RadioCard (port of RadioCardLite): a 180px tile with the seed
artwork centered on an elevated panel, a wordmark label over it,
and a title/subtitle below; hover reveals play. (The Tauri
palette-derived panel colour is approximated with a neutral
elevated panel.)
- foryou::load_spotlight rotates among the top-5 favorites by
wall-clock seconds, fetches get_artist_page, and extracts up to 6
albums (album > live > ep-single > compilation, deduped) plus
whether the artist has top tracks. ForYouState gains the
spotlight-* fields; two new artwork targets feed the portrait +
album covers.
- Wiring: ForYouView renders Spotlight after Artists to Follow.
play-top-tracks routes to the existing artist play-top action;
"start radio" has no artist-radio backend yet so it falls back to
playing top tracks (logged).
Remaining For You: Radio Stations section (old card design), Qobuz
Mixes row, and the reco-DB sections (More from library, Rediscover).
cc
195 lines
6.6 KiB
Plaintext
195 lines
6.6 KiB
Plaintext
// Discover > For You "Spotlight" — port of Tauri's SpotlightLite.
|
|
// One favorite artist highlighted: a header, a hero (portrait +
|
|
// ARTIST + name + play-top-tracks / open-artist circle buttons), and
|
|
// a draggable row mixing a TOP TRACKS card, a RADIO card, and the
|
|
// artist's albums.
|
|
|
|
import { Theme } from "../foundation/semantic-colors.slint";
|
|
import { Typography } from "../foundation/typography.slint";
|
|
import { ForYouState, AlbumCardItem } from "../state.slint";
|
|
import { AlbumCard } from "AlbumCard.slint";
|
|
import { RadioCard } from "RadioCard.slint";
|
|
import { QbzIcon } from "../primitives/QbzIcon.slint";
|
|
|
|
component CircleButton inherits Rectangle {
|
|
in property <image> icon;
|
|
in property <bool> primary: false;
|
|
callback clicked();
|
|
width: 44px;
|
|
height: 44px;
|
|
border-radius: 22px;
|
|
background: root.primary
|
|
? (ta.has-hover ? #ffffffd6 : Theme.accent)
|
|
: (ta.has-hover ? Theme.surface-hover : Theme.surface-elevated);
|
|
QbzIcon {
|
|
source: root.icon;
|
|
width: root.primary ? 18px : 16px;
|
|
height: root.primary ? 18px : 16px;
|
|
x: (parent.width - self.width) / 2;
|
|
y: (parent.height - self.height) / 2;
|
|
tint: root.primary ? #ffffff : Theme.text-secondary;
|
|
}
|
|
ta := TouchArea {
|
|
mouse-cursor: pointer;
|
|
clicked => {
|
|
root.clicked();
|
|
}
|
|
}
|
|
}
|
|
|
|
export component Spotlight inherits VerticalLayout {
|
|
callback open-artist(string);
|
|
callback open-album(string);
|
|
callback play-top-tracks(string);
|
|
callback start-radio(string);
|
|
callback media-action(string, string, string);
|
|
|
|
property <length> gap: 24px;
|
|
// Row content width: TopTracks(180) + Radio(180) + albums(220 each)
|
|
// + gaps. has-top-tracks toggles the first card.
|
|
property <length> radio-cards-width:
|
|
(ForYouState.spotlight-has-top-tracks ? 180px + root.gap : 0px) + 180px + root.gap;
|
|
property <int> album-count: ForYouState.spotlight-albums.length;
|
|
property <length> content-width:
|
|
root.radio-cards-width
|
|
+ root.album-count * (220px + root.gap);
|
|
|
|
spacing: 12px;
|
|
|
|
// Header.
|
|
VerticalLayout {
|
|
spacing: 2px;
|
|
Text {
|
|
text: @tr("Spotlight");
|
|
color: Theme.text-primary;
|
|
font-size: 18px;
|
|
font-weight: Typography.semibold;
|
|
}
|
|
Text {
|
|
text: @tr("Shine a light on one of your favourite artists.");
|
|
color: Theme.text-muted;
|
|
font-size: Typography.legal;
|
|
}
|
|
}
|
|
|
|
// Hero.
|
|
HorizontalLayout {
|
|
spacing: 16px;
|
|
alignment: start;
|
|
Rectangle {
|
|
width: 96px;
|
|
height: 96px;
|
|
border-radius: 48px;
|
|
background: Theme.surface-elevated;
|
|
clip: true;
|
|
Image {
|
|
width: 100%;
|
|
height: 100%;
|
|
source: ForYouState.spotlight-image;
|
|
image-fit: cover;
|
|
}
|
|
if ForYouState.spotlight-image-url == "": QbzIcon {
|
|
source: @image-url("../assets/icons/user.svg");
|
|
width: 40px;
|
|
height: 40px;
|
|
x: (parent.width - self.width) / 2;
|
|
y: (parent.height - self.height) / 2;
|
|
tint: Theme.text-muted;
|
|
}
|
|
portrait-ta := TouchArea {
|
|
mouse-cursor: pointer;
|
|
clicked => {
|
|
root.open-artist(ForYouState.spotlight-artist-id);
|
|
}
|
|
}
|
|
}
|
|
VerticalLayout {
|
|
alignment: center;
|
|
spacing: 8px;
|
|
if ForYouState.spotlight-category != "": Text {
|
|
text: @tr("ARTIST");
|
|
color: Theme.text-muted;
|
|
font-size: 10px;
|
|
font-weight: Typography.semibold;
|
|
letter-spacing: 1.5px;
|
|
}
|
|
Text {
|
|
text: ForYouState.spotlight-name;
|
|
color: Theme.text-primary;
|
|
font-size: Typography.title;
|
|
font-weight: Typography.bold;
|
|
}
|
|
HorizontalLayout {
|
|
spacing: 10px;
|
|
alignment: start;
|
|
if ForYouState.spotlight-has-top-tracks: CircleButton {
|
|
icon: @image-url("../assets/icons/play-fill.svg");
|
|
primary: true;
|
|
clicked => {
|
|
root.play-top-tracks(ForYouState.spotlight-artist-id);
|
|
}
|
|
}
|
|
CircleButton {
|
|
icon: @image-url("../assets/icons/user.svg");
|
|
clicked => {
|
|
root.open-artist(ForYouState.spotlight-artist-id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle { height: 4px; }
|
|
|
|
// Content row — draggable (Flickable), like the other carousels.
|
|
Rectangle {
|
|
height: 270px;
|
|
clip: true;
|
|
Flickable {
|
|
width: 100%;
|
|
height: parent.height;
|
|
viewport-width: root.content-width;
|
|
viewport-height: self.height;
|
|
|
|
HorizontalLayout {
|
|
spacing: root.gap;
|
|
alignment: start;
|
|
|
|
if ForYouState.spotlight-has-top-tracks: RadioCard {
|
|
seed-title: @tr("Top tracks");
|
|
seed-subtitle: @tr("By {}", ForYouState.spotlight-name);
|
|
label: "TOP TRACKS";
|
|
artwork: ForYouState.spotlight-image;
|
|
clicked => {
|
|
root.play-top-tracks(ForYouState.spotlight-artist-id);
|
|
}
|
|
play => {
|
|
root.play-top-tracks(ForYouState.spotlight-artist-id);
|
|
}
|
|
}
|
|
RadioCard {
|
|
seed-title: ForYouState.spotlight-name;
|
|
seed-subtitle: @tr("Qobuz Radio Station");
|
|
label: "RADIO";
|
|
artwork: ForYouState.spotlight-image;
|
|
clicked => {
|
|
root.start-radio(ForYouState.spotlight-artist-id);
|
|
}
|
|
play => {
|
|
root.start-radio(ForYouState.spotlight-artist-id);
|
|
}
|
|
}
|
|
for album in ForYouState.spotlight-albums: AlbumCard {
|
|
album: album;
|
|
clicked(id) => {
|
|
root.open-album(id);
|
|
}
|
|
media-action(kind, id, action) => {
|
|
root.media-action(kind, id, action);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|