mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 15:59:30 +00:00
fix ios qr scanner lifecycle (#101235)
* fix ios qr scanner lifecycle * fix(ios): tighten QR scanner lifecycle change --------- Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
This commit is contained in:
parent
ceb7a4adba
commit
632efa2d73
2 changed files with 79 additions and 12 deletions
|
|
@ -120,23 +120,14 @@ struct QRScannerView: UIViewControllerRepresentable {
|
|||
context.coordinator.reportError("Camera scanning is currently unavailable.")
|
||||
return UIViewController()
|
||||
}
|
||||
let scanner = DataScannerViewController(
|
||||
recognizedDataTypes: [.barcode(symbologies: [.qr])],
|
||||
isHighlightingEnabled: true)
|
||||
scanner.delegate = context.coordinator
|
||||
do {
|
||||
try scanner.startScanning()
|
||||
} catch {
|
||||
context.coordinator.reportError("Could not start QR scanner.")
|
||||
}
|
||||
return scanner
|
||||
return QRScannerContainerViewController(coordinator: context.coordinator)
|
||||
}
|
||||
|
||||
func updateUIViewController(_: UIViewController, context _: Context) {}
|
||||
|
||||
static func dismantleUIViewController(_ uiViewController: UIViewController, coordinator: Coordinator) {
|
||||
if let scanner = uiViewController as? DataScannerViewController {
|
||||
scanner.stopScanning()
|
||||
if let scanner = uiViewController as? QRScannerContainerViewController {
|
||||
scanner.stopScannerCapture()
|
||||
}
|
||||
coordinator.parent.onDismiss()
|
||||
}
|
||||
|
|
@ -145,6 +136,68 @@ struct QRScannerView: UIViewControllerRepresentable {
|
|||
Coordinator(parent: self)
|
||||
}
|
||||
|
||||
final class QRScannerContainerViewController: UIViewController {
|
||||
private let coordinator: Coordinator
|
||||
private let scanner: DataScannerViewController
|
||||
private var didStartScanning = false
|
||||
|
||||
init(coordinator: Coordinator) {
|
||||
self.coordinator = coordinator
|
||||
self.scanner = DataScannerViewController(
|
||||
recognizedDataTypes: [.barcode(symbologies: [.qr])],
|
||||
isHighlightingEnabled: true)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
self.scanner.delegate = coordinator
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder _: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.view.backgroundColor = .systemBackground
|
||||
self.addChild(self.scanner)
|
||||
self.scanner.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.view.addSubview(self.scanner.view)
|
||||
NSLayoutConstraint.activate([
|
||||
self.scanner.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
|
||||
self.scanner.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
|
||||
self.scanner.view.topAnchor.constraint(equalTo: self.view.topAnchor),
|
||||
self.scanner.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
|
||||
])
|
||||
self.scanner.didMove(toParent: self)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
// VisionKit owns the camera session; start it only after UIKit has
|
||||
// presented the scanner so sheet teardown cannot race construction.
|
||||
self.startScanningIfNeeded()
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
self.stopScannerCapture()
|
||||
super.viewWillDisappear(animated)
|
||||
}
|
||||
|
||||
func stopScannerCapture() {
|
||||
self.scanner.stopScanning()
|
||||
self.didStartScanning = false
|
||||
}
|
||||
|
||||
private func startScanningIfNeeded() {
|
||||
guard !self.didStartScanning else { return }
|
||||
do {
|
||||
try self.scanner.startScanning()
|
||||
self.didStartScanning = true
|
||||
} catch {
|
||||
self.coordinator.reportError("Could not start QR scanner.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class Coordinator: NSObject, DataScannerViewControllerDelegate {
|
||||
let parent: QRScannerView
|
||||
private var handled = false
|
||||
|
|
|
|||
|
|
@ -792,6 +792,14 @@ struct RootTabsSourceGuardTests {
|
|||
settingsPendingSetupHandler.range(of: "self.scannerResultHandoff.cancel()"))
|
||||
let settingsSetupStaging = try #require(
|
||||
settingsPendingSetupHandler.range(of: "self.stagedGatewaySetupLink = link"))
|
||||
let scannerMake = try Self.extract(
|
||||
scannerSource,
|
||||
from: "func makeUIViewController",
|
||||
to: "func updateUIViewController")
|
||||
let scannerLifecycle = try Self.extract(
|
||||
scannerSource,
|
||||
from: "final class QRScannerContainerViewController",
|
||||
to: "final class Coordinator")
|
||||
let scannerDelivery = try Self.extract(
|
||||
scannerSource,
|
||||
from: "private func deliver(_ result: QRScannerResult",
|
||||
|
|
@ -799,6 +807,12 @@ struct RootTabsSourceGuardTests {
|
|||
let stopScanning = try #require(scannerDelivery.range(of: "scanner.stopScanning()"))
|
||||
let deliverResult = try #require(scannerDelivery.range(of: "self.parent.onResult(result)"))
|
||||
#expect(scannerSource.contains("static let defaultSettlingNanoseconds: UInt64 = 1_200_000_000"))
|
||||
#expect(scannerSource.contains("QRScannerContainerViewController(coordinator: context.coordinator)"))
|
||||
#expect(!scannerMake.contains("startScanning()"))
|
||||
#expect(scannerLifecycle.contains("override func viewDidAppear"))
|
||||
#expect(scannerLifecycle.contains("try self.scanner.startScanning()"))
|
||||
#expect(scannerLifecycle.contains("override func viewWillDisappear"))
|
||||
#expect(scannerLifecycle.contains("self.stopScannerCapture()"))
|
||||
let activeProblemToast = try Self.extract(
|
||||
rootSource,
|
||||
from: "private var activeGatewayProblemToast: GatewayConnectionProblem?",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue