This commit is contained in:
Forrest 2026-08-04 16:08:51 -04:00
parent d558aba246
commit 3bd713d667
17 changed files with 1566 additions and 132 deletions

View file

@ -406,6 +406,52 @@ class PlaybackController extends StateNotifier<PlaybackState> {
await player.removeAudioSourceAt(index);
}
/// Move the queue entry from [oldIndex] to [newIndex] (drag-and-drop reorder).
///
/// Indices are "clean" post-removal targets — the same convention as
/// just_audio's `moveAudioSource` and Flutter's `ReorderableListView` after
/// its standard `newIndex -= 1` adjustment (done by the caller). Reorder
/// mutates the currently-active order: applied while shuffled, the move sticks
/// among the shuffled tail; hitting shuffle afterwards re-randomizes as usual.
/// A single targeted `moveAudioSource` keeps the current track playing without
/// the re-buffer a full source rebuild ([_applyOrder]) would cause.
Future<void> reorderQueue(int oldIndex, int newIndex) async {
final q = state.queue;
if (oldIndex < 0 || oldIndex >= q.length) return;
if (newIndex < 0 || newIndex >= q.length) return;
if (oldIndex == newIndex) return;
final next = [...q];
next.insert(newIndex, next.removeAt(oldIndex));
final player = _player;
if (player == null) {
// Desktop/no-audio: no stream will correct the index for us, so follow
// the current track to its new slot by hand.
final cur = state.currentIndex;
var newCur = cur;
if (cur != null) {
if (cur == oldIndex) {
newCur = newIndex;
} else {
var c = cur;
if (oldIndex < c) c -= 1;
if (newIndex <= c) c += 1;
newCur = c;
}
}
state = state.copyWith(queue: next, currentIndex: newCur);
_notifyCurrent();
return;
}
// Mobile: just_audio adjusts its own current index and re-emits
// `currentIndexStream`; the id dedupe in [_notifyCurrent] avoids a spurious
// re-scrobble when the playing track didn't actually change.
state = state.copyWith(queue: next);
await player.moveAudioSource(oldIndex, newIndex);
}
Future<void> togglePlayPause() async {
final player = _player;
if (player == null) return;