General cleanup, only disable auto-sleep temporarily

Auto sleep timer is only disabled until the end of
the current time period (e.g. when the sleep timer
would be disabled automatically).
This commit is contained in:
Nicholas Wallace 2025-01-25 19:00:43 -07:00
parent 161614f6c9
commit 13b020732f
3 changed files with 107 additions and 115 deletions

View file

@ -6,7 +6,6 @@ import android.util.Log
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 java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.concurrent.schedule import kotlin.concurrent.schedule
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -22,7 +21,7 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
private var sleepTimerElapsed: Long = 0L private var sleepTimerElapsed: Long = 0L
private var sleepTimerFinishedAt: Long = 0L private var sleepTimerFinishedAt: Long = 0L
private var isAutoSleepTimer: Boolean = false // When timer was auto-set private var isAutoSleepTimer: Boolean = false // When timer was auto-set
private var isFirstAutoSleepTimer: Boolean = true private var autoTimerDisabled: Boolean = false // Disable until out of auto timer period
private var sleepTimerSessionId: String = "" private var sleepTimerSessionId: String = ""
/** /**
@ -91,38 +90,47 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
/** /**
* Sets the sleep timer. * Sets the sleep timer.
* @param time Long - the time to set the sleep timer for. * @param time Long - the time to set the sleep timer for. When 0L, use end of chapter/track time.
* @param isChapterTime Boolean - true if the time is for the end of a chapter, false otherwise.
* @return Boolean - true if the sleep timer was set successfully, false otherwise. * @return Boolean - true if the sleep timer was set successfully, false otherwise.
*/ */
private fun setSleepTimer(time: Long, isChapterTime: Boolean): Boolean { private fun setSleepTimer(time: Long): Boolean {
Log.d(tag, "Setting Sleep Timer for $time is chapter time $isChapterTime") Log.d(tag, "Setting Sleep Timer for $time")
sleepTimerTask?.cancel() sleepTimerTask?.cancel()
sleepTimerRunning = true sleepTimerRunning = true
sleepTimerFinishedAt = 0L sleepTimerFinishedAt = 0L
sleepTimerElapsed = 0L sleepTimerElapsed = 0L
setVolume(1f) setVolume(1f)
// Register shake sensor if (time == 0L) {
playerNotificationService.registerSensor() // Get the current chapter time and set the sleep timer to the end of the chapter
val chapterEndTime = this.getChapterEndTime()
val currentTime = getCurrentTime() if (chapterEndTime == null) {
if (isChapterTime) { Log.e(tag, "Setting sleep timer to end of chapter/track but there is no current session")
if (currentTime > time) {
Log.d(tag, "Invalid sleep timer - current time is already passed chapter time $time")
return false return false
} }
sleepTimerEndTime = time
sleepTimerLength = 0 val currentTime = getCurrentTime()
if (currentTime > chapterEndTime) {
Log.d(tag, "Invalid sleep timer - time is already past chapter time $chapterEndTime")
return false
}
sleepTimerEndTime = chapterEndTime
if (sleepTimerEndTime > getDuration()) { if (sleepTimerEndTime > getDuration()) {
sleepTimerEndTime = getDuration() sleepTimerEndTime = getDuration()
} }
} else { } else {
sleepTimerLength = time
sleepTimerEndTime = 0L sleepTimerEndTime = 0L
} }
// Set sleep timer length. Will be 0L if using chapter end time
sleepTimerLength = time
// Register shake sensor
playerNotificationService.registerSensor()
playerNotificationService.clientEventEmitter?.onSleepTimerSet( playerNotificationService.clientEventEmitter?.onSleepTimerSet(
getSleepTimerTimeRemainingSeconds(getPlaybackSpeed()), getSleepTimerTimeRemainingSeconds(getPlaybackSpeed()),
isAutoSleepTimer isAutoSleepTimer
@ -189,7 +197,13 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
fun setManualSleepTimer(playbackSessionId: String, time: Long, isChapterTime: Boolean): Boolean { fun setManualSleepTimer(playbackSessionId: String, time: Long, isChapterTime: Boolean): Boolean {
sleepTimerSessionId = playbackSessionId sleepTimerSessionId = playbackSessionId
isAutoSleepTimer = false isAutoSleepTimer = false
return setSleepTimer(time, isChapterTime) if (isChapterTime) {
Log.d(tag, "Setting manual sleep timer for end of chapter")
return setSleepTimer(0L)
} else {
Log.d(tag, "Setting manual sleep timer for $time")
return setSleepTimer(time)
}
} }
/** Clears the sleep timer. */ /** Clears the sleep timer. */
@ -216,9 +230,8 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
Log.d(tag, "Canceling Sleep Timer") Log.d(tag, "Canceling Sleep Timer")
if (isAutoSleepTimer) { if (isAutoSleepTimer) {
Log.i(tag, "Disabling auto sleep timer") Log.i(tag, "Disabling auto sleep timer for this time period")
DeviceManager.deviceData.deviceSettings?.autoSleepTimer = false autoTimerDisabled = true
DeviceManager.dbManager.saveDeviceData(DeviceManager.deviceData)
} }
clearSleepTimer() clearSleepTimer()
@ -280,19 +293,35 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
} }
} }
/** Resets the chapter timer. */ /**
private fun resetChapterTimer() { * Rewind auto sleep timer if setting enabled. To ensure the first rewind of the time period does
this.getChapterEndTime()?.let { chapterEndTime -> * not take place, make sure to set `isAutoSleepTimer` after calling this function.
Log.d(tag, "Resetting stopped sleep timer to end of chapter $chapterEndTime") */
vibrateFeedback() private fun tryRewindAutoSleepTimer() {
setSleepTimer(chapterEndTime, true) DeviceManager.deviceData.deviceSettings?.let { deviceSettings ->
play() if (isAutoSleepTimer && deviceSettings.autoSleepTimerAutoRewind) {
Log.i(
tag,
"Auto sleep timer auto rewind seeking back ${deviceSettings.autoSleepTimerAutoRewindTime}ms"
)
playerNotificationService.seekBackward(deviceSettings.autoSleepTimerAutoRewindTime)
}
} }
} }
/** Checks if the sleep timer should be reset. */ /** Checks if the sleep timer should be reset. */
private fun checkShouldResetSleepTimer() { private fun checkShouldResetSleepTimer() {
if (!sleepTimerRunning) { if (sleepTimerRunning) {
// Reset the sleep timer if it has been running for at least 3 seconds or it is an end of
// chapter/track timer
if (sleepTimerLength == 0L || sleepTimerElapsed > 3000L) {
Log.d(tag, "Resetting running sleep timer")
vibrateFeedback()
setSleepTimer(sleepTimerLength)
play()
}
} else {
if (sleepTimerFinishedAt <= 0L) return if (sleepTimerFinishedAt <= 0L) return
val finishedAtDistance = System.currentTimeMillis() - sleepTimerFinishedAt val finishedAtDistance = System.currentTimeMillis() - sleepTimerFinishedAt
@ -303,53 +332,15 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
return return
} }
// Automatically Rewind in the book if settings is enabled // Automatically rewind in the book if settings are enabled
if (isAutoSleepTimer) { tryRewindAutoSleepTimer()
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 // Set sleep timer
// When sleepTimerLength is 0 then use end of chapter/track time Log.d(tag, "Resetting stopped sleep timer")
if (sleepTimerLength == 0L) {
Log.d(tag, "Resetting stopped chapter sleep timer")
resetChapterTimer()
} else {
Log.d(tag, "Resetting stopped sleep timer to length $sleepTimerLength")
vibrateFeedback() vibrateFeedback()
setSleepTimer(sleepTimerLength, false) setSleepTimer(sleepTimerLength)
play() play()
} }
return
}
// Does not apply to chapter sleep timers and timer must be running for at least 3 seconds
if (sleepTimerLength > 0L && sleepTimerElapsed > 3000L) {
Log.d(tag, "Resetting running sleep timer to length $sleepTimerLength")
vibrateFeedback()
setSleepTimer(sleepTimerLength, false)
} else if (sleepTimerLength == 0L) {
// When navigating to previous chapters make sure this is still the end of the current chapter
this.getChapterEndTime()?.let { chapterEndTime ->
if (chapterEndTime != sleepTimerEndTime) {
Log.d(
tag,
"Resetting chapter sleep timer to end of chapter $chapterEndTime from $sleepTimerEndTime"
)
vibrateFeedback()
setSleepTimer(chapterEndTime, true)
play()
}
}
}
} }
/** Handles the shake event to reset the sleep timer. */ /** Handles the shake event to reset the sleep timer. */
@ -419,7 +410,7 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
) )
} }
/** Checks if the auto sleep timer should be set. */ /** Checks whether the auto sleep timer should be set, and set up auto sleep timer if so. */
fun checkAutoSleepTimer() { fun checkAutoSleepTimer() {
if (sleepTimerRunning) { // Sleep timer already running if (sleepTimerRunning) { // Sleep timer already running
return return
@ -451,46 +442,36 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
} }
} }
val currentHour = SimpleDateFormat("HH:mm", Locale.getDefault()).format(currentCalendar.time) val isDuringAutoTime =
if (currentCalendar.after(startCalendar) && currentCalendar.before(endCalendar)) { 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 // Determine whether to set the auto sleep timer or not
if (deviceSettings.autoSleepTimerAutoRewind && !isFirstAutoSleepTimer) { if (autoTimerDisabled) {
Log.i( if (!isDuringAutoTime) {
tag, // Check if sleep timer was disabled during the previous period and enable again
"Auto sleep timer auto rewind seeking back ${deviceSettings.autoSleepTimerAutoRewindTime}ms" Log.i(tag, "Leaving disabled auto sleep time period, enabling for next time period")
) autoTimerDisabled = false
playerNotificationService.seekBackward(deviceSettings.autoSleepTimerAutoRewindTime) } else {
// Auto time is disabled, do not set sleep timer
Log.i(tag, "Auto sleep timer is disabled for this time period")
} }
isFirstAutoSleepTimer = false } else {
if (isDuringAutoTime) {
// Start an auto sleep timer
val currentHour = currentCalendar.get(Calendar.HOUR_OF_DAY)
val currentMin = currentCalendar.get(Calendar.MINUTE)
Log.i(tag, "Starting sleep timer at $currentHour:$currentMin")
// Set sleep timer // Automatically rewind in the book if settings is enabled
// When sleepTimerLength is 0 then use end of chapter/track time tryRewindAutoSleepTimer()
if (deviceSettings.sleepTimerLength == 0L) {
val chapterEndTimeMs = this.getChapterEndTime() // Set `isAutoSleepTimer` to true to indicate that the timer was set automatically
if (chapterEndTimeMs == null) { // and to not cause the timer to rewind
Log.e(
tag,
"Setting auto sleep timer to end of chapter/track but there is no current session"
)
} else {
isAutoSleepTimer = true isAutoSleepTimer = true
setSleepTimer(chapterEndTimeMs, true) setSleepTimer(deviceSettings.sleepTimerLength)
}
} else { } else {
isAutoSleepTimer = true Log.d(tag, "Not in auto sleep time period")
setSleepTimer(deviceSettings.sleepTimerLength, false)
} }
} else {
isFirstAutoSleepTimer = true
Log.d(
tag,
"Current hour $currentHour is NOT between ${deviceSettings.autoSleepTimerStartTime} and ${deviceSettings.autoSleepTimerEndTime}"
)
} }
} }
} }
@ -506,9 +487,7 @@ constructor(private val playerNotificationService: PlayerNotificationService) {
// will stay on and reset to 10 mins // will stay on and reset to 10 mins
if (sleepTimerSessionId == playbackSessionId || sleepTimerRunning) { if (sleepTimerSessionId == playbackSessionId || sleepTimerRunning) {
checkShouldResetSleepTimer() checkShouldResetSleepTimer()
} else { } else {}
isFirstAutoSleepTimer = true
}
sleepTimerSessionId = playbackSessionId sleepTimerSessionId = playbackSessionId
checkAutoSleepTimer() checkAutoSleepTimer()

View file

@ -86,6 +86,9 @@ export default {
}, },
timeRemainingPretty() { timeRemainingPretty() {
return this.$secondsToTimestamp(this.currentTime) return this.$secondsToTimestamp(this.currentTime)
},
isIos() {
return this.$platform === 'ios'
} }
}, },
methods: { methods: {
@ -103,11 +106,19 @@ export default {
}, },
async cancelSleepTimer() { async cancelSleepTimer() {
if (this.isAuto) { if (this.isAuto) {
if (this.$platform === 'ios') {
const { value } = await Dialog.confirm({ const { value } = await Dialog.confirm({
title: 'Confirm', title: 'Confirm',
message: 'Are you sure you want to disable the auto sleep timer? You will need to enable this again in settings.' message: this.$strings.MessageConfirmDisableAutoTimerIos
}) })
if (!value) return if (!value) return
} else {
const { value } = await Dialog.confirm({
title: 'Confirm',
message: this.$strings.MessageConfirmDisableAutoTimerAndroid
})
if (!value) return
}
} }
await this.$hapticsImpact() await this.$hapticsImpact()

View file

@ -278,6 +278,8 @@
"MessageBookshelfEmpty": "Bookshelf empty", "MessageBookshelfEmpty": "Bookshelf empty",
"MessageConfirmDeleteLocalEpisode": "Remove local episode \"{0}\" from your device? The file on the server will be unaffected.", "MessageConfirmDeleteLocalEpisode": "Remove local episode \"{0}\" from your device? The file on the server will be unaffected.",
"MessageConfirmDeleteLocalFiles": "Remove local files of this item from your device? The files on the server and your progress will be unaffected.", "MessageConfirmDeleteLocalFiles": "Remove local files of this item from your device? The files on the server and your progress will be unaffected.",
"MessageConfirmDisableAutoTimerAndroid": "Are you sure you want to disable the auto timer for the rest of today? The timer will be re-enabled at the end of this auto-sleep timer period, or if you restart the app.",
"MessageConfirmDisableAutoTimerIos": "Are you sure you want to disable the auto sleep timer? You will need to enable this again in settings.",
"MessageConfirmDiscardProgress": "Are you sure you want to reset your progress?", "MessageConfirmDiscardProgress": "Are you sure you want to reset your progress?",
"MessageConfirmDownloadUsingCellular": "You are about to download using cellular data. This may include carrier data charges. Do you wish to continue?", "MessageConfirmDownloadUsingCellular": "You are about to download using cellular data. This may include carrier data charges. Do you wish to continue?",
"MessageConfirmMarkAsFinished": "Are you sure you want to mark this item as finished?", "MessageConfirmMarkAsFinished": "Are you sure you want to mark this item as finished?",