passforios/pass/Controllers/QRScannerController.swift

147 lines
5.8 KiB
Swift
Raw Normal View History

//
// QRScannerController.swift
// pass
//
// Created by Yishi Lin on 7/4/17.
// Copyright © 2017 Yishi Lin. All rights reserved.
//
import AVFoundation
import OneTimePassword
import passKit
import SVProgressHUD
import UIKit
protocol QRScannerControllerDelegate: AnyObject {
func checkScannedOutput(line: String) -> (accept: Bool, message: String)
func handleScannedOutput(line: String)
}
class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
@IBOutlet var scannerOutput: UILabel!
2018-12-09 16:59:07 -08:00
var captureSession: AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
var qrCodeFrameView: UIView?
2018-12-09 16:59:07 -08:00
let supportedCodeTypes = [AVMetadataObject.ObjectType.qr]
2018-12-09 16:59:07 -08:00
weak var delegate: QRScannerControllerDelegate?
2018-12-09 16:59:07 -08:00
override func viewDidLoad() {
super.viewDidLoad()
2018-12-09 16:59:07 -08:00
if AVCaptureDevice.authorizationStatus(for: .video) == .denied {
presentCameraSettings()
}
2018-12-09 16:59:07 -08:00
// Get an instance of the AVCaptureDevice class to initialize a device object and provide the video as the media type parameter.
2019-10-03 14:27:00 +08:00
guard let captureDevice = AVCaptureDevice.default(for: .video) else {
scannerOutput.text = "CameraAccessDenied.".localize()
return
}
do {
// Get an instance of the AVCaptureDeviceInput class using the previous device object.
2019-10-03 14:27:00 +08:00
let input = try AVCaptureDeviceInput(device: captureDevice)
2018-12-09 16:59:07 -08:00
// Initialize the captureSession object.
captureSession = AVCaptureSession()
// Set the input device on the capture session.
captureSession?.addInput(input)
2018-12-09 16:59:07 -08:00
// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
let captureMetadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadataOutput)
2018-12-09 16:59:07 -08:00
// Set delegate and use the default dispatch queue to execute the call back
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
captureMetadataOutput.metadataObjectTypes = supportedCodeTypes
2018-12-09 16:59:07 -08:00
// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
2018-12-09 16:59:07 -08:00
// Start video capture.
captureSession?.startRunning()
2018-12-09 16:59:07 -08:00
// Move the message label to the front
scannerOutput.layer.cornerRadius = 10
2019-01-14 20:57:45 +01:00
scannerOutput.text = "NoQrCodeDetected.".localize()
2019-05-01 17:49:27 +02:00
view.bringSubviewToFront(scannerOutput)
2018-12-09 16:59:07 -08:00
// Initialize QR Code Frame to highlight the QR code
qrCodeFrameView = UIView()
2018-12-09 16:59:07 -08:00
if let qrCodeFrameView = qrCodeFrameView {
qrCodeFrameView.layer.borderColor = UIColor.green.cgColor
qrCodeFrameView.layer.borderWidth = 2
view.addSubview(qrCodeFrameView)
2019-05-01 17:49:27 +02:00
view.bringSubviewToFront(qrCodeFrameView)
}
} catch {
scannerOutput.text = error.localizedDescription
}
}
2018-12-09 16:59:07 -08:00
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
2018-12-09 16:59:07 -08:00
// MARK: - AVCaptureMetadataOutputObjectsDelegate Methods
2018-12-09 16:59:07 -08:00
func metadataOutput(_: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from _: AVCaptureConnection) {
if let metadataObj = metadataObjects.first as? AVMetadataMachineReadableCodeObject,
supportedCodeTypes.contains(metadataObj.type),
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) {
// draw a bounds on the found QR code
qrCodeFrameView?.frame = barCodeObject.bounds
2018-12-09 16:59:07 -08:00
// check whether it is a valid result
if let scanned = metadataObj.stringValue {
if let (accept, message) = delegate?.checkScannedOutput(line: scanned) {
scannerOutput.text = message
if accept == true {
captureSession?.stopRunning()
delegate?.handleScannedOutput(line: scanned)
DispatchQueue.main.async {
2019-01-14 20:57:45 +01:00
SVProgressHUD.showSuccess(withStatus: "Done".localize())
SVProgressHUD.dismiss(withDelay: 1)
self.navigationController?.popViewController(animated: true)
}
}
} else {
// no delegate, show the scanned result
scannerOutput.text = scanned
}
} else {
2019-01-14 20:57:45 +01:00
scannerOutput.text = "NoStringValue".localize()
}
} else {
qrCodeFrameView?.frame = CGRect.zero
2019-01-14 20:57:45 +01:00
scannerOutput.text = "NoQrCodeDetected.".localize()
}
}
2018-12-09 16:59:07 -08:00
func presentCameraSettings() {
let alertController = UIAlertController(
title: "Error".localize(),
message: "CameraAccessDenied.".localize() | "WarningToggleCameraPermissionsResetsApp.".localize(),
preferredStyle: .alert
)
2019-01-14 20:57:45 +01:00
alertController.addAction(UIAlertAction(title: "Cancel".localize(), style: .default))
alertController.addAction(
UIAlertAction(title: "Settings".localize(), style: .cancel) { _ in
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url, options: [:]) { _ in }
}
}
)
2018-12-09 16:59:07 -08:00
present(alertController, animated: true)
}
}