summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios/qiosapplication.swift
blob: 6f75ebd0b5e831098cdc7e623197cce535f257b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

import SwiftUI
import CompositorServices
import QIOSIntegrationPlugin
import RealityKit

struct QIOSSwiftApplication: App {
    @UIApplicationDelegateAdaptor private var appDelegate: QIOSApplicationDelegate

    var body: some SwiftUI.Scene {
        WindowGroup() {
            ImmersiveSpaceControlView()
        }

        ImmersiveSpace(id: "QIOSImmersiveSpace") {
            CompositorLayer(configuration: QIOSLayerConfiguration()) { layerRenderer in
                QIOSIntegration.instance().renderCompositorLayer(layerRenderer)
            }
        }
        // CompositorLayer immersive spaces are always full, and should not need
        // to set the immersion style, but lacking this we get a warning in the
        // console about not being able to "configure an immersive space with
        // selected style 'AutomaticImmersionStyle' since it is not in the list
        // of supported styles for this type of content: 'FullImmersionStyle'."
        .immersionStyle(selection: .constant(.full), in: .full)
    }
}

public struct QIOSLayerConfiguration: CompositorLayerConfiguration {
    public func makeConfiguration(capabilities: LayerRenderer.Capabilities,
                                  configuration: inout LayerRenderer.Configuration) {
        // Use reflection to pull out underlying C handles
        // FIXME: Use proper bridging APIs when available
        let capabilitiesMirror = Mirror(reflecting: capabilities)
        let configurationMirror = Mirror(reflecting: configuration)
        QIOSIntegration.instance().configureCompositorLayer(
            capabilitiesMirror.descendant("c_capabilities") as? cp_layer_renderer_capabilities_t,
            configurationMirror.descendant("box", "value") as? cp_layer_renderer_configuration_t
        )
    }
}

public func runSwiftAppMain() {
    QIOSSwiftApplication.main()
}

public class ImmersiveState: ObservableObject {
    static let shared = ImmersiveState()
    @Published var showImmersiveSpace: Bool = false
}

struct ImmersiveSpaceControlView: View {
    @ObservedObject private var immersiveState = ImmersiveState.shared

    @Environment(\.openImmersiveSpace) var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace

    var body: some View {
        VStack {}
        .onChange(of: immersiveState.showImmersiveSpace) { _, newValue in
            Task {
                if newValue {
                    await openImmersiveSpace(id: "QIOSImmersiveSpace")
                } else {
                    await dismissImmersiveSpace()
                }
            }
        }
    }
}

public class ImmersiveSpaceManager : NSObject {
    @objc public static func openImmersiveSpace() {
        ImmersiveState.shared.showImmersiveSpace = true
    }

    @objc public static func dismissImmersiveSpace() {
        ImmersiveState.shared.showImmersiveSpace = false
    }
}