feat(slint): favorites tracks group-by (Off / Album / Artist / Name)
Add a group QbzSelect to the Tracks toolbar. derive_tracks reorders the visible rows by the group key (album+title, artist+album+title, or title) so a group's tracks sit together. Visible group-header rows are deferred until the list is virtualized (the list is a plain for today); this is the group-ordering half, matching how Tauri's tracks tab uses grouping as the ordering mechanism. cc
This commit is contained in:
4 files changed
+60
-3
No files matched your search
@@ -427,19 +427,39 @@ pub fn derive_tracks(window: &AppWindow) {
|
||||
let state = window.global::<FavoritesState>();
|
||||
let query_owned = state.get_tracks_search().to_lowercase();
|
||||
let query = query_owned.trim();
|
||||
let group = state.get_tracks_group_mode().to_string();
|
||||
let all = state.get_tracks();
|
||||
if query.is_empty() {
|
||||
// Fast path: no search + no grouping -> share full model (artwork live).
|
||||
if query.is_empty() && group == "off" {
|
||||
state.set_tracks_visible(all);
|
||||
return;
|
||||
}
|
||||
let filtered: Vec<TrackItem> = (0..all.row_count())
|
||||
let mut filtered: Vec<TrackItem> = (0..all.row_count())
|
||||
.filter_map(|i| all.row_data(i))
|
||||
.filter(|t| {
|
||||
t.title.to_lowercase().contains(query)
|
||||
query.is_empty()
|
||||
|| t.title.to_lowercase().contains(query)
|
||||
|| t.artist.to_lowercase().contains(query)
|
||||
|| t.album.to_lowercase().contains(query)
|
||||
})
|
||||
.collect();
|
||||
// Group-by reorders the rows so a group's tracks sit together (Tauri
|
||||
// adds visible headers; v1 here is group-ordering without header rows
|
||||
// until the list is virtualized).
|
||||
let lc = |s: &slint::SharedString| s.to_lowercase();
|
||||
match group.as_str() {
|
||||
"album" => {
|
||||
filtered.sort_by(|a, b| lc(&a.album).cmp(&lc(&b.album)).then(lc(&a.title).cmp(&lc(&b.title))))
|
||||
}
|
||||
"artist" => filtered.sort_by(|a, b| {
|
||||
lc(&a.artist)
|
||||
.cmp(&lc(&b.artist))
|
||||
.then(lc(&a.album).cmp(&lc(&b.album)))
|
||||
.then(lc(&a.title).cmp(&lc(&b.title)))
|
||||
}),
|
||||
"name" => filtered.sort_by(|a, b| lc(&a.title).cmp(&lc(&b.title))),
|
||||
_ => {}
|
||||
}
|
||||
state.set_tracks_visible(ModelRc::new(VecModel::from(filtered)));
|
||||
}
|
||||
|
||||
|
||||
@@ -4398,6 +4398,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
// Group the favorite tracks (off / album / artist / name).
|
||||
let weak = window.as_weak();
|
||||
window
|
||||
.global::<FavoritesActions>()
|
||||
.on_tracks_set_group(move |g| {
|
||||
if let Some(w) = weak.upgrade() {
|
||||
w.global::<FavoritesState>().set_tracks_group_mode(g);
|
||||
favorites::derive_tracks(&w);
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
// Play all favorite tracks as a fresh queue.
|
||||
let runtime = app_runtime.clone();
|
||||
|
||||
@@ -420,6 +420,29 @@ export component FavoritesView inherits Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
QbzSelect {
|
||||
menu-width: 150px;
|
||||
options: [
|
||||
@tr("Group: Off"),
|
||||
@tr("Group: Album"),
|
||||
@tr("Group: Artist"),
|
||||
@tr("Group: Name"),
|
||||
];
|
||||
current-index: FavoritesState.tracks-group-mode == "off" ? 0
|
||||
: FavoritesState.tracks-group-mode == "album" ? 1
|
||||
: FavoritesState.tracks-group-mode == "artist" ? 2
|
||||
: 3;
|
||||
selected(i) => {
|
||||
FavoritesActions.tracks-set-group(
|
||||
i == 0 ? "off"
|
||||
: i == 1 ? "album"
|
||||
: i == 2 ? "artist"
|
||||
: "name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if FavoritesState.tracks.length > 0: Rectangle { height: 12px; }
|
||||
|
||||
|
||||
@@ -1458,6 +1458,7 @@ export global FavoritesState {
|
||||
in property <[TrackItem]> tracks: [];
|
||||
in property <[TrackItem]> tracks-visible: [];
|
||||
in-out property <string> tracks-search: "";
|
||||
in-out property <string> tracks-group-mode: "off"; // off|album|artist|name
|
||||
in-out property <bool> tracks-multi-select: false;
|
||||
in property <int> tracks-selected-count: 0;
|
||||
in property <[AlbumCardItem]> albums: [];
|
||||
@@ -1490,6 +1491,7 @@ export global FavoritesActions {
|
||||
callback play-track(string /* track id */);
|
||||
callback track-action(string /* track id */, string /* action */);
|
||||
callback search-tracks(string /* query */);
|
||||
callback tracks-set-group(string /* off | album | artist | name */);
|
||||
callback play-all-tracks();
|
||||
callback shuffle-tracks();
|
||||
callback toggle-multi-select();
|
||||
|
||||
Reference in new issue
Block a user