feat(slint): in-page search for the artist view

Mirrors Tauri's `.page-search` substring filter — Popular Tracks
(title + artist) and every release-section album (title) hide on
each keystroke when they don't match, restore when the query is
cleared.

UI:
  - Search row added between the artist header and Popular Tracks,
    always visible while artist data is present. Search icon +
    inline TextInput, surface-card background with a thin border
    that highlights on focus. Placeholder "Search this page…".

State:
  - New ArtistActions global with `callback search(string)`, re-
    exported through app.slint so main.rs can wire it.

Controller (artist.rs):
  - Thread-local FULL_TOP_TRACKS and FULL_RELEASE_SECTIONS cache the
    rendered models on the UI thread (same pattern as
    AlbumPageView's FULL_TRACKS), populated in apply_artist so the
    filter never round-trips to the backend.
  - filter_artist(window, query): trim+lowercase the query, then
    rebuild ArtistState.top_tracks and ArtistState.release_sections.
    Sections whose albums all filter out are dropped from the visible
    list, matching Tauri's behavior.

main.rs:
  - ArtistActions::on_search wired to artist::filter_artist (same
    shape as the existing AlbumActions::on_search wiring).

cc
This commit is contained in:
vicrodh committed 2026-05-20 11:27:11 -06:00
1 parent 6642b5ef13
commit 381ab04ef0
5 files changed
+145 -2

No files matched your search

@@ -10,6 +10,7 @@ import { Typography } from "../foundation/typography.slint";
import { Radius } from "../foundation/radius.slint";
import {
ArtistState,
ArtistActions,
AlbumTrackItem,
NavState,
ContentView,
@@ -467,7 +468,64 @@ export component ArtistPageView inherits Rectangle {
}
}
Rectangle { height: 36px; }
Rectangle { height: 24px; }
// --- In-page search ---------------------------------------------
// Single client-side substring filter — applied to Popular
// Tracks (title + artist) and to every release-section
// album title. Same pattern as Tauri's `.page-search` plus
// the AlbumActions.search wiring AlbumPageView uses for
// its track list.
if !ArtistState.loading || ArtistState.top-tracks.length > 0:
Rectangle {
height: 36px;
border-radius: Radius.sm;
background: Theme.surface-card;
border-width: 1px;
border-color: artist-search.has-focus
? Theme.border-subtle
: transparent;
HorizontalLayout {
padding-left: 12px;
padding-right: 12px;
spacing: 8px;
VerticalLayout {
alignment: center;
horizontal-stretch: 0;
QbzIcon {
source: @image-url("../assets/icons/search.svg");
width: 14px;
height: 14px;
tint: Theme.text-muted;
}
}
Rectangle {
horizontal-stretch: 1;
artist-search := TextInput {
width: 100%;
height: 100%;
color: Theme.text-primary;
font-size: Typography.body;
vertical-alignment: center;
single-line: true;
edited => {
ArtistActions.search(self.text);
}
}
Text {
visible: artist-search.text == "";
width: 100%;
height: 100%;
text: @tr("Search this page…");
color: Theme.text-muted;
font-size: Typography.body;
vertical-alignment: center;
}
}
}
}
Rectangle { height: 12px; }
if ArtistState.loading && ArtistState.top-tracks.length == 0: Rectangle {
height: 280px;