Merge pull request #1508 from complacentsee/ios_sleep_fadeout

IOS: Add support for fading out on sleep timer end
This commit is contained in:
advplyr 2025-03-11 17:30:57 -05:00 committed by GitHub
commit bcf40c0b76
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 75 additions and 5 deletions

View file

@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Override point for customization after application launch.
let configuration = Realm.Configuration(
schemaVersion: 18,
schemaVersion: 19,
migrationBlock: { [weak self] migration, oldSchemaVersion in
if (oldSchemaVersion < 1) {
self?.logger.log("Realm schema version was \(oldSchemaVersion)")
@ -61,6 +61,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
newObject?["streamingUsingCellular"] = "ALWAYS"
}
}
if (oldSchemaVersion < 18) {
self?.logger.log("Realm schema version was \(oldSchemaVersion)... Adding disableSleepTimerFadeOut settings")
migration.enumerateObjects(ofType: PlayerSettings.className()) { oldObject, newObject in
newObject?["disableSleepTimerFadeOut"] = false
}
}
}
)

View file

@ -246,6 +246,7 @@ public class AbsDatabase: CAPPlugin {
let languageCode = call.getString("languageCode") ?? "en-us"
let downloadUsingCellular = call.getString("downloadUsingCellular") ?? "ALWAYS"
let streamingUsingCellular = call.getString("streamingUsingCellular") ?? "ALWAYS"
let disableSleepTimerFadeOut = call.getBool("disableSleepTimerFadeOut") ?? false
let settings = DeviceSettings()
settings.disableAutoRewind = disableAutoRewind
settings.enableAltView = enableAltView
@ -257,6 +258,7 @@ public class AbsDatabase: CAPPlugin {
settings.languageCode = languageCode
settings.downloadUsingCellular = downloadUsingCellular
settings.streamingUsingCellular = streamingUsingCellular
settings.disableSleepTimerFadeOut = disableSleepTimerFadeOut
Database.shared.setDeviceSettings(deviceSettings: settings)

View file

@ -19,6 +19,7 @@ class DeviceSettings: Object {
@Persisted var languageCode: String = "en-us"
@Persisted var downloadUsingCellular: String = "ALWAYS"
@Persisted var streamingUsingCellular: String = "ALWAYS"
@Persisted var disableSleepTimerFadeOut: Bool = false
}
func getDefaultDeviceSettings() -> DeviceSettings {
@ -36,6 +37,7 @@ func deviceSettingsToJSON(settings: DeviceSettings) -> Dictionary<String, Any> {
"hapticFeedback": settings.hapticFeedback,
"languageCode": settings.languageCode,
"downloadUsingCellular": settings.downloadUsingCellular,
"streamingUsingCellular": settings.streamingUsingCellular
"streamingUsingCellular": settings.streamingUsingCellular,
"disableSleepTimerFadeOut": settings.disableSleepTimerFadeOut
]
}

View file

@ -365,7 +365,57 @@ class AudioPlayer: NSObject {
self.status = .paused
updateNowPlaying()
}
public func startFadeOut() {
guard self.isInitialized() else { return }
guard let currentTime = self.getCurrentTime() else { return }
logger.log("fadeOut: Fading out playback")
// Define fade parameters.
let fadeDuration: Float = 60.0 // total fade duration in seconds
let interval: Float = 1.0 // timer interval in seconds
// Get the current volume.
let initialVolume = self.audioPlayer.volume
let targetVolume: Float = 0.0
// If the current volume is already at or below zero, just pause.
if initialVolume <= targetVolume {
self.pause()
return
}
// Calculate the volume change per timer tick.
// (targetVolume - initialVolume) is negative since target < initial.
let step = (targetVolume - initialVolume) * interval / fadeDuration
// Schedule a timer on the main queue to adjust the volume.
DispatchQueue.runOnMainQueue { [weak self] in
var timer = Timer.scheduledTimer(withTimeInterval: TimeInterval(interval), repeats: true) { t in
guard let self = self else {
t.invalidate()
return
}
// Calculate the new volume.
let newVolume = self.audioPlayer.volume + step
// Check if the next step would go below zero.
if newVolume > targetVolume {
self.audioPlayer.volume = newVolume
} else {
// Ensure volume is exactly zero and end fade.
self.audioPlayer.volume = targetVolume
t.invalidate()
self.logger.log("Fadeout: Fade complete, pausing playback")
self.pause()
self.audioPlayer.volume = initialVolume
self.seek(currentTime, from: "fadeOut")
}
}
}
}
public func seek(_ to: Double, from: String) {
logger.log("SEEK: Seek to \(to) from \(from)")

View file

@ -125,7 +125,11 @@ extension AudioPlayer {
if var sleepTimeRemaining = self.sleepTimeRemaining {
sleepTimeRemaining -= 1
self.sleepTimeRemaining = sleepTimeRemaining
if sleepTimeRemaining == 60 && self.isSleepTimerFadeOutEnabled() {
self.startFadeOut()
}
// Handle the sleep if the timer has expired
if sleepTimeRemaining <= 0 {
self.handleSleepEnd()
@ -154,5 +158,9 @@ extension AudioPlayer {
private func isChapterSleepTimerSet() -> Bool {
return self.sleepTimeChapterStopAt != nil
}
private func isSleepTimerFadeOutEnabled() -> Bool {
let deviceSettings = Database.shared.getDeviceSettings()
return !deviceSettings.disableSleepTimerFadeOut
}
}

View file

@ -84,6 +84,7 @@
<ui-text-input :value="shakeSensitivityOption" readonly append-icon="expand_more" style="width: 145px; max-width: 145px" />
</div>
</div>
</template>
<div class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleDisableSleepTimerFadeOut">
<ui-toggle-switch v-model="settings.disableSleepTimerFadeOut" @input="saveSettings" />
@ -91,6 +92,7 @@
<p class="pl-4">{{ $strings.LabelDisableAudioFadeOut }}</p>
<span class="material-icons-outlined ml-2" @click.stop="showInfo('disableSleepTimerFadeOut')">info</span>
</div>
<template v-if="!isiOS">
<div class="flex items-center py-3">
<div class="w-10 flex justify-center" @click="toggleDisableSleepTimerResetFeedback">
<ui-toggle-switch v-model="settings.disableSleepTimerResetFeedback" @input="saveSettings" />