Files
damus/damus/Views/CodeScanner/CodeScanner.swift
T
2023-05-09 18:57:04 -07:00

115 lines
3.9 KiB
Swift

//
// CodeScanner.swift
// https://github.com/twostraws/CodeScanner
//
// Created by Paul Hudson on 14/12/2021.
// Copyright © 2021 Paul Hudson. All rights reserved.
//
import AVFoundation
import SwiftUI
/// An enum describing the ways CodeScannerView can hit scanning problems.
public enum ScanError: Error {
/// The camera could not be accessed.
case badInput
/// The camera was not capable of scanning the requested codes.
case badOutput
/// Initialization failed.
case initError(_ error: Error)
}
/// The result from a successful scan: the string that was scanned, and also the type of data that was found.
/// The type is useful for times when you've asked to scan several different code types at the same time, because
/// it will report the exact code type that was found.
public struct ScanResult {
/// The contents of the code.
public let string: String
/// The type of code that was matched.
public let type: AVMetadataObject.ObjectType
}
/// The operating mode for CodeScannerView.
public enum ScanMode {
/// Scan exactly one code, then stop.
case once
/// Scan each code no more than once.
case oncePerCode
/// Keep scanning all codes until dismissed.
case continuous
}
/// A SwiftUI view that is able to scan barcodes, QR codes, and more, and send back what was found.
/// To use, set `codeTypes` to be an array of things to scan for, e.g. `[.qr]`, and set `completion` to
/// a closure that will be called when scanning has finished. This will be sent the string that was detected or a `ScanError`.
/// For testing inside the simulator, set the `simulatedData` property to some test data you want to send back.
public struct CodeScannerView: UIViewControllerRepresentable {
public let codeTypes: [AVMetadataObject.ObjectType]
public let scanMode: ScanMode
public let scanInterval: Double
public let showViewfinder: Bool
public var simulatedData = ""
public var shouldVibrateOnSuccess: Bool
public var isTorchOn: Bool
public var isGalleryPresented: Binding<Bool>
public var videoCaptureDevice: AVCaptureDevice?
public var completion: (Result<ScanResult, ScanError>) -> Void
public init(
codeTypes: [AVMetadataObject.ObjectType],
scanMode: ScanMode = .once,
scanInterval: Double = 2.0,
showViewfinder: Bool = false,
simulatedData: String = "",
shouldVibrateOnSuccess: Bool = true,
isTorchOn: Bool = false,
isGalleryPresented: Binding<Bool> = .constant(false),
videoCaptureDevice: AVCaptureDevice? = AVCaptureDevice.default(for: .video),
completion: @escaping (Result<ScanResult, ScanError>) -> Void
) {
self.codeTypes = codeTypes
self.scanMode = scanMode
self.showViewfinder = showViewfinder
self.scanInterval = scanInterval
self.simulatedData = simulatedData
self.shouldVibrateOnSuccess = shouldVibrateOnSuccess
self.isTorchOn = isTorchOn
self.isGalleryPresented = isGalleryPresented
self.videoCaptureDevice = videoCaptureDevice
self.completion = completion
}
public func makeCoordinator() -> ScannerCoordinator {
ScannerCoordinator(parent: self)
}
public func makeUIViewController(context: Context) -> ScannerViewController {
let viewController = ScannerViewController(showViewfinder: showViewfinder)
viewController.delegate = context.coordinator
return viewController
}
public func updateUIViewController(_ uiViewController: ScannerViewController, context: Context) {
uiViewController.updateViewController(
isTorchOn: isTorchOn,
isGalleryPresented: isGalleryPresented.wrappedValue
)
}
}
@available(macCatalyst 14.0, *)
struct CodeScannerView_Previews: PreviewProvider {
static var previews: some View {
CodeScannerView(codeTypes: [.qr]) { result in
// do nothing
}
}
}