feat(slint): favorites Artists A-Z grouping + alpha strip
Add the optional A-Z group toggle to the Artists grid (Group: Off/A-Z QbzSelect, default Off, persisted via favorites_prefs artists_group). derive_artists now buckets the filtered set into FavArtistSection letter groups (# first, then A-Z) and builds the alpha-jump model; the grouped grid renders per-letter headers + sub-grids and an AlphaStrip on the right that jumps the Flickable proportionally (mirrors the Albums alpha grouping). Also renames the favorites view header title "Favorites" -> "Library" to match Qobuz. cc
This commit is contained in:
4 files changed
+150
-22
No files matched your search
@@ -567,7 +567,7 @@ export component FavoritesView inherits Rectangle {
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
Text {
|
||||
text: @tr("Favorites");
|
||||
text: @tr("Library");
|
||||
color: Theme.text-primary;
|
||||
font-size: Typography.section;
|
||||
font-weight: Typography.bold;
|
||||
@@ -827,6 +827,21 @@ export component FavoritesView inherits Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
QbzSelect {
|
||||
menu-width: 150px;
|
||||
options: [
|
||||
@tr("Group: Off"),
|
||||
@tr("Group: A-Z"),
|
||||
];
|
||||
sm: true;
|
||||
current-index: FavoritesState.artists-group-enabled ? 1 : 0;
|
||||
selected(i) => {
|
||||
FavoritesActions.artists-set-group(i == 0 ? "off" : "alpha");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1067,14 +1082,8 @@ export component FavoritesView inherits Rectangle {
|
||||
}
|
||||
|
||||
// --- Artists tab ---
|
||||
if FavoritesState.active-tab == "artists": artists-grid := Rectangle {
|
||||
property <int> columns: Math.max(
|
||||
1,
|
||||
Math.floor((self.width + root.gap) / (root.artist-w + root.gap)));
|
||||
property <int> rows: Math.ceil(FavoritesState.artists-visible.length / self.columns);
|
||||
height: self.rows > 0
|
||||
? self.rows * root.artist-h + Math.max(0, self.rows - 1) * root.gap
|
||||
: 0px;
|
||||
if FavoritesState.active-tab == "artists": VerticalLayout {
|
||||
spacing: 0px;
|
||||
if FavoritesState.artists.length == 0: Text {
|
||||
text: @tr("No favorite artists yet.");
|
||||
color: Theme.text-muted;
|
||||
@@ -1086,11 +1095,49 @@ export component FavoritesView inherits Rectangle {
|
||||
color: Theme.text-muted;
|
||||
font-size: Typography.body;
|
||||
}
|
||||
for artist[i] in FavoritesState.artists-visible: FavArtistCard {
|
||||
x: Math.mod(i, artists-grid.columns) * (root.artist-w + root.gap);
|
||||
y: Math.floor(i / artists-grid.columns) * (root.artist-h + root.gap);
|
||||
item: artist;
|
||||
clicked(id) => { root.open-artist(id); }
|
||||
// Flat grid (grouping off).
|
||||
if !FavoritesState.artists-group-enabled: artists-grid := Rectangle {
|
||||
property <int> columns: Math.max(
|
||||
1,
|
||||
Math.floor((self.width + root.gap) / (root.artist-w + root.gap)));
|
||||
property <int> rows: Math.ceil(FavoritesState.artists-visible.length / self.columns);
|
||||
height: self.rows > 0
|
||||
? self.rows * root.artist-h + Math.max(0, self.rows - 1) * root.gap
|
||||
: 0px;
|
||||
for artist[i] in FavoritesState.artists-visible: FavArtistCard {
|
||||
x: Math.mod(i, artists-grid.columns) * (root.artist-w + root.gap);
|
||||
y: Math.floor(i / artists-grid.columns) * (root.artist-h + root.gap);
|
||||
item: artist;
|
||||
clicked(id) => { root.open-artist(id); }
|
||||
}
|
||||
}
|
||||
// Grouped (A-Z) — sections with letter headers.
|
||||
if FavoritesState.artists-group-enabled: VerticalLayout {
|
||||
spacing: 10px;
|
||||
for section[s] in FavoritesState.artists-grouped: VerticalLayout {
|
||||
spacing: 6px;
|
||||
Text {
|
||||
text: section.title;
|
||||
color: Theme.text-secondary;
|
||||
font-size: Typography.legal;
|
||||
font-weight: Typography.semibold;
|
||||
}
|
||||
section-grid := Rectangle {
|
||||
property <int> columns: Math.max(
|
||||
1,
|
||||
Math.floor((self.width + root.gap) / (root.artist-w + root.gap)));
|
||||
property <int> rows: Math.ceil(section.artists.length / self.columns);
|
||||
height: self.rows > 0
|
||||
? self.rows * root.artist-h + Math.max(0, self.rows - 1) * root.gap
|
||||
: 0px;
|
||||
for artist[i] in section.artists: FavArtistCard {
|
||||
x: Math.mod(i, section-grid.columns) * (root.artist-w + root.gap);
|
||||
y: Math.floor(i / section-grid.columns) * (root.artist-h + root.gap);
|
||||
item: artist;
|
||||
clicked(id) => { root.open-artist(id); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1221,6 +1268,18 @@ export component FavoritesView inherits Rectangle {
|
||||
* Math.max(0, (other-flick.viewport-height - other-flick.height) / 1px) * 1px;
|
||||
}
|
||||
}
|
||||
// A-Z jump strip (artists grouping) — proportional jump.
|
||||
if FavoritesState.active-tab == "artists"
|
||||
&& FavoritesState.artists-group-enabled
|
||||
&& FavoritesState.artists-alpha.length > 0: AlphaStrip {
|
||||
x: parent.width - self.width - 20px;
|
||||
height: 100%;
|
||||
jumps: FavoritesState.artists-alpha;
|
||||
jump(ord, idx) => {
|
||||
other-flick.viewport-y = -(ord / Math.max(1, FavoritesState.artists-alpha.length - 1))
|
||||
* Math.max(0, (other-flick.viewport-height - other-flick.height) / 1px) * 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user