1+ import 'dart:async' ;
2+
13import 'package:audio_service/audio_service.dart' ;
24import 'package:flutter/material.dart' ;
35import 'package:media_kit/media_kit.dart' ;
@@ -31,6 +33,13 @@ class PlayerManager extends BaseAudioHandler with SeekHandler {
3133 ],
3234 ),
3335 );
36+ _positionSubscription = controller.player.stream.position.listen (
37+ _setPosition,
38+ );
39+ _durationSubscription = controller.player.stream.duration.listen (
40+ _setDuration,
41+ );
42+ _bufferedSubscription = controller.player.stream.buffer.listen (_setBuffer);
3443 }
3544
3645 final VideoController _controller;
@@ -48,27 +57,30 @@ class PlayerManager extends BaseAudioHandler with SeekHandler {
4857 String ? remoteSourceArtUrl,
4958 String ? remoteSourceTitle,
5059 }) {
51- final art = remoteSourceArtUrl? .endsWith ('.ico' ) == true
52- ? null
53- : remoteSourceArtUrl;
60+ final previousArtUri = mediaItem.value? .artUri;
61+ final artUri =
62+ (remoteSourceArtUrl == null
63+ ? previousArtUri
64+ : Uri .tryParse (remoteSourceArtUrl)) ??
65+ previousArtUri;
66+
5467 playerViewState.value = playerViewState.value.copyWith (
5568 fullMode: fullMode,
5669 showPlayerExplorer: showPlayerExplorer,
5770 explorerIndex: explorerIndex,
5871 color: color,
59- remoteSourceArtUrl: art ,
72+ remoteSourceArtUrl: artUri. toString () ,
6073 remoteSourceTitle: remoteSourceTitle,
6174 );
6275
6376 if (remoteSourceTitle != null ) {
64- final uri = Uri .tryParse (art ?? '' );
6577 final split = remoteSourceTitle.splitByDash;
6678 mediaItem.add (
6779 MediaItem (
6880 id: remoteSourceTitle,
6981 title: remoteSourceTitle,
7082 artist: currentMedia? .artist ?? split.artist,
71- artUri: uri ,
83+ artUri: artUri ,
7284 ),
7385 );
7486 }
@@ -77,24 +89,33 @@ class PlayerManager extends BaseAudioHandler with SeekHandler {
7789 Player get _player => _controller.player;
7890 Player get player => _player;
7991
80- Stream <Duration > get positionStream => _player.stream.position.map ((e) {
81- playbackState.add (playbackState.value.copyWith (updatePosition: position));
82- return e;
83- }).distinct ();
84-
85- Duration get position => _player.state.position;
92+ StreamSubscription <Duration >? _positionSubscription;
93+ final _position = SafeValueNotifier (Duration .zero);
94+ SafeValueNotifier <Duration > get position => _position;
95+ void _setPosition (Duration value) {
96+ playbackState.add (playbackState.value.copyWith (updatePosition: value));
97+ if (value.inSeconds == _position.value.inSeconds) return ;
98+ _position.value = value;
99+ }
86100
87- Stream <Duration > get bufferedPositionStream =>
88- _player.stream.buffer.distinct ();
101+ StreamSubscription <Duration >? _bufferedSubscription;
102+ final _buffer = SafeValueNotifier (Duration .zero);
103+ SafeValueNotifier <Duration > get buffer => _buffer;
104+ void _setBuffer (Duration value) {
105+ if (value.inSeconds == _buffer.value.inSeconds) return ;
106+ _buffer.value = value;
107+ }
89108
90- Stream <Duration > get durationStream => _player.stream.duration.map ((e) {
109+ StreamSubscription <Duration >? _durationSubscription;
110+ final _duration = SafeValueNotifier <Duration >(Duration .zero);
111+ SafeValueNotifier <Duration > get duration => _duration;
112+ void _setDuration (Duration d) {
91113 if (mediaItem.value != null ) {
92- mediaItem.add (mediaItem.value! .copyWith (duration: duration ));
114+ mediaItem.add (mediaItem.value! .copyWith (duration: d ));
93115 }
94- return e;
95- }).distinct ();
96-
97- Duration get duration => _player.state.duration;
116+ if (d.inSeconds == _duration.value.inSeconds) return ;
117+ _duration.value = d;
118+ }
98119
99120 Stream <bool > get isPlayingStream => _player.stream.playing.map ((e) {
100121 playbackState.add (
@@ -139,7 +160,7 @@ class PlayerManager extends BaseAudioHandler with SeekHandler {
139160 title: media.title ?? media.uri.toString (),
140161 artist: media.artist,
141162 album: media.collectionName,
142- duration: media.duration ?? duration,
163+ duration: media.duration ?? duration.value ,
143164 artUri: artUri,
144165 ),
145166 );
@@ -224,7 +245,13 @@ class PlayerManager extends BaseAudioHandler with SeekHandler {
224245 Future <void > skipToNext () async => _player.next ();
225246
226247 @override
227- Future <void > skipToPrevious () async => _player.previous ();
248+ Future <void > skipToPrevious () async {
249+ if (position.value.inSeconds < 10 ) {
250+ await seek (Duration .zero);
251+ return ;
252+ }
253+ return _player.previous ();
254+ }
228255
229256 Future <void > setShuffle (bool shuffle) async => _player.setShuffle (shuffle);
230257
@@ -248,7 +275,12 @@ class PlayerManager extends BaseAudioHandler with SeekHandler {
248275 Future <void > setPlaylistMode (PlaylistMode mode) async =>
249276 _player.setPlaylistMode (mode);
250277
251- Future <void > dispose () async => _player.dispose ();
278+ Future <void > dispose () async {
279+ await _positionSubscription? .cancel ();
280+ await _durationSubscription? .cancel ();
281+ await _bufferedSubscription? .cancel ();
282+ await _player.dispose ();
283+ }
252284
253285 Future <void > _setLocalColor (LocalMedia media) async {
254286 try {
0 commit comments