mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 20:05:19 +00:00
Fix QR verification sending multiple notifications (#773)
The camera scanner was continuously detecting the same QR code (10-30+ times/second), causing multiple verification notifications to be sent. This happened because: 1. AVCaptureMetadataOutput fires repeatedly while QR is visible 2. Each detection triggered a new verification flow 3. After receiving response, pendingQRVerifications was cleared, allowing duplicate scans Changes: - Add deduplication using lastValid state to ignore re-scans of same QR code - Only set lastValid after successful verification initiation - Add onSuccess callback to close scanner after successful scan - Automatically return to "My QR" view after verification starts - Apply same logic to both iOS camera and macOS manual input paths This ensures exactly one verification request per scan session. Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
@@ -109,6 +109,7 @@ struct ImageWrapper: View {
|
|||||||
struct QRScanView: View {
|
struct QRScanView: View {
|
||||||
@EnvironmentObject var viewModel: ChatViewModel
|
@EnvironmentObject var viewModel: ChatViewModel
|
||||||
var isActive: Bool = true
|
var isActive: Bool = true
|
||||||
|
var onSuccess: (() -> Void)? = nil // Called when verification succeeds
|
||||||
@State private var input = ""
|
@State private var input = ""
|
||||||
@State private var result: String = "" // not shown for iOS scanner
|
@State private var result: String = "" // not shown for iOS scanner
|
||||||
@State private var lastValid: String = ""
|
@State private var lastValid: String = ""
|
||||||
@@ -131,10 +132,18 @@ struct QRScanView: View {
|
|||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
CameraScannerView(isActive: isActive) { code in
|
CameraScannerView(isActive: isActive) { code in
|
||||||
|
// Deduplicate: ignore if we just processed this exact QR code
|
||||||
|
guard code != lastValid else { return }
|
||||||
|
|
||||||
if let qr = VerificationService.shared.verifyScannedQR(code) {
|
if let qr = VerificationService.shared.verifyScannedQR(code) {
|
||||||
let ok = viewModel.beginQRVerification(with: qr)
|
let ok = viewModel.beginQRVerification(with: qr)
|
||||||
if !ok { /* already pending; continue scanning */ }
|
if ok {
|
||||||
lastValid = code
|
// Successfully initiated verification; remember this QR to prevent re-scanning
|
||||||
|
lastValid = code
|
||||||
|
// Close scanner and return to "My QR" view
|
||||||
|
onSuccess?()
|
||||||
|
}
|
||||||
|
// If !ok, peer not found or already pending - don't set lastValid so user can retry
|
||||||
} else {
|
} else {
|
||||||
// ignore invalid reads; continue scanning
|
// ignore invalid reads; continue scanning
|
||||||
}
|
}
|
||||||
@@ -148,9 +157,22 @@ struct QRScanView: View {
|
|||||||
.frame(height: 100)
|
.frame(height: 100)
|
||||||
.border(Color.gray.opacity(0.4))
|
.border(Color.gray.opacity(0.4))
|
||||||
Button(Strings.validate) {
|
Button(Strings.validate) {
|
||||||
|
// Deduplicate: ignore if we just processed this exact QR
|
||||||
|
guard input != lastValid else {
|
||||||
|
result = Strings.requested("") // Already processed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if let qr = VerificationService.shared.verifyScannedQR(input) {
|
if let qr = VerificationService.shared.verifyScannedQR(input) {
|
||||||
let ok = viewModel.beginQRVerification(with: qr)
|
let ok = viewModel.beginQRVerification(with: qr)
|
||||||
result = ok ? Strings.requested(qr.nickname) : Strings.notFound
|
if ok {
|
||||||
|
result = Strings.requested(qr.nickname)
|
||||||
|
lastValid = input
|
||||||
|
// Close scanner and return to "My QR" view
|
||||||
|
onSuccess?()
|
||||||
|
} else {
|
||||||
|
result = Strings.notFound
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result = Strings.invalid
|
result = Strings.invalid
|
||||||
}
|
}
|
||||||
@@ -308,12 +330,16 @@ struct VerificationSheetView: View {
|
|||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.foregroundColor(accentColor)
|
.foregroundColor(accentColor)
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
QRScanView(isActive: showingScanner)
|
QRScanView(isActive: showingScanner, onSuccess: {
|
||||||
|
showingScanner = false
|
||||||
|
})
|
||||||
.environmentObject(viewModel)
|
.environmentObject(viewModel)
|
||||||
.frame(height: 280)
|
.frame(height: 280)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
#else
|
#else
|
||||||
QRScanView()
|
QRScanView(onSuccess: {
|
||||||
|
showingScanner = false
|
||||||
|
})
|
||||||
.environmentObject(viewModel)
|
.environmentObject(viewModel)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user