From dc9d884efd9e4d4c69b5d4006a5f60b0ac211d95 Mon Sep 17 00:00:00 2001 From: Valeri Gokadze Date: Wed, 19 Feb 2025 01:31:18 +0400 Subject: [PATCH] feat: improve sleep timer feature --- lib/screens/now_playing_page.dart | 65 +++++++++++++++++++++++++----- lib/services/audio_service.dart | 6 +-- lib/services/settings_manager.dart | 2 + 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/lib/screens/now_playing_page.dart b/lib/screens/now_playing_page.dart index 871271a3..8ea43c82 100644 --- a/lib/screens/now_playing_page.dart +++ b/lib/screens/now_playing_page.dart @@ -30,6 +30,7 @@ import 'package:musify/models/position_data.dart'; import 'package:musify/services/settings_manager.dart'; import 'package:musify/utilities/common_variables.dart'; import 'package:musify/utilities/flutter_bottom_sheet.dart'; +import 'package:musify/utilities/flutter_toast.dart'; import 'package:musify/utilities/formatter.dart'; import 'package:musify/utilities/mediaitem.dart'; import 'package:musify/utilities/utils.dart'; @@ -526,8 +527,9 @@ class NowPlayingPage extends StatelessWidget { showDialog( context: context, builder: (context) { - var hours = 0; - var minutes = 10; + final duration = sleepTimerNotifier.value ?? Duration.zero; + var hours = duration.inMinutes ~/ 60; + var minutes = duration.inMinutes % 60; return StatefulBuilder( builder: (context, setState) { return AlertDialog( @@ -537,7 +539,6 @@ class NowPlayingPage extends StatelessWidget { children: [ Text(context.l10n!.selectDuration), const SizedBox(height: 16), - Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -548,7 +549,13 @@ class NowPlayingPage extends StatelessWidget { icon: const Icon(Icons.remove), onPressed: () { if (hours > 0) { - setState(() => hours--); + setState(() { + hours--; + sleepTimerNotifier.value = Duration( + hours: hours, + minutes: minutes, + ); + }); } }, ), @@ -556,7 +563,13 @@ class NowPlayingPage extends StatelessWidget { IconButton( icon: const Icon(Icons.add), onPressed: () { - setState(() => hours++); + setState(() { + hours++; + sleepTimerNotifier.value = Duration( + hours: hours, + minutes: minutes, + ); + }); }, ), ], @@ -574,7 +587,13 @@ class NowPlayingPage extends StatelessWidget { icon: const Icon(Icons.remove), onPressed: () { if (minutes > 0) { - setState(() => minutes--); + setState(() { + minutes--; + sleepTimerNotifier.value = Duration( + hours: hours, + minutes: minutes, + ); + }); } }, ), @@ -582,7 +601,13 @@ class NowPlayingPage extends StatelessWidget { IconButton( icon: const Icon(Icons.add), onPressed: () { - setState(() => minutes++); + setState(() { + minutes++; + sleepTimerNotifier.value = Duration( + hours: hours, + minutes: minutes, + ); + }); }, ), ], @@ -601,6 +626,7 @@ class NowPlayingPage extends StatelessWidget { final duration = Duration(hours: hours, minutes: minutes); if (duration.inSeconds > 0) { audioHandler.setSleepTimer(duration); + showToast(context, context.l10n!.addedSuccess); } Navigator.pop(context); }, @@ -702,10 +728,27 @@ class NowPlayingPage extends StatelessWidget { iconSize: iconSize, onPressed: _lyricsController.flipcard, ), - IconButton.filledTonal( - icon: Icon(FluentIcons.timer_24_regular, color: _primaryColor), - iconSize: iconSize, - onPressed: () => _showSleepTimerDialog(context), + ValueListenableBuilder( + valueListenable: sleepTimerNotifier, + builder: (_, value, __) { + return IconButton.filledTonal( + icon: Icon( + value != null + ? FluentIcons.timer_24_filled + : FluentIcons.timer_24_regular, + color: _primaryColor, + ), + iconSize: iconSize, + onPressed: () { + if (value != null) { + audioHandler.cancelSleepTimer(); + sleepTimerNotifier.value = null; + } else { + _showSleepTimerDialog(context); + } + }, + ); + }, ), ValueListenableBuilder( valueListenable: songLikeStatus, diff --git a/lib/services/audio_service.dart b/lib/services/audio_service.dart index 7676118b..e863d21f 100644 --- a/lib/services/audio_service.dart +++ b/lib/services/audio_service.dart @@ -52,7 +52,6 @@ class MusifyAudioHandler extends BaseAudioHandler { ); Timer? _sleepTimer; - bool sleepTimerExpired = false; late StreamSubscription _playbackEventSubscription; late StreamSubscription _durationSubscription; @@ -80,7 +79,7 @@ class MusifyAudioHandler extends BaseAudioHandler { try { if (event.processingState == ProcessingState.completed && audioPlayer.playing && - !sleepTimerExpired) { + _sleepTimer == null) { skipToNext(); } _updatePlaybackState(); @@ -396,11 +395,9 @@ class MusifyAudioHandler extends BaseAudioHandler { Future setSleepTimer(Duration duration) async { _sleepTimer?.cancel(); - sleepTimerExpired = false; _sleepTimer = Timer(duration, () async { await stop(); playNextSongAutomatically.value = false; - sleepTimerExpired = true; _sleepTimer = null; }); } @@ -409,7 +406,6 @@ class MusifyAudioHandler extends BaseAudioHandler { if (_sleepTimer != null) { _sleepTimer!.cancel(); _sleepTimer = null; - sleepTimerExpired = false; } } diff --git a/lib/services/settings_manager.dart b/lib/services/settings_manager.dart index 66f5ced6..42c6e5c3 100644 --- a/lib/services/settings_manager.dart +++ b/lib/services/settings_manager.dart @@ -82,6 +82,8 @@ final repeatNotifier = ValueNotifier( AudioServiceRepeatMode.none, ); +var sleepTimerNotifier = ValueNotifier(null); + // Server-Notifiers final announcementURL = ValueNotifier(null);