Add queue Move/RemoveAt + dormant-Enqueue coherence and shared QueueList (Phase 17.1)

This commit is contained in:
daniel-c-harvey
2026-06-19 14:32:08 -04:00
parent ebbaa3f84f
commit f296bbdf00
4 changed files with 524 additions and 6 deletions
+70 -2
View File
@@ -95,6 +95,11 @@ public sealed class QueueService : IQueueService, IDisposable
public void Enqueue(TrackDto track)
{
_items.Add(track);
// OQ8: appending into a dormant (empty) queue leaves a coherent CurrentIndex so the next
// play/skip is correct — but does NOT auto-play (add is not play). PlayCurrent is never
// called here, so this stays interop-free and prerender-safe.
if (CurrentIndex == -1)
CurrentIndex = 0;
QueueChanged?.Invoke();
}
@@ -102,8 +107,71 @@ public sealed class QueueService : IQueueService, IDisposable
{
var before = _items.Count;
_items.AddRange(tracks);
if (_items.Count != before)
QueueChanged?.Invoke();
if (_items.Count == before) return;
// OQ8: see Enqueue — first append into a dormant queue stages a coherent CurrentIndex
// without playing. The first newly-appended track becomes current.
if (CurrentIndex == -1)
CurrentIndex = 0;
QueueChanged?.Invoke();
}
public void Move(int fromIndex, int toIndex)
{
if (fromIndex == toIndex) return;
if (fromIndex < 0 || fromIndex >= _items.Count) return;
if (toIndex < 0 || toIndex >= _items.Count) return;
var moved = _items[fromIndex];
_items.RemoveAt(fromIndex);
_items.Insert(toIndex, moved);
// Keep the same track current across the reorder. No playback is touched (C2): we only
// recompute which index the current track now sits at.
if (CurrentIndex == fromIndex)
{
CurrentIndex = toIndex;
}
else if (fromIndex < CurrentIndex && toIndex >= CurrentIndex)
{
// The current track shifted one slot toward the front to fill the vacated lower slot.
CurrentIndex--;
}
else if (fromIndex > CurrentIndex && toIndex <= CurrentIndex)
{
// An item inserted at/above the current slot pushed the current track one slot back.
CurrentIndex++;
}
QueueChanged?.Invoke();
}
public void RemoveAt(int index)
{
if (index < 0 || index >= _items.Count) return;
_items.RemoveAt(index);
if (_items.Count == 0)
{
// Last remaining track removed → empty + dormant. Does not stop the player (C2).
CurrentIndex = -1;
}
else if (index < CurrentIndex)
{
// A track before the current was removed: the same track stays current at a lower index.
CurrentIndex--;
}
else if (index == CurrentIndex && CurrentIndex >= _items.Count)
{
// The current track was removed and it was the last slot: there is no "next" occupant to
// resolve to, so the queue goes dormant (CurrentIndex == -1). Playback is NOT stopped
// (C2) — the just-removed track keeps playing to its natural end; auto-advance simply has
// nothing further. Removing current when it is NOT the last leaves CurrentIndex pointing
// at the new occupant of that slot (the next track), so no adjustment is needed there.
CurrentIndex = -1;
}
QueueChanged?.Invoke();
}
public async Task Next()