Untitled
unknown
plain_text
5 months ago
3.3 kB
8
Indexable
// // QRCodeScannerView.swift // PocketCaddy // // Created by Dylan Anderson on 10/12/23. // import SwiftUI import AVFoundation final class CaptureSessionManager: ObservableObject { var captureSession: AVCaptureSession? init() { captureSession = AVCaptureSession() } } struct QRCodeScannerView<T>: UIViewControllerRepresentable { @ObservedObject var captureSessionManager = CaptureSessionManager() var didFindCode: (T?) -> Void var onError: (Error) -> Void class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate { var parent: QRCodeScannerView init(parent: QRCodeScannerView) { self.parent = parent } func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { if let metadataObject = metadataObjects.first, let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject, let stringValue = readableObject.stringValue { AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) parent.didFindCode(stringValue as? T) parent.captureSessionManager.captureSession?.stopRunning() } } } func makeCoordinator() -> Coordinator { return Coordinator(parent: self) } func makeUIViewController(context: Context) -> UIViewController { let viewController = UIViewController() guard let videoCaptureDevice = AVCaptureDevice.default(for: .video), let captureSession = captureSessionManager.captureSession else { onError(QRCodeScannerError.noCamera) return viewController } do { let videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) if captureSession.canAddInput(videoInput) { captureSession.addInput(videoInput) } else { onError(QRCodeScannerError.videoInputInitFail) return viewController } } catch { onError(error) return viewController } let metadataOutput = AVCaptureMetadataOutput() if captureSession.canAddOutput(metadataOutput) { captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(context.coordinator, queue: DispatchQueue.main) metadataOutput.metadataObjectTypes = [.qr] } else { onError(QRCodeScannerError.outputInitFail) return viewController } let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.frame = viewController.view.layer.bounds previewLayer.videoGravity = .resizeAspectFill viewController.view.layer.addSublayer(previewLayer) DispatchQueue.global(qos: .userInitiated).async { captureSession.startRunning() } return viewController } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { DispatchQueue.global(qos: .userInitiated).async { if let captureSession = self.captureSessionManager.captureSession, !captureSession.isRunning { captureSession.startRunning() } } } } extension QRCodeScannerView { enum QRCodeScannerError: LocalizedError { case noCamera case videoInputInitFail case outputInitFail var errorDescription: String? { switch self { case .noCamera: return "No camera available" case .videoInputInitFail: return "Video input initialization failed" case .outputInitFail: return "Output initialization failed" } } } }
Editor is loading...
Leave a Comment