v2.50.4 — Glow-Pulsation rebuildet + Cover-Crossfade beim Songwechsel

## Fix 1 (MED): Glow-Pulsation rebuildet jetzt wirklich
- now_playing_screen.dart: Cover-Container mit AnimatedBuilder(animation: _glowController) gewrappt — BoxShadow (blur 50–70 / spread 6–12) wird jetzt pro Animations-Tick neu gebaut statt nur bei fremden setStates (Pulsation war vorher nur zufällig über positionStream sichtbar und fror bei Pause/Pufferung ein)

## Fix 2 (MED): Echter Crossfade beim Songwechsel
- _songSub-Listener setzt _hatCover/_coverPfad jetzt SYNCHRON auf false/null (im selben setState) — Hintergrund und Front-Cover zeigen beim Songwechsel kein altes Cover mehr, bis die async Existenz-Prüfung durch ist
- _hintergrundBlur-Key auf den tatsächlichen Cover-Pfad gelegt ('cover-$pfad' statt song.id) — Switcher wechselt erst bei geladenem neuem Cover (Crossfade Gradient→Cover), kein Fade alt→alt + harter Cut mehr

flutter analyze: 0 Issues, Tests 98/98 grün, keine neuen Packages
This commit is contained in:
Dustin
2026-08-04 20:55:24 +02:00
parent dfa19c999b
commit 0439ce3ed2
+40 -25
View File
@@ -91,6 +91,12 @@ class _NowPlayingScreenState extends State<NowPlayingScreen>
_zeigeLyrics = false; _zeigeLyrics = false;
_lyrics = null; _lyrics = null;
_lyricsLaden = true; _lyricsLaden = true;
// Cover-Zustand SYNCHRON zurücksetzen: Sonst rendern Hintergrund
// (und Front-Cover) beim Songwechsel kurz das ALTE Cover, bis die
// async Existenz-Prüfung durch ist — der Switcher-Key (song.id)
// wechselt sofort → Fade alt→alt, dann harter Cut aufs neue Cover.
_hatCover = false;
_coverPfad = null;
}); });
_ladeLyricsFuer(song, _ladeGeneration); _ladeLyricsFuer(song, _ladeGeneration);
_ladeFavoritStatus(song); _ladeFavoritStatus(song);
@@ -567,7 +573,11 @@ class _NowPlayingScreenState extends State<NowPlayingScreen>
); );
} }
return ImageFiltered( return ImageFiltered(
key: ValueKey('cover-${song?.id ?? pfad}'), // Key auf den tatsächlichen Cover-Pfad statt song.id: Der Switcher
// wechselt erst, wenn das NEUE Cover wirklich geladen ist (echter
// Crossfade) — nie vorher (altes Bild unter neuem Key = unsichtbarer
// Fade + harter Cut beim Nachladen).
key: ValueKey('cover-$pfad'),
imageFilter: ImageFilter.blur(sigmaX: 45, sigmaY: 45), imageFilter: ImageFilter.blur(sigmaX: 45, sigmaY: 45),
child: Image.file(File(pfad), fit: BoxFit.cover), child: Image.file(File(pfad), fit: BoxFit.cover),
); );
@@ -636,30 +646,35 @@ class _NowPlayingScreenState extends State<NowPlayingScreen>
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const SizedBox(height: 16), const SizedBox(height: 16),
// Cover mit Glow // Cover mit Glow — AnimatedBuilder um den Container: Ohne Listener/
Container( // Builder würde der BoxShadow nur bei fremden setStates neu gebaut
width: coverGroesse, // (Pulsation zufällig sichtbar, friert bei Pause/Pufferung ein).
height: coverGroesse, AnimatedBuilder(
decoration: BoxDecoration( animation: _glowController,
borderRadius: BorderRadius.circular(20), builder: (context, _) => Container(
boxShadow: [ width: coverGroesse,
BoxShadow( height: coverGroesse,
// Glow in der Akzentfarbe des Users, pulsierend bei Wiedergabe decoration: BoxDecoration(
color: MeloTheme.akzent.withValues(alpha: 0.45), borderRadius: BorderRadius.circular(20),
blurRadius: 50 + 20 * _glowController.value, // 5070 boxShadow: [
spreadRadius: 6 + 6 * _glowController.value, // 612 BoxShadow(
), // Glow in der Akzentfarbe des Users, pulsierend bei Wiedergabe
], color: MeloTheme.akzent.withValues(alpha: 0.45),
), blurRadius: 50 + 20 * _glowController.value, // 5070
child: ClipRRect( spreadRadius: 6 + 6 * _glowController.value, // 612
borderRadius: BorderRadius.circular(20), ),
child: hatCover ],
? Image.file(File(_coverPfad!), fit: BoxFit.cover) ),
: Container( child: ClipRRect(
color: MeloTheme.rotHell, borderRadius: BorderRadius.circular(20),
child: const Icon(Icons.music_note, child: hatCover
size: 90, color: MeloTheme.rot), ? Image.file(File(_coverPfad!), fit: BoxFit.cover)
), : Container(
color: MeloTheme.rotHell,
child: const Icon(Icons.music_note,
size: 90, color: MeloTheme.rot),
),
),
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),