@webspatial/platform-visionos 1.0.3 → 1.0.5
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 +2 -2
- package/web-spatial/EventEmitter.swift +56 -0
- package/web-spatial/JSBCommand.swift +348 -0
- package/web-spatial/SpatialObject.swift +108 -0
- package/web-spatial/WebMsgCommand.swift +119 -0
- package/web-spatial/WebSpatialApp.swift +111 -0
- package/web-spatial/{libs/uiKitDelegate/Window.swift → Window.swift} +1 -0
- package/web-spatial/manager/Dynamic3DManager.swift +114 -0
- package/web-spatial/manager/JSBManager.swift +148 -0
- package/web-spatial/manager/WKWebViewManager.swift +39 -0
- package/web-spatial/{libs/webView/manifest.swift → manifest.swift} +16 -5
- package/web-spatial/model/SpatialApp.swift +190 -0
- package/web-spatial/model/SpatialScene.swift +1042 -0
- package/web-spatial/model/Spatialized2DElement.swift +128 -0
- package/web-spatial/model/SpatializedDynamic3DElement.swift +34 -0
- package/web-spatial/model/SpatializedElement.swift +95 -0
- package/web-spatial/model/SpatializedStatic3DElement.swift +19 -0
- package/web-spatial/model/dynamic3d/Geometry.swift +95 -0
- package/web-spatial/model/dynamic3d/SpatialComponent.swift +72 -0
- package/web-spatial/model/dynamic3d/SpatialEntity.swift +211 -0
- package/web-spatial/model/dynamic3d/SpatialMaterial.swift +39 -0
- package/web-spatial/model/dynamic3d/SpatialModelEntity.swift +39 -0
- package/web-spatial/model/dynamic3d/SpatialModelResource.swift +38 -0
- package/web-spatial/model/dynamic3d/SpatialTextureResource.swift +18 -0
- package/web-spatial/protocol/ScrollAbleSpatialElementContainer.swift +1 -0
- package/web-spatial/protocol/SpatialScrollAble.swift +8 -0
- package/web-spatial/protocol/SpatializedElementContainer.swift +8 -0
- package/web-spatial/protocol/WebMsgSender.swift +5 -0
- package/web-spatial/types/Vec2.swift +12 -0
- package/web-spatial/types/Vec3.swift +7 -0
- package/web-spatial/view/SceneHandlerUIView.swift +92 -0
- package/web-spatial/{views/ui/NavView.swift → view/SpatialNavView.swift} +149 -77
- package/web-spatial/view/SpatialSceneContentView.swift +218 -0
- package/web-spatial/view/SpatialSceneView.swift +53 -0
- package/web-spatial/view/Spatialized2DElementView.swift +96 -0
- package/web-spatial/view/SpatializedDynamic3DView.swift +104 -0
- package/web-spatial/view/SpatializedElementView.swift +178 -0
- package/web-spatial/view/SpatializedStatic3DView.swift +70 -0
- package/web-spatial/{views → view/view-modifier}/MaterialWithBorderCornerModifier.swift +28 -8
- package/web-spatial/webview/SpatialWebController.swift +300 -0
- package/web-spatial/webview/SpatialWebView.swift +34 -0
- package/web-spatial/webview/SpatialWebViewModel.swift +307 -0
- package/web-spatial.xcodeproj/project.pbxproj +126 -207
- package/web-spatial/libs/EventEmitter.swift +0 -25
- package/web-spatial/libs/SpatialComponent.swift +0 -24
- package/web-spatial/libs/SpatialEntity.swift +0 -172
- package/web-spatial/libs/SpatialInputComponent.swift +0 -19
- package/web-spatial/libs/SpatialMeshResource.swift +0 -12
- package/web-spatial/libs/SpatialModel3DComponent.swift +0 -51
- package/web-spatial/libs/SpatialModelComponent.swift +0 -25
- package/web-spatial/libs/SpatialObject.swift +0 -140
- package/web-spatial/libs/SpatialPhysicallyBasedMaterial.swift +0 -19
- package/web-spatial/libs/SpatialViewComponent.swift +0 -8
- package/web-spatial/libs/SpatialWindowComponent.swift +0 -454
- package/web-spatial/libs/SpatialWindowContainer.swift +0 -153
- package/web-spatial/libs/Utils/CommandManager.swift +0 -823
- package/web-spatial/libs/Utils/PerfClock.swift +0 -43
- package/web-spatial/libs/Utils/SceneManager.swift +0 -101
- package/web-spatial/libs/Utils/WindowContainerMgr.swift +0 -122
- package/web-spatial/libs/json/JsonParser.swift +0 -45
- package/web-spatial/libs/webView/UpdateSystem.swift +0 -26
- package/web-spatial/libs/webView/backend/NativeWebView.swift +0 -350
- package/web-spatial/views/ImmersiveView.swift +0 -17
- package/web-spatial/views/OpenDismissHandlerUI.swift +0 -45
- package/web-spatial/views/PlainWindowContainerView.swift +0 -132
- package/web-spatial/views/SpatialModel3DView.swift +0 -187
- package/web-spatial/views/SpatialViewUI.swift +0 -168
- package/web-spatial/views/SpatialWebViewUI.swift +0 -179
- package/web-spatial/views/VolumetricWindowContainerView.swift +0 -30
- package/web-spatial/web_spatialApp.swift +0 -141
- /package/web-spatial/{libs/Utils → Utils}/ColorExtension.swift +0 -0
- /package/web-spatial/{libs/Utils → Utils}/Logger.swift +0 -0
- /package/web-spatial/{views → view}/LoadingView.swift +0 -0
- /package/web-spatial/{views → view/view-modifier}/HideViewModifier.swift +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import RealityKit
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class SpatialModelEntity: SpatialEntity{
|
|
6
|
+
private var modelEntity:Entity? = nil
|
|
7
|
+
required init(_ modelResource:SpatialModelResource, _ _name:String = ""){
|
|
8
|
+
super.init(_name)
|
|
9
|
+
modelEntity = modelResource.resource
|
|
10
|
+
addChild(modelEntity!)
|
|
11
|
+
generateCollisionShapes(recursive: true)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
required init() {
|
|
15
|
+
super.init()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override internal func onDestroy(){
|
|
19
|
+
super.onDestroy()
|
|
20
|
+
if let modelEntity = self.modelEntity{
|
|
21
|
+
removeChild(modelEntity)
|
|
22
|
+
}
|
|
23
|
+
modelEntity = nil
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
enum CodingKeys: String, CodingKey {
|
|
27
|
+
case id, name, isDestroyed, children, components, model
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override func encode(to encoder: any Encoder) throws {
|
|
31
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
32
|
+
try container.encode(spatialId, forKey: .id)
|
|
33
|
+
try container.encode(name, forKey: .name)
|
|
34
|
+
try container.encode(isDestroyed, forKey: .isDestroyed)
|
|
35
|
+
try container.encode(spatialChildren, forKey: .children)
|
|
36
|
+
try container.encode(spatialComponents, forKey: .components)
|
|
37
|
+
try container.encode(modelEntity?.id, forKey: .model)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class SpatialModelResource: SpatialObject {
|
|
6
|
+
var _resource: Entity? = nil
|
|
7
|
+
var resource: Entity? {
|
|
8
|
+
_resource
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
init(_ urlString: String, _ onload: @escaping (Result<SpatialModelResource, Error>) -> Void) {
|
|
12
|
+
super.init()
|
|
13
|
+
Dynamic3DManager.loadResourceToLocal(urlString) { result in
|
|
14
|
+
switch result {
|
|
15
|
+
case let .success(url):
|
|
16
|
+
DispatchQueue.main.async {
|
|
17
|
+
do {
|
|
18
|
+
let entity = try Entity.load(contentsOf: url)
|
|
19
|
+
self._resource = entity
|
|
20
|
+
onload(.success(self))
|
|
21
|
+
} catch {
|
|
22
|
+
print("Failed to load entity from URL: \(error)")
|
|
23
|
+
onload(.failure(error))
|
|
24
|
+
self.destroy()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
case let .failure(error):
|
|
28
|
+
print("Failed to download model: \(error)")
|
|
29
|
+
onload(.failure(error))
|
|
30
|
+
self.destroy()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override func onDestroy() {
|
|
36
|
+
_resource = nil
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import RealityKit
|
|
3
|
+
|
|
4
|
+
@Observable
|
|
5
|
+
class SpatialTextureResource:SpatialObject {
|
|
6
|
+
internal var _resource:TextureResource? = nil
|
|
7
|
+
var resource:TextureResource? {
|
|
8
|
+
_resource
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
override init(_ url:String){
|
|
12
|
+
super.init()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
override internal func onDestroy() {
|
|
16
|
+
_resource = nil
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
protocol ScrollAbleSpatialElementContainer: SpatialScrollAble, SpatializedElementContainer {}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
protocol SpatializedElementContainer {
|
|
2
|
+
var id: String { get }
|
|
3
|
+
var parent: ScrollAbleSpatialElementContainer? { get }
|
|
4
|
+
func addChild(_ spatializedElement: SpatializedElement)
|
|
5
|
+
func removeChild(_ spatializedElement: SpatializedElement)
|
|
6
|
+
func getChildren() -> [String: SpatializedElement]
|
|
7
|
+
func getChildrenOfType(_ type: SpatializedElementType) -> [String: SpatializedElement]
|
|
8
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
struct SceneHandlerUIView: View {
|
|
4
|
+
@Environment(\.openImmersiveSpace) private var openImmersiveSpace
|
|
5
|
+
@Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace
|
|
6
|
+
@Environment(\.openWindow) private var openWindow
|
|
7
|
+
@Environment(\.dismissWindow) private var dismissWindow
|
|
8
|
+
@EnvironmentObject private var sceneDelegate: SceneDelegate
|
|
9
|
+
|
|
10
|
+
@State var spatialScene: SpatialScene
|
|
11
|
+
|
|
12
|
+
@Environment(\.scenePhase) private var scenePhase
|
|
13
|
+
|
|
14
|
+
private func setResizibility(resizingRestrictions: UIWindowScene.ResizingRestrictions) {
|
|
15
|
+
sceneDelegate.window?.windowScene?
|
|
16
|
+
.requestGeometryUpdate(
|
|
17
|
+
.Vision(
|
|
18
|
+
resizingRestrictions: resizingRestrictions
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private func setResizeRange(resizeRange: ResizeRange) {
|
|
24
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.0) {
|
|
25
|
+
sceneDelegate.window?.windowScene?
|
|
26
|
+
.requestGeometryUpdate(
|
|
27
|
+
.Vision(
|
|
28
|
+
minimumSize: CGSize(
|
|
29
|
+
width: resizeRange.minWidth ?? 0,
|
|
30
|
+
height: resizeRange
|
|
31
|
+
.minHeight ?? 0
|
|
32
|
+
),
|
|
33
|
+
maximumSize: CGSize(
|
|
34
|
+
width: resizeRange.maxWidth ?? .infinity,
|
|
35
|
+
height: resizeRange.maxHeight ?? .infinity
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
) { error in
|
|
39
|
+
print("error:", error)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var body: some View {
|
|
45
|
+
VStack {}
|
|
46
|
+
.onAppear {
|
|
47
|
+
// window scene only resize logic
|
|
48
|
+
guard spatialScene.windowStyle == .window else {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if let range = spatialScene.sceneConfig?.resizeRange {
|
|
52
|
+
self.setResizeRange(resizeRange: range)
|
|
53
|
+
if (range.minWidth != nil || range.minHeight != nil) && range.minWidth == range.maxWidth && range.minHeight == range.maxHeight {
|
|
54
|
+
self.setResizibility(resizingRestrictions: .none)
|
|
55
|
+
} else {
|
|
56
|
+
self.setResizibility(resizingRestrictions: .freeform)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
.onDisappear {
|
|
61
|
+
print("onScene Disappear")
|
|
62
|
+
spatialScene.destroy()
|
|
63
|
+
}
|
|
64
|
+
.onReceive(spatialScene.openWindowData) { sceneID in
|
|
65
|
+
if let spatialScene = SpatialApp.Instance.getScene(sceneID) {
|
|
66
|
+
let _ = openWindow(
|
|
67
|
+
id: spatialScene.windowStyle.rawValue,
|
|
68
|
+
value: sceneID
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
.onReceive(spatialScene.closeWindowData) { sceneID in
|
|
73
|
+
if let spatialScene = SpatialApp.Instance.getScene(sceneID) {
|
|
74
|
+
dismissWindow(
|
|
75
|
+
id: spatialScene.windowStyle.rawValue,
|
|
76
|
+
value: sceneID
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
.onReceive(spatialScene.setLoadingWindowData) { wd in
|
|
81
|
+
if wd.method == .show {
|
|
82
|
+
openWindow(id: "loading", value: wd.sceneID)
|
|
83
|
+
} else if wd.method == .hide {
|
|
84
|
+
dismissWindow(id: "loading", value: wd.sceneID)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.onChange(of: scenePhase) { oldValue, newValue in
|
|
89
|
+
logger.debug("OpenDismissHandlerUI: Value changed from \(oldValue) to \(newValue)")
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -1,11 +1,75 @@
|
|
|
1
1
|
import SwiftUI
|
|
2
|
-
import WebKit
|
|
3
2
|
|
|
4
|
-
struct
|
|
5
|
-
|
|
3
|
+
struct NavButtonStyle: ButtonStyle {
|
|
4
|
+
func makeBody(configuration: Configuration) -> some View {
|
|
5
|
+
configuration.label
|
|
6
|
+
.background(Color.clear)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
struct NavDivider: View {
|
|
11
|
+
var width: CGFloat = 1
|
|
12
|
+
var height: CGFloat = 16
|
|
13
|
+
var paddingLR: CGFloat = 4
|
|
14
|
+
var paddingTB: CGFloat = 12
|
|
15
|
+
var body: some View {
|
|
16
|
+
VStack {
|
|
17
|
+
Rectangle().fill(Color(hex: "#FFFFFF3D")).frame(width: width, height: height)
|
|
18
|
+
}
|
|
19
|
+
.padding([.top, .bottom], paddingTB)
|
|
20
|
+
.padding([.leading, .trailing], paddingLR)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
struct NavButton: View {
|
|
26
|
+
var action: () -> Void
|
|
27
|
+
var children: Image
|
|
28
|
+
var size: CGFloat = 44
|
|
29
|
+
var padding: CGFloat = 10
|
|
30
|
+
var clearBackGround: Bool = true
|
|
31
|
+
var body: some View {
|
|
32
|
+
if clearBackGround {
|
|
33
|
+
Button(action: action, label: {
|
|
34
|
+
ZStack {
|
|
35
|
+
Circle()
|
|
36
|
+
.fill(Color.white.opacity(0))
|
|
37
|
+
.frame(width: size, height: size)
|
|
38
|
+
.overlay(
|
|
39
|
+
children.resizable().frame(width: size - padding * 2, height: size - padding * 2)
|
|
40
|
+
)
|
|
41
|
+
.contentShape(Circle())
|
|
42
|
+
}
|
|
43
|
+
}).buttonStyle(NavButtonStyle()).frame(width: size, height: size).hoverEffect(.highlight)
|
|
44
|
+
} else {
|
|
45
|
+
Button(action: action, label: {
|
|
46
|
+
Circle()
|
|
47
|
+
.fill(Color.white.opacity(0))
|
|
48
|
+
.frame(width: size, height: size)
|
|
49
|
+
.overlay(
|
|
50
|
+
children.resizable().frame(width: size - padding * 2, height: size - padding * 2)
|
|
51
|
+
)
|
|
52
|
+
.contentShape(Circle())
|
|
53
|
+
}).hoverEffect(.highlight)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
struct SpatialNavView: View {
|
|
60
|
+
static let navHeight: CGFloat = SpatialScene.navHeight
|
|
6
61
|
static let minWidth: CGFloat = 400
|
|
7
|
-
|
|
8
|
-
|
|
62
|
+
var spatialScene: SpatialScene
|
|
63
|
+
var model:SpatialWebViewModel? {
|
|
64
|
+
get {
|
|
65
|
+
return spatialScene.spatialWebViewModel
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
var url: String {
|
|
69
|
+
get {
|
|
70
|
+
return spatialScene.url
|
|
71
|
+
}
|
|
72
|
+
}
|
|
9
73
|
@State var navWidth: CGFloat = 0
|
|
10
74
|
@State private var showCopyTip = false
|
|
11
75
|
@State private var contentHeight: CGFloat = 60
|
|
@@ -17,6 +81,36 @@ struct NavView: View {
|
|
|
17
81
|
@State private var showNav: Double = 0
|
|
18
82
|
@State private var showUrl: Double = 0
|
|
19
83
|
@Namespace var hoverNamespace
|
|
84
|
+
|
|
85
|
+
func checkButtonState(){
|
|
86
|
+
canGoBack = model!.getController().webview!.canGoBack
|
|
87
|
+
canGoForward = model!.getController().webview!.canGoForward
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func goBack() {
|
|
91
|
+
model?.getController().webview?.goBack()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func goForward() {
|
|
95
|
+
model?.getController().webview?.goForward()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func reload() {
|
|
99
|
+
model?.getController().webview?.reload()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func navigateToURL(url: URL) {
|
|
103
|
+
model?.load(url.absoluteString)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func getURL() -> URL? {
|
|
107
|
+
return model?.getController().webview?.url
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@State var canGoBack: Bool = false
|
|
111
|
+
|
|
112
|
+
@State var canGoForward: Bool = false
|
|
113
|
+
|
|
20
114
|
var navHoverGroup: HoverEffectGroup {
|
|
21
115
|
HoverEffectGroup(hoverNamespace)
|
|
22
116
|
}
|
|
@@ -28,9 +122,19 @@ struct NavView: View {
|
|
|
28
122
|
Image("logo").resizable().frame(width: 32, height: 32)
|
|
29
123
|
.cornerRadius(100)
|
|
30
124
|
if pwaManager.display == .minimal {
|
|
31
|
-
NavButton(
|
|
32
|
-
|
|
33
|
-
|
|
125
|
+
NavButton(
|
|
126
|
+
action: { self.goBack()
|
|
127
|
+
},
|
|
128
|
+
children: Image("arrow_left"),
|
|
129
|
+
clearBackGround: true)
|
|
130
|
+
.disabled(!(self.canGoBack))
|
|
131
|
+
NavButton(
|
|
132
|
+
action: { self.goForward()
|
|
133
|
+
},
|
|
134
|
+
children: Image("arrow_right"),
|
|
135
|
+
clearBackGround: true)
|
|
136
|
+
.disabled(!(self.canGoBack))
|
|
137
|
+
NavButton(action: { self.reload() }, children: Image("refresh"), clearBackGround: true)
|
|
34
138
|
NavDivider()
|
|
35
139
|
}
|
|
36
140
|
NavButton(action: { print("click"); withAnimation(.easeInOut(duration: 0.5)) { showNav = 1.0; showEnter = 0 } }, children: Image("more"), clearBackGround: true)
|
|
@@ -49,12 +153,20 @@ struct NavView: View {
|
|
|
49
153
|
.opacity(showEnter)
|
|
50
154
|
HStack(spacing: 14) {
|
|
51
155
|
if pwaManager.display == .minimal {
|
|
52
|
-
NavButton(
|
|
53
|
-
|
|
54
|
-
|
|
156
|
+
NavButton(
|
|
157
|
+
action: { self.goBack()
|
|
158
|
+
},
|
|
159
|
+
children: Image("arrow_left"))
|
|
160
|
+
.disabled(!(self.canGoBack))
|
|
161
|
+
NavButton(
|
|
162
|
+
action: { self.goForward()
|
|
163
|
+
},
|
|
164
|
+
children: Image("arrow_right"))
|
|
165
|
+
.disabled(!(self.canGoBack))
|
|
166
|
+
NavButton(action: { self.reload() }, children: Image("refresh"))
|
|
55
167
|
NavDivider()
|
|
56
168
|
}
|
|
57
|
-
NavButton(action: {
|
|
169
|
+
NavButton(action: { self.navigateToURL(url: URL(string: pwaManager.start_url)!) }, children: Image("home"))
|
|
58
170
|
NavButton(action: { withAnimation(.easeInOut(duration: 0.5)) { showUrl = 1; showNav = 0 } }, children: Image("link"))
|
|
59
171
|
NavButton(action: { showNav = 0; showEnter = 1 }, children: Image("back"))
|
|
60
172
|
}
|
|
@@ -70,7 +182,11 @@ struct NavView: View {
|
|
|
70
182
|
}
|
|
71
183
|
}
|
|
72
184
|
HStack(spacing: 6) {
|
|
73
|
-
Text(
|
|
185
|
+
Text(
|
|
186
|
+
url.count > 0 ? url : (
|
|
187
|
+
self.getURL()?.absoluteString ?? ""
|
|
188
|
+
)
|
|
189
|
+
)
|
|
74
190
|
.lineLimit(1)
|
|
75
191
|
.textSelection(.enabled)
|
|
76
192
|
.padding(12)
|
|
@@ -80,18 +196,29 @@ struct NavView: View {
|
|
|
80
196
|
.background(.black)
|
|
81
197
|
.cornerRadius(100)
|
|
82
198
|
NavButton(action: {
|
|
83
|
-
UIPasteboard.general.string =
|
|
199
|
+
UIPasteboard.general.string = self.getURL()?.absoluteString ?? ""
|
|
84
200
|
showCopyTip = true
|
|
85
201
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
86
202
|
showCopyTip = false
|
|
87
203
|
}
|
|
88
204
|
withAnimation(.easeInOut(duration: 0.5)) { showUrl = 0; showNav = 1 }
|
|
89
205
|
}, children: Image("copy"))
|
|
90
|
-
NavButton(
|
|
206
|
+
NavButton(
|
|
207
|
+
action: {
|
|
91
208
|
print("open browser")
|
|
92
|
-
UIApplication.shared
|
|
209
|
+
UIApplication.shared
|
|
210
|
+
.open(
|
|
211
|
+
URL(
|
|
212
|
+
string: url.count > 0 ? url : (
|
|
213
|
+
self.getURL()?.absoluteString ?? ""
|
|
214
|
+
)
|
|
215
|
+
)!,
|
|
216
|
+
options: [:],
|
|
217
|
+
completionHandler: nil
|
|
218
|
+
)
|
|
93
219
|
withAnimation(.easeInOut(duration: 0.5)) { showUrl = 0; showNav = 1 }
|
|
94
|
-
},
|
|
220
|
+
},
|
|
221
|
+
children: Image("browser"))
|
|
95
222
|
NavButton(action: { withAnimation(.easeInOut(duration: 0.5)) { showUrl = 0; showNav = 1 } }, children: Image("close"))
|
|
96
223
|
}
|
|
97
224
|
.popover(isPresented: $showCopyTip) {
|
|
@@ -105,6 +232,11 @@ struct NavView: View {
|
|
|
105
232
|
.cornerRadius(100)
|
|
106
233
|
.opacity(showUrl)
|
|
107
234
|
}
|
|
235
|
+
.onAppear(){
|
|
236
|
+
model?.addStateListener(.didFinishLoad){
|
|
237
|
+
self.checkButtonState()
|
|
238
|
+
}
|
|
239
|
+
}
|
|
108
240
|
}
|
|
109
241
|
|
|
110
242
|
private func startTimer() {
|
|
@@ -128,63 +260,3 @@ struct NavView: View {
|
|
|
128
260
|
timer = nil
|
|
129
261
|
}
|
|
130
262
|
}
|
|
131
|
-
|
|
132
|
-
struct NavButtonStyle: ButtonStyle {
|
|
133
|
-
func makeBody(configuration: Configuration) -> some View {
|
|
134
|
-
configuration.label
|
|
135
|
-
.background(Color.clear)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
struct NavButton: View {
|
|
140
|
-
var action: () -> Void
|
|
141
|
-
var children: Image
|
|
142
|
-
var size: CGFloat = 44
|
|
143
|
-
var padding: CGFloat = 10
|
|
144
|
-
var clearBackGround: Bool = true
|
|
145
|
-
var body: some View {
|
|
146
|
-
if clearBackGround {
|
|
147
|
-
Button(action: action, label: {
|
|
148
|
-
ZStack {
|
|
149
|
-
Circle()
|
|
150
|
-
.fill(Color.white.opacity(0))
|
|
151
|
-
.frame(width: size, height: size)
|
|
152
|
-
.overlay(
|
|
153
|
-
children.resizable().frame(width: size - padding * 2, height: size - padding * 2)
|
|
154
|
-
)
|
|
155
|
-
.contentShape(Circle())
|
|
156
|
-
}
|
|
157
|
-
}).buttonStyle(NavButtonStyle()).frame(width: size, height: size).hoverEffect(.highlight)
|
|
158
|
-
} else {
|
|
159
|
-
Button(action: action, label: {
|
|
160
|
-
Circle()
|
|
161
|
-
.fill(Color.white.opacity(0))
|
|
162
|
-
.frame(width: size, height: size)
|
|
163
|
-
.overlay(
|
|
164
|
-
children.resizable().frame(width: size - padding * 2, height: size - padding * 2)
|
|
165
|
-
)
|
|
166
|
-
.contentShape(Circle())
|
|
167
|
-
}).hoverEffect(.highlight)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
struct NavDivider: View {
|
|
173
|
-
var width: CGFloat = 1
|
|
174
|
-
var height: CGFloat = 16
|
|
175
|
-
var paddingLR: CGFloat = 4
|
|
176
|
-
var paddingTB: CGFloat = 12
|
|
177
|
-
var body: some View {
|
|
178
|
-
VStack {
|
|
179
|
-
Rectangle().fill(Color(hex: "#FFFFFF3D")).frame(width: width, height: height)
|
|
180
|
-
}
|
|
181
|
-
.padding([.top, .bottom], paddingTB)
|
|
182
|
-
.padding([.leading, .trailing], paddingLR)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// struct NavView_Previews: PreviewProvider {
|
|
187
|
-
// static var previews: some View {
|
|
188
|
-
// NavView()
|
|
189
|
-
// }
|
|
190
|
-
// }
|