- Updated notification body to use proper German quotation marks for download failure alerts. - Refactored audio interruption handling in PlayerEngine to utilize MainActor.assumeIsolated for better performance. - Introduced nonisolated properties for support and downloads directories in ProgressSyncManager. - Improved FullHistoryView and MainView with additional toolbar items and alerts for download failures. - Added new toggles in SettingsView for parallel downloads and mobile data usage. - Created new color assets for the DownloadWidgetExtension and updated widget appearance. - Implemented Info.plist for DownloadWidgetExtension to support widget functionality. - Enabled live activities support in iOS Info.plist.
82 lines
2.6 KiB
Swift
82 lines
2.6 KiB
Swift
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() {
|
|
// Nur die Kategorie registrieren — setActive(true) passiert erst in play(),
|
|
// damit beim App-Start keine laufende Fremd-Wiedergabe unterbrochen wird.
|
|
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, 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
|