mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-23 07:18:11 +00:00
iOS: - QR scanner view using DataScannerViewController - Photo library QR detection via CIDetector for saved QR images - Deep link parser for openclaw://gateway URLs and base64url setup codes - Onboarding wizard: full-screen welcome with "Scan QR Code" button, auto-connect on scan, back navigation, step indicators for manual flow Backend: - Add /pair qr action to device-pair extension for QR code generation - TUI/WebUI differentiation: ASCII QR for TUI, markdown image for WebUI - Telegram: send QR as media attachment via sendMessageTelegram - Add data URI support to loadWebMedia for generic base64 media handling - Export renderQrPngBase64 from plugin SDK for extension use Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66 lines
2.3 KiB
Swift
66 lines
2.3 KiB
Swift
import OpenClawKit
|
|
import SwiftUI
|
|
import VisionKit
|
|
|
|
struct QRScannerView: UIViewControllerRepresentable {
|
|
let onGatewayLink: (GatewayConnectDeepLink) -> Void
|
|
let onError: (String) -> Void
|
|
let onDismiss: () -> Void
|
|
|
|
func makeUIViewController(context: Context) -> DataScannerViewController {
|
|
let scanner = DataScannerViewController(
|
|
recognizedDataTypes: [.barcode(symbologies: [.qr])],
|
|
isHighlightingEnabled: true)
|
|
scanner.delegate = context.coordinator
|
|
try? scanner.startScanning()
|
|
return scanner
|
|
}
|
|
|
|
func updateUIViewController(_: DataScannerViewController, context _: Context) {}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(parent: self)
|
|
}
|
|
|
|
final class Coordinator: NSObject, DataScannerViewControllerDelegate {
|
|
let parent: QRScannerView
|
|
private var handled = false
|
|
|
|
init(parent: QRScannerView) {
|
|
self.parent = parent
|
|
}
|
|
|
|
func dataScanner(_: DataScannerViewController, didAdd items: [RecognizedItem], allItems _: [RecognizedItem]) {
|
|
guard !self.handled else { return }
|
|
for item in items {
|
|
guard case let .barcode(barcode) = item,
|
|
let payload = barcode.payloadStringValue
|
|
else { continue }
|
|
|
|
// Try setup code format first (base64url JSON from /pair qr).
|
|
if let link = GatewayConnectDeepLink.fromSetupCode(payload) {
|
|
self.handled = true
|
|
self.parent.onGatewayLink(link)
|
|
return
|
|
}
|
|
|
|
// Fall back to deep link URL format (openclaw://gateway?...).
|
|
if let url = URL(string: payload),
|
|
let route = DeepLinkParser.parse(url),
|
|
case let .gateway(link) = route
|
|
{
|
|
self.handled = true
|
|
self.parent.onGatewayLink(link)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func dataScanner(_: DataScannerViewController, didRemove _: [RecognizedItem], allItems _: [RecognizedItem]) {}
|
|
|
|
func dataScanner(_: DataScannerViewController, becameUnavailableWithError error: DataScannerViewController.ScanningUnavailable) {
|
|
self.parent.onError("Camera is not available on this device.")
|
|
}
|
|
}
|
|
}
|