feat(player): docked queue overlay with reorder, remove, jump, and clear-upcoming

Add a Queue toggle to the docked player bar opening a centered editable queue
overlay. New additive QueueService.ClearUpcoming keeps the playing track while
dropping the rest. Current track is non-removable.
This commit is contained in:
daniel-c-harvey
2026-06-19 15:18:25 -04:00
parent 4317a2f9e7
commit fe3819f378
10 changed files with 413 additions and 5 deletions
@@ -138,4 +138,15 @@ public interface IQueueService
/// <summary>Empties the queue and resets the position. Does not stop the player.</summary>
void Clear();
/// <summary>
/// Empties the up-next while keeping the currently-playing track: removes every item except
/// <see cref="Current"/>, leaving it as the sole remaining item at <see cref="CurrentIndex"/> == 0,
/// and re-emits <see cref="QueueChanged"/>. Unlike <see cref="Clear"/> (which empties everything and
/// goes dormant), this preserves what is playing — the player is never stopped and the current track
/// stays queued, so playback continues uninterrupted while the rest of the queue is discarded.
/// Interop-free; safe during prerender. No-op (no throw, no <see cref="QueueChanged"/>) when the queue
/// is empty/dormant or already holds only the current track.
/// </summary>
void ClearUpcoming();
}
@@ -201,6 +201,20 @@ public sealed class QueueService : IQueueService, IDisposable
QueueChanged?.Invoke();
}
public void ClearUpcoming()
{
// Keep the currently-playing track, drop everything else. No current track (dormant/empty) or a
// queue that already holds only the current → nothing to clear.
var current = Current;
if (current is null || _items.Count <= 1) return;
_items.Clear();
_items.Add(current);
CurrentIndex = 0;
// Playback is untouched (C2): the current track keeps streaming; we only discarded the up-next.
QueueChanged?.Invoke();
}
// Advance on organic end-of-stream only. TrackEnded is not raised by stop/unload/track-switch,
// so a manual stop or a fresh single-track selection elsewhere never spuriously advances the
// queue. When the queue is past its last track, end-of-stream simply stops — nothing to advance.