// // AppDelegate.swift // LeCountdown // // Created by Laurent Morvillier on 24/01/2023. // import Foundation import UIKit import AVFoundation import FirebaseCore import FirebaseCrashlytics class AppDelegate : NSObject, UIApplicationDelegate { override init() { super.init() NotificationCenter.default.addObserver(self, selector: #selector(_contextDidChange), name: NSNotification.Name.NSManagedObjectContextDidSave, object: nil) } func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { FirebaseApp.configure() UNUserNotificationCenter.current().delegate = self self._initSchemaIfNeeded() // self._activateAudioSession() Sound.computeSoundDurationsIfNecessary() Conductor.maestro.cleanup() if Preferences.installDate == nil { Preferences.installDate = Date() } return true } func applicationWillEnterForeground(_ application: UIApplication) { self._activateAudioSession() } func applicationWillTerminate(_ application: UIApplication) { Logger.log("applicationWillTerminate") FileLogger.log("applicationWillTerminate") } func applicationDidReceiveMemoryWarning(_ application: UIApplication) { Conductor.maestro.memoryWarningReceived = true Logger.log("applicationDidReceiveMemoryWarning") FileLogger.log("applicationDidReceiveMemoryWarning") } fileprivate func _initSchemaIfNeeded() { if !Preferences.cloudKitSchemaInitialized { do { try PersistenceController.shared.container.initializeCloudKitSchema() Preferences.cloudKitSchemaInitialized = true } catch { print("initializeCloudKitSchema error: \(error)") } } } fileprivate func _activateAudioSession() { Logger.log("_activateAudioSession") do { let audioSession: AVAudioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.playback, options: .duckOthers) try audioSession.setActive(true) } catch { Logger.error(error) } } func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if userActivity.interaction == nil { Logger.log("restorationHandler called! interaction is nil") return false } return true } @objc fileprivate func _contextDidChange(_ notification: Notification) { TimerShortcuts.updateAppShortcutParameters() } deinit { NotificationCenter.default.removeObserver(self) } } extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { print("didReceive notification") FileLogger.log("userNotificationCenter didReceive > cancelling sound player") let timerId = self._timerId(notificationId: response.notification.request.identifier) Conductor.maestro.cancelSoundPlayer(id: timerId) } func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { print("willPresent notification") // completionHandler([.sound]) let timerId = self._timerId(notificationId: notification.request.identifier) Conductor.maestro.notifyUser(countdownId: timerId) } fileprivate func _timerId(notificationId: String) -> TimerID { let components = notificationId.components(separatedBy: CountdownScheduler.notificationIdSeparator) if components.count == 2 { return components[0] } else { FileLogger.log("app terminated by ourselves") fatalError("bad notification format : \(notificationId)") } } }