Skip to content

Commit

Permalink
feat: add repeat playlist feature (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
gokadzev committed Dec 23, 2024
1 parent ecccfc8 commit da5cc27
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 33 deletions.
21 changes: 11 additions & 10 deletions lib/screens/now_playing_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -373,20 +373,23 @@ class NowPlayingPage extends StatelessWidget {
),
],
),
ValueListenableBuilder<bool>(
ValueListenableBuilder<AudioServiceRepeatMode>(
valueListenable: repeatNotifier,
builder: (_, value, __) {
return value
builder: (_, repeatMode, __) {
return repeatMode != AudioServiceRepeatMode.none
? IconButton.filled(
icon: Icon(
FluentIcons.arrow_repeat_1_24_filled,
repeatMode == AudioServiceRepeatMode.all
? FluentIcons.arrow_repeat_all_24_filled
: FluentIcons.arrow_repeat_1_24_filled,
color: _secondaryColor,
),
iconSize: iconSize,
onPressed: () {
audioHandler.setRepeatMode(
AudioServiceRepeatMode.none,
);
repeatNotifier.value =
repeatMode == AudioServiceRepeatMode.all
? AudioServiceRepeatMode.one
: AudioServiceRepeatMode.none;
},
)
: IconButton.filledTonal(
Expand All @@ -396,9 +399,7 @@ class NowPlayingPage extends StatelessWidget {
),
iconSize: iconSize,
onPressed: () {
audioHandler.setRepeatMode(
AudioServiceRepeatMode.all,
);
repeatNotifier.value = AudioServiceRepeatMode.all;
},
);
},
Expand Down
43 changes: 21 additions & 22 deletions lib/services/audio_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class MusifyAudioHandler extends BaseAudioHandler {
_initialize();
}

AudioPlayer audioPlayer = AudioPlayer();
final AudioPlayer audioPlayer = AudioPlayer();

late StreamSubscription<PlaybackEvent> _playbackEventSubscription;
late StreamSubscription<Duration?> _durationSubscription;
Expand All @@ -65,22 +65,11 @@ class MusifyAudioHandler extends BaseAudioHandler {
ProcessingState.completed: AudioProcessingState.completed,
};

final repeatModeMap = {
LoopMode.off: AudioServiceRepeatMode.none,
LoopMode.one: AudioServiceRepeatMode.one,
LoopMode.all: AudioServiceRepeatMode.all,
};

void _handlePlaybackEvent(PlaybackEvent event) {
try {
if (event.processingState == ProcessingState.completed &&
audioPlayer.playing) {
if (hasNext) {
skipToNext();
} else if (playNextSongAutomatically.value &&
nextRecommendedSong != null) {
playSong(nextRecommendedSong);
}
skipToNext();
}
_updatePlaybackState();
} catch (e, stackTrace) {
Expand Down Expand Up @@ -167,7 +156,7 @@ class MusifyAudioHandler extends BaseAudioHandler {
},
androidCompactActionIndices: const [0, 1, 3],
processingState: processingStateMap[audioPlayer.processingState]!,
repeatMode: repeatModeMap[audioPlayer.loopMode]!,
repeatMode: repeatNotifier.value,
shuffleMode: audioPlayer.shuffleModeEnabled
? AudioServiceShuffleMode.all
: AudioServiceShuffleMode.none,
Expand Down Expand Up @@ -333,7 +322,24 @@ class MusifyAudioHandler extends BaseAudioHandler {

@override
Future<void> skipToNext() async {
await skipToSong(activeSongId + 1);
if (repeatNotifier.value == AudioServiceRepeatMode.one) {
// If repeat mode is set to repeat the current song, play the current song again
await skipToSong(activeSongId);
} else if (!hasNext && repeatNotifier.value == AudioServiceRepeatMode.all) {
// If repeat mode is set to repeat the playlist, start from the beginning
await skipToSong(0);
} else if (!hasNext &&
playNextSongAutomatically.value &&
nextRecommendedSong != null) {
// If there's no next song but playNextSongAutomatically is enabled, play the recommended song
await playSong(nextRecommendedSong);
} else if (hasNext) {
// If there is a next song, skip to the next song
await skipToSong(activeSongId + 1);
} else {
// Handle end of playlist without repeat
await audioPlayer.stop();
}
}

@override
Expand All @@ -348,13 +354,6 @@ class MusifyAudioHandler extends BaseAudioHandler {
await audioPlayer.setShuffleModeEnabled(shuffleEnabled);
}

@override
Future<void> setRepeatMode(AudioServiceRepeatMode repeatMode) async {
final repeatEnabled = repeatMode != AudioServiceRepeatMode.none;
repeatNotifier.value = repeatEnabled;
await audioPlayer.setLoopMode(repeatEnabled ? LoopMode.one : LoopMode.off);
}

void changeSponsorBlockStatus() {
sponsorBlockSupport.value = !sponsorBlockSupport.value;
addOrUpdateData(
Expand Down
4 changes: 3 additions & 1 deletion lib/services/settings_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* please visit: https://github.com/gokadzev/Musify
*/

import 'package:audio_service/audio_service.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:musify/main.dart';
Expand Down Expand Up @@ -76,7 +77,8 @@ Color primaryColorSetting =
// Non-Storage Notifiers

final shuffleNotifier = ValueNotifier<bool>(false);
final repeatNotifier = ValueNotifier<bool>(false);
final repeatNotifier =
ValueNotifier<AudioServiceRepeatMode>(AudioServiceRepeatMode.none);

// Server-Notifiers

Expand Down

0 comments on commit da5cc27

Please sign in to comment.