perf(player): isolate high-frequency playback updates

This commit is contained in:
zarzet
2026-07-15 22:09:20 +07:00
parent 82ba586b72
commit 6f566a9f03
4 changed files with 261 additions and 156 deletions
+27 -9
View File
@@ -23,8 +23,7 @@ class _MiniPlayerState extends ConsumerState<MiniPlayer> {
final mediaItem = ref.watch(currentMediaItemProvider).value;
if (mediaItem == null) return const SizedBox.shrink();
final playback = ref.watch(playbackStateProvider).value;
final isPlaying = playback?.playing ?? false;
final isPlaying = ref.watch(playbackPlayingProvider);
if (mediaItem.id == _dismissedItemId && !isPlaying) {
return const SizedBox.shrink();
}
@@ -32,10 +31,6 @@ class _MiniPlayerState extends ConsumerState<MiniPlayer> {
final controller = ref.read(musicPlayerControllerProvider);
final colorScheme = Theme.of(context).colorScheme;
final duration = mediaItem.duration?.inMilliseconds ?? 0;
final position = playback?.position.inMilliseconds ?? 0;
final progress = duration > 0 ? (position / duration).clamp(0.0, 1.0) : 0.0;
return Dismissible(
key: ValueKey('mini-player-${mediaItem.id}'),
direction: DismissDirection.horizontal,
@@ -64,9 +59,8 @@ class _MiniPlayerState extends ConsumerState<MiniPlayer> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
LinearProgressIndicator(
value: progress,
minHeight: 2,
_MiniPlayerProgress(
duration: mediaItem.duration ?? Duration.zero,
backgroundColor: colorScheme.surfaceContainerHighest,
),
Padding(
@@ -136,3 +130,27 @@ class _MiniPlayerState extends ConsumerState<MiniPlayer> {
);
}
}
class _MiniPlayerProgress extends ConsumerWidget {
final Duration duration;
final Color backgroundColor;
const _MiniPlayerProgress({
required this.duration,
required this.backgroundColor,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final durationMs = duration.inMilliseconds;
final positionMs = ref.watch(playbackPositionProvider).inMilliseconds;
final progress = durationMs > 0
? (positionMs / durationMs).clamp(0.0, 1.0)
: 0.0;
return LinearProgressIndicator(
value: progress,
minHeight: 2,
backgroundColor: backgroundColor,
);
}
}
+11 -12
View File
@@ -17,9 +17,9 @@ class PreviewButton extends ConsumerWidget {
await ref.read(previewPlayerProvider.notifier).toggle(track.previewUrl);
} catch (_) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.previewUnavailable)),
);
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(context.l10n.previewUnavailable)));
}
}
@@ -41,8 +41,7 @@ class PreviewButton extends ConsumerWidget {
// it (consistent with the mini player) rather than the preview snippet.
final mainItem = ref.watch(currentMediaItemProvider).value;
if (_isCurrentMainTrack(mainItem)) {
final isPlaying =
ref.watch(playbackStateProvider).value?.playing ?? false;
final isPlaying = ref.watch(playbackPlayingProvider);
return Transform.translate(
offset: const Offset(18, 0),
child: IconButton(
@@ -57,9 +56,12 @@ class PreviewButton extends ConsumerWidget {
: Icons.play_circle_fill_rounded,
color: colorScheme.primary,
),
tooltip: isPlaying ? context.l10n.previewStop : context.l10n.previewPlay,
onPressed: () =>
ref.read(musicPlayerControllerProvider).togglePlayPause(isPlaying),
tooltip: isPlaying
? context.l10n.previewStop
: context.l10n.previewPlay,
onPressed: () => ref
.read(musicPlayerControllerProvider)
.togglePlayPause(isPlaying),
),
);
}
@@ -92,10 +94,7 @@ class PreviewButton extends ConsumerWidget {
tooltip = context.l10n.previewStop;
break;
case PreviewStatus.paused:
icon = Icon(
Icons.play_circle_fill_rounded,
color: colorScheme.primary,
);
icon = Icon(Icons.play_circle_fill_rounded, color: colorScheme.primary);
tooltip = context.l10n.previewPlay;
break;
case PreviewStatus.idle: