ScannerCoordinator.swift (2472B)
1 // 2 // CodeScanner.swift 3 // https://github.com/twostraws/CodeScanner 4 // 5 // Created by Paul Hudson on 14/12/2021. 6 // Copyright © 2021 Paul Hudson. All rights reserved. 7 // 8 9 import AVFoundation 10 import SwiftUI 11 12 extension CodeScannerView { 13 @available(macCatalyst 14.0, *) 14 public class ScannerCoordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate { 15 var parent: CodeScannerView 16 var codesFound = Set<String>() 17 var didFinishScanning = false 18 var lastTime = Date(timeIntervalSince1970: 0) 19 20 init(parent: CodeScannerView) { 21 self.parent = parent 22 } 23 24 public func reset() { 25 codesFound.removeAll() 26 didFinishScanning = false 27 lastTime = Date(timeIntervalSince1970: 0) 28 } 29 30 public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { 31 if let metadataObject = metadataObjects.first { 32 guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return } 33 guard let stringValue = readableObject.stringValue else { return } 34 guard didFinishScanning == false else { return } 35 let result = ScanResult(string: stringValue, type: readableObject.type) 36 37 switch parent.scanMode { 38 case .once: 39 found(result) 40 // make sure we only trigger scan once per use 41 didFinishScanning = true 42 43 case .oncePerCode: 44 if !codesFound.contains(stringValue) { 45 codesFound.insert(stringValue) 46 found(result) 47 } 48 49 case .continuous: 50 if isPastScanInterval() { 51 found(result) 52 } 53 } 54 } 55 } 56 57 func isPastScanInterval() -> Bool { 58 Date().timeIntervalSince(lastTime) >= parent.scanInterval 59 } 60 61 func found(_ result: ScanResult) { 62 lastTime = Date() 63 64 if parent.shouldVibrateOnSuccess { 65 AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) 66 } 67 68 parent.completion(.success(result)) 69 } 70 71 func didFail(reason: ScanError) { 72 parent.completion(.failure(reason)) 73 } 74 } 75 }