feat(slint): seed favorites tab counts up front

Favorites tab badges previously showed a count only after visiting each
tab (the per-tab load set its own total). Add favorites::load_counts —
cheap limit=1 probes per type + the playlist count — applied to
FavoritesState once at startup, so all five badges in the new tab menu
are populated before the user opens a tab. A tab's own load still
refreshes its count.

cc
This commit is contained in:
vicrodh committed 2026-05-27 09:41:59 -06:00
1 parent f8c8808ba7
commit 7f0c227084
2 files changed
+69

No files matched your search

+62
View File
@@ -236,6 +236,68 @@ where
})
}
/// All five favorites tab counts, seeded up front so the tab badges are
/// ready before the user opens a given tab.
pub struct FavCounts {
pub tracks: i32,
pub albums: i32,
pub artists: i32,
pub playlists: i32,
pub labels: i32,
}
async fn total_for<A>(runtime: &Arc<AppRuntime<A>>, key: &str) -> i32
where
A: FrontendAdapter + Send + Sync + 'static,
{
runtime
.core()
.get_favorites(key, 1, 0)
.await
.ok()
.and_then(|v| {
v.get(key)
.and_then(|b| b.get("total"))
.and_then(|t| t.as_u64())
})
.unwrap_or(0) as i32
}
/// Fetch the five favorites counts (cheap limit=1 probes + the playlist
/// count). Runs on a worker; apply with `apply_counts` on the UI thread.
pub async fn load_counts<A>(runtime: &Arc<AppRuntime<A>>) -> FavCounts
where
A: FrontendAdapter + Send + Sync + 'static,
{
let tracks = total_for(runtime, "tracks").await;
let albums = total_for(runtime, "albums").await;
let artists = total_for(runtime, "artists").await;
let labels = total_for(runtime, "labels").await;
let playlists = runtime
.core()
.get_user_playlists()
.await
.map(|p| p.len() as i32)
.unwrap_or(0);
FavCounts {
tracks,
albums,
artists,
playlists,
labels,
}
}
/// Apply the seeded counts to `FavoritesState` (the tab badges).
pub fn apply_counts(window: &AppWindow, c: FavCounts) {
let st = window.global::<FavoritesState>();
st.set_tracks_total(c.tracks);
st.set_albums_total(c.albums);
st.set_artists_total(c.artists);
st.set_playlists_total(c.playlists);
st.set_labels_total(c.labels);
}
fn mmss(secs: u32) -> String {
format!("{}:{:02}", secs / 60, secs % 60)
}
+7
View File
@@ -138,6 +138,13 @@ async fn enter_shell(
});
reload_home(&runtime, &weak, &image_cache, "home".to_string()).await;
// Seed the favorites tab counts so the badges are ready before the
// user opens each tab (they otherwise only count on first visit).
let counts = favorites::load_counts(&runtime).await;
let _ = weak.upgrade_in_event_loop(move |w| {
favorites::apply_counts(&w, counts);
});
}
/// The shared genre-filter selection expanded to descendant ids, as the