iOS onboarding: prevent pairing flicker during auto-resume (#20310)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 691808b747
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
Mariano
2026-02-18 19:39:41 +00:00
committed by GitHub
parent c2d12b7e31
commit 6e7f1a6a1b
2 changed files with 23 additions and 5 deletions

View File

@@ -1,4 +1,5 @@
import CoreImage
import Combine
import OpenClawKit
import PhotosUI
import SwiftUI
@@ -68,6 +69,7 @@ struct OnboardingWizardView: View {
@State private var scannerError: String?
@State private var selectedPhoto: PhotosPickerItem?
@State private var lastPairingAutoResumeAttemptAt: Date?
private static let pairingAutoResumeTicker = Timer.publish(every: 2.0, on: .main, in: .common).autoconnect()
let allowSkip: Bool
let onClose: () -> Void
@@ -271,6 +273,7 @@ struct OnboardingWizardView: View {
}
.onChange(of: self.appModel.gatewayServerName) { _, newValue in
guard newValue != nil else { return }
self.showQRScanner = false
self.statusLine = "Connected."
if !self.didMarkCompleted, let selectedMode {
OnboardingStateStore.markCompleted(mode: selectedMode)
@@ -282,6 +285,9 @@ struct OnboardingWizardView: View {
guard newValue == .active else { return }
self.attemptAutomaticPairingResumeIfNeeded()
}
.onReceive(Self.pairingAutoResumeTicker) { _ in
self.attemptAutomaticPairingResumeIfNeeded()
}
}
@ViewBuilder
@@ -685,7 +691,16 @@ struct OnboardingWizardView: View {
Task { await self.retryLastAttempt() }
}
private func resumeAfterPairingApprovalInBackground() {
// Keep the pairing issue sticky to avoid visual flicker while we probe for approval.
self.appModel.gatewayAutoReconnectEnabled = true
self.appModel.gatewayPairingPaused = false
self.appModel.gatewayPairingRequestId = nil
Task { await self.retryLastAttempt(silent: true) }
}
private func attemptAutomaticPairingResumeIfNeeded() {
guard self.scenePhase == .active else { return }
guard self.step == .auth else { return }
guard self.issue.needsPairing else { return }
guard self.connectingGatewayID == nil else { return }
@@ -695,7 +710,7 @@ struct OnboardingWizardView: View {
return
}
self.lastPairingAutoResumeAttemptAt = now
self.resumeAfterPairingApproval()
self.resumeAfterPairingApprovalInBackground()
}
private func detectQRCode(from data: Data) -> String? {
@@ -837,11 +852,13 @@ struct OnboardingWizardView: View {
await self.gatewayController.connectManual(host: host, port: self.manualPort, useTLS: self.manualTLS)
}
private func retryLastAttempt() async {
self.connectingGatewayID = "retry"
private func retryLastAttempt(silent: Bool = false) async {
self.connectingGatewayID = silent ? "retry-auto" : "retry"
// Keep current auth/pairing issue sticky while retrying to avoid Step 3 UI flip-flop.
self.connectMessage = "Retrying…"
self.statusLine = "Retrying last connection"
if !silent {
self.connectMessage = "Retrying…"
self.statusLine = "Retrying last connection…"
}
defer { self.connectingGatewayID = nil }
await self.gatewayController.connectLastKnown()
}