diff options
author | Eric Kuck <eric@bluelinelabs.com> | 2018-08-21 11:00:41 -0500 |
---|---|---|
committer | Roopesh Chander <roop@roopc.net> | 2018-10-28 18:26:41 +0530 |
commit | 3082863fd193f82127da9379462e6b972141621f (patch) | |
tree | d6c60627f39b4be172abcacf1dfbb12ea8cdbccb /WireGuard/WireGuard/UI/iOS/QRScanViewController.swift | |
parent | Model: Ensure name is not empty (diff) | |
download | wireguard-apple-3082863fd193f82127da9379462e6b972141621f.tar.xz wireguard-apple-3082863fd193f82127da9379462e6b972141621f.zip |
QR code: Ability to add tunnels with a QR code scan
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
Diffstat (limited to 'WireGuard/WireGuard/UI/iOS/QRScanViewController.swift')
-rw-r--r-- | WireGuard/WireGuard/UI/iOS/QRScanViewController.swift | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift b/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift new file mode 100644 index 0000000..f15d30b --- /dev/null +++ b/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift @@ -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 {} |