From 6038ce5777e2fed2069652fcc0454a84fd9d3a27 Mon Sep 17 00:00:00 2001 From: zarzet <42882290+zarzet@users.noreply.github.com> Date: Sun, 20 Sep 2026 17:20:52 +0700 Subject: [PATCH] perf(mornye): release outgoing artwork decoders when replaced Retain the outgoing decoder only while its frame remains displayed, then release its provider subscription as soon as replacement artwork is ready. Verify decoder disposal while preserving cover transitions. --- lib/widgets/mornye_player_artwork.dart | 11 ++++++----- test/motion_header_banner_test.dart | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/widgets/mornye_player_artwork.dart b/lib/widgets/mornye_player_artwork.dart index 4bfa3129..5680c74e 100644 --- a/lib/widgets/mornye_player_artwork.dart +++ b/lib/widgets/mornye_player_artwork.dart @@ -53,11 +53,6 @@ class _MornyePlayerArtworkState extends ConsumerState { return fallback; } final videoUrl = widget.videoUrl; - // Keep one outgoing decoder alive until the next cover is ready. Rapid - // skips must not replace a visible frame with a loading placeholder. - if (_displayedSource != null && _displayedSource != videoUrl) { - ref.watch(playerArtworkVideoProvider(_displayedSource!)); - } final prepared = videoUrl == null ? null : ref.watch(playerArtworkVideoProvider(videoUrl)); @@ -74,6 +69,12 @@ class _MornyePlayerArtworkState extends ConsumerState { _displayedSource = null; _displayedController = null; } + // Retain the outgoing decoder only while it is still displayed. Watching + // it before accepting the new frame keeps its heap alive until a later + // unrelated rebuild, even after the old banner has been removed. + if (_displayedSource != null && _displayedSource != videoUrl) { + ref.watch(playerArtworkVideoProvider(_displayedSource!)); + } return Stack( fit: StackFit.expand, children: [ diff --git a/test/motion_header_banner_test.dart b/test/motion_header_banner_test.dart index f0949542..65979cb7 100644 --- a/test/motion_header_banner_test.dart +++ b/test/motion_header_banner_test.dart @@ -181,6 +181,8 @@ void main() { ready(2); await tester.pump(); await tester.pump(); + await tester.runAsync(() => Future.delayed(Duration.zero)); + expect(platform.disposals, 1, reason: 'Release the outgoing decoder'); expect( tester .widget(find.byType(MotionHeaderBanner))