fix(public): break OnStateChanged callback chain and lazy-init audio player to stop circuit memory blowup
This commit is contained in:
@@ -7,7 +7,7 @@ namespace DeepDrftPublic.Client.Controls.AudioPlayerBar;
|
||||
|
||||
public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
|
||||
{
|
||||
[CascadingParameter] public required IStreamingPlayerService PlayerService { get; set; }
|
||||
[CascadingParameter] public IStreamingPlayerService? PlayerService { get; set; }
|
||||
[Inject] public required IBrowserViewportService BrowserViewportService { get; set; }
|
||||
|
||||
private bool _isMinimized = true;
|
||||
@@ -16,21 +16,21 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
|
||||
private bool _isDesktop = true;
|
||||
private Guid _viewportSubscriptionId;
|
||||
|
||||
private bool IsLoaded => PlayerService.IsLoaded;
|
||||
private bool IsLoading => PlayerService.IsLoading;
|
||||
private bool IsStreaming => PlayerService.CanStartStreaming;
|
||||
private bool IsStreamingMode => PlayerService.IsStreamingMode;
|
||||
private bool IsPlaying => PlayerService.IsPlaying;
|
||||
private bool IsPaused => PlayerService.IsPaused;
|
||||
private double? Duration => PlayerService.Duration;
|
||||
private double Volume => PlayerService.Volume;
|
||||
private double LoadProgress => PlayerService.LoadProgress;
|
||||
private string? ErrorMessage => PlayerService.ErrorMessage;
|
||||
private bool IsLoaded => PlayerService?.IsLoaded ?? false;
|
||||
private bool IsLoading => PlayerService?.IsLoading ?? false;
|
||||
private bool IsStreaming => PlayerService?.CanStartStreaming ?? false;
|
||||
private bool IsStreamingMode => PlayerService?.IsStreamingMode ?? false;
|
||||
private bool IsPlaying => PlayerService?.IsPlaying ?? false;
|
||||
private bool IsPaused => PlayerService?.IsPaused ?? false;
|
||||
private double? Duration => PlayerService?.Duration;
|
||||
private double Volume => PlayerService?.Volume ?? 0;
|
||||
private double LoadProgress => PlayerService?.LoadProgress ?? 0;
|
||||
private string? ErrorMessage => PlayerService?.ErrorMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Display time - shows seek position while dragging, otherwise current playback time.
|
||||
/// </summary>
|
||||
private double DisplayTime => _isSeeking ? _seekPosition : PlayerService.CurrentTime;
|
||||
private double DisplayTime => _isSeeking ? _seekPosition : (PlayerService?.CurrentTime ?? 0);
|
||||
|
||||
/// <summary>
|
||||
/// Seek is enabled once track is loaded AND duration is known (from WAV header).
|
||||
@@ -38,26 +38,16 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
|
||||
/// </summary>
|
||||
private bool CanSeek => IsLoaded && Duration.HasValue && Duration.Value > 0;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
// Set up EventCallback for track selection
|
||||
PlayerService.OnTrackSelected = new EventCallback(this, Expand);
|
||||
|
||||
// Store the original OnStateChanged callback set by the provider
|
||||
var originalOnStateChanged = PlayerService.OnStateChanged;
|
||||
|
||||
// Set up a wrapper that calls both the original callback and our StateHasChanged
|
||||
PlayerService.OnStateChanged = new EventCallback(this, async () =>
|
||||
// PlayerService is cascaded by AudioPlayerProvider; once it arrives,
|
||||
// wire our track-selection handler. The provider owns OnStateChanged —
|
||||
// we intentionally do NOT wrap or replace it. Re-renders propagate
|
||||
// from the provider via the standard Blazor child render path.
|
||||
if (PlayerService != null)
|
||||
{
|
||||
// Invoke the original callback (AudioPlayerProvider's StateHasChanged)
|
||||
if (originalOnStateChanged.HasValue)
|
||||
{
|
||||
await originalOnStateChanged.Value.InvokeAsync();
|
||||
}
|
||||
// Also trigger our own re-render
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
PlayerService.OnTrackSelected = new EventCallback(this, Expand);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Expand()
|
||||
@@ -76,16 +66,19 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
|
||||
|
||||
private async Task TogglePlayPause()
|
||||
{
|
||||
if (PlayerService == null) return;
|
||||
await PlayerService.TogglePlayPause();
|
||||
}
|
||||
|
||||
private async Task Stop()
|
||||
{
|
||||
if (PlayerService == null) return;
|
||||
await PlayerService.Stop();
|
||||
}
|
||||
|
||||
private void OnSeekStart()
|
||||
{
|
||||
if (PlayerService == null) return;
|
||||
_isSeeking = true;
|
||||
_seekPosition = PlayerService.CurrentTime;
|
||||
}
|
||||
@@ -98,20 +91,22 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
|
||||
|
||||
private async Task OnSeekEnd(double position)
|
||||
{
|
||||
if (PlayerService == null) return;
|
||||
_isSeeking = false;
|
||||
await PlayerService.Seek(position);
|
||||
}
|
||||
|
||||
private async Task OnVolumeChange(double volume)
|
||||
{
|
||||
if (PlayerService == null) return;
|
||||
await PlayerService.SetVolume(volume);
|
||||
}
|
||||
|
||||
|
||||
private void ClearError()
|
||||
{
|
||||
PlayerService.ClearError();
|
||||
PlayerService?.ClearError();
|
||||
}
|
||||
|
||||
|
||||
private void ToggleMinimized()
|
||||
{
|
||||
_isMinimized = !_isMinimized;
|
||||
@@ -120,7 +115,7 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
|
||||
|
||||
private async Task Close()
|
||||
{
|
||||
if (PlayerService.IsLoaded)
|
||||
if (PlayerService != null && PlayerService.IsLoaded)
|
||||
{
|
||||
await PlayerService.Unload();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user