diff --git a/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt b/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt index 6af12b3c..0a4222b6 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/player/PlayerController.kt @@ -288,6 +288,37 @@ class PlayerController @Inject constructor( controller.addMediaItem(track.toMediaItem(source = null)) } + /** + * Reorder the queue: move the item at [from] to [to], keeping the domain + * snapshot in lock-step with the player's MediaItem timeline. Media3 emits + * onEvents → uiState reflects the new order (and the still-playing item's + * index). No-op on bad indices or a no-move. + */ + fun moveInQueue(from: Int, to: Int) { + val controller = mediaController ?: return + if (from !in queueRefs.indices || to !in queueRefs.indices || from == to) return + queueRefs = queueRefs.toMutableList().apply { add(to, removeAt(from)) } + controller.moveMediaItem(from, to) + } + + /** + * Remove the queue item at [index]. When it's the currently-playing item + * Media3 advances to the next automatically. No-op on a bad index. + */ + fun removeFromQueue(index: Int) { + val controller = mediaController ?: return + if (index !in queueRefs.indices) return + queueRefs = queueRefs.toMutableList().apply { removeAt(index) } + controller.removeMediaItem(index) + } + + /** Empty the queue and stop playback. */ + fun clearQueue() { + val controller = mediaController ?: return + queueRefs = emptyList() + controller.clearMediaItems() + } + /** * Seed a fresh radio queue from [trackId]. The `source` tag is * "radio:" so the server-side rotation reporter can diff --git a/android/app/src/main/java/com/fabledsword/minstrel/player/ui/PlayerViewModel.kt b/android/app/src/main/java/com/fabledsword/minstrel/player/ui/PlayerViewModel.kt index e20a3407..674728f8 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/player/ui/PlayerViewModel.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/player/ui/PlayerViewModel.kt @@ -55,6 +55,9 @@ class PlayerViewModel @Inject constructor( fun seekToIndex(index: Int) = controller.seekToIndex(index) fun toggleShuffle() = controller.toggleShuffle() fun cycleRepeat() = controller.cycleRepeat() + fun moveInQueue(from: Int, to: Int) = controller.moveInQueue(from, to) + fun removeFromQueue(index: Int) = controller.removeFromQueue(index) + fun clearQueue() = controller.clearQueue() fun toggleLikeTrack(trackId: String) { val desired = trackId !in likedTrackIds.value