feat(slint): wire play-next media action for tracks and albums

Add play_track_next and enqueue_album_next to playback.rs, calling the
core's add_track_next to insert after the current track. Album play-next
inserts tracks in reverse so they land in order, mirroring Tauri's
v2_add_tracks_to_queue_next. Route ("track"/"album", "play-next")
through the on_media_action handler. Add the lucide list-end icon used
for the existing "Add to queue" item.

cc
This commit is contained in:
vicrodh committed 2026-05-19 04:18:42 -06:00
1 parent fe815318db
commit 6203a2db26
3 files changed
+101

No files matched your search

+16
View File
@@ -652,6 +652,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
);
}
}
("album", "play-next") => playback::enqueue_album_next(
runtime.clone(),
weak.clone(),
handle.clone(),
id,
),
("track", "play-next") => {
if let Ok(track_id) = id.parse::<u64>() {
playback::play_track_next(
runtime.clone(),
weak.clone(),
handle.clone(),
track_id,
);
}
}
_ => {}
}
});
+78
View File
@@ -410,6 +410,49 @@ pub fn enqueue_album(runtime: Runtime, _weak: slint::Weak<AppWindow>, handle: to
});
}
/// Insert an album's tracks immediately after the current track ("Play next").
///
/// The core's `add_track_next` inserts a single track after the current index,
/// so the album tracks are inserted in reverse order to land in the right
/// sequence — mirroring Tauri's `v2_add_tracks_to_queue_next`.
pub fn enqueue_album_next(
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,
Err(e) => {
log::error!("[qbz-slint] playback: play-next get_album {album_id} failed: {e}");
return;
}
};
let album_title = album.title.clone();
let album_artist = album.artist.name.clone();
let album_artwork = album.image.best().cloned().unwrap_or_default();
let tracks: Vec<QueueTrack> = album
.tracks
.as_ref()
.map(|container| container.items.as_slice())
.unwrap_or_default()
.iter()
.map(|track| {
make_queue_track(track, &album.id, &album_title, &album_artist, &album_artwork)
})
.collect();
if tracks.is_empty() {
return;
}
// Insert in reverse so the tracks end up in the correct order.
for track in tracks.into_iter().rev() {
runtime.core().add_track_next(track).await;
}
refresh_sidebar(false);
});
}
/// 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) {
handle.spawn(async move {
@@ -440,6 +483,41 @@ pub fn enqueue_track(runtime: Runtime, _weak: slint::Weak<AppWindow>, handle: to
});
}
/// Insert a single track immediately after the current track ("Play next").
pub fn play_track_next(
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,
Err(e) => {
log::error!("[qbz-slint] playback: play-next get_track {track_id} failed: {e}");
return;
}
};
let (album_id, album_title, album_artwork) = match track.album.as_ref() {
Some(album) => (
album.id.clone(),
album.title.clone(),
album.image.best().cloned().unwrap_or_default(),
),
None => (String::new(), String::new(), String::new()),
};
let album_artist = track
.performer
.as_ref()
.map(|p| p.name.clone())
.unwrap_or_default();
let queue_track =
make_queue_track(&track, &album_id, &album_title, &album_artist, &album_artwork);
runtime.core().add_track_next(queue_track).await;
refresh_sidebar(false);
});
}
/// Toggle play / pause on the live player.
pub fn toggle_play_pause(runtime: Runtime, handle: tokio::runtime::Handle) {
handle.spawn(async move {
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 12H3" />
<path d="M16 6H3" />
<path d="M10 18H3" />
<path d="M21 18V8a2 2 0 0 0-2-2h-5" />
<path d="m16 8-2-2 2-2" />
</svg>

After

Width:  |  Height:  |  Size: 325 B