QR code: Ability to add tunnels with a QR code scan
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
This commit is contained in:
parent
3d4409fc93
commit
3082863fd1
|
@ -0,0 +1,107 @@
|
|||
//
|
||||
// QRScanViewController.swift
|
||||
// WireGuard
|
||||
//
|
||||
// Created by Eric Kuck on 8/20/18.
|
||||
// Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
import CoreData
|
||||
import UIKit
|
||||
|
||||
protocol QRScanViewControllerDelegate: class {
|
||||
func didSave(tunnel: Tunnel, qrScanViewController: QRScanViewController)
|
||||
}
|
||||
|
||||
class QRScanViewController: UIViewController {
|
||||
|
||||
private var viewContext: NSManagedObjectContext!
|
||||
private weak var delegate: QRScanViewControllerDelegate?
|
||||
var captureSession: AVCaptureSession? = AVCaptureSession()
|
||||
let metadataOutput = AVCaptureMetadataOutput()
|
||||
var previewLayer: AVCaptureVideoPreviewLayer!
|
||||
|
||||
func configure(context: NSManagedObjectContext, delegate: QRScanViewControllerDelegate? = nil) {
|
||||
viewContext = context
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video),
|
||||
let videoInput = try? AVCaptureDeviceInput(device: videoCaptureDevice),
|
||||
let captureSession = captureSession,
|
||||
captureSession.canAddInput(videoInput),
|
||||
captureSession.canAddOutput(metadataOutput) else {
|
||||
scanDidEncounterError(title: "Scanning Not Supported", message: "This device does not have the ability to scan QR codes.")
|
||||
return
|
||||
}
|
||||
|
||||
captureSession.addInput(videoInput)
|
||||
captureSession.addOutput(metadataOutput)
|
||||
|
||||
metadataOutput.setMetadataObjectsDelegate(self, queue: .main)
|
||||
metadataOutput.metadataObjectTypes = [.qr]
|
||||
|
||||
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
|
||||
previewLayer.frame = view.layer.bounds
|
||||
previewLayer.videoGravity = .resizeAspectFill
|
||||
view.layer.addSublayer(previewLayer)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
if captureSession?.isRunning == false {
|
||||
captureSession?.startRunning()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
if captureSession?.isRunning == true {
|
||||
captureSession?.stopRunning()
|
||||
}
|
||||
}
|
||||
|
||||
func scanDidComplete(withCode code: String) {
|
||||
do {
|
||||
let tunnel = try Tunnel.fromConfig(code, context: viewContext)
|
||||
delegate?.didSave(tunnel: tunnel, qrScanViewController: self)
|
||||
} catch {
|
||||
scanDidEncounterError(title: "Invalid Code", message: "The scanned code is not a valid WireGuard config file.")
|
||||
}
|
||||
}
|
||||
|
||||
func scanDidEncounterError(title: String, message: String) {
|
||||
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak self] _ in
|
||||
self?.navigationController?.popViewController(animated: true)
|
||||
}))
|
||||
present(alertController, animated: true)
|
||||
captureSession = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension QRScanViewController: AVCaptureMetadataOutputObjectsDelegate {
|
||||
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
||||
captureSession?.stopRunning()
|
||||
|
||||
guard let metadataObject = metadataObjects.first,
|
||||
let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject,
|
||||
let stringValue = readableObject.stringValue else {
|
||||
scanDidEncounterError(title: "Invalid Code", message: "The scanned code could not be read.")
|
||||
return
|
||||
}
|
||||
|
||||
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
|
||||
scanDidComplete(withCode: stringValue)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension QRScanViewController: Identifyable {}
|
Loading…
Reference in New Issue