mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix ios canvas presentation
This commit is contained in:
@@ -1034,18 +1034,18 @@ final class NodeAppModel {
|
||||
OpenClawCanvasPresentParams()
|
||||
let url = params.url?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
if url.isEmpty {
|
||||
self.screen.showDefaultCanvas()
|
||||
self.screen.presentDefaultCanvas()
|
||||
} else {
|
||||
self.screen.navigate(to: url)
|
||||
self.screen.present(urlString: url)
|
||||
}
|
||||
return BridgeInvokeResponse(id: req.id, ok: true)
|
||||
case OpenClawCanvasCommand.hide.rawValue:
|
||||
self.screen.showDefaultCanvas()
|
||||
self.screen.hideCanvas()
|
||||
return BridgeInvokeResponse(id: req.id, ok: true)
|
||||
case OpenClawCanvasCommand.navigate.rawValue:
|
||||
let params = try Self.decodeParams(OpenClawCanvasNavigateParams.self, from: req.paramsJSON)
|
||||
let trimmedURL = params.url.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
self.screen.navigate(to: trimmedURL)
|
||||
self.screen.present(urlString: trimmedURL)
|
||||
return BridgeInvokeResponse(id: req.id, ok: true)
|
||||
case OpenClawCanvasCommand.evalJS.rawValue:
|
||||
let params = try Self.decodeParams(OpenClawCanvasEvalParams.self, from: req.paramsJSON)
|
||||
|
||||
@@ -200,6 +200,36 @@ struct RootTabs: View {
|
||||
RootCameraFlashOverlay(nonce: self.appModel.cameraFlashNonce)
|
||||
}
|
||||
}
|
||||
.overlay {
|
||||
if self.appModel.screen.isCanvasPresented {
|
||||
self.canvasPresentationOverlay
|
||||
.transition(.opacity)
|
||||
.zIndex(20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var canvasPresentationOverlay: some View {
|
||||
ZStack(alignment: .topTrailing) {
|
||||
Color.black.ignoresSafeArea()
|
||||
ScreenWebView(controller: self.appModel.screen)
|
||||
.ignoresSafeArea()
|
||||
Button {
|
||||
self.appModel.screen.hideCanvas()
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.font(.system(size: 30, weight: .semibold))
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.foregroundStyle(.white)
|
||||
.shadow(color: .black.opacity(0.32), radius: 8, y: 2)
|
||||
.frame(width: 48, height: 48)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel("Close canvas")
|
||||
.safeAreaPadding(.top, 8)
|
||||
.padding(.trailing, 12)
|
||||
}
|
||||
}
|
||||
|
||||
private func rootLifecycle(_ content: some View) -> some View {
|
||||
|
||||
@@ -10,6 +10,7 @@ final class ScreenController {
|
||||
|
||||
var urlString: String = ""
|
||||
var errorText: String?
|
||||
var isCanvasPresented: Bool = false
|
||||
|
||||
/// Callback invoked when an openclaw:// deep link is tapped in the canvas
|
||||
var onDeepLink: ((URL) -> Void)?
|
||||
@@ -75,7 +76,23 @@ final class ScreenController {
|
||||
self.reload()
|
||||
}
|
||||
|
||||
func presentDefaultCanvas() {
|
||||
self.isCanvasPresented = true
|
||||
self.showDefaultCanvas()
|
||||
}
|
||||
|
||||
func present(urlString: String) {
|
||||
self.isCanvasPresented = true
|
||||
self.navigate(to: urlString)
|
||||
}
|
||||
|
||||
func hideCanvas() {
|
||||
self.isCanvasPresented = false
|
||||
self.showDefaultCanvas()
|
||||
}
|
||||
|
||||
func showLocalA2UI() {
|
||||
self.isCanvasPresented = true
|
||||
guard let url = Self.localA2UIURL else {
|
||||
self.showDefaultCanvas()
|
||||
return
|
||||
|
||||
@@ -45,6 +45,23 @@ private func mountScreen(_ screen: ScreenController) throws -> (ScreenWebViewCoo
|
||||
#expect(screen.urlString.isEmpty)
|
||||
}
|
||||
|
||||
@Test @MainActor func canvasPresentationTracksExplicitPresentAndHide() {
|
||||
let screen = ScreenController()
|
||||
|
||||
#expect(screen.isCanvasPresented == false)
|
||||
|
||||
screen.showDefaultCanvas()
|
||||
#expect(screen.isCanvasPresented == false)
|
||||
|
||||
screen.presentDefaultCanvas()
|
||||
#expect(screen.isCanvasPresented == true)
|
||||
#expect(screen.urlString.isEmpty)
|
||||
|
||||
screen.hideCanvas()
|
||||
#expect(screen.isCanvasPresented == false)
|
||||
#expect(screen.urlString.isEmpty)
|
||||
}
|
||||
|
||||
@Test @MainActor func evalExecutesJavaScript() async throws {
|
||||
let screen = ScreenController()
|
||||
let (coordinator, _) = try mountScreen(screen)
|
||||
|
||||
Reference in New Issue
Block a user