SceneDelegate.swift 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. //
  2. // SceneDelegate.swift
  3. // LoopFollow
  4. //
  5. // Created by Jon Fawcett on 6/1/20.
  6. // Copyright © 2020 Jon Fawcett. All rights reserved.
  7. //
  8. import UIKit
  9. import AVFoundation
  10. class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  11. var window: UIWindow?
  12. let synthesizer = AVSpeechSynthesizer()
  13. let appStateController = AppStateController()
  14. func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
  15. // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
  16. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
  17. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
  18. guard let _ = (scene as? UIWindowScene) else { return }
  19. // get the tabBar
  20. guard let tabBarController = window?.rootViewController as? UITabBarController,
  21. let viewControllers = tabBarController.viewControllers
  22. else {
  23. return
  24. }
  25. // set the main controllers' connection to the app sate
  26. // other controllers that need to know app state are setup programatically
  27. for i in 0..<viewControllers.count {
  28. if let vc = viewControllers[i] as? MainViewController {
  29. vc.appStateController = appStateController
  30. }
  31. if let vc = viewControllers[i] as? NightscoutViewController {
  32. vc.appStateController = appStateController
  33. }
  34. if let vc = viewControllers[i] as? SettingsViewController {
  35. vc.appStateController = appStateController
  36. }
  37. if let vc = viewControllers[i] as? AlarmViewController {
  38. vc.appStateController = appStateController
  39. }
  40. if let vc = viewControllers[i] as? SnoozeViewController {
  41. vc.appStateController = appStateController
  42. }
  43. if let vc = viewControllers[i] as? debugViewController {
  44. vc.appStateController = appStateController
  45. }
  46. }
  47. // Register the SceneDelegate as an observer for the "toggleSpeakBG" notification, which will be triggered when the user toggles the "Speak BG" feature in General Settings. This helps ensure that the Quick Action is updated according to the current setting.
  48. NotificationCenter.default.addObserver(self, selector: #selector(handleToggleSpeakBGEvent), name: NSNotification.Name("toggleSpeakBG"), object: nil)
  49. updateQuickActions()
  50. }
  51. func sceneDidDisconnect(_ scene: UIScene) {
  52. // Called as the scene is being released by the system.
  53. // This occurs shortly after the scene enters the background, or when its session is discarded.
  54. // Release any resources associated with this scene that can be re-created the next time the scene connects.
  55. // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
  56. NotificationCenter.default.removeObserver(self, name: NSNotification.Name("toggleSpeakBG"), object: nil)
  57. }
  58. func sceneDidBecomeActive(_ scene: UIScene) {
  59. // Called when the scene has moved from an inactive state to an active state.
  60. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
  61. }
  62. func sceneWillResignActive(_ scene: UIScene) {
  63. // Called when the scene will move from an active state to an inactive state.
  64. // This may occur due to temporary interruptions (ex. an incoming phone call).
  65. }
  66. func sceneWillEnterForeground(_ scene: UIScene) {
  67. // Called as the scene transitions from the background to the foreground.
  68. // Use this method to undo the changes made on entering the background.
  69. }
  70. func sceneDidEnterBackground(_ scene: UIScene) {
  71. // Called as the scene transitions from the foreground to the background.
  72. // Use this method to save data, release shared resources, and store enough scene-specific state information
  73. // to restore the scene back to its current state.
  74. // Save changes in the application's managed object context when the application transitions to the background.
  75. (UIApplication.shared.delegate as? AppDelegate)?.saveContext()
  76. }
  77. // Update the Home Screen Quick Action for toggling the "Speak BG" feature based on the current setting in UserDefaultsRepository. This function uses UIApplicationShortcutItem to create a 3D touch action for controlling the feature.
  78. func updateQuickActions() {
  79. let iconName = UserDefaultsRepository.speakBG.value ? "pause.circle.fill" : "play.circle.fill"
  80. let iconTemplate = UIApplicationShortcutIcon(systemImageName: iconName)
  81. let shortcut = UIApplicationShortcutItem(type: Bundle.main.bundleIdentifier! + ".toggleSpeakBG",
  82. localizedTitle: "Speak BG",
  83. localizedSubtitle: nil,
  84. icon: iconTemplate,
  85. userInfo: nil)
  86. UIApplication.shared.shortcutItems = [shortcut]
  87. }
  88. // Handle the UIApplicationShortcutItem when the user taps on the Home Screen Quick Action. This function toggles the "Speak BG" setting in UserDefaultsRepository, speaks the current state (on/off) using AVSpeechSynthesizer, and updates the Quick Action appearance.
  89. func handleShortcutItem(_ shortcutItem: UIApplicationShortcutItem) {
  90. if let bundleIdentifier = Bundle.main.bundleIdentifier {
  91. let expectedType = bundleIdentifier + ".toggleSpeakBG"
  92. if shortcutItem.type == expectedType {
  93. UserDefaultsRepository.speakBG.value.toggle()
  94. let message = UserDefaultsRepository.speakBG.value ? "BG Speak is now on" : "BG Speak is now off"
  95. let utterance = AVSpeechUtterance(string: message)
  96. synthesizer.speak(utterance)
  97. updateQuickActions()
  98. }
  99. }
  100. }
  101. // The following method is called when the user taps on the Home Screen Quick Action
  102. func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
  103. handleShortcutItem(shortcutItem)
  104. }
  105. @objc func handleToggleSpeakBGEvent() {
  106. updateQuickActions()
  107. }
  108. }