// // TestVideoLeakOneImmersiveViewApp.swift // TestVideoLeakOneImmersiveView // import OSLog import SwiftUI let SUBSYSTEM = Bundle.main.bundleIdentifier! let scaleForAttachements = SIMD3(2.5, 2.5, 2.5) @main struct TestVideoLeakOneImmersiveViewApp: App { let logger = Logger(subsystem: SUBSYSTEM, category: "TestVideoLeakOneImmersiveViewApp") @Environment(\.openImmersiveSpace) var openImmersiveSpace @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace @Environment(\.scenePhase) var scenePhase @State private var appModel = AppModel() var body: some Scene { Group { ImmersiveSpace(id: "InitialImmersiveView") { InitialImmersiveView() .environment(appModel) .onAppear { appModel.immersiveSpaceState = .open // When app backgrounds, `immersiveSpaceID` will remain no matter which scene was showing prior to background. // Since `InitialImmersiveView` is the first scene of the app, visionOS will display // `InitialImmersiveView` when foregrounded. // Setting immersiveSpaceID to `InitialImmersiveView` ensures that when it is changed // in `InitialImmersiveView`, the listener here below will execute upon changing of `immersiveSpaceID` appModel.immersiveSpaceID = "InitialImmersiveView" } .onDisappear { appModel.immersiveSpaceState = .closed } } .immersionStyle(selection: .constant(.mixed), in: .mixed) ImmersiveSpace(id: "ImmersiveView") { ImmersiveView() .environment(appModel) .onAppear { appModel.immersiveSpaceState = .open } .onDisappear { appModel.immersiveSpaceState = .closed } } .immersionStyle(selection: .constant(.mixed), in: .mixed) } .onChange(of: appModel.immersiveSpaceID) { oldValue, newValue in logger.info("\(#function) \(#line) `.onChange(of: appModel.immersiveSpaceID` oldValue \(String(describing: oldValue)) newValue \(String(describing: newValue))") Task { guard scenePhase == .active else { logger.info("\(#function) \(#line) escaping since scene is not active") return } logger.info("\(#function) \(#line) opening appModel.immersiveSpaceID: \(appModel.immersiveSpaceID)") await dismissImmersiveSpace() let result = await openImmersiveSpace(id: appModel.immersiveSpaceID) switch result { case .opened: logger.info("\(#function) \(#line) should be presenting appModel.immersiveSpaceID: \(appModel.immersiveSpaceID)") case .error: logger.error("\(#function) \(#line) could not open scene appModel.immersiveSpaceID: \(appModel.immersiveSpaceID)") assertionFailure("could not open scene") case .userCancelled: logger.info("\(#function) \(#line) userCancelled the openning of the scene appModel.immersiveSpaceID: \(appModel.immersiveSpaceID)") fallthrough @unknown default: logger.error("\(#function) \(#line) unhandled result \(String(describing: result))") assertionFailure("could not open scene") } } } .onChange(of: scenePhase, { oldValue, newValue in logger.info("\(#function) \(#line) `onChange(of: scenePhase` scenePhase oldValue \(String(describing: oldValue)) scenePhase newValue \(String(describing: newValue))") switch newValue { case .active: logger.info("\(#function) \(#line) scenePhase newValue \(String(describing: newValue))") case .background: logger.info("\(#function) \(#line) scenePhase newValue \(String(describing: newValue))") // reset appmodel for initial immersive space case .inactive: logger.info("\(#function) \(#line) scenePhase newValue \(String(describing: newValue))") @unknown default: logger.warning("\(#function) \(#line) scenePhase newValue \(String(describing: newValue))") } }) } }