diff --git a/lib/components/Player/PlayerControls.dart b/lib/components/Player/PlayerControls.dart index fcd556ed9..204ad7089 100644 --- a/lib/components/Player/PlayerControls.dart +++ b/lib/components/Player/PlayerControls.dart @@ -103,20 +103,17 @@ class PlayerControls extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ IconButton( - icon: const Icon(Icons.shuffle_rounded), - color: playback.isShuffled - ? Theme.of(context).primaryColor - : iconColor, - onPressed: () { - if (playback.track == null || playback.playlist == null) { - return; - } - try { - playback.toggleShuffle(); - } catch (e, stack) { - logger.e("onShuffle", e, stack); - } - }), + icon: Icon( + playback.isLoop + ? Icons.repeat_one_rounded + : playback.isShuffled + ? Icons.shuffle_rounded + : Icons.repeat_rounded, + ), + onPressed: playback.track == null || playback.playlist == null + ? null + : playback.cyclePlaybackMode, + ), IconButton( icon: const Icon(Icons.skip_previous_rounded), color: iconColor, diff --git a/lib/provider/Playback.dart b/lib/provider/Playback.dart index b4ec38de7..ba93eec8d 100644 --- a/lib/provider/Playback.dart +++ b/lib/provider/Playback.dart @@ -37,9 +37,15 @@ enum AudioQuality { low, } +enum PlaybackMode { + repeat, + shuffle, + normal, +} + class Playback extends PersistedChangeNotifier { // player properties - bool isShuffled; + PlaybackMode playbackMode; bool isPlaying; Duration currentDuration; double volume; @@ -72,9 +78,9 @@ class Playback extends PersistedChangeNotifier { required this.youtube, required this.ref, this.mobileAudioService, - }) : volume = 0, - isShuffled = false, + }) : volume = 1, isPlaying = false, + playbackMode = PlaybackMode.normal, currentDuration = Duration.zero, _subscriptions = [], status = PlaybackStatus.idle, @@ -102,7 +108,13 @@ class Playback extends PersistedChangeNotifier { ), player.onPlayerComplete.listen((_) { if (track?.id != null) { - seekForward(); + if (isLoop) { + final prevTrack = track; + track = null; + play(prevTrack!); + } else if (playlist != null) { + seekForward(); + } } else { isPlaying = false; status = PlaybackStatus.idle; @@ -250,12 +262,26 @@ class Playback extends PersistedChangeNotifier { isPlaying ? await pause() : await resume(); } - toggleShuffle() { - final result = isShuffled ? playlist?.unshuffle() : playlist?.shuffle(); - if (result == true) { - isShuffled = !isShuffled; - notifyListeners(); + void cyclePlaybackMode() { + switch (playbackMode) { + case PlaybackMode.normal: + playbackMode = PlaybackMode.shuffle; + playlist?.shuffle(); + break; + case PlaybackMode.shuffle: + playbackMode = PlaybackMode.repeat; + playlist?.unshuffle(); + break; + case PlaybackMode.repeat: + playbackMode = PlaybackMode.normal; + break; } + notifyListeners(); + } + + void setPlaybackMode(PlaybackMode mode) { + playbackMode = mode; + notifyListeners(); } Future seekPosition(Duration position) { @@ -273,7 +299,7 @@ class Playback extends PersistedChangeNotifier { await player.stop(); await player.release(); isPlaying = false; - isShuffled = false; + playbackMode = PlaybackMode.normal; playlist = null; track = null; status = PlaybackStatus.idle; @@ -553,6 +579,10 @@ class Playback extends PersistedChangeNotifier { "volume": volume, }; } + + bool get isLoop => playbackMode == PlaybackMode.repeat; + bool get isShuffled => playbackMode == PlaybackMode.shuffle; + bool get isNormal => playbackMode == PlaybackMode.normal; } final playbackProvider = ChangeNotifierProvider((ref) { diff --git a/lib/services/LinuxAudioService.dart b/lib/services/LinuxAudioService.dart index b5544ad71..9930df555 100644 --- a/lib/services/LinuxAudioService.dart +++ b/lib/services/LinuxAudioService.dart @@ -275,7 +275,9 @@ class _MprisMediaPlayer2Player extends DBusObject { /// Sets property org.mpris.MediaPlayer2.Player.Shuffle Future setShuffle(bool value) async { - playback.toggleShuffle(); + playback.setPlaybackMode( + value ? PlaybackMode.shuffle : PlaybackMode.normal, + ); return DBusMethodSuccessResponse(); }