From 0439ce3ed2387c64b7f87ab0a79e25602353ddca Mon Sep 17 00:00:00 2001 From: Dustin Date: Tue, 4 Aug 2026 20:55:24 +0200 Subject: [PATCH] =?UTF-8?q?v2.50.4=20=E2=80=94=20Glow-Pulsation=20rebuilde?= =?UTF-8?q?t=20+=20Cover-Crossfade=20beim=20Songwechsel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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 --- lib/screens/now_playing_screen.dart | 65 ++++++++++++++++++----------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/lib/screens/now_playing_screen.dart b/lib/screens/now_playing_screen.dart index f8ff20c..64e9371 100644 --- a/lib/screens/now_playing_screen.dart +++ b/lib/screens/now_playing_screen.dart @@ -91,6 +91,12 @@ class _NowPlayingScreenState extends State _zeigeLyrics = false; _lyrics = null; _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); _ladeFavoritStatus(song); @@ -567,7 +573,11 @@ class _NowPlayingScreenState extends State ); } 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), child: Image.file(File(pfad), fit: BoxFit.cover), ); @@ -636,30 +646,35 @@ class _NowPlayingScreenState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 16), - // Cover mit Glow - Container( - width: coverGroesse, - height: coverGroesse, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - // Glow in der Akzentfarbe des Users, pulsierend bei Wiedergabe - color: MeloTheme.akzent.withValues(alpha: 0.45), - blurRadius: 50 + 20 * _glowController.value, // 50–70 - spreadRadius: 6 + 6 * _glowController.value, // 6–12 - ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: hatCover - ? Image.file(File(_coverPfad!), fit: BoxFit.cover) - : Container( - color: MeloTheme.rotHell, - child: const Icon(Icons.music_note, - size: 90, color: MeloTheme.rot), - ), + // Cover mit Glow — AnimatedBuilder um den Container: Ohne Listener/ + // Builder würde der BoxShadow nur bei fremden setStates neu gebaut + // (Pulsation zufällig sichtbar, friert bei Pause/Pufferung ein). + AnimatedBuilder( + animation: _glowController, + builder: (context, _) => Container( + width: coverGroesse, + height: coverGroesse, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + // Glow in der Akzentfarbe des Users, pulsierend bei Wiedergabe + color: MeloTheme.akzent.withValues(alpha: 0.45), + blurRadius: 50 + 20 * _glowController.value, // 50–70 + spreadRadius: 6 + 6 * _glowController.value, // 6–12 + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: hatCover + ? 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),