Add:Android sleep timer setting to play a chime when almost finished #600

This commit is contained in:
advplyr 2025-04-24 16:42:55 -05:00
parent e7ad62760f
commit d97c6a0872
7 changed files with 52 additions and 3 deletions

View file

@ -135,6 +135,7 @@ data class DeviceSettings(
var sleepTimerLength: Long, // Time in milliseconds var sleepTimerLength: Long, // Time in milliseconds
var disableSleepTimerFadeOut: Boolean, var disableSleepTimerFadeOut: Boolean,
var disableSleepTimerResetFeedback: Boolean, var disableSleepTimerResetFeedback: Boolean,
var enableSleepTimerAlmostDoneChime: Boolean,
var languageCode: String, var languageCode: String,
var downloadUsingCellular: DownloadUsingCellularSetting, var downloadUsingCellular: DownloadUsingCellularSetting,
var streamingUsingCellular: StreamingUsingCellularSetting, var streamingUsingCellular: StreamingUsingCellularSetting,
@ -163,6 +164,7 @@ data class DeviceSettings(
autoSleepTimerAutoRewindTime = 300000L, // 5 minutes autoSleepTimerAutoRewindTime = 300000L, // 5 minutes
disableSleepTimerFadeOut = false, disableSleepTimerFadeOut = false,
disableSleepTimerResetFeedback = false, disableSleepTimerResetFeedback = false,
enableSleepTimerAlmostDoneChime = false,
languageCode = "en-us", languageCode = "en-us",
downloadUsingCellular = DownloadUsingCellularSetting.ALWAYS, downloadUsingCellular = DownloadUsingCellularSetting.ALWAYS,
streamingUsingCellular = StreamingUsingCellularSetting.ALWAYS, streamingUsingCellular = StreamingUsingCellularSetting.ALWAYS,
@ -188,9 +190,9 @@ data class DeviceSettings(
@JsonIgnore @JsonIgnore
fun getShakeThresholdGravity() : Float { // Used in ShakeDetector fun getShakeThresholdGravity() : Float { // Used in ShakeDetector
return if (shakeSensitivity == ShakeSensitivitySetting.VERY_HIGH) 1.2f return if (shakeSensitivity == ShakeSensitivitySetting.VERY_HIGH) 1.1f
else if (shakeSensitivity == ShakeSensitivitySetting.HIGH) 1.4f else if (shakeSensitivity == ShakeSensitivitySetting.HIGH) 1.3f
else if (shakeSensitivity == ShakeSensitivitySetting.MEDIUM) 1.6f else if (shakeSensitivity == ShakeSensitivitySetting.MEDIUM) 1.5f
else if (shakeSensitivity == ShakeSensitivitySetting.LOW) 2f else if (shakeSensitivity == ShakeSensitivitySetting.LOW) 2f
else if (shakeSensitivity == ShakeSensitivitySetting.VERY_LOW) 2.7f else if (shakeSensitivity == ShakeSensitivitySetting.VERY_LOW) 2.7f
else { else {

View file

@ -64,6 +64,10 @@ object DeviceManager {
if (deviceData.deviceSettings?.autoSleepTimerAutoRewindTime == null) { if (deviceData.deviceSettings?.autoSleepTimerAutoRewindTime == null) {
deviceData.deviceSettings?.autoSleepTimerAutoRewindTime = 300000L // 5 minutes deviceData.deviceSettings?.autoSleepTimerAutoRewindTime = 300000L // 5 minutes
} }
// Initialize sleep timer almost done chime added in v0.9.81
if (deviceData.deviceSettings?.enableSleepTimerAlmostDoneChime == null) {
deviceData.deviceSettings?.enableSleepTimerAlmostDoneChime = false
}
// Language added in v0.9.69 // Language added in v0.9.69
if (deviceData.deviceSettings?.languageCode == null) { if (deviceData.deviceSettings?.languageCode == null) {

View file

@ -1,15 +1,20 @@
package com.audiobookshelf.app.managers package com.audiobookshelf.app.managers
import android.content.Context import android.content.Context
import android.media.MediaPlayer
import android.os.* import android.os.*
import android.util.Log import android.util.Log
import com.audiobookshelf.app.R
import com.audiobookshelf.app.device.DeviceManager import com.audiobookshelf.app.device.DeviceManager
import com.audiobookshelf.app.player.PlayerNotificationService import com.audiobookshelf.app.player.PlayerNotificationService
import com.audiobookshelf.app.player.SLEEP_TIMER_WAKE_UP_EXPIRATION import com.audiobookshelf.app.player.SLEEP_TIMER_WAKE_UP_EXPIRATION
import com.audiobookshelf.app.plugins.AbsLogger
import java.util.* import java.util.*
import kotlin.concurrent.schedule import kotlin.concurrent.schedule
import kotlin.math.roundToInt import kotlin.math.roundToInt
const val SLEEP_TIMER_CHIME_SOUND_VOLUME = 0.7f
class SleepTimerManager class SleepTimerManager
constructor(private val playerNotificationService: PlayerNotificationService) { constructor(private val playerNotificationService: PlayerNotificationService) {
private val tag = "SleepTimerManager" private val tag = "SleepTimerManager"
@ -156,6 +161,10 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
) )
} }
if (sleepTimeSecondsRemaining == 30 && sleepTimerElapsed > 1 && DeviceManager.deviceData.deviceSettings?.enableSleepTimerAlmostDoneChime == true) {
playChimeSound()
}
if (sleepTimeSecondsRemaining <= 0) { if (sleepTimeSecondsRemaining <= 0) {
Log.d(tag, "Sleep Timer Pausing Player on Chapter") Log.d(tag, "Sleep Timer Pausing Player on Chapter")
pause() pause()
@ -263,6 +272,19 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
} }
} }
/** Plays chime sound */
private fun playChimeSound() {
AbsLogger.info(tag, "playChimeSound: Playing sleep timer chime sound")
val ctx = playerNotificationService.getContext()
val mediaPlayer = MediaPlayer.create(ctx, R.raw.bell)
mediaPlayer.setVolume(SLEEP_TIMER_CHIME_SOUND_VOLUME, SLEEP_TIMER_CHIME_SOUND_VOLUME)
mediaPlayer.start()
mediaPlayer.setOnCompletionListener {
AbsLogger.info(tag, "playChimeSound: Releasing mediaPlayer after chime sound")
mediaPlayer.release()
}
}
/** /**
* Gets the chapter end time for use in End of Chapter timers. If less than 10 seconds remain in * Gets the chapter end time for use in End of Chapter timers. If less than 10 seconds remain in
* the chapter, then use the next chapter. * the chapter, then use the next chapter.

View file

@ -5,6 +5,7 @@ import android.hardware.SensorEvent
import android.hardware.SensorEventListener import android.hardware.SensorEventListener
import android.hardware.SensorManager import android.hardware.SensorManager
import com.audiobookshelf.app.device.DeviceManager import com.audiobookshelf.app.device.DeviceManager
import com.audiobookshelf.app.plugins.AbsLogger
import kotlin.math.sqrt import kotlin.math.sqrt
class ShakeDetector : SensorEventListener { class ShakeDetector : SensorEventListener {
@ -46,6 +47,7 @@ class ShakeDetector : SensorEventListener {
if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) { if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
mShakeCount = 0 mShakeCount = 0
} }
AbsLogger.info("ShakeDetector", "Device shake above threshold ($gForce > $shakeThreshold)")
mShakeTimestamp = now mShakeTimestamp = now
mShakeCount++ mShakeCount++
mListener!!.onShake(mShakeCount) mListener!!.onShake(mShakeCount)

Binary file not shown.

View file

@ -100,6 +100,13 @@
<p class="pl-4">{{ $strings.LabelDisableVibrateOnReset }}</p> <p class="pl-4">{{ $strings.LabelDisableVibrateOnReset }}</p>
<span class="material-symbols text-xl ml-2" @click.stop="showInfo('disableSleepTimerResetFeedback')">info</span> <span class="material-symbols text-xl ml-2" @click.stop="showInfo('disableSleepTimerResetFeedback')">info</span>
</div> </div>
<div class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleSleepTimerAlmostDoneChime">
<ui-toggle-switch v-model="settings.enableSleepTimerAlmostDoneChime" @input="saveSettings" />
</div>
<p class="pl-4">{{ $strings.LabelSleepTimerAlmostDoneChime }}</p>
<span class="material-symbols text-xl ml-2" @click.stop="showInfo('enableSleepTimerAlmostDoneChime')">info</span>
</div>
<div class="flex items-center py-3"> <div class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleAutoSleepTimer"> <div class="w-10 flex justify-center" @click="toggleAutoSleepTimer">
<ui-toggle-switch v-model="settings.autoSleepTimer" @input="saveSettings" /> <ui-toggle-switch v-model="settings.autoSleepTimer" @input="saveSettings" />
@ -207,6 +214,7 @@ export default {
sleepTimerLength: 900000, // 15 minutes sleepTimerLength: 900000, // 15 minutes
disableSleepTimerFadeOut: false, disableSleepTimerFadeOut: false,
disableSleepTimerResetFeedback: false, disableSleepTimerResetFeedback: false,
enableSleepTimerAlmostDoneChime: false,
autoSleepTimerAutoRewind: false, autoSleepTimerAutoRewind: false,
autoSleepTimerAutoRewindTime: 300000, // 5 minutes autoSleepTimerAutoRewindTime: 300000, // 5 minutes
languageCode: 'en-us', languageCode: 'en-us',
@ -234,6 +242,10 @@ export default {
name: this.$strings.LabelDisableVibrateOnReset, name: this.$strings.LabelDisableVibrateOnReset,
message: this.$strings.LabelDisableVibrateOnResetHelp message: this.$strings.LabelDisableVibrateOnResetHelp
}, },
enableSleepTimerAlmostDoneChime: {
name: this.$strings.LabelSleepTimerAlmostDoneChime,
message: this.$strings.LabelSleepTimerAlmostDoneChimeHelp
},
autoSleepTimerAutoRewind: { autoSleepTimerAutoRewind: {
name: this.$strings.LabelAutoSleepTimerAutoRewind, name: this.$strings.LabelAutoSleepTimerAutoRewind,
message: this.$strings.LabelAutoSleepTimerAutoRewindHelp message: this.$strings.LabelAutoSleepTimerAutoRewindHelp
@ -549,6 +561,10 @@ export default {
this.settings.disableSleepTimerResetFeedback = !this.settings.disableSleepTimerResetFeedback this.settings.disableSleepTimerResetFeedback = !this.settings.disableSleepTimerResetFeedback
this.saveSettings() this.saveSettings()
}, },
toggleSleepTimerAlmostDoneChime() {
this.settings.enableSleepTimerAlmostDoneChime = !this.settings.enableSleepTimerAlmostDoneChime
this.saveSettings()
},
toggleDisableAutoRewind() { toggleDisableAutoRewind() {
this.settings.disableAutoRewind = !this.settings.disableAutoRewind this.settings.disableAutoRewind = !this.settings.disableAutoRewind
this.saveSettings() this.saveSettings()
@ -620,6 +636,7 @@ export default {
this.settings.sleepTimerLength = !isNaN(deviceSettings.sleepTimerLength) ? deviceSettings.sleepTimerLength : 900000 // 15 minutes this.settings.sleepTimerLength = !isNaN(deviceSettings.sleepTimerLength) ? deviceSettings.sleepTimerLength : 900000 // 15 minutes
this.settings.disableSleepTimerFadeOut = !!deviceSettings.disableSleepTimerFadeOut this.settings.disableSleepTimerFadeOut = !!deviceSettings.disableSleepTimerFadeOut
this.settings.disableSleepTimerResetFeedback = !!deviceSettings.disableSleepTimerResetFeedback this.settings.disableSleepTimerResetFeedback = !!deviceSettings.disableSleepTimerResetFeedback
this.settings.enableSleepTimerAlmostDoneChime = !!deviceSettings.enableSleepTimerAlmostDoneChime
this.settings.autoSleepTimerAutoRewind = !!deviceSettings.autoSleepTimerAutoRewind this.settings.autoSleepTimerAutoRewind = !!deviceSettings.autoSleepTimerAutoRewind
this.settings.autoSleepTimerAutoRewindTime = !isNaN(deviceSettings.autoSleepTimerAutoRewindTime) ? deviceSettings.autoSleepTimerAutoRewindTime : 300000 // 5 minutes this.settings.autoSleepTimerAutoRewindTime = !isNaN(deviceSettings.autoSleepTimerAutoRewindTime) ? deviceSettings.autoSleepTimerAutoRewindTime : 300000 // 5 minutes

View file

@ -241,6 +241,8 @@
"LabelShowAll": "Show All", "LabelShowAll": "Show All",
"LabelSize": "Size", "LabelSize": "Size",
"LabelSleepTimer": "Sleep timer", "LabelSleepTimer": "Sleep timer",
"LabelSleepTimerAlmostDoneChime": "Play a chime when almost finished",
"LabelSleepTimerAlmostDoneChimeHelp": "Play a chime when the sleep timer has 30 seconds remaining",
"LabelStart": "Start", "LabelStart": "Start",
"LabelStartTime": "Start time", "LabelStartTime": "Start time",
"LabelStatsBestDay": "Best Day", "LabelStatsBestDay": "Best Day",