From 249c8fbf805e0069cf93bb4c487578badab455ea Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 29 Aug 2024 00:41:40 +0800 Subject: [PATCH] :recycle: Improve progress display --- lib/providers/audio_player.dart | 9 ++ lib/screens/player/view.dart | 125 +++++++++++--------------- lib/widgets/lyrics/synced.dart | 7 +- lib/widgets/player/bottom_player.dart | 13 +-- 4 files changed, 66 insertions(+), 88 deletions(-) diff --git a/lib/providers/audio_player.dart b/lib/providers/audio_player.dart index 9034da5..b562463 100644 --- a/lib/providers/audio_player.dart +++ b/lib/providers/audio_player.dart @@ -11,6 +11,10 @@ import 'package:spotify/spotify.dart' hide Playlist; import 'package:rhythm_box/services/audio_player/audio_player.dart'; class AudioPlayerProvider extends GetxController { + Rx durationTotal = Rx(Duration.zero); + Rx durationCurrent = Rx(Duration.zero); + Rx durationBuffered = Rx(Duration.zero); + RxBool isPlaying = false.obs; Rx state = Rx(AudioPlayerState( @@ -54,6 +58,11 @@ class AudioPlayerProvider extends GetxController { state.value = state.value.copyWith(playlist: playlist); await _updatePlaylist(playlist); }), + audioPlayer.durationStream.listen((value) => durationTotal.value = value), + audioPlayer.positionStream + .listen((value) => durationCurrent.value = value), + audioPlayer.bufferedPositionStream + .listen((value) => durationBuffered.value = value), ]; _readSavedState(); diff --git a/lib/screens/player/view.dart b/lib/screens/player/view.dart index 2bc4f79..4660f0b 100644 --- a/lib/screens/player/view.dart +++ b/lib/screens/player/view.dart @@ -39,13 +39,6 @@ class _PlayerScreenState extends State { bool get _isFetchingActiveTrack => _query.isQueryingTrackInfo.value; PlaylistMode get _loopMode => _playback.state.value.loopMode; - double _bufferProgress = 0; - - Duration _durationCurrent = Duration.zero; - Duration _durationTotal = Duration.zero; - - List? _subscriptions; - Future _togglePlayState() async { if (!audioPlayer.isPlaying) { await audioPlayer.resume(); @@ -57,32 +50,6 @@ class _PlayerScreenState extends State { double? _draggingValue; - @override - void initState() { - super.initState(); - _durationCurrent = audioPlayer.position; - _durationTotal = audioPlayer.duration; - _bufferProgress = audioPlayer.bufferedPosition.inMilliseconds.toDouble(); - _subscriptions = [ - audioPlayer.durationStream - .listen((dur) => setState(() => _durationTotal = dur)), - audioPlayer.positionStream - .listen((dur) => setState(() => _durationCurrent = dur)), - audioPlayer.bufferedPositionStream.listen((dur) => - setState(() => _bufferProgress = dur.inMilliseconds.toDouble())), - ]; - } - - @override - void dispose() { - if (_subscriptions != null) { - for (final subscription in _subscriptions!) { - subscription.cancel(); - } - } - super.dispose(); - } - @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; @@ -134,50 +101,58 @@ class _PlayerScreenState extends State { overflow: TextOverflow.ellipsis, ), const Gap(24), - Column( - children: [ - SliderTheme( - data: SliderThemeData( - trackHeight: 2, - trackShape: _PlayerProgressTrackShape(), - thumbShape: const RoundSliderThumbShape( - enabledThumbRadius: 8, + Obx( + () => Column( + children: [ + SliderTheme( + data: SliderThemeData( + trackHeight: 2, + trackShape: _PlayerProgressTrackShape(), + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 8, + ), + overlayShape: SliderComponentShape.noOverlay, + ), + child: Slider( + secondaryTrackValue: _playback + .durationBuffered.value.inMilliseconds + .abs() + .toDouble(), + value: _draggingValue?.abs() ?? + _playback.durationCurrent.value.inMilliseconds + .toDouble() + .abs(), + min: 0, + max: max( + _playback.durationCurrent.value.inMilliseconds.abs(), + _playback.durationTotal.value.inMilliseconds.abs(), + ).toDouble(), + onChanged: (value) { + setState(() => _draggingValue = value); + }, + onChangeEnd: (value) { + audioPlayer + .seek(Duration(milliseconds: value.toInt())); + }, ), - overlayShape: SliderComponentShape.noOverlay, ), - child: Slider( - secondaryTrackValue: _bufferProgress.abs(), - value: _draggingValue?.abs() ?? - _durationCurrent.inMilliseconds.toDouble().abs(), - min: 0, - max: max( - _durationTotal.inMilliseconds.abs(), - _durationTotal.inMilliseconds.abs(), - ).toDouble(), - onChanged: (value) { - setState(() => _draggingValue = value); - }, - onChangeEnd: (value) { - print('Seek to $value ms'); - audioPlayer.seek(Duration(milliseconds: value.toInt())); - }, - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - _durationCurrent.toHumanReadableString(), - style: GoogleFonts.robotoMono(fontSize: 12), - ), - Text( - _durationTotal.toHumanReadableString(), - style: GoogleFonts.robotoMono(fontSize: 12), - ), - ], - ).paddingSymmetric(horizontal: 8, vertical: 4), - ], - ).paddingSymmetric(horizontal: 24), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + _playback.durationCurrent.value + .toHumanReadableString(), + style: GoogleFonts.robotoMono(fontSize: 12), + ), + Text( + _playback.durationTotal.value.toHumanReadableString(), + style: GoogleFonts.robotoMono(fontSize: 12), + ), + ], + ).paddingSymmetric(horizontal: 8, vertical: 4), + ], + ).paddingSymmetric(horizontal: 24), + ), const Gap(24), Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/widgets/lyrics/synced.dart b/lib/widgets/lyrics/synced.dart index 3e463a1..cf180ea 100644 --- a/lib/widgets/lyrics/synced.dart +++ b/lib/widgets/lyrics/synced.dart @@ -107,7 +107,7 @@ class _SyncedLyricsState extends State { ) : Padding( padding: idx == _lyric!.lyrics.length - 1 - ? const EdgeInsets.all(8.0).copyWith(bottom: 100) + ? const EdgeInsets.all(8.0).copyWith(bottom: 80) : const EdgeInsets.all(8.0), child: AnimatedDefaultTextStyle( duration: const Duration(milliseconds: 250), @@ -141,8 +141,9 @@ class _SyncedLyricsState extends State { ), ).animate(target: isActive ? 1 : 0).scale( duration: 300.ms, - begin: const Offset(0.9, 0.9), - end: const Offset(1.3, 1.3), + begin: const Offset(1, 1), + end: const Offset(1.25, 1.25), + curve: Curves.easeInOut, ); }).paddingSymmetric(horizontal: 12), ), diff --git a/lib/widgets/player/bottom_player.dart b/lib/widgets/player/bottom_player.dart index d46aa5b..907d247 100644 --- a/lib/widgets/player/bottom_player.dart +++ b/lib/widgets/player/bottom_player.dart @@ -44,9 +44,6 @@ class _BottomPlayerState extends State bool get _isPlaying => _playback.isPlaying.value; bool get _isFetchingActiveTrack => _query.isQueryingTrackInfo.value; - Duration _durationCurrent = Duration.zero; - Duration _durationTotal = Duration.zero; - List? _subscriptions; Future _togglePlayState() async { @@ -63,10 +60,6 @@ class _BottomPlayerState extends State void initState() { super.initState(); _subscriptions = [ - audioPlayer.durationStream - .listen((dur) => setState(() => _durationTotal = dur)), - audioPlayer.positionStream - .listen((dur) => setState(() => _durationCurrent = dur)), _playback.state.listen((state) { if (state.playlist.medias.isNotEmpty && !_isLifted) { _animationController.animateTo(1); @@ -109,12 +102,12 @@ class _BottomPlayerState extends State behavior: HitTestBehavior.translucent, child: Column( children: [ - if (_durationCurrent != Duration.zero) + if (_playback.durationCurrent.value != Duration.zero) TweenAnimationBuilder( tween: Tween( begin: 0, - end: _durationCurrent.inMilliseconds / - max(_durationTotal.inMilliseconds, 1), + end: _playback.durationCurrent.value.inMilliseconds / + max(_playback.durationTotal.value.inMilliseconds, 1), ), duration: const Duration(milliseconds: 1000), builder: (context, value, _) => LinearProgressIndicator(