From b67fa6f9834f7869f5eb93da844dba0ccfa2e56f Mon Sep 17 00:00:00 2001 From: MSOB7YY Date: Tue, 30 Jan 2024 22:34:45 +0200 Subject: [PATCH] feat: previous button replays option closes #112 --- lib/base/audio_handler.dart | 21 ++++++++++++++++++- lib/controller/settings_controller.dart | 7 +++++++ lib/core/translations/keys.dart | 2 ++ .../widgets/settings/playback_settings.dart | 19 +++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/base/audio_handler.dart b/lib/base/audio_handler.dart index cd3da044..1c151751 100644 --- a/lib/base/audio_handler.dart +++ b/lib/base/audio_handler.dart @@ -1174,6 +1174,8 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { @override Duration get defaultVolume0ResumeThreshold => Duration(minutes: settings.volume0ResumeThresholdMin.value); + bool get previousButtonReplays => settings.previousButtonReplays.value; + // ------------------------------------------------------------ Future togglePlayPause() async { @@ -1214,7 +1216,24 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { Future skipToNext([bool? andPlay]) async => await onSkipToNext(andPlay); @override - Future skipToPrevious() async => await onSkipToPrevious(); + Future skipToPrevious() async { + if (previousButtonReplays) { + final int secondsToReplay; + if (settings.isSeekDurationPercentage.value) { + final sFromP = (currentItemDuration?.inSeconds ?? 0) * (settings.seekDurationInPercentage.value / 100); + secondsToReplay = sFromP.toInt(); + } else { + secondsToReplay = settings.seekDurationInSeconds.value; + } + + if (secondsToReplay > 0 && currentPositionMS > secondsToReplay * 1000) { + await seek(Duration.zero); + return; + } + } + + await onSkipToPrevious(); + } @override Future skipToQueueItem(int index, [bool? andPlay]) async => await onSkipToQueueItem(index, andPlay); diff --git a/lib/controller/settings_controller.dart b/lib/controller/settings_controller.dart index b93803ea..7304987a 100644 --- a/lib/controller/settings_controller.dart +++ b/lib/controller/settings_controller.dart @@ -177,6 +177,7 @@ class SettingsController { final RxBool ytTopComments = true.obs; final RxBool artworkGestureScale = false.obs; final RxBool artworkGestureDoubleTapLRC = true.obs; + final RxBool previousButtonReplays = false.obs; final RxList tagFieldsToEdit = [ TagField.trackNumber, TagField.year, @@ -465,6 +466,7 @@ class SettingsController { ytTopComments.value = json['ytTopComments'] ?? ytTopComments.value; artworkGestureScale.value = json['artworkGestureScale'] ?? artworkGestureScale.value; artworkGestureDoubleTapLRC.value = json['artworkGestureDoubleTapLRC'] ?? artworkGestureDoubleTapLRC.value; + previousButtonReplays.value = json['previousButtonReplays'] ?? previousButtonReplays.value; final listFromStorage = List.from(json['tagFieldsToEdit'] ?? []); tagFieldsToEdit.value = listFromStorage.isNotEmpty ? List.from(listFromStorage.map((e) => TagField.values.getEnum(e))) : tagFieldsToEdit; @@ -697,6 +699,7 @@ class SettingsController { 'ytTopComments': ytTopComments.value, 'artworkGestureScale': artworkGestureScale.value, 'artworkGestureDoubleTapLRC': artworkGestureDoubleTapLRC.value, + 'previousButtonReplays': previousButtonReplays.value, 'tagFieldsToEdit': tagFieldsToEdit.mapped((element) => element.convertToString), 'wakelockMode': wakelockMode.value.convertToString, 'localVideoMatchingType': localVideoMatchingType.value.convertToString, @@ -893,6 +896,7 @@ class SettingsController { bool? ytTopComments, bool? artworkGestureScale, bool? artworkGestureDoubleTapLRC, + bool? previousButtonReplays, List? tagFieldsToEdit, WakelockMode? wakelockMode, LocalVideoMatchingType? localVideoMatchingType, @@ -1389,6 +1393,9 @@ class SettingsController { if (artworkGestureDoubleTapLRC != null) { this.artworkGestureDoubleTapLRC.value = artworkGestureDoubleTapLRC; } + if (previousButtonReplays != null) { + this.previousButtonReplays.value = previousButtonReplays; + } if (tagFieldsToEdit != null) { tagFieldsToEdit.loop((d, index) { if (!this.tagFieldsToEdit.contains(d)) { diff --git a/lib/core/translations/keys.dart b/lib/core/translations/keys.dart index 951f8bb2..bc2eb176 100644 --- a/lib/core/translations/keys.dart +++ b/lib/core/translations/keys.dart @@ -441,6 +441,8 @@ abstract class LanguageKeys { String get PREVENT_DUPLICATED_TRACKS_SUBTITLE => _getKey('PREVENT_DUPLICATED_TRACKS_SUBTITLE'); String get PREVENT_DUPLICATED_TRACKS => _getKey('PREVENT_DUPLICATED_TRACKS'); String get PREVIEW => _getKey('PREVIEW'); + String get PREVIOUS_BUTTON_REPLAYS => _getKey('PREVIOUS_BUTTON_REPLAYS'); + String get PREVIOUS_BUTTON_REPLAYS_SUBTITLE => _getKey('PREVIOUS_BUTTON_REPLAYS_SUBTITLE'); String get PRIORITIZE_EMBEDDED_LYRICS => _getKey('PRIORITIZE_EMBEDDED_LYRICS'); String get PROGRESS => _getKey('PROGRESS'); String get PROMPT_INDEXING_REFRESH => _getKey('PROMPT_INDEXING_REFRESH'); diff --git a/lib/ui/widgets/settings/playback_settings.dart b/lib/ui/widgets/settings/playback_settings.dart index cbd3fc4d..9e68ddb0 100644 --- a/lib/ui/widgets/settings/playback_settings.dart +++ b/lib/ui/widgets/settings/playback_settings.dart @@ -34,6 +34,7 @@ enum _PlaybackSettingsKeys { onVolume0, onInterruption, jumpToFirstTrackAfterFinishing, + previousButtonReplays, seekDuration, minimumTrackDurToRestoreLastPosition, countListenAfter, @@ -65,6 +66,7 @@ class PlaybackSettings extends SettingSubpageProvider { _PlaybackSettingsKeys.onVolume0: [lang.ON_VOLUME_ZERO], _PlaybackSettingsKeys.onInterruption: [lang.ON_INTERRUPTION], _PlaybackSettingsKeys.jumpToFirstTrackAfterFinishing: [lang.JUMP_TO_FIRST_TRACK_AFTER_QUEUE_FINISH], + _PlaybackSettingsKeys.previousButtonReplays: [lang.PREVIOUS_BUTTON_REPLAYS, lang.PREVIOUS_BUTTON_REPLAYS_SUBTITLE], _PlaybackSettingsKeys.seekDuration: [lang.SEEK_DURATION, lang.SEEK_DURATION_INFO], _PlaybackSettingsKeys.minimumTrackDurToRestoreLastPosition: [lang.MIN_TRACK_DURATION_TO_RESTORE_LAST_POSITION], _PlaybackSettingsKeys.countListenAfter: [lang.MIN_VALUE_TO_COUNT_TRACK_LISTEN], @@ -667,6 +669,23 @@ class PlaybackSettings extends SettingSubpageProvider { ), ), ), + getItemWrapper( + key: _PlaybackSettingsKeys.previousButtonReplays, + child: Obx( + () => CustomSwitchListTile( + bgColor: getBgColor(_PlaybackSettingsKeys.previousButtonReplays), + leading: const StackedIcon( + baseIcon: Broken.previous, + secondaryIcon: Broken.rotate_left, + secondaryIconSize: 12.0, + ), + title: lang.PREVIOUS_BUTTON_REPLAYS, + subtitle: lang.PREVIOUS_BUTTON_REPLAYS_SUBTITLE, + onChanged: (value) => settings.save(previousButtonReplays: !value), + value: settings.previousButtonReplays.value, + ), + ), + ), getItemWrapper( key: _PlaybackSettingsKeys.seekDuration, child: Obx(