feat(player): add append-only "Add to Queue" buttons beside detail-page play affordances

Cut header (release → EnqueueRange), Cut track rows + Session/Mix hero (track → Enqueue). Reuses existing engine path; add is not play.
This commit is contained in:
daniel-c-harvey
2026-06-19 15:18:38 -04:00
parent 4317a2f9e7
commit 1d387c2a34
4 changed files with 56 additions and 0 deletions
@@ -0,0 +1,46 @@
@namespace DeepDrftPublic.Client.Controls
@using DeepDrftModels.DTOs
@using DeepDrftPublic.Client.Services
@* Append-only "Add to Queue" affordance placed beside a play control. Add is NOT play: it calls the
cascaded IQueueService's Enqueue/EnqueueRange (which append without disturbing current playback and
leave a coherent CurrentIndex on a first add into a dormant queue) — never PlayRelease/Start/Select.
Track mode (Track set) appends a single track; release mode (ReleaseTracks set) appends the whole
ordered list. Reads queue state from the layout-level cascade (C1); owns no data fetch. *@
<MudTooltip Text="@Tooltip">
<MudIconButton Icon="@Icons.Material.Filled.PlaylistAdd"
Color="@Color"
Size="@Size"
Disabled="@(Queue is null || !RendererInfo.IsInteractive)"
OnClick="@AddToQueue" />
</MudTooltip>
@code {
[CascadingParameter] public IQueueService? Queue { get; set; }
/// <summary>Single track to append (track mode). Mutually exclusive with <see cref="ReleaseTracks"/>.</summary>
[Parameter] public TrackDto? Track { get; set; }
/// <summary>Ordered release tracks to append (release mode). Mutually exclusive with <see cref="Track"/>.</summary>
[Parameter] public IReadOnlyList<TrackDto>? ReleaseTracks { get; set; }
[Parameter] public Size Size { get; set; } = Size.Medium;
[Parameter] public Color Color { get; set; } = Color.Secondary;
private string Tooltip => ReleaseTracks is not null ? "Add release to queue" : "Add to queue";
private void AddToQueue()
{
if (Queue is null) return;
if (ReleaseTracks is not null)
{
Queue.EnqueueRange(ReleaseTracks);
}
else if (Track is not null)
{
Queue.Enqueue(Track);
}
}
}
@@ -94,6 +94,10 @@ else
Play
</MudButton>
@* Append the whole album (TrackNumber order) to the queue — same ordered list
header Play uses. Append-only: does not start playback (AC7/AC8). *@
<AddToQueueButton ReleaseTracks="@ViewModel.Tracks" />
@* Release-mode share: copies the canonical /cuts/{entryKey} URL, not a single track (§3b). *@
<SharePopover ReleaseEntryKey="@release.EntryKey" ReleaseMedium="@release.Medium" />
</div>
@@ -138,6 +142,8 @@ else
OnToggle="@(() => PlayTrack(track, index))" />
</div>
<span class="cut-detail-track-name text-truncate">@track.TrackName</span>
@* Append this single track to the queue (append-only, does not play). *@
<AddToQueueButton Track="@track" />
<SharePopover EntryKey="@track.EntryKey" />
</div>
}
@@ -81,6 +81,8 @@ else
@if (ViewModel.Track is not null)
{
<PlayStateIcon Track="@ViewModel.Track" Size="Size.Large" Color="Color.Secondary" OnToggle="@PlayTrack" />
@* Append-only: queues the mix's single track without starting playback. *@
<AddToQueueButton Track="@ViewModel.Track" Size="Size.Large" />
}
</PlayContent>
</ReleaseHeroOverlay>
@@ -79,6 +79,8 @@ else
@if (ViewModel.Track is not null)
{
<PlayStateIcon Track="@ViewModel.Track" Size="Size.Large" Color="Color.Secondary" OnToggle="@PlayTrack" />
@* Append-only: queues the session's single track without starting playback. *@
<AddToQueueButton Track="@ViewModel.Track" Size="Size.Large" />
}
</PlayContent>
</ReleaseHeroOverlay>