@webspatial/platform-visionos 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/web-spatial/EventEmitter.swift +11 -11
- package/web-spatial/JSBCommand.swift +15 -3
- package/web-spatial/WebMsgCommand.swift +7 -3
- package/web-spatial/WebSpatialApp.swift +10 -10
- package/web-spatial/Window.swift +2 -2
- package/web-spatial/manager/AttachmentManager.swift +81 -0
- package/web-spatial/manager/JSBManager.swift +1 -2
- package/web-spatial/manifest.swift +1 -1
- package/web-spatial/model/SpatialApp.swift +59 -55
- package/web-spatial/model/SpatialScene.swift +97 -14
- package/web-spatial/model/Spatialized2DElement.swift +4 -5
- package/web-spatial/model/SpatializedStatic3DElement.swift +1 -1
- package/web-spatial/model/dynamic3d/SpatialComponent.swift +27 -27
- package/web-spatial/model/dynamic3d/SpatialEntity.swift +2 -2
- package/web-spatial/model/dynamic3d/SpatialMaterial.swift +15 -15
- package/web-spatial/model/dynamic3d/SpatialModelEntity.swift +10 -10
- package/web-spatial/model/dynamic3d/SpatialModelResource.swift +1 -1
- package/web-spatial/model/dynamic3d/SpatialTextureResource.swift +8 -8
- package/web-spatial/view/SpatialNavView.swift +52 -47
- package/web-spatial/view/SpatializedDynamic3DView.swift +68 -4
- package/web-spatial/view/SpatializedElementView.swift +28 -13
- package/web-spatial/view/SpatializedStatic3DView.swift +4 -6
- package/web-spatial/view/view-modifier/HideViewModifier.swift +2 -2
- package/web-spatial/webview/SpatialWebController.swift +27 -24
- package/web-spatial/webview/SpatialWebView.swift +5 -1
- package/web-spatial/webview/SpatialWebViewModel.swift +13 -7
- package/web-spatial.xcodeproj/project.pbxproj +13 -0
- package/web-spatialTests/NavigationCleanupTests.swift +33 -0
package/package.json
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
class EventEmitter {
|
|
2
2
|
private var listeners: [String: [(_ object: Any, _ data: Any) -> Void]] = [:]
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
func on(event: String, listener: @escaping (_ object: Any, _ data: Any) -> Void) {
|
|
5
5
|
if listeners[event] == nil {
|
|
6
6
|
listeners[event] = []
|
|
7
7
|
}
|
|
8
8
|
listeners[event]?.append(listener)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
func emit(event: String, data: Any) {
|
|
12
12
|
listeners[event]?.forEach { listener in
|
|
13
13
|
listener(self, data)
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
func off(event: String, listener: @escaping (_ object: Any, _ data: Any) -> Void) {
|
|
18
18
|
listeners[event]?.removeAll(where: { $0 as AnyObject === listener as AnyObject })
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
|
|
21
|
+
func reset() {
|
|
22
22
|
listeners = [:]
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
protocol EventEmitterProtocol{
|
|
27
|
-
var listeners: [String: [(_ object: Any, _ data: Any) -> Void]] {get set}
|
|
28
|
-
|
|
26
|
+
protocol EventEmitterProtocol {
|
|
27
|
+
var listeners: [String: [(_ object: Any, _ data: Any) -> Void]] { get set }
|
|
28
|
+
|
|
29
29
|
mutating func on(event: String, listener: @escaping (_ object: Any, _ data: Any) -> Void)
|
|
30
30
|
func emit(event: String, data: Any)
|
|
31
31
|
mutating func off(event: String, listener: @escaping (_ object: Any, _ data: Any) -> Void)
|
|
32
32
|
mutating func reset()
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
extension EventEmitterProtocol{
|
|
35
|
+
extension EventEmitterProtocol {
|
|
36
36
|
mutating func on(event: String, listener: @escaping (_ object: Any, _ data: Any) -> Void) {
|
|
37
37
|
if listeners[event] == nil {
|
|
38
38
|
listeners[event] = []
|
|
@@ -49,8 +49,8 @@ extension EventEmitterProtocol{
|
|
|
49
49
|
mutating func off(event: String, listener: @escaping (_ object: Any, _ data: Any) -> Void) {
|
|
50
50
|
listeners[event]?.removeAll(where: { $0 as AnyObject === listener as AnyObject })
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
mutating func reset(){
|
|
52
|
+
|
|
53
|
+
mutating func reset() {
|
|
54
54
|
listeners = [:]
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -197,8 +197,8 @@ struct UpdateSpatialized2DElementProperties: SpatializedElementProperties {
|
|
|
197
197
|
let material: BackgroundMaterial?
|
|
198
198
|
let cornerRadius: CornerRadius?
|
|
199
199
|
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
/// this value is used by previous WebSpatial code, keep it here only for Compatibility consideration
|
|
201
|
+
/// may delete it when we think it's not needed
|
|
202
202
|
let scrollEdgeInsetsMarginRight: Double?
|
|
203
203
|
}
|
|
204
204
|
|
|
@@ -269,7 +269,7 @@ struct AddSpatializedElementToSpatialized2DElement: SpatialObjectCommand {
|
|
|
269
269
|
let spatializedElementId: String
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
/// incomming JSB data
|
|
273
273
|
struct XSceneOptionsJSB: Codable {
|
|
274
274
|
let defaultSize: Size?
|
|
275
275
|
let type: SpatialScene.WindowStyle?
|
|
@@ -338,3 +338,15 @@ struct FocusSceneCommand: CommandDataProtocol {
|
|
|
338
338
|
struct GetSpatialSceneStateCommand: CommandDataProtocol {
|
|
339
339
|
static let commandType = "GetSpatialSceneState"
|
|
340
340
|
}
|
|
341
|
+
|
|
342
|
+
struct UpdateAttachmentEntityCommand: CommandDataProtocol {
|
|
343
|
+
static let commandType = "UpdateAttachmentEntity"
|
|
344
|
+
let id: String
|
|
345
|
+
let position: [Float]?
|
|
346
|
+
let size: AttachmentSize?
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
struct AttachmentSize: Codable {
|
|
350
|
+
let width: Double
|
|
351
|
+
let height: Double
|
|
352
|
+
}
|
|
@@ -30,14 +30,14 @@ enum SpatialWebMsgType: String, Encodable {
|
|
|
30
30
|
case objectdestroy
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
/// notify Spatialized3DElement Container Cube, used for ref.current.getBoundingClientCube()
|
|
34
34
|
struct SpatiaizedContainerClientCube: Encodable {
|
|
35
35
|
let type: SpatialWebMsgType = .cubeInfo
|
|
36
36
|
let origin: Point3D
|
|
37
37
|
let size: Size3D
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
/// notify Spatialized3DElement Container Transform to SpatialScene, used for ref.current.convertToSpatialScene()
|
|
41
41
|
struct SpatiaizedContainerTransform: Encodable {
|
|
42
42
|
let type: SpatialWebMsgType = .transform
|
|
43
43
|
let detail: AffineTransform3D
|
|
@@ -45,9 +45,11 @@ struct SpatiaizedContainerTransform: Encodable {
|
|
|
45
45
|
|
|
46
46
|
struct WebSpatialTapGuestureEventDetail: Encodable {
|
|
47
47
|
let location3D: Point3D
|
|
48
|
+
/// Global scene location (maps to clientX/clientY/clientZ on the web side).
|
|
49
|
+
let globalLocation3D: Point3D?
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
/// notify SpatializedElement/SpatialEntity tapped
|
|
51
53
|
struct WebSpatialTapGuestureEvent: Encodable {
|
|
52
54
|
let type: SpatialWebMsgType = .spatialtap
|
|
53
55
|
let detail: WebSpatialTapGuestureEventDetail
|
|
@@ -55,6 +57,8 @@ struct WebSpatialTapGuestureEvent: Encodable {
|
|
|
55
57
|
|
|
56
58
|
struct WebSpatialDragStartGuestureEventDetail: Encodable {
|
|
57
59
|
let startLocation3D: Point3D
|
|
60
|
+
/// Global scene location for the drag start point.
|
|
61
|
+
let globalLocation3D: Point3D?
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
struct WebSpatialDragStartGuestureEvent: Encodable {
|
|
@@ -22,26 +22,22 @@ struct WebSpatialApp: App {
|
|
|
22
22
|
@State var app = SpatialApp.Instance
|
|
23
23
|
|
|
24
24
|
func getDefaultSize() -> CGSize {
|
|
25
|
-
|
|
25
|
+
return CGSize(
|
|
26
26
|
width: app
|
|
27
27
|
.getSceneOptions().defaultSize!.width,
|
|
28
28
|
height: app
|
|
29
29
|
.getSceneOptions().defaultSize!.height
|
|
30
30
|
)
|
|
31
|
-
|
|
32
|
-
return ans
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
func getDefaultSize3D() -> Size3D {
|
|
36
|
-
|
|
34
|
+
return Size3D(
|
|
37
35
|
width: app
|
|
38
36
|
.getSceneOptions().defaultSize!.width,
|
|
39
37
|
height: app
|
|
40
38
|
.getSceneOptions().defaultSize!.height,
|
|
41
39
|
depth: app.getSceneOptions().defaultSize!.depth ?? 0
|
|
42
40
|
)
|
|
43
|
-
|
|
44
|
-
return ans
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
var body: some Scene {
|
|
@@ -74,13 +70,17 @@ struct WebSpatialApp: App {
|
|
|
74
70
|
SpatialSceneView(spatialScene: spatialScene!)
|
|
75
71
|
.frame(
|
|
76
72
|
minWidth: getCGFloat(
|
|
77
|
-
app.getSceneOptions(windowData)?.resizeRange?.minWidth
|
|
73
|
+
app.getSceneOptions(windowData)?.resizeRange?.minWidth
|
|
74
|
+
),
|
|
78
75
|
maxWidth: getCGFloat(
|
|
79
|
-
app.getSceneOptions(windowData)?.resizeRange?.maxWidth
|
|
76
|
+
app.getSceneOptions(windowData)?.resizeRange?.maxWidth
|
|
77
|
+
),
|
|
80
78
|
minHeight: getCGFloat(
|
|
81
|
-
app.getSceneOptions(windowData)?.resizeRange?.minHeight
|
|
79
|
+
app.getSceneOptions(windowData)?.resizeRange?.minHeight
|
|
80
|
+
),
|
|
82
81
|
maxHeight: getCGFloat(
|
|
83
|
-
app.getSceneOptions(windowData)?.resizeRange?.maxHeight
|
|
82
|
+
app.getSceneOptions(windowData)?.resizeRange?.maxHeight
|
|
83
|
+
)
|
|
84
84
|
)
|
|
85
85
|
}
|
|
86
86
|
defaultValue: {
|
package/web-spatial/Window.swift
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import SwiftUI
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/// Access window (https://stackoverflow.com/questions/60359808/how-to-access-own-window-within-swiftui-view/60359809#60359809)
|
|
5
5
|
class SceneDelegate: NSObject, ObservableObject, UIWindowSceneDelegate {
|
|
6
6
|
var window: UIWindow? // << contract of `UIWindowSceneDelegate`
|
|
7
7
|
|
|
@@ -11,7 +11,7 @@ class SceneDelegate: NSObject, ObservableObject, UIWindowSceneDelegate {
|
|
|
11
11
|
window?.overrideUserInterfaceStyle = .light
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
/// do memory cleanup after scene removed, otherwise windowContainer cannot destroy content after being dismissed
|
|
15
15
|
func sceneDidDisconnect(_ scene: UIScene) {
|
|
16
16
|
window = nil
|
|
17
17
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
struct AttachmentInfo: Identifiable, Equatable {
|
|
5
|
+
let id: String
|
|
6
|
+
var parentEntityId: String
|
|
7
|
+
var position: SIMD3<Float>
|
|
8
|
+
var size: CGSize
|
|
9
|
+
var webViewModel: SpatialWebViewModel
|
|
10
|
+
|
|
11
|
+
static func == (lhs: AttachmentInfo, rhs: AttachmentInfo) -> Bool {
|
|
12
|
+
return lhs.id == rhs.id
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Observable
|
|
17
|
+
class AttachmentManager {
|
|
18
|
+
var attachments: [String: AttachmentInfo] = [:]
|
|
19
|
+
|
|
20
|
+
// TODO: AttachmentManager.remove() dispatches destroy() asynchronously while
|
|
21
|
+
// SwiftUI tears down the outgoing SpatialWebView from the RealityView's
|
|
22
|
+
// ForEach. Both happen on the main queue but ordering isn't guaranteed — if
|
|
23
|
+
// destroy() nils the controller before SwiftUI finishes teardown,
|
|
24
|
+
// getController() re-creates it with only `model` set, missing the four
|
|
25
|
+
// callback registrations from init(url:). Refactor to give attachments a
|
|
26
|
+
// dedicated view path (e.g. AttachmentWebView) that doesn't depend on
|
|
27
|
+
// SpatialWebViewModel's lazy re-init.
|
|
28
|
+
func create(
|
|
29
|
+
id: String,
|
|
30
|
+
parentEntityId: String,
|
|
31
|
+
position: SIMD3<Float>,
|
|
32
|
+
size: CGSize
|
|
33
|
+
) -> AttachmentInfo {
|
|
34
|
+
let webViewModel = SpatialWebViewModel(url: nil)
|
|
35
|
+
webViewModel.setBackgroundTransparent(true)
|
|
36
|
+
// webViewModel.scrollEnabled = false
|
|
37
|
+
|
|
38
|
+
let info = AttachmentInfo(
|
|
39
|
+
id: id,
|
|
40
|
+
parentEntityId: parentEntityId,
|
|
41
|
+
position: position,
|
|
42
|
+
size: size,
|
|
43
|
+
webViewModel: webViewModel
|
|
44
|
+
)
|
|
45
|
+
attachments[id] = info
|
|
46
|
+
return info
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func update(id: String, position: SIMD3<Float>?, size: CGSize?) {
|
|
50
|
+
guard var info = attachments[id] else { return }
|
|
51
|
+
if let position = position {
|
|
52
|
+
info.position = position
|
|
53
|
+
}
|
|
54
|
+
if let size = size {
|
|
55
|
+
info.size = size
|
|
56
|
+
}
|
|
57
|
+
attachments[id] = info
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func remove(id: String) {
|
|
61
|
+
if let info = attachments.removeValue(forKey: id) {
|
|
62
|
+
DispatchQueue.main.async {
|
|
63
|
+
info.webViewModel.destroy()
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func get(id: String) -> AttachmentInfo? {
|
|
69
|
+
return attachments[id]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func destroyAll() {
|
|
73
|
+
let toDestroy = Array(attachments.values)
|
|
74
|
+
attachments.removeAll()
|
|
75
|
+
DispatchQueue.main.async {
|
|
76
|
+
for info in toDestroy {
|
|
77
|
+
info.webViewModel.destroy()
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -123,8 +123,7 @@ class JSBManager {
|
|
|
123
123
|
if cmdContent == nil {
|
|
124
124
|
return nil
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
return concreteData
|
|
126
|
+
return try decoder.decode(type.self, from: cmdContent!.data(using: .utf8)!)
|
|
128
127
|
}
|
|
129
128
|
|
|
130
129
|
private func typeof(for key: String) -> CommandDataProtocol.Type? {
|
|
@@ -3,10 +3,10 @@ import SwiftUI
|
|
|
3
3
|
|
|
4
4
|
let logger = Logger()
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/// To load a local path, remove http:// eg. "static-web/"
|
|
7
7
|
let nativeAPIVersion = pwaManager.getVersion()
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/// start URL
|
|
10
10
|
let startURL = pwaManager.start_url
|
|
11
11
|
|
|
12
12
|
let DefaultPlainWindowContainerSize = CGSize(width: 1280, height: 720)
|
|
@@ -37,7 +37,6 @@ struct Size: Codable {
|
|
|
37
37
|
var depth: Double?
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
40
|
extension SceneOptions {
|
|
42
41
|
init(_ options: XSceneOptionsJSB) {
|
|
43
42
|
defaultSize = Size(
|
|
@@ -47,7 +46,7 @@ extension SceneOptions {
|
|
|
47
46
|
)
|
|
48
47
|
windowResizability = decodeWindowResizability(nil)
|
|
49
48
|
resizeRange = options.resizability
|
|
50
|
-
|
|
49
|
+
// volume only
|
|
51
50
|
worldScaling = options.worldScaling?.toSDK ?? .automatic
|
|
52
51
|
worldAlignment = options.worldAlignment?.toSDK ?? .automatic
|
|
53
52
|
baseplateVisibility = options.baseplateVisibility?.toSDK ?? .automatic
|
|
@@ -56,31 +55,44 @@ extension SceneOptions {
|
|
|
56
55
|
|
|
57
56
|
func decodeWindowResizability(_ windowResizability: String?) -> WindowResizability {
|
|
58
57
|
switch windowResizability {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
case "automatic":
|
|
59
|
+
return .automatic
|
|
60
|
+
case "contentSize":
|
|
61
|
+
return .contentSize
|
|
62
|
+
case "contentMinSize":
|
|
63
|
+
return .contentMinSize
|
|
64
|
+
default:
|
|
65
|
+
return .automatic
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
@Observable
|
|
71
70
|
class SpatialApp {
|
|
72
71
|
private var scenes = [String: SpatialScene]()
|
|
73
|
-
|
|
74
|
-
// delegate properties to pwaManager
|
|
75
|
-
var name: String { pwaManager.name }
|
|
76
|
-
var scope: String { pwaManager.scope }
|
|
77
|
-
var displayMode: PWADisplayMode { pwaManager.display }
|
|
78
|
-
var version: String { pwaManager.getVersion() }
|
|
79
|
-
var startURL: String { pwaManager.start_url }
|
|
80
|
-
|
|
81
|
-
// used to cache scene config
|
|
82
|
-
private var sceneOptions: SceneOptions
|
|
83
72
|
|
|
73
|
+
/// delegate properties to pwaManager
|
|
74
|
+
var name: String {
|
|
75
|
+
pwaManager.name
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var scope: String {
|
|
79
|
+
pwaManager.scope
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var displayMode: PWADisplayMode {
|
|
83
|
+
pwaManager.display
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
var version: String {
|
|
87
|
+
pwaManager.getVersion()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
var startURL: String {
|
|
91
|
+
pwaManager.start_url
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// used to cache scene config
|
|
95
|
+
private var sceneOptions: SceneOptions
|
|
84
96
|
|
|
85
97
|
static let Instance: SpatialApp = .init()
|
|
86
98
|
|
|
@@ -90,14 +102,12 @@ class SpatialApp {
|
|
|
90
102
|
|
|
91
103
|
Logger.initLogger()
|
|
92
104
|
|
|
93
|
-
sceneOptions = SceneOptions(pwaManager.mainScene)
|
|
94
|
-
|
|
95
|
-
print("plainSceneOptions",sceneOptions)
|
|
96
|
-
|
|
105
|
+
sceneOptions = SceneOptions(pwaManager.mainScene)
|
|
106
|
+
|
|
107
|
+
print("plainSceneOptions", sceneOptions)
|
|
108
|
+
|
|
97
109
|
logger.debug("WebSpatial App Started -------- rootURL: " + startURL)
|
|
98
110
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
111
|
|
|
102
112
|
func createScene(_ url: String, _ style: SpatialScene.WindowStyle, _ state: SpatialScene.SceneStateKind, _ sceneOptions: SceneOptions? = nil) -> SpatialScene {
|
|
103
113
|
var scene = SpatialScene(url, style, state, sceneOptions)
|
|
@@ -105,15 +115,14 @@ class SpatialApp {
|
|
|
105
115
|
scene
|
|
106
116
|
.on(event: SpatialObject.Events.Destroyed.rawValue, listener: onSceneDestroyed)
|
|
107
117
|
|
|
108
|
-
|
|
109
118
|
return scene
|
|
110
119
|
}
|
|
111
|
-
|
|
120
|
+
|
|
112
121
|
private func onSceneDestroyed(_ object: Any, _ data: Any) {
|
|
113
122
|
var spatialObject = object as! SpatialObject
|
|
114
123
|
spatialObject
|
|
115
124
|
.off(event: SpatialObject.Events.Destroyed.rawValue, listener: onSceneDestroyed)
|
|
116
|
-
|
|
125
|
+
|
|
117
126
|
scenes.removeValue(forKey: spatialObject.id)
|
|
118
127
|
}
|
|
119
128
|
|
|
@@ -121,63 +130,58 @@ class SpatialApp {
|
|
|
121
130
|
return scenes[id]
|
|
122
131
|
}
|
|
123
132
|
|
|
124
|
-
|
|
125
133
|
func getSceneOptions() -> SceneOptions {
|
|
126
134
|
return sceneOptions
|
|
127
135
|
}
|
|
128
|
-
|
|
129
|
-
func getSceneOptions(_ sceneId:String) -> SceneOptions? {
|
|
136
|
+
|
|
137
|
+
func getSceneOptions(_ sceneId: String) -> SceneOptions? {
|
|
130
138
|
let spatialScene = getScene(sceneId)
|
|
131
139
|
return spatialScene?.sceneConfig
|
|
132
140
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
public func openWindowGroup(
|
|
141
|
+
|
|
142
|
+
/// used form window.open logic
|
|
143
|
+
func openWindowGroup(
|
|
137
144
|
_ targetSpatialScene: SpatialScene,
|
|
138
145
|
_ sceneData: SceneOptions
|
|
139
146
|
) {
|
|
140
147
|
if let activeScene = firstActiveScene {
|
|
141
148
|
// cache scene config
|
|
142
149
|
sceneOptions = sceneData
|
|
143
|
-
|
|
144
|
-
DispatchQueue.main.async
|
|
150
|
+
|
|
151
|
+
DispatchQueue.main.async {
|
|
145
152
|
activeScene.openWindowData.send(targetSpatialScene.id)
|
|
146
153
|
}
|
|
147
|
-
|
|
148
154
|
}
|
|
149
155
|
}
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
|
|
157
|
+
func closeWindowGroup(_ targetSpatialScene: SpatialScene) {
|
|
152
158
|
if let activeScene = firstActiveScene {
|
|
153
159
|
activeScene.closeWindowData
|
|
154
160
|
.send(targetSpatialScene.id)
|
|
155
161
|
}
|
|
156
162
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
|
|
164
|
+
/// used form window.open logic with loading ui
|
|
165
|
+
func openLoadingUI(_ targetSpatialScene: SpatialScene, _ open: Bool) {
|
|
160
166
|
let lwgdata = XLoadingViewData(
|
|
161
167
|
sceneID: targetSpatialScene.id,
|
|
162
168
|
method: open ? .show : .hide,
|
|
163
169
|
windowStyle: nil
|
|
164
170
|
)
|
|
165
|
-
|
|
171
|
+
|
|
166
172
|
if let activeScene = firstActiveScene {
|
|
167
173
|
activeScene.setLoadingWindowData.send(lwgdata)
|
|
168
174
|
}
|
|
169
175
|
}
|
|
170
|
-
|
|
176
|
+
|
|
171
177
|
private var firstActiveScene: SpatialScene? {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
kv.value.state == .visible
|
|
175
|
-
}
|
|
176
|
-
return (activeKV?.value)
|
|
178
|
+
let activeKV = scenes.first { kv in
|
|
179
|
+
kv.value.state == .visible
|
|
177
180
|
}
|
|
181
|
+
return (activeKV?.value)
|
|
178
182
|
}
|
|
179
|
-
|
|
180
|
-
|
|
183
|
+
|
|
184
|
+
func focusScene(_ targetSpatialScene: SpatialScene) {
|
|
181
185
|
// only work when fully visible
|
|
182
186
|
if targetSpatialScene.state != .visible {
|
|
183
187
|
return
|