feat(slint): wire playlist queue/play-next + toast confirm on enqueue
Playlist cards (carousels, search, favorites) emitted ("playlist","queue")
and ("playlist","play-next") but no handler existed, so the menu items
were dead. Add enqueue_playlist (fetch the playlist's tracks by id and
append, or insert-next in reverse to keep order) and the two match arms.
The album/track enqueue paths already worked but gave no visible feedback
when the queue panel was closed, reading as "unwired" — add a success
toast (Added to queue / Playing next) to every enqueue path.
cc
This commit is contained in:
2 files changed
+86
-4
No files matched your search
@@ -2694,6 +2694,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
playback::play_tracks(runtime, weak, handle, tracks, 0);
|
||||
});
|
||||
}
|
||||
("playlist", "queue") => playback::enqueue_playlist(
|
||||
runtime.clone(),
|
||||
weak.clone(),
|
||||
handle.clone(),
|
||||
id,
|
||||
false,
|
||||
),
|
||||
("playlist", "play-next") => playback::enqueue_playlist(
|
||||
runtime.clone(),
|
||||
weak.clone(),
|
||||
handle.clone(),
|
||||
id,
|
||||
true,
|
||||
),
|
||||
("playlist", "favorite") => {
|
||||
// Favorite/unfavorite the open playlist.
|
||||
if let Some(w) = weak.upgrade() {
|
||||
|
||||
@@ -1015,7 +1015,7 @@ pub fn play_album_radio(
|
||||
}
|
||||
|
||||
/// Enqueue an album's tracks at the end of the current queue.
|
||||
pub fn enqueue_album(runtime: Runtime, _weak: slint::Weak<AppWindow>, handle: tokio::runtime::Handle, album_id: String) {
|
||||
pub fn enqueue_album(runtime: Runtime, weak: slint::Weak<AppWindow>, handle: tokio::runtime::Handle, album_id: String) {
|
||||
handle.spawn(async move {
|
||||
let album = match runtime.core().get_album(&album_id).await {
|
||||
Ok(album) => album,
|
||||
@@ -1043,6 +1043,7 @@ pub fn enqueue_album(runtime: Runtime, _weak: slint::Weak<AppWindow>, handle: to
|
||||
}
|
||||
runtime.core().add_tracks(tracks).await;
|
||||
refresh_sidebar(false);
|
||||
crate::toast::success_weak(&weak, "Added to queue");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1053,7 +1054,7 @@ pub fn enqueue_album(runtime: Runtime, _weak: slint::Weak<AppWindow>, handle: to
|
||||
/// sequence — mirroring Tauri's `v2_add_tracks_to_queue_next`.
|
||||
pub fn enqueue_album_next(
|
||||
runtime: Runtime,
|
||||
_weak: slint::Weak<AppWindow>,
|
||||
weak: slint::Weak<AppWindow>,
|
||||
handle: tokio::runtime::Handle,
|
||||
album_id: String,
|
||||
) {
|
||||
@@ -1087,11 +1088,12 @@ pub fn enqueue_album_next(
|
||||
runtime.core().add_track_next(track).await;
|
||||
}
|
||||
refresh_sidebar(false);
|
||||
crate::toast::success_weak(&weak, "Playing next");
|
||||
});
|
||||
}
|
||||
|
||||
/// Enqueue a single track at the end of the current queue.
|
||||
pub fn enqueue_track(runtime: Runtime, _weak: slint::Weak<AppWindow>, handle: tokio::runtime::Handle, track_id: u64) {
|
||||
pub fn enqueue_track(runtime: Runtime, weak: slint::Weak<AppWindow>, handle: tokio::runtime::Handle, track_id: u64) {
|
||||
handle.spawn(async move {
|
||||
let track = match runtime.core().get_track(track_id).await {
|
||||
Ok(track) => track,
|
||||
@@ -1117,13 +1119,14 @@ pub fn enqueue_track(runtime: Runtime, _weak: slint::Weak<AppWindow>, handle: to
|
||||
make_queue_track(&track, &album_id, &album_title, &album_artist, &album_artwork);
|
||||
runtime.core().add_track(queue_track).await;
|
||||
refresh_sidebar(false);
|
||||
crate::toast::success_weak(&weak, "Added to queue");
|
||||
});
|
||||
}
|
||||
|
||||
/// Insert a single track immediately after the current track ("Play next").
|
||||
pub fn play_track_next(
|
||||
runtime: Runtime,
|
||||
_weak: slint::Weak<AppWindow>,
|
||||
weak: slint::Weak<AppWindow>,
|
||||
handle: tokio::runtime::Handle,
|
||||
track_id: u64,
|
||||
) {
|
||||
@@ -1152,6 +1155,71 @@ pub fn play_track_next(
|
||||
make_queue_track(&track, &album_id, &album_title, &album_artist, &album_artwork);
|
||||
runtime.core().add_track_next(queue_track).await;
|
||||
refresh_sidebar(false);
|
||||
crate::toast::success_weak(&weak, "Playing next");
|
||||
});
|
||||
}
|
||||
|
||||
/// Enqueue a whole playlist (by id) at the end of the queue, or immediately
|
||||
/// after the current track when `next`. Fetches the playlist's tracks fresh,
|
||||
/// so it works from any playlist CARD (carousels, search, favorites) — not just
|
||||
/// the currently-open PlaylistView. Mirrors the album enqueue paths.
|
||||
pub fn enqueue_playlist(
|
||||
runtime: Runtime,
|
||||
weak: slint::Weak<AppWindow>,
|
||||
handle: tokio::runtime::Handle,
|
||||
playlist_id: String,
|
||||
next: bool,
|
||||
) {
|
||||
let Ok(pid) = playlist_id.parse::<u64>() else {
|
||||
return;
|
||||
};
|
||||
handle.spawn(async move {
|
||||
let playlist = match runtime.core().get_playlist(pid).await {
|
||||
Ok(playlist) => playlist,
|
||||
Err(e) => {
|
||||
log::error!("[qbz-slint] playback: enqueue get_playlist {pid} failed: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let tracks: Vec<QueueTrack> = playlist
|
||||
.tracks
|
||||
.as_ref()
|
||||
.map(|container| container.items.as_slice())
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(|track| {
|
||||
let (album_id, album_title, album_artwork) = track
|
||||
.album
|
||||
.as_ref()
|
||||
.map(|a| {
|
||||
(
|
||||
a.id.clone(),
|
||||
a.title.clone(),
|
||||
a.image.best().cloned().unwrap_or_default(),
|
||||
)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let album_artist = track
|
||||
.performer
|
||||
.as_ref()
|
||||
.map(|p| p.name.clone())
|
||||
.unwrap_or_default();
|
||||
make_queue_track(track, &album_id, &album_title, &album_artist, &album_artwork)
|
||||
})
|
||||
.collect();
|
||||
if tracks.is_empty() {
|
||||
return;
|
||||
}
|
||||
if next {
|
||||
// Reverse so the inserted block keeps the playlist's order.
|
||||
for track in tracks.into_iter().rev() {
|
||||
runtime.core().add_track_next(track).await;
|
||||
}
|
||||
} else {
|
||||
runtime.core().add_tracks(tracks).await;
|
||||
}
|
||||
refresh_sidebar(false);
|
||||
crate::toast::success_weak(&weak, if next { "Playing next" } else { "Added to queue" });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user