perf(library): dispose unused playback row subscriptions

Auto-dispose media-item playback providers after their last listener leaves so scrolling does not retain every visited row subscription. Test disposal of 200 rows, active-row behavior and reattachment.
This commit is contained in:
zarzet committed 2026-09-20 17:21:01 +07:00
1 parent cb5ce3df62
commit d91bfae155
2 files changed
+86 -16

No files matched your search

+18 -16
View File
@@ -86,22 +86,24 @@ final playbackLoadingProvider = Provider<bool>((ref) {
/// Transport state for one media item. Non-current Library cells only watch
/// the current media ID; the active cell additionally follows play/loading so
/// a transport toggle does not rebuild the entire Library grid.
final mediaItemPlaybackUiProvider =
Provider.family<({bool isCurrent, bool isPlaying, bool isLoading}), String>(
(ref, mediaId) {
final currentId = ref.watch(
currentMediaItemProvider.select((state) => state.value?.id),
);
if (mediaId.isEmpty || currentId != mediaId) {
return (isCurrent: false, isPlaying: false, isLoading: false);
}
return (
isCurrent: true,
isPlaying: ref.watch(playbackPlayingProvider),
isLoading: ref.watch(playbackLoadingProvider),
);
},
);
/// Release each cell's subscription when it scrolls out of the Library.
final mediaItemPlaybackUiProvider = Provider.autoDispose
.family<({bool isCurrent, bool isPlaying, bool isLoading}), String>((
ref,
mediaId,
) {
final currentId = ref.watch(
currentMediaItemProvider.select((state) => state.value?.id),
);
if (mediaId.isEmpty || currentId != mediaId) {
return (isCurrent: false, isPlaying: false, isLoading: false);
}
return (
isCurrent: true,
isPlaying: ref.watch(playbackPlayingProvider),
isLoading: ref.watch(playbackLoadingProvider),
);
});
final playQueueProvider = StreamProvider<List<MediaItem>>((ref) {
return musicPlayerQueueEvents();