From fca8fc53189804ee5ac69a3295902b3d6d058730 Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Sat, 2 May 2026 22:50:22 +0200 Subject: [PATCH] fix(seekbar): blank canvas after update from legacy build (#432) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After PR #316 split the 'waveform' seekbar style into 'truewave' / 'pseudowave', users who carried any other unrecognised persisted value (legacy variants, undefined, tampered strings) ended up with a blank seekbar — the rehydrate migration matched only the literal 'waveform' string, and the drawSeekbar dispatcher had no default branch, so an unknown style drew nothing. Two-layer fix: * authStore migration now treats *any* value not in the current SeekbarStyle union as legacy and resets it to 'truewave'. * drawSeekbar gains a default case that falls back to the truewave renderer, so even if a future style mismatch slips through the store-level guard the user still sees a usable seekbar. Visible to affected users on next app start (rehydrate runs once per session). Clicking a style in Settings has always worked around the issue; this fix removes that workaround. --- src/components/WaveformSeek.tsx | 4 ++++ src/store/authStore.ts | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/WaveformSeek.tsx b/src/components/WaveformSeek.tsx index f0c44668..ab6eae9f 100644 --- a/src/components/WaveformSeek.tsx +++ b/src/components/WaveformSeek.tsx @@ -785,6 +785,10 @@ export function drawSeekbar( case 'particletrail': drawParticleTrail(canvas, progress, buffered, anim); break; case 'liquidfill': drawLiquidFill(canvas, progress, buffered, anim); break; case 'retrotape': drawRetroTape(canvas, progress, buffered, anim); break; + // Safety net: if a legacy or tampered persisted style sneaks past the + // authStore migration, fall back to the truewave renderer instead of + // leaving a blank canvas. + default: drawWaveform(canvas, heights, progress, buffered); break; } } diff --git a/src/store/authStore.ts b/src/store/authStore.ts index decfe04a..f178c564 100644 --- a/src/store/authStore.ts +++ b/src/store/authStore.ts @@ -800,12 +800,18 @@ export const useAuthStore = create()( } catch { /* ignore */ } } - // One-time: 'waveform' style was renamed to 'truewave' (with 'pseudowave' - // added as the deterministic legacy variant). Existing persisted value - // 'waveform' should land on the new bins-based default. - const seekbarStyleMigrated = (state.seekbarStyle as string) === 'waveform' - ? { seekbarStyle: 'truewave' as SeekbarStyle } - : {}; + // 'waveform' style was renamed to 'truewave' (with 'pseudowave' added + // as the deterministic legacy variant). Any persisted value that is + // not a valid SeekbarStyle (legacy 'waveform', undefined, tampered + // strings) lands on the new bins-based default — otherwise the + // dispatcher's switch finds no match and the seekbar renders blank. + const VALID_SEEKBAR_STYLES = new Set([ + 'truewave', 'pseudowave', 'linedot', 'bar', 'thick', + 'segmented', 'neon', 'pulsewave', 'particletrail', 'liquidfill', 'retrotape', + ]); + const seekbarStyleMigrated = VALID_SEEKBAR_STYLES.has(state.seekbarStyle as string) + ? {} + : { seekbarStyle: 'truewave' as SeekbarStyle }; const st = state as { loudnessTargetLufs?: unknown;