diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt index 93fd4c72..a85a84a2 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt @@ -103,6 +103,8 @@ data class DeviceSettings( var autoSleepTimer: Boolean, var autoSleepTimerStartTime: String, var autoSleepTimerEndTime: String, + var autoSleepTimerAutoRewind: Boolean, + var autoSleepTimerAutoRewindTime: Long, //Time in milliseconds var sleepTimerLength: Long, // Time in milliseconds var disableSleepTimerFadeOut: Boolean, var disableSleepTimerResetFeedback: Boolean @@ -123,6 +125,8 @@ data class DeviceSettings( autoSleepTimerStartTime = "22:00", autoSleepTimerEndTime = "06:00", sleepTimerLength = 900000L, // 15 minutes + autoSleepTimerAutoRewind = false, + autoSleepTimerAutoRewindTime = 300000L, // 5 minutes disableSleepTimerFadeOut = false, disableSleepTimerResetFeedback = false ) @@ -142,6 +146,7 @@ data class DeviceSettings( @get:JsonIgnore val autoSleepTimerEndMinute get() = autoSleepTimerEndTime.split(":")[1].toInt() + @JsonIgnore fun getShakeThresholdGravity() : Float { // Used in ShakeDetector return if (shakeSensitivity == ShakeSensitivitySetting.VERY_HIGH) 1.2f diff --git a/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt b/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt index 57245e19..77391ae2 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/device/DeviceManager.kt @@ -39,6 +39,10 @@ object DeviceManager { if (deviceData.deviceSettings?.shakeSensitivity == null) { deviceData.deviceSettings?.shakeSensitivity = ShakeSensitivitySetting.MEDIUM } + // Initialize auto sleep timer auto rewind added in v0.9.64 + if (deviceData.deviceSettings?.autoSleepTimerAutoRewindTime == null) { + deviceData.deviceSettings?.autoSleepTimerAutoRewindTime = 300000L // 5 minutes + } } fun getBase64Id(id:String):String { diff --git a/android/app/src/main/java/com/audiobookshelf/app/managers/SleepTimerManager.kt b/android/app/src/main/java/com/audiobookshelf/app/managers/SleepTimerManager.kt index 47c3113c..1d13eb30 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/managers/SleepTimerManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/managers/SleepTimerManager.kt @@ -1,6 +1,7 @@ package com.audiobookshelf.app.managers import android.content.Context +import android.media.metrics.PlaybackSession import android.os.* import android.util.Log import com.audiobookshelf.app.device.DeviceManager @@ -21,6 +22,8 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe private var sleepTimerElapsed:Long = 0L private var sleepTimerFinishedAt:Long = 0L private var isAutoSleepTimer:Boolean = false // When timer was auto-set + private var isFirstAutoSleepTimer: Boolean = true + private var sleepTimerSessionId:String = "" private fun getCurrentTime():Long { return playerNotificationService.getCurrentTime() @@ -123,7 +126,8 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe return true } - fun setManualSleepTimer(time: Long, isChapterTime:Boolean):Boolean { + fun setManualSleepTimer(playbackSessionId:String, time: Long, isChapterTime:Boolean):Boolean { + sleepTimerSessionId = playbackSessionId isAutoSleepTimer = false return setSleepTimer(time, isChapterTime) } @@ -133,7 +137,6 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe sleepTimerTask = null sleepTimerEndTime = 0 sleepTimerRunning = false - isAutoSleepTimer = false playerNotificationService.unregisterSensor() setVolume(1f) @@ -227,6 +230,17 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe return } + // Automatically Rewind in the book if settings is enabled + if (isAutoSleepTimer) { + DeviceManager.deviceData.deviceSettings?.let { deviceSettings -> + if (deviceSettings.autoSleepTimerAutoRewind && !isFirstAutoSleepTimer) { + Log.i(tag, "Auto sleep timer auto rewind seeking back ${deviceSettings.autoSleepTimerAutoRewindTime}ms") + playerNotificationService.seekBackward(deviceSettings.autoSleepTimerAutoRewindTime) + } + isFirstAutoSleepTimer = false + } + } + // Set sleep timer // When sleepTimerLength is 0 then use end of chapter/track time if (sleepTimerLength == 0L) { @@ -343,6 +357,13 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe if (currentCalendar.after(startCalendar) && currentCalendar.before(endCalendar)) { Log.i(tag, "Current hour $currentHour is between ${deviceSettings.autoSleepTimerStartTime} and ${deviceSettings.autoSleepTimerEndTime} - starting sleep timer") + // Automatically Rewind in the book if settings is enabled + if (deviceSettings.autoSleepTimerAutoRewind && !isFirstAutoSleepTimer) { + Log.i(tag, "Auto sleep timer auto rewind seeking back ${deviceSettings.autoSleepTimerAutoRewindTime}ms") + playerNotificationService.seekBackward(deviceSettings.autoSleepTimerAutoRewindTime) + } + isFirstAutoSleepTimer = false + // Set sleep timer // When sleepTimerLength is 0 then use end of chapter/track time if (deviceSettings.sleepTimerLength == 0L) { @@ -358,13 +379,23 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe setSleepTimer(deviceSettings.sleepTimerLength, false) } } else { + isFirstAutoSleepTimer = true Log.d(tag, "Current hour $currentHour is NOT between ${deviceSettings.autoSleepTimerStartTime} and ${deviceSettings.autoSleepTimerEndTime}") } } } - fun handleMediaPlayEvent() { - checkShouldResetSleepTimer() + fun handleMediaPlayEvent(playbackSessionId:String) { + // Check if the playback session has changed + // If it hasn't changed OR the sleep timer is running then check reset the timer + // e.g. You set a manual sleep timer for 10 mins, then decide to change books, the sleep timer will stay on and reset to 10 mins + if (sleepTimerSessionId == playbackSessionId || sleepTimerRunning) { + checkShouldResetSleepTimer() + } else { + isFirstAutoSleepTimer = true + } + sleepTimerSessionId = playbackSessionId + checkAutoSleepTimer() } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt index d7d42f7a..e4ae9c47 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt @@ -92,12 +92,15 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) : // Start/stop progress sync interval if (isPlaying) { - // Handles auto-starting sleep timer and resetting sleep timer - playerNotificationService.sleepTimerManager.handleMediaPlayEvent() - - player.volume = 1F // Volume on sleep timer might have decreased this val playbackSession: PlaybackSession? = playerNotificationService.mediaProgressSyncer.currentPlaybackSession ?: playerNotificationService.currentPlaybackSession - playbackSession?.let { playerNotificationService.mediaProgressSyncer.play(it) } + playbackSession?.let { + // Handles auto-starting sleep timer and resetting sleep timer + playerNotificationService.sleepTimerManager.handleMediaPlayEvent(it.id) + + player.volume = 1F // Volume on sleep timer might have decreased this + + playerNotificationService.mediaProgressSyncer.play(it) + } } else { playerNotificationService.mediaProgressSyncer.pause { Log.d(tag, "Media Progress Syncer paused and synced") diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt index a19d2227..a3b6a6e1 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt @@ -341,7 +341,8 @@ class AbsAudioPlayer : Plugin() { val isChapterTime:Boolean = call.getBoolean("isChapterTime", false) == true Handler(Looper.getMainLooper()).post { - val success:Boolean = playerNotificationService.sleepTimerManager.setManualSleepTimer(time, isChapterTime) + val playbackSession: PlaybackSession? = playerNotificationService.mediaProgressSyncer.currentPlaybackSession ?: playerNotificationService.currentPlaybackSession + val success:Boolean = playerNotificationService.sleepTimerManager.setManualSleepTimer(playbackSession?.id ?: "", time, isChapterTime) val ret = JSObject() ret.put("success", success) call.resolve(ret) diff --git a/components/modals/AutoSleepTimerRewindLengthModal.vue b/components/modals/AutoSleepTimerRewindLengthModal.vue new file mode 100644 index 00000000..2f13df25 --- /dev/null +++ b/components/modals/AutoSleepTimerRewindLengthModal.vue @@ -0,0 +1,95 @@ + + + diff --git a/pages/settings.vue b/pages/settings.vue index 66a8a5e3..76c7a594 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -95,9 +95,23 @@ +
+
+ +
+

Auto Sleep Timer Auto Rewind

+ info +
+
+

Auto Rewind Time

+
+ +
+
+ @@ -110,6 +124,7 @@ export default { deviceData: null, showMoreMenuDialog: false, showSleepTimerLengthModal: false, + showAutoSleepTimerRewindLengthModal: false, moreMenuSetting: '', settings: { disableAutoRewind: false, @@ -125,7 +140,9 @@ export default { autoSleepTimerEndTime: '06:00', sleepTimerLength: 900000, // 15 minutes disableSleepTimerFadeOut: false, - disableSleepTimerResetFeedback: false + disableSleepTimerResetFeedback: false, + autoSleepTimerAutoRewind: false, + autoSleepTimerAutoRewindTime: 300000 // 5 minutes }, lockCurrentOrientation: false, settingInfo: { @@ -144,6 +161,10 @@ export default { disableSleepTimerResetFeedback: { name: 'Disable vibrate on reset', message: 'When the sleep timer gets reset your device will vibrate. Enable this setting to not vibrate when the sleep timer resets.' + }, + autoSleepTimerAutoRewind: { + name: 'Enable sleep timer auto rewind', + message: 'When the auto sleep timer finishes, playing the item again will automatically rewind your position.' } }, hapticFeedbackItems: [ @@ -234,6 +255,10 @@ export default { const minutes = Number(this.settings.sleepTimerLength) / 1000 / 60 return `${minutes} min` }, + autoSleepTimerRewindLengthOption() { + const minutes = Number(this.settings.autoSleepTimerAutoRewindTime) / 1000 / 60 + return `${minutes} min` + }, moreMenuItems() { if (this.moreMenuSetting === 'shakeSensitivity') return this.shakeSensitivityItems else if (this.moreMenuSetting === 'hapticFeedback') return this.hapticFeedbackItems @@ -245,9 +270,16 @@ export default { this.settings.sleepTimerLength = value this.saveSettings() }, + showAutoSleepTimerRewindLengthModalSelection(value) { + this.settings.autoSleepTimerAutoRewindTime = value + this.saveSettings() + }, showSleepTimerOptions() { this.showSleepTimerLengthModal = true }, + showAutoSleepTimerRewindOptions() { + this.showAutoSleepTimerRewindLengthModal = true + }, showHapticFeedbackOptions() { this.moreMenuSetting = 'hapticFeedback' this.showMoreMenuDialog = true @@ -287,6 +319,10 @@ export default { this.settings.autoSleepTimer = !this.settings.autoSleepTimer this.saveSettings() }, + toggleAutoSleepTimerAutoRewind() { + this.settings.autoSleepTimerAutoRewind = !this.settings.autoSleepTimerAutoRewind + this.saveSettings() + }, toggleDisableSleepTimerFadeOut() { this.settings.disableSleepTimerFadeOut = !this.settings.disableSleepTimerFadeOut this.saveSettings() @@ -364,6 +400,9 @@ export default { this.settings.sleepTimerLength = !isNaN(deviceSettings.sleepTimerLength) ? deviceSettings.sleepTimerLength : 900000 // 15 minutes this.settings.disableSleepTimerFadeOut = !!deviceSettings.disableSleepTimerFadeOut this.settings.disableSleepTimerResetFeedback = !!deviceSettings.disableSleepTimerResetFeedback + + this.settings.autoSleepTimerAutoRewind = !!deviceSettings.autoSleepTimerAutoRewind + this.settings.autoSleepTimerAutoRewindTime = !isNaN(deviceSettings.autoSleepTimerAutoRewindTime) ? deviceSettings.autoSleepTimerAutoRewindTime : 300000 // 5 minutes } }, mounted() {