Fix player position performance issue (#606)

This commit is contained in:
Piotr Rogowski 2023-08-01 15:44:00 +02:00 committed by GitHub
parent affdb57ecd
commit 3e0834f83c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 296 additions and 300 deletions

View File

@ -5,6 +5,7 @@
"danceability", "danceability",
"instrumentalness", "instrumentalness",
"Mpris", "Mpris",
"riverpod",
"speechiness", "speechiness",
"Spotube", "Spotube",
"winget" "winget"

View File

@ -48,7 +48,6 @@ class PlayerControls extends HookConsumerWidget {
final playing = final playing =
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
final buffering = useStream(audioPlayer.bufferingStream).data ?? true;
final theme = Theme.of(context); final theme = Theme.of(context);
final isDominantColorDark = ThemeData.estimateBrightnessForColor( final isDominantColorDark = ThemeData.estimateBrightnessForColor(
@ -89,8 +88,7 @@ class PlayerControls extends HookConsumerWidget {
iconSize: compact ? 18 : 24, iconSize: compact ? 18 : 24,
); );
return RepaintBoundary( return GestureDetector(
child: GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
onTap: () { onTap: () {
if (focusNode.canRequestFocus) { if (focusNode.canRequestFocus) {
@ -147,8 +145,7 @@ class PlayerControls extends HookConsumerWidget {
// than total duration. Keeping it resolved // than total duration. Keeping it resolved
value: progress.value.toDouble(), value: progress.value.toDouble(),
secondaryTrackValue: bufferProgress, secondaryTrackValue: bufferProgress,
onChanged: onChanged: playlist.isFetching == true
playlist.isFetching == true || buffering
? null ? null
: (v) { : (v) {
progress.value = v; progress.value = v;
@ -156,14 +153,12 @@ class PlayerControls extends HookConsumerWidget {
onChangeEnd: (value) async { onChangeEnd: (value) async {
await audioPlayer.seek( await audioPlayer.seek(
Duration( Duration(
seconds: seconds: (value * duration.inSeconds).toInt(),
(value * duration.inSeconds).toInt(),
), ),
); );
}, },
activeColor: sliderColor, activeColor: sliderColor,
secondaryActiveColor: secondaryActiveColor: sliderColor.withOpacity(0.2),
sliderColor.withOpacity(0.2),
inactiveColor: sliderColor.withOpacity(0.15), inactiveColor: sliderColor.withOpacity(0.15),
), ),
), ),
@ -176,8 +171,7 @@ class PlayerControls extends HookConsumerWidget {
color: palette?.dominantColor?.bodyTextColor, color: palette?.dominantColor?.bodyTextColor,
), ),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Text("$currentMinutes:$currentSeconds"), Text("$currentMinutes:$currentSeconds"),
Text("$totalMinutes:$totalSeconds"), Text("$totalMinutes:$totalSeconds"),
@ -202,7 +196,7 @@ class PlayerControls extends HookConsumerWidget {
: context.l10n.shuffle_playlist, : context.l10n.shuffle_playlist,
icon: const Icon(SpotubeIcons.shuffle), icon: const Icon(SpotubeIcons.shuffle),
style: shuffled ? activeButtonStyle : buttonStyle, style: shuffled ? activeButtonStyle : buttonStyle,
onPressed: playlist.isFetching == true || buffering onPressed: playlist.isFetching == true
? null ? null
: () { : () {
if (shuffled) { if (shuffled) {
@ -217,7 +211,7 @@ class PlayerControls extends HookConsumerWidget {
tooltip: context.l10n.previous_track, tooltip: context.l10n.previous_track,
icon: const Icon(SpotubeIcons.skipBack), icon: const Icon(SpotubeIcons.skipBack),
style: buttonStyle, style: buttonStyle,
onPressed: playlist.isFetching == true || buffering onPressed: playlist.isFetching == true
? null ? null
: playlistNotifier.previous, : playlistNotifier.previous,
), ),
@ -249,15 +243,14 @@ class PlayerControls extends HookConsumerWidget {
tooltip: context.l10n.next_track, tooltip: context.l10n.next_track,
icon: const Icon(SpotubeIcons.skipForward), icon: const Icon(SpotubeIcons.skipForward),
style: buttonStyle, style: buttonStyle,
onPressed: playlist.isFetching == true || buffering onPressed: playlist.isFetching == true
? null ? null
: playlistNotifier.next, : playlistNotifier.next,
), ),
StreamBuilder<PlaybackLoopMode>( StreamBuilder<PlaybackLoopMode>(
stream: audioPlayer.loopModeStream, stream: audioPlayer.loopModeStream,
builder: (context, snapshot) { builder: (context, snapshot) {
final loopMode = final loopMode = snapshot.data ?? PlaybackLoopMode.none;
snapshot.data ?? PlaybackLoopMode.none;
return IconButton( return IconButton(
tooltip: loopMode == PlaybackLoopMode.one tooltip: loopMode == PlaybackLoopMode.one
? context.l10n.loop_track ? context.l10n.loop_track
@ -273,7 +266,7 @@ class PlayerControls extends HookConsumerWidget {
loopMode == PlaybackLoopMode.all loopMode == PlaybackLoopMode.all
? activeButtonStyle ? activeButtonStyle
: buttonStyle, : buttonStyle,
onPressed: playlist.isFetching == true || buffering onPressed: playlist.isFetching == true
? null ? null
: () async { : () async {
switch (await audioPlayer.loopMode) { switch (await audioPlayer.loopMode) {
@ -300,7 +293,6 @@ class PlayerControls extends HookConsumerWidget {
), ),
), ),
), ),
),
); );
} }
} }

View File

@ -62,7 +62,6 @@ class PlayerOverlay extends HookConsumerWidget {
child: AnimatedOpacity( child: AnimatedOpacity(
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
opacity: canShow ? 1 : 0, opacity: canShow ? 1 : 0,
child: RepaintBoundary(
child: Material( child: Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: Column( child: Column(
@ -124,8 +123,7 @@ class PlayerOverlay extends HookConsumerWidget {
? const SizedBox( ? const SizedBox(
height: 20, height: 20,
width: 20, width: 20,
child: child: CircularProgressIndicator(),
CircularProgressIndicator(),
) )
: Icon( : Icon(
playing playing
@ -133,8 +131,7 @@ class PlayerOverlay extends HookConsumerWidget {
: SpotubeIcons.play, : SpotubeIcons.play,
color: textColor, color: textColor,
), ),
onPressed: onPressed: Actions.handler<PlayPauseIntent>(
Actions.handler<PlayPauseIntent>(
context, context,
PlayPauseIntent(ref), PlayPauseIntent(ref),
), ),
@ -160,7 +157,6 @@ class PlayerOverlay extends HookConsumerWidget {
), ),
), ),
), ),
),
); );
} }
} }

View File

@ -1,6 +1,5 @@
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
({ ({
@ -9,21 +8,29 @@ import 'package:spotube/services/audio_player/audio_player.dart';
Duration duration, Duration duration,
double bufferProgress double bufferProgress
}) useProgress(WidgetRef ref) { }) useProgress(WidgetRef ref) {
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
final bufferProgress = final bufferProgress =
useStream(audioPlayer.bufferedPositionStream).data?.inSeconds ?? 0; useStream(audioPlayer.bufferedPositionStream).data?.inSeconds ?? 0;
Duration audioPlayerDuration = Duration.zero;
Duration audioPlayerPosition = Duration.zero;
// Duration future is needed for getting the duration of the song // Duration future is needed for getting the duration of the song
// as stream can be null when no event occurs (Mostly needed for android) // as stream can be null when no event occurs (Mostly needed for android)
final durationFuture = useFuture(audioPlayer.duration); audioPlayer.duration.then((value) {
final duration = useStream(audioPlayer.durationStream).data ?? if (value != null) {
durationFuture.data ?? audioPlayerDuration = value;
Duration.zero; }
});
final positionFuture = useFuture(audioPlayer.position); audioPlayer.position.then((value) {
final position = useState<Duration>(positionFuture.data ?? Duration.zero); if (value != null) {
audioPlayerPosition = value;
}
});
final position = useState<Duration>(audioPlayerPosition);
final duration =
useStream(audioPlayer.durationStream).data ?? audioPlayerDuration;
final sliderMax = duration.inSeconds; final sliderMax = duration.inSeconds;
final sliderValue = position.value.inSeconds; final sliderValue = position.value.inSeconds;
@ -38,7 +45,7 @@ import 'package:spotube/services/audio_player/audio_player.dart';
lastPosition = event; lastPosition = event;
position.value = event; position.value = event;
}).cancel; }).cancel;
}, []); }, [audioPlayerPosition, audioPlayerDuration]);
return ( return (
progressStatic: progressStatic: