refactor(settings): remove redundant Animations 3-state setting (#495)

* refactor(settings): remove redundant Animations 3-state setting under Seekbar Style

The `animationMode` setting (Full / Reduced / Static) duplicated work
the perf-flag system and OS-level reduced-motion preference already
covered:

- `perfFlags.disableMarqueeScroll` already kills marquee scrolling on
  demand, replacing what `static` mode used to gate.
- The `data-perf-disable-animations` html-level switch already strips
  every `*` animation, replacing what `static` mode used to do globally.
- `@media (prefers-reduced-motion: reduce)` honours the OS setting for
  every user that asked for it via system preferences.
- The 30 fps cap that `reduced` mode applied to the seekbar wave was
  better served by per-feature perf toggles cucadmuh added later.

Removed:
- `AnimationMode` type, `animationMode` field + setter from auth store.
- Settings UI block (3 buttons + hint text) under Appearance > Seekbar
  Style.
- `animationMode === 'static'` short-circuit in WaveformSeek's rAF
  effect; `isReduced` skip-every-other-frame logic; `static`-checks in
  `drawNow` / `needsDirectDraw`.
- `animationMode !== 'static'` guard and `data-anim-mode` attribute in
  MarqueeText.
- `[data-anim-mode="static"]` and `[data-anim-mode="reduced"]` rules in
  layout.css.
- Seven i18n keys (animationMode + 6 variants) across all eight
  locales.

Migration: the persist layer strips `animationMode` (and the legacy
`reducedAnimations` boolean predecessor) so anyone who had `'reduced'`
or `'static'` selected silently lands on the former `'full'` path on
first launch after upgrade. No user-facing prompt — the missing setting
just stops existing.

cucadmuh's PR #472 (FPS overlay), #476 (preview-freeze main seekbar,
sleep-recovery hooks, card-hover removal) and #486 (interpolation
anchor reset on resume) are all preserved untouched — they live in
separate effects / files and were not driven by `animationMode`.

* docs(changelog): add Removed section for animationMode setting (PR #495)

* docs(changelog): refine animationMode removal rationale (drop prefers-reduced-motion overstatement)
This commit is contained in:
Frank Stellmacher
2026-05-07 12:53:19 +02:00
committed by GitHub
parent ba73649360
commit ddb1f29af9
14 changed files with 24 additions and 164 deletions
+8 -19
View File
@@ -25,7 +25,6 @@ export interface ServerProfile {
export type SeekbarStyle = 'truewave' | 'pseudowave' | 'linedot' | 'bar' | 'thick' | 'segmented' | 'neon' | 'pulsewave' | 'particletrail' | 'liquidfill' | 'retrotape';
export type LoggingMode = 'off' | 'normal' | 'debug';
export type NormalizationEngine = 'off' | 'replaygain' | 'loudness';
export type AnimationMode = 'full' | 'reduced' | 'static';
export type DiscordCoverSource = 'none' | 'apple' | 'server';
/** Integrated-loudness target presets (Settings + analysis). */
@@ -179,12 +178,6 @@ interface AuthState {
lastSeenChangelogVersion: string;
seekbarStyle: SeekbarStyle;
/** Animation budget across the UI:
* - `full` = native frame rate
* - `reduced`= 30 fps cap on animated seekbar; marquee at half frame rate
* - `static` = ~1 fps progress (no rAF interpolation); marquee disabled (truncate)
*/
animationMode: AnimationMode;
/** Persisted UI toggle: is the Now Playing section in queue panel collapsed */
queueNowPlayingCollapsed: boolean;
@@ -337,7 +330,6 @@ interface AuthState {
setShowChangelogOnUpdate: (v: boolean) => void;
setLastSeenChangelogVersion: (v: string) => void;
setSeekbarStyle: (v: SeekbarStyle) => void;
setAnimationMode: (v: AnimationMode) => void;
setQueueNowPlayingCollapsed: (v: boolean) => void;
setEnableHiRes: (v: boolean) => void;
setAudioOutputDevice: (v: string | null) => void;
@@ -475,7 +467,6 @@ export const useAuthStore = create<AuthState>()(
showChangelogOnUpdate: true,
lastSeenChangelogVersion: '',
seekbarStyle: 'truewave',
animationMode: 'full',
queueNowPlayingCollapsed: false,
enableHiRes: false,
audioOutputDevice: null,
@@ -640,7 +631,6 @@ export const useAuthStore = create<AuthState>()(
setLastSeenChangelogVersion: (v) => set({ lastSeenChangelogVersion: v }),
setSeekbarStyle: (v) => set({ seekbarStyle: v }),
setAnimationMode: (v) => set({ animationMode: v }),
setQueueNowPlayingCollapsed: (v: boolean) => set({ queueNowPlayingCollapsed: v }),
setEnableHiRes: (v) => set({ enableHiRes: v }),
setAudioOutputDevice: (v) => set({ audioOutputDevice: v }),
@@ -843,14 +833,14 @@ export const useAuthStore = create<AuthState>()(
? {}
: { seekbarStyle: 'truewave' as SeekbarStyle };
// `reducedAnimations: boolean` superseded by `animationMode: AnimationMode`.
// Map legacy true → 'reduced', false/missing → 'full'. Static is opt-in only.
let animationModeMigrated: { animationMode?: AnimationMode } = {};
const legacyReduced = (state as { reducedAnimations?: unknown }).reducedAnimations;
const VALID_ANIM_MODES = new Set<string>(['full', 'reduced', 'static']);
if (!VALID_ANIM_MODES.has(state.animationMode as string)) {
animationModeMigrated = { animationMode: legacyReduced === true ? 'reduced' : 'full' };
}
// The `animationMode` 3-state setting was removed; users on `'reduced'`
// or `'static'` collapse onto the former `'full'` path automatically as
// soon as the field is gone from the store. Strip the persisted field
// so it doesn't sit in localStorage as cruft.
delete (state as { animationMode?: unknown }).animationMode;
// The earlier `reducedAnimations: boolean` predecessor likewise loses
// its meaning; clear it for the same reason.
delete (state as { reducedAnimations?: unknown }).reducedAnimations;
const st = state as {
loudnessTargetLufs?: unknown;
@@ -891,7 +881,6 @@ export const useAuthStore = create<AuthState>()(
...lyricsSourcesMigrated,
...wheelSmoothOneTime,
...seekbarStyleMigrated,
...animationModeMigrated,
...discordCoverSourceMigrated,
});
},