diff --git a/Loop.xcodeproj/project.pbxproj b/Loop.xcodeproj/project.pbxproj index 624fe51e6b..1bdfcc9cfa 100644 --- a/Loop.xcodeproj/project.pbxproj +++ b/Loop.xcodeproj/project.pbxproj @@ -319,6 +319,7 @@ 89F9119424358E4500ECCAF3 /* CarbAbsorptionTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F9119324358E4500ECCAF3 /* CarbAbsorptionTime.swift */; }; 89F9119624358E6900ECCAF3 /* BolusPickerValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F9119524358E6900ECCAF3 /* BolusPickerValues.swift */; }; 89FE21AD24AC57E30033F501 /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FE21AC24AC57E30033F501 /* Collection.swift */; }; + A8C6D00D302CDFE200D4360D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C6D00C302CDFE200D4360D /* SceneDelegate.swift */; }; A90EF53C25DEF06200F32D61 /* PluginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16DA84122E8E112008624C2 /* PluginManager.swift */; }; A90EF54425DEF0A000F32D61 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5EE209D84BE00D17AA8 /* OSLog.swift */; }; A91D2A3F26CF0FF80023B075 /* IconTitleSubtitleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D2A3E26CF0FF80023B075 /* IconTitleSubtitleTableViewCell.swift */; }; @@ -1128,6 +1129,7 @@ 89F9119324358E4500ECCAF3 /* CarbAbsorptionTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbAbsorptionTime.swift; sourceTree = ""; }; 89F9119524358E6900ECCAF3 /* BolusPickerValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusPickerValues.swift; sourceTree = ""; }; 89FE21AC24AC57E30033F501 /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; }; + A8C6D00C302CDFE200D4360D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; A900531A28D60862000BC15B /* Loop.shortcut */ = {isa = PBXFileReference; lastKnownFileType = file; path = Loop.shortcut; sourceTree = ""; }; A900531B28D608CA000BC15B /* Cancel Override.shortcut */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Cancel Override.shortcut"; sourceTree = ""; }; A900531C28D6090D000BC15B /* Loop Remote Overrides.shortcut */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Loop Remote Overrides.shortcut"; sourceTree = ""; }; @@ -1726,6 +1728,7 @@ 43776F8E1B8022E90074EA36 /* Loop */ = { isa = PBXGroup; children = ( + A8C6D00C302CDFE200D4360D /* SceneDelegate.swift */, C16DA84022E8E104008624C2 /* Plugins */, B66D1F322E6A5D6600471149 /* Localizable.xcstrings */, B66D1F382E6A5D6600471149 /* InfoPlist.xcstrings */, @@ -3477,6 +3480,7 @@ 4389916B1E91B689000EEF90 /* ChartSettings+Loop.swift in Sources */, C178249A1E1999FA00D9D25C /* CaseCountable.swift in Sources */, B4F3D25124AF890C0095CE44 /* BluetoothStateManager.swift in Sources */, + A8C6D00D302CDFE200D4360D /* SceneDelegate.swift in Sources */, 1DDE273D24AEA4B000796622 /* SettingsViewModel.swift in Sources */, DD3DBD292A33AFE9000F8B5B /* IntegralRetrospectiveCorrectionSelectionView.swift in Sources */, A9347F3124E7521800C99C34 /* CarbBackfillRequestUserInfo.swift in Sources */, diff --git a/Loop/AppDelegate.swift b/Loop/AppDelegate.swift index ebb05d5c12..b1f43901f7 100644 --- a/Loop/AppDelegate.swift +++ b/Loop/AppDelegate.swift @@ -12,7 +12,7 @@ import LoopKit final class AppDelegate: UIResponder, UIApplicationDelegate, WindowProvider { var window: UIWindow? - private let loopAppManager = LoopAppManager() + let loopAppManager = LoopAppManager() private let log = DiagnosticLog(category: "AppDelegate") // MARK: - UIApplicationDelegate - Initialization @@ -24,17 +24,14 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, WindowProvider { log.default("lastPathComponent = %{public}@", String(describing: Bundle.main.appStoreReceiptURL?.lastPathComponent)) - loopAppManager.initialize(windowProvider: self, launchOptions: launchOptions) - loopAppManager.launch() - return loopAppManager.isLaunchComplete + // SceneDelegate handles LoopAppManager initialization and launch. + return true } // MARK: - UIApplicationDelegate - Life Cycle func applicationDidBecomeActive(_ application: UIApplication) { log.default(#function) - - loopAppManager.didBecomeActive() } func applicationWillResignActive(_ application: UIApplication) { diff --git a/Loop/Info.plist b/Loop/Info.plist index db76e6e846..d1d3aab26b 100644 --- a/Loop/Info.plist +++ b/Loop/Info.plist @@ -82,6 +82,25 @@ NewCarbEntryIntent ViewLoopStatus + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + UIBackgroundModes bluetooth-central diff --git a/Loop/SceneDelegate.swift b/Loop/SceneDelegate.swift new file mode 100644 index 0000000000..0b476da287 --- /dev/null +++ b/Loop/SceneDelegate.swift @@ -0,0 +1,51 @@ +// +// SceneDelegate.swift +// Loop +// +// Scene-based lifecycle support for iOS 27. +// + +import UIKit + +final class SceneDelegate: UIResponder, UIWindowSceneDelegate, WindowProvider { + + var window: UIWindow? + + private var loopAppManager: LoopAppManager { + (UIApplication.shared.delegate as! AppDelegate).loopAppManager + } + + func scene( + _ scene: UIScene, + willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions + ) { + guard let windowScene = scene as? UIWindowScene else { + return + } + + let storyboard = UIStoryboard(name: "Main", bundle: nil) + + guard let rootViewController = storyboard.instantiateInitialViewController() else { + return + } + + let window = UIWindow(windowScene: windowScene) + window.rootViewController = rootViewController + + self.window = window + + window.makeKeyAndVisible() + + loopAppManager.initialize( + windowProvider: self, + launchOptions: nil + ) + + loopAppManager.launch() + } + + func sceneDidBecomeActive(_ scene: UIScene) { + loopAppManager.didBecomeActive() + } +} diff --git a/Loop/Views/FavoriteFoodDetailView.swift b/Loop/Views/FavoriteFoodDetailView.swift index 8c76e1fe8f..7a485e3483 100644 --- a/Loop/Views/FavoriteFoodDetailView.swift +++ b/Loop/Views/FavoriteFoodDetailView.swift @@ -23,10 +23,10 @@ public struct FavoriteFoodDetailView: View { public init(food: StoredFavoriteFood?, onFoodDelete: @escaping (StoredFavoriteFood) -> Void, isConfirmingDelete: Bool = false, carbFormatter: QuantityFormatter, absorptionTimeFormatter: DateComponentsFormatter, preferredCarbUnit: HKUnit = HKUnit.gram()) { self.food = food self.onFoodDelete = onFoodDelete - self.isConfirmingDelete = isConfirmingDelete self.carbFormatter = carbFormatter self.absorptionTimeFormatter = absorptionTimeFormatter self.preferredCarbUnit = preferredCarbUnit + self.isConfirmingDelete = isConfirmingDelete } public var body: some View {