From b8a51e46560d857a8ada4fbed877d0b4a31f2311 Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Wed, 3 Jun 2026 12:40:49 -0400 Subject: [PATCH] docs: update cascade type references and close resolved TODO item --- DeepDrftPublic.Client/CLAUDE.md | 8 ++++---- TODO.md | 8 -------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/DeepDrftPublic.Client/CLAUDE.md b/DeepDrftPublic.Client/CLAUDE.md index 8385645..e2fa7ef 100644 --- a/DeepDrftPublic.Client/CLAUDE.md +++ b/DeepDrftPublic.Client/CLAUDE.md @@ -16,7 +16,7 @@ All interactive UI for the site. Blazor WebAssembly. Pages, controls, the stream - `TrackCard.razor`: Individual track display (image, name, artist, album, genre, release date). - `TracksGallery.razor`: Responsive grid of `TrackCard` items (MudBlazor `MudGrid` with breakpoints). - `AppNavLink.razor`: Nav link with active-page highlight. - - `AudioPlayerProvider.razor`: Cascading host for `IPlayerService`. Everything inside it gets the player via `[CascadingParameter]`. + - `AudioPlayerProvider.razor`: Cascading host for `IStreamingPlayerService`. Everything inside it gets the player via `[CascadingParameter]`. - `AudioPlayerBar.razor`: Dock UI at the bottom (play/pause/seek/volume). - `SpectrumVisualizer.razor`: Bar-graph spectrum display, driven by `getSpectrumData` JS callback. - `Services/`: Audio player + dark-mode services. @@ -66,10 +66,10 @@ Both are configured with JSON serializer settings (case-insensitive property mat - `AudioInteropService` also manages callback registrations for progress (fired by `PlaybackScheduler`), end-of-playback (fired by `PlaybackScheduler`), and spectrum data (fired by `SpectrumAnalyzer`). Each callback is a `DotNetObjectReference` to a delegate. ### Component integration -- `AudioPlayerProvider.razor` is the cascading host. It injects `IPlayerService` (resolved to `StreamingAudioPlayerService` in DI), stores it in a cascade, and keeps it alive across navigation. +- `AudioPlayerProvider.razor` is the cascading host. It injects `IStreamingPlayerService` (resolved to `StreamingAudioPlayerService` in DI), stores it in a cascade, and keeps it alive across navigation. - `AudioPlayerBar.razor` is the dock UI. It cascades the player, binds buttons to `Play()` / `Pause()` / `Seek()` / `SetVolume()`, and displays current time / duration / progress bar. - `SpectrumVisualizer.razor` calls `AudioInteropService.GetSpectrumData()` on a timer, receives bar heights, renders via MudBlazor `MudChart` or custom canvas. -- `TracksView.razor` injects `TracksViewModel` + cascaded `IPlayerService`. `PlayTrack(track)` calls `PlayerService.SelectTrack(track)` (which resolves to `StreamingAudioPlayerService.SelectTrackStreaming(track)`). +- `TracksView.razor` injects `TracksViewModel` + cascaded `IStreamingPlayerService`. `PlayTrack(track)` calls `PlayerService.SelectTrack(track)` (which resolves to `StreamingAudioPlayerService.SelectTrackStreaming(track)`). ## Dark-mode plumbing @@ -118,7 +118,7 @@ dotnet test DeepDrftTests/ ## Important patterns -- **Cascading parameters**: `AudioPlayerProvider` cascades `IPlayerService`. All children (including `MainLayout` and pages) access it via `[CascadingParameter] IPlayerService Player { get; set; }`. +- **Cascading parameters**: `AudioPlayerProvider` cascades `IStreamingPlayerService`. All children (including `MainLayout` and pages) access it via `[CascadingParameter] IStreamingPlayerService Player { get; set; }`. - **Result types**: Clients return `ApiResult` from NetBlocks. UI checks `Success` before using `Value`. - **Async/await**: All operations are async. - **Stream consumption**: `TrackMediaClient.GetAudioStreamAsync` returns a `Stream` (not fully buffered). `StreamingAudioPlayerService` reads it in chunks to avoid memory pressure on large files. diff --git a/TODO.md b/TODO.md index e7c08c7..93a6a93 100644 --- a/TODO.md +++ b/TODO.md @@ -4,14 +4,6 @@ Pre-existing bugs and known issues not yet triaged into the roadmap. Items here --- -## Player controls do not activate — cascade type mismatch [CRITICAL] - -Full analysis in `PLAYER_ANALYSIS.md` (2026-06-03). - -- **Symptom:** Backend streaming works; player controls never respond. Clicking a track does nothing visible, the dock never expands, transport buttons render disabled. -- **Root cause:** `AudioPlayerProvider.razor` publishes `` where `_audioPlayerService` is typed as the concrete `StreamingAudioPlayerService`. Blazor binds cascading values **by the declared `TValue` type**. Every consumer asks for an interface — `AudioPlayerBar` / `SpectrumVisualizer` want `IStreamingPlayerService`, `TracksView` / `Home` want `IPlayerService` — so **none match the cascade and all receive `null`.** Null-guarded controls render disabled and silent; `TracksView.PlayerService` is `required` and will throw on first click once the bar alone is fixed. -- **Fix shape:** Type the provider field/cascade as a single interface (`IStreamingPlayerService`) and align all four consumers to it; or register the service in DI and use `AddCascadingValue`. Minimal correct move is the former. Detail in `PLAYER_ANALYSIS.md §2.3`. - ## Player stack — adjacent correctness/hygiene issues Surfaced by the same 2026-06-03 analysis (`PLAYER_ANALYSIS.md §4`). Distinct from the cascade bug.