@namespace DeepDrftPublic.Client.Controls @using DeepDrftPublic.Client.Services @implements IDisposable @inject WaveformVisualizerControlState State @* Theater-Mode toggle (Phase 20 §3). The single affordance placed identically on all three release detail pages — immediately to the LEFT of the lava-lamp WaveformVisualizerControlPopover trigger. It is purely a mutation surface: tapping it flips State.TheaterMode and raises Changed; the detail pages observe that to gate their content @if, and the player bar observes it to grow. This component reaches into no page and no bar — single source, multiple observers (§6). Visible only when the lava OR waveform subsystem is on — there is nothing to go to theater FOR if both are off (§3.2) — AND when is true. The page supplies Available so the toggle only appears when this page's release is the one playing (Phase 20 Wave 2 §3): the toggle owns the subsystem gate; the page owns the release-playing predicate. Disabled until interactive (§3.4), the same prerender guard the lava/Play buttons use. Active visual state when Theater is ON. .dd-accent-icon gives the green-accent glyph in both themes with zero new CSS (§8) — same as the lava-lamp trigger. *@ @if (Available && (State.LavaEnabled || State.WaveformEnabled)) {
} @code { /// Trigger-icon size. Defaults Large to match the lava-lamp popover trigger it sits beside. [Parameter] public Size IconSize { get; set; } = Size.Large; /// /// Whether the toggle is available on this surface (Phase 20 Wave 2 §3). The page passes the /// "this release is the one playing" predicate here; Theater Mode only applies to the playing /// release, so a detail page whose release is not playing passes false and shows no toggle. /// Defaults true so surfaces with no release-scoping (none today) keep the subsystem-only gate. /// [Parameter] public bool Available { get; set; } = true; protected override void OnInitialized() => State.Changed += OnStateChanged; // The toggle's own visibility and active state both key off State, which another observer (or this // button) may mutate, so re-render on every Changed — same idempotent posture the visualizer bridge uses. private void OnStateChanged() => InvokeAsync(StateHasChanged); private void Toggle() { State.TheaterMode = !State.TheaterMode; State.NotifyChanged(); } public void Dispose() => State.Changed -= OnStateChanged; }