Reflect real playback state on gallery cards and toggle pause/resume

Add IsPaused/OnPause to TrackCard, make TracksGallery controlled, and
drive the active track from PlayerService.CurrentTrack as the single
source of truth.
This commit is contained in:
daniel-c-harvey
2026-06-06 09:51:31 -04:00
parent d055c2a548
commit 766e98fd2b
5 changed files with 54 additions and 40 deletions
@@ -8,13 +8,24 @@ public partial class TrackCard : ComponentBase
{
[Parameter] public required TrackDto TrackModel { get; set; }
[Parameter] public EventCallback<TrackDto> OnPlay { get; set; }
[Parameter] public EventCallback<TrackDto> OnPause { get; set; }
[Parameter] public bool IsPlaying { get; set; } = false;
[Parameter] public bool IsPaused { get; set; } = false;
private string PlayPauseIcon => IsPlaying ? Icons.Material.Filled.MusicNote : Icons.Material.Filled.PlayArrow;
// Pause only when actively playing; every other state (idle, paused) reads as "press to play".
private bool IsActivelyPlaying => IsPlaying && !IsPaused;
private string PlayPauseIcon =>
IsActivelyPlaying ? Icons.Material.Filled.Pause : Icons.Material.Filled.PlayArrow;
private async Task PlayClick()
{
if (!IsPlaying && OnPlay.HasDelegate)
if (IsActivelyPlaying)
{
if (OnPause.HasDelegate)
await OnPause.InvokeAsync(TrackModel);
}
else if (OnPlay.HasDelegate)
{
await OnPlay.InvokeAsync(TrackModel);
}
@@ -4,7 +4,11 @@
{
<MudItem xs="12" sm="6" md="4" lg="3" xl="3">
<div class="deepdrft-track-gallery-item-center">
<TrackCard TrackModel="@track" IsPlaying="@(track.Id == SelectedTrack?.Id)" OnPlay="@HandlePlayClick"/>
<TrackCard TrackModel="@track"
IsPlaying="@(IsPlaying && ActiveTrack?.Id == track.Id)"
IsPaused="@(IsPaused && ActiveTrack?.Id == track.Id)"
OnPlay="@HandlePlayClick"
OnPause="@HandlePauseClick"/>
</div>
</MudItem>
}
@@ -6,18 +6,20 @@ namespace DeepDrftShared.Client.Components;
public partial class TracksGallery : ComponentBase
{
[Parameter] public IEnumerable<TrackDto> Tracks { get; set; } = [];
[Parameter] public TrackDto? SelectedTrack { get; set; }
[Parameter] public EventCallback<TrackDto?> SelectedTrackChanged { get; set; }
private async Task HandlePlayClick(TrackDto track)
{
if (SelectedTrack == track) return;
SelectedTrack = track;
StateHasChanged();
// Controlled play-state inputs: the parent owns playback truth (the player service)
// and drives these. The gallery is presentational — it only matches by id to decide
// which card reflects the active state.
[Parameter] public TrackDto? ActiveTrack { get; set; }
[Parameter] public bool IsPlaying { get; set; }
[Parameter] public bool IsPaused { get; set; }
if (SelectedTrackChanged.HasDelegate)
{
await SelectedTrackChanged.InvokeAsync(track);
}
}
[Parameter] public EventCallback<TrackDto> OnPlay { get; set; }
[Parameter] public EventCallback<TrackDto> OnPause { get; set; }
private Task HandlePlayClick(TrackDto track) =>
OnPlay.HasDelegate ? OnPlay.InvokeAsync(track) : Task.CompletedTask;
private Task HandlePauseClick(TrackDto track) =>
OnPause.HasDelegate ? OnPause.InvokeAsync(track) : Task.CompletedTask;
}