From 4747119a7fefea47a99cda1f6d7eb36649d42341 Mon Sep 17 00:00:00 2001 From: zarzet Date: Fri, 27 Feb 2026 15:05:16 +0700 Subject: [PATCH] fix(playback): prevent internal mini-player flash in external mode --- lib/providers/playback_provider.dart | 77 ++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/lib/providers/playback_provider.dart b/lib/providers/playback_provider.dart index 72d98f45..90863db5 100644 --- a/lib/providers/playback_provider.dart +++ b/lib/providers/playback_provider.dart @@ -914,11 +914,17 @@ class PlaybackController extends Notifier { bool _isPlayRequestCurrent(int epoch) => epoch == _playRequestEpoch; - void _clearLyricsForTrackChange({PlaybackItem? upcomingItem}) { + void _clearLyricsForTrackChange({ + PlaybackItem? upcomingItem, + bool updateCurrentItem = true, + }) { // Invalidate any in-flight lyrics fetch from previous track. _lyricsGeneration++; state = state.copyWith( - currentItem: upcomingItem ?? state.currentItem, + clearCurrentItem: !updateCurrentItem, + currentItem: updateCurrentItem + ? (upcomingItem ?? state.currentItem) + : null, lyricsLoading: false, clearLyrics: true, ); @@ -1323,7 +1329,30 @@ class PlaybackController extends Notifier { track: track ?? fallbackTrack, ); - _clearLyricsForTrackChange(upcomingItem: item); + final routeToExternal = _shouldRouteToExternalPlayer(item); + _clearLyricsForTrackChange( + upcomingItem: item, + updateCurrentItem: !routeToExternal, + ); + + if (routeToExternal) { + state = state.copyWith( + clearCurrentItem: true, + queue: const [], + currentIndex: -1, + isLoading: false, + isBuffering: false, + isPlaying: false, + seekSupported: false, + position: Duration.zero, + bufferedPosition: Duration.zero, + duration: Duration.zero, + clearError: true, + ); + unawaited(_savePlaybackSnapshot()); + await _setSourceAndPlay(uri, item, expectedRequestEpoch: requestEpoch); + return; + } // Replacing single-track playback should also replace queue to avoid stale UI. state = state.copyWith( @@ -1588,20 +1617,31 @@ class PlaybackController extends Notifier { _trackKeyFromPlaybackItem(item)) { _rememberRecentPlayed(previousItem); } - _clearLyricsForTrackChange(upcomingItem: item); + final routeToExternal = _shouldRouteToExternalPlayer(item); + _clearLyricsForTrackChange( + upcomingItem: item, + updateCurrentItem: !routeToExternal, + ); state = state.copyWith( currentIndex: index, - currentItem: item, - isLoading: true, - isBuffering: true, + clearCurrentItem: routeToExternal, + currentItem: routeToExternal ? null : item, + isLoading: routeToExternal ? false : true, + isBuffering: routeToExternal ? false : true, isPlaying: false, - seekSupported: _inferSeekSupportedForQueueItem(item), - position: - pendingResumePosition != null && pendingResumePosition > Duration.zero - ? pendingResumePosition - : Duration.zero, + seekSupported: routeToExternal + ? false + : _inferSeekSupportedForQueueItem(item), + position: routeToExternal + ? Duration.zero + : (pendingResumePosition != null && + pendingResumePosition > Duration.zero + ? pendingResumePosition + : Duration.zero), bufferedPosition: Duration.zero, - duration: _fallbackDurationForItem(item), + duration: routeToExternal + ? Duration.zero + : _fallbackDurationForItem(item), clearError: true, ); await _savePlaybackSnapshot(); @@ -1630,7 +1670,7 @@ class PlaybackController extends Notifier { expectedRequestEpoch: requestEpoch, ); if (!_isPlayRequestCurrent(requestEpoch) || - state.currentIndex != index) { + (!routeToExternal && state.currentIndex != index)) { return; } _clearPendingResumeForIndex(index); @@ -1746,9 +1786,7 @@ class PlaybackController extends Notifier { required PlaybackItem item, int? expectedRequestEpoch, }) async { - final settings = ref.read(settingsProvider); - if (settings.playerMode != 'external') return false; - if (!item.isLocal) return false; + if (!_shouldRouteToExternalPlayer(item)) return false; final externalPath = _externalPathFromPlaybackUri(uri); if (externalPath == null || externalPath.isEmpty) return false; @@ -1802,6 +1840,11 @@ class PlaybackController extends Notifier { } } + bool _shouldRouteToExternalPlayer(PlaybackItem item) { + final settings = ref.read(settingsProvider); + return settings.playerMode == 'external' && item.isLocal; + } + String? _externalPathFromPlaybackUri(Uri uri) { if (uri.scheme == 'content') { return uri.toString();