diff --git a/ntfy/Persistence/SubscriptionManager.swift b/ntfy/Persistence/SubscriptionManager.swift index 123b271..81560eb 100644 --- a/ntfy/Persistence/SubscriptionManager.swift +++ b/ntfy/Persistence/SubscriptionManager.swift @@ -37,6 +37,13 @@ struct SubscriptionManager { } func poll(_ subscription: Subscription, completionHandler: @escaping ([Message]) -> Void) { + // This is a bit of a hack but it prevents us from polling dead subscriptions + if (subscription.baseUrl == nil) { + Log.d(tag, "Attempting to poll dead subscription failed") + completionHandler([]) + return + } + let user = store.getUser(baseUrl: subscription.baseUrl!)?.toBasicUser() Log.d(tag, "Polling from \(subscription.urlString()) with user \(user?.username ?? "anonymous")") ApiService.shared.poll(subscription: subscription, user: user) { messages, error in diff --git a/ntfy/Utils/QRScannerUIView.swift b/ntfy/Utils/QRScannerUIView.swift index 5b607d9..9ecf8d2 100644 --- a/ntfy/Utils/QRScannerUIView.swift +++ b/ntfy/Utils/QRScannerUIView.swift @@ -45,14 +45,28 @@ struct QRScannerUIView: UIViewRepresentable { class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate { var onCodeDetected: (String) -> Void + private var lastScanDate: Date? + private let debounceInterval: TimeInterval = 3.0 init(onCodeDetected: @escaping (String) -> Void) { self.onCodeDetected = onCodeDetected } + + func qrCodeScanned(_ code: String) { + let now = Date() + + // If it's the first scan or the interval since the last scan is more than the debounce interval + if let lastScan = lastScanDate, now.timeIntervalSince(lastScan) < debounceInterval { + return + } + + onCodeDetected(code) + lastScanDate = now + } func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { if let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject, let stringValue = metadataObject.stringValue { - onCodeDetected(stringValue) + qrCodeScanned(stringValue) } } }