From 4885dca04f06658391d1063e6c5a009547391a6f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 2 Aug 2023 11:12:22 +0600 Subject: [PATCH] fix: duration is always zero in PlayerView --- lib/hooks/use_progress.dart | 62 +++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/lib/hooks/use_progress.dart b/lib/hooks/use_progress.dart index 40429190..62dccbce 100644 --- a/lib/hooks/use_progress.dart +++ b/lib/hooks/use_progress.dart @@ -1,3 +1,4 @@ +import 'package:async/async.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; @@ -11,47 +12,60 @@ import 'package:spotube/services/audio_player/audio_player.dart'; final bufferProgress = useStream(audioPlayer.bufferedPositionStream).data?.inSeconds ?? 0; - Duration audioPlayerDuration = Duration.zero; - Duration audioPlayerPosition = Duration.zero; + final duration = useState(Duration.zero); + final position = useState(Duration.zero); - // Duration future is needed for getting the duration of the song - // as stream can be null when no event occurs (Mostly needed for android) - audioPlayer.duration.then((value) { - if (value != null) { - audioPlayerDuration = value; - } - }); - - audioPlayer.position.then((value) { - if (value != null) { - audioPlayerPosition = value; - } - }); - - final position = useState(audioPlayerPosition); - final duration = - useStream(audioPlayer.durationStream).data ?? audioPlayerDuration; - final sliderMax = duration.inSeconds; + final sliderMax = duration.value.inSeconds; final sliderValue = position.value.inSeconds; useEffect(() { + final durationOperation = + CancelableOperation.fromFuture(audioPlayer.duration); + durationOperation.then((value) { + if (value != null) { + duration.value = value; + } + }); + + final durationSubscription = audioPlayer.durationStream.listen((event) { + duration.value = event; + }); + + final positionOperation = + CancelableOperation.fromFuture(audioPlayer.position); + + positionOperation.then((value) { + if (value != null) { + position.value = value; + } + }); + // audioPlayer.positionStream is fired every 200ms and only 1s delay is // enough. Thus only update the position if the difference is more than 1s // Reduces CPU usage var lastPosition = position.value; - return audioPlayer.positionStream.listen((event) { + + final positionSubscription = audioPlayer.positionStream.listen((event) { if (event.inMilliseconds > 1000 && event.inMilliseconds - lastPosition.inMilliseconds < 1000) return; + lastPosition = event; position.value = event; - }).cancel; - }, [audioPlayerPosition, audioPlayerDuration]); + }); + + return () { + positionOperation.cancel(); + positionSubscription.cancel(); + durationOperation.cancel(); + durationSubscription.cancel(); + }; + }, []); return ( progressStatic: sliderMax == 0 || sliderValue > sliderMax ? 0 : sliderValue / sliderMax, position: position.value, - duration: duration, + duration: duration.value, bufferProgress: sliderMax == 0 || bufferProgress > sliderMax ? 0 : bufferProgress / sliderMax,