Skip to content

Commit 0568b94

Browse files
authored
Merge pull request #80 from twostraws/coordinator
Refactoring coordinator
2 parents b1acc06 + 078e8ca commit 0568b94

File tree

3 files changed

+91
-119
lines changed

3 files changed

+91
-119
lines changed

Sources/CodeScanner/CodeScanner.swift

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,12 @@ public struct CodeScannerView: UIViewControllerRepresentable {
9696
self.completion = completion
9797
}
9898

99-
public func makeCoordinator() -> ScannerCoordinator {
100-
ScannerCoordinator(parent: self)
101-
}
102-
10399
public func makeUIViewController(context: Context) -> ScannerViewController {
104-
let viewController = ScannerViewController(showViewfinder: showViewfinder)
105-
viewController.delegate = context.coordinator
106-
return viewController
100+
return ScannerViewController(showViewfinder: showViewfinder, parentView: self)
107101
}
108102

109103
public func updateUIViewController(_ uiViewController: ScannerViewController, context: Context) {
110-
context.coordinator.parent = self
104+
uiViewController.parentView = self
111105
uiViewController.updateViewController(
112106
isTorchOn: isTorchOn,
113107
isGalleryPresented: isGalleryPresented.wrappedValue,

Sources/CodeScanner/ScannerCoordinator.swift

Lines changed: 0 additions & 93 deletions
This file was deleted.

Sources/CodeScanner/ScannerViewController.swift

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,25 @@ import UIKit
1212
@available(macCatalyst 14.0, *)
1313
extension CodeScannerView {
1414

15-
public class ScannerViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
15+
public class ScannerViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, AVCaptureMetadataOutputObjectsDelegate {
1616

17-
var delegate: ScannerCoordinator?
17+
var parentView: CodeScannerView!
18+
var codesFound = Set<String>()
19+
var didFinishScanning = false
20+
var lastTime = Date(timeIntervalSince1970: 0)
1821
private let showViewfinder: Bool
1922

2023
private var isGalleryShowing: Bool = false {
2124
didSet {
2225
// Update binding
23-
if delegate?.parent.isGalleryPresented.wrappedValue != isGalleryShowing {
24-
delegate?.parent.isGalleryPresented.wrappedValue = isGalleryShowing
26+
if parentView.isGalleryPresented.wrappedValue != isGalleryShowing {
27+
parentView.isGalleryPresented.wrappedValue = isGalleryShowing
2528
}
2629
}
2730
}
2831

29-
public init(showViewfinder: Bool = false) {
32+
public init(showViewfinder: Bool = false, parentView: CodeScannerView) {
33+
self.parentView = parentView
3034
self.showViewfinder = showViewfinder
3135
super.init(nibName: nil, bundle: nil)
3236
}
@@ -62,10 +66,10 @@ extension CodeScannerView {
6266
}
6367

6468
if qrCodeLink == "" {
65-
delegate?.didFail(reason: .badOutput)
69+
didFail(reason: .badOutput)
6670
} else {
6771
let result = ScanResult(string: qrCodeLink, type: .qr)
68-
delegate?.found(result)
72+
found(result)
6973
}
7074
} else {
7175
print("Something went wrong")
@@ -203,7 +207,7 @@ extension CodeScannerView {
203207
view.layer.addSublayer(previewLayer)
204208
addviewfinder()
205209

206-
delegate?.reset()
210+
reset()
207211

208212
if (captureSession.isRunning == false) {
209213
DispatchQueue.global(qos: .userInteractive).async {
@@ -217,7 +221,7 @@ extension CodeScannerView {
217221
case .restricted:
218222
break
219223
case .denied:
220-
self.delegate?.didFail(reason: .permissionDenied)
224+
self.didFail(reason: .permissionDenied)
221225
case .notDetermined:
222226
self.requestCameraAccess {
223227
self.setupCaptureDevice()
@@ -237,7 +241,7 @@ extension CodeScannerView {
237241
private func requestCameraAccess(completion: (() -> Void)?) {
238242
AVCaptureDevice.requestAccess(for: .video) { [weak self] status in
239243
guard status else {
240-
self?.delegate?.didFail(reason: .permissionDenied)
244+
self?.didFail(reason: .permissionDenied)
241245
return
242246
}
243247
completion?()
@@ -260,7 +264,7 @@ extension CodeScannerView {
260264
private func setupCaptureDevice() {
261265
captureSession = AVCaptureSession()
262266

263-
guard let videoCaptureDevice = delegate?.parent.videoCaptureDevice ?? fallbackVideoCaptureDevice else {
267+
guard let videoCaptureDevice = parentView.videoCaptureDevice ?? fallbackVideoCaptureDevice else {
264268
return
265269
}
266270

@@ -269,14 +273,14 @@ extension CodeScannerView {
269273
do {
270274
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
271275
} catch {
272-
delegate?.didFail(reason: .initError(error))
276+
didFail(reason: .initError(error))
273277
return
274278
}
275279

276280
if (captureSession!.canAddInput(videoInput)) {
277281
captureSession!.addInput(videoInput)
278282
} else {
279-
delegate?.didFail(reason: .badInput)
283+
didFail(reason: .badInput)
280284
return
281285
}
282286

@@ -285,10 +289,10 @@ extension CodeScannerView {
285289
if (captureSession!.canAddOutput(metadataOutput)) {
286290
captureSession!.addOutput(metadataOutput)
287291

288-
metadataOutput.setMetadataObjectsDelegate(delegate, queue: DispatchQueue.main)
289-
metadataOutput.metadataObjectTypes = delegate?.parent.codeTypes
292+
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
293+
metadataOutput.metadataObjectTypes = parentView.codeTypes
290294
} else {
291-
delegate?.didFail(reason: .badOutput)
295+
didFail(reason: .badOutput)
292296
return
293297
}
294298
}
@@ -330,7 +334,7 @@ extension CodeScannerView {
330334
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
331335
guard touches.first?.view == view,
332336
let touchPoint = touches.first,
333-
let device = delegate?.parent.videoCaptureDevice ?? fallbackVideoCaptureDevice,
337+
let device = parentView.videoCaptureDevice ?? fallbackVideoCaptureDevice,
334338
device.isFocusPointOfInterestSupported
335339
else { return }
336340

@@ -355,7 +359,7 @@ extension CodeScannerView {
355359
}
356360

357361
@objc func manualCapturePressed(_ sender: Any?) {
358-
self.delegate?.readyManualCapture()
362+
self.readyManualCapture()
359363
}
360364

361365
func showManualCaptureButton(_ isManualCapture: Bool) {
@@ -408,5 +412,72 @@ extension CodeScannerView {
408412
#endif
409413
}
410414

415+
public func reset() {
416+
codesFound.removeAll()
417+
didFinishScanning = false
418+
lastTime = Date(timeIntervalSince1970: 0)
419+
}
420+
421+
public func readyManualCapture() {
422+
guard parentView.scanMode == .manual else { return }
423+
self.reset()
424+
lastTime = Date()
425+
}
426+
427+
public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
428+
if let metadataObject = metadataObjects.first {
429+
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
430+
guard let stringValue = readableObject.stringValue else { return }
431+
guard didFinishScanning == false else { return }
432+
let result = ScanResult(string: stringValue, type: readableObject.type)
433+
434+
switch parentView.scanMode {
435+
case .once:
436+
found(result)
437+
// make sure we only trigger scan once per use
438+
didFinishScanning = true
439+
440+
case .manual:
441+
if !didFinishScanning, isWithinManualCaptureInterval() {
442+
found(result)
443+
didFinishScanning = true
444+
}
445+
446+
case .oncePerCode:
447+
if !codesFound.contains(stringValue) {
448+
codesFound.insert(stringValue)
449+
found(result)
450+
}
451+
452+
case .continuous:
453+
if isPastScanInterval() {
454+
found(result)
455+
}
456+
}
457+
}
458+
}
459+
460+
func isPastScanInterval() -> Bool {
461+
Date().timeIntervalSince(lastTime) >= parentView.scanInterval
462+
}
463+
464+
func isWithinManualCaptureInterval() -> Bool {
465+
Date().timeIntervalSince(lastTime) <= 0.5
466+
}
467+
468+
func found(_ result: ScanResult) {
469+
lastTime = Date()
470+
471+
if parentView.shouldVibrateOnSuccess {
472+
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
473+
}
474+
475+
parentView.completion(.success(result))
476+
}
477+
478+
func didFail(reason: ScanError) {
479+
parentView.completion(.failure(reason))
480+
}
481+
411482
}
412483
}

0 commit comments

Comments
 (0)