import SwiftUI #if os(iOS) import AVFAudio import UIKit #endif @main struct Audiobookshelf_swiftApp: App { @State private var appState = AppState() #if os(iOS) /// Bridges the UIKit-only `handleEventsForBackgroundURLSession` callback /// (used by iOS to wake the app when a background download completes) /// into the SwiftUI lifecycle. Without this, in-flight downloads can't /// notify the app of completion after a swipe-away. @UIApplicationDelegateAdaptor(BackgroundDownloadAppDelegate.self) private var appDelegate #endif init() { configureImageCache() #if os(iOS) configureAudioSession() #endif } /// Increases the shared URLCache so AsyncImage covers persist across renders /// and app launches. Default capacity is tiny (~4 MB / 20 MB). private func configureImageCache() { let memoryCapacity = 50 * 1024 * 1024 // 50 MB let diskCapacity = 500 * 1024 * 1024 // 500 MB URLCache.shared = URLCache( memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "covers" ) } var body: some Scene { #if os(macOS) WindowGroup { ContentView() .environment(appState) } .windowResizability(.contentSize) Settings { SettingsView() .environment(appState) } #else WindowGroup { ContentView() .environment(appState) } #endif } #if os(iOS) private func configureAudioSession() { // `.spokenAudio` + `.longFormAudio` policy: iOS-Hinweis dass es sich um // ernsthafte Audio-Wiedergabe handelt (nicht Tasten-Sounds). Aktiviert // u. a. das AirPlay-Routing im Control Center / Lockscreen und sorgt // für richtigen Ducking-/Interruption-Behavior bei Anrufen. // setActive(true) passiert erst in play() damit beim App-Start // keine laufende Fremd-Wiedergabe unterbrochen wird. try? AVAudioSession.sharedInstance().setCategory( .playback, mode: .spokenAudio, policy: .longFormAudio, options: [] ) } #endif } #if os(iOS) /// Receives the system's background URLSession completion callback and routes /// the handler to whichever `DownloadManager` is currently active. We can't /// reach the SwiftUI-owned `AppState` from here directly, so the handler is /// stashed on `DownloadManager.pendingBackgroundCompletion` and consumed when /// `urlSessionDidFinishEvents(forBackgroundURLSession:)` fires. final class BackgroundDownloadAppDelegate: NSObject, UIApplicationDelegate { func application( _ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void ) { DownloadManager.pendingBackgroundCompletion = completionHandler } } #endif