flutter_barcode_reader/ios/Classes/BarcodeScannerViewController.swift
2017-10-29 10:05:11 -07:00

214 lines
7.8 KiB
Swift

//
// BarcodeScannerViewController.swift
// AppTreeRevolution
//
// Created by Matthew Smith on 2/18/15.
// Copyright (c) 2015 AppTree Software. All rights reserved.
//
import UIKit
import MTBBarcodeScanner
protocol BarcodeScannerViewControllerDelegate : class {
func barcodeScannerViewController(_ controller : BarcodeScannerViewController, didScanBarcodeWithResult result: String)
}
struct BarcodeScanContext {
var attributeIndex : Int?
}
protocol TorchSupport {
var flashOn: Bool { get }
var hasTorch: Bool { get }
func toggleFlash(to flashOn: Bool)
}
extension TorchSupport {
var flashOn: Bool {
if let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) {
return device.torchMode == AVCaptureTorchMode.on && device.flashMode == AVCaptureFlashMode.on
}
return false
}
var hasTorch: Bool {
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
return device?.hasTorch ?? false
}
func toggleFlash(to flashOn: Bool) {
let device : AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
do {
if device.hasFlash && device.hasTorch {
try device.lockForConfiguration()
if flashOn {
device.flashMode = AVCaptureFlashMode.on
device.torchMode = AVCaptureTorchMode.on
} else {
device.flashMode = AVCaptureFlashMode.off
device.torchMode = AVCaptureTorchMode.off
}
device.unlockForConfiguration()
}
} catch {
print("Could not lock the camera configuration")
}
}
}
class BarcodeScannerOverlayView : UIView, TorchSupport {
var turnLightOnLabel : UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
_init()
}
override func awakeFromNib() {
super.awakeFromNib()
}
func _init() {
turnLightOnLabel = UILabel()
turnLightOnLabel.translatesAutoresizingMaskIntoConstraints = false
turnLightOnLabel.textColor = UIColor.white
turnLightOnLabel.layer.cornerRadius = 8.0
turnLightOnLabel.clipsToBounds = true
turnLightOnLabel.alpha = 0.8
turnLightOnLabel.text = "Tap to toggle flash"
self.addSubview(turnLightOnLabel)
self.addConstraints(NSLayoutConstraint
.constraints(withVisualFormat: "V:|[turnLightOnLabel(20)]-20-|",
options: NSLayoutFormatOptions.alignAllBottom,
metrics: nil,
views: ["turnLightOnLabel" : turnLightOnLabel]))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
UIView.animate(withDuration: 0.35, animations: {
self.turnLightOnLabel.alpha = 0.0
})
self.toggleFlash(to: true)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
UIView.animate(withDuration: 0.35, animations: {
self.turnLightOnLabel.alpha = 0.8
})
self.toggleFlash(to: false)
}
}
class BarcodeScannerViewController: UIViewController, TorchSupport {
var overlayView: BarcodeScannerOverlayView!
var previewView: UIView!
var scanner : MTBBarcodeScanner!
var context : BarcodeScanContext = BarcodeScanContext()
weak var delegate : BarcodeScannerViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.previewView = UIView(frame: self.view.bounds)
self.previewView.translatesAutoresizingMaskIntoConstraints = false
self.overlayView = BarcodeScannerOverlayView(frame: self.view.bounds)
self.overlayView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(previewView)
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[previewView]", options: NSLayoutFormatOptions.alignAllBottom, metrics: nil, views: ["previewView" : previewView]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[previewView]", options: NSLayoutFormatOptions.alignAllBottom, metrics: nil, views: ["previewView" : previewView]))
// self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[overlayView]", options: NSLayoutFormatOptions.alignAllBottom, metrics: nil, views: ["overlayView" : overlayView]))
// self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[overlayView]", options: NSLayoutFormatOptions.alignAllBottom, metrics: nil, views: ["overlayView" : overlayView]))
scanner = MTBBarcodeScanner(previewView: previewView)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(BarcodeScannerViewController.cancel))
updateFlashButton()
}
private func updateFlashButton() {
if !self.hasTorch {
return
}
if self.flashOn {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Flash Off", style: .plain, target: self, action: #selector(BarcodeScannerViewController.toggle))
} else {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Flash On", style: .plain, target: self, action: #selector(BarcodeScannerViewController.toggle))
}
}
func toggle() {
self.toggleFlash(to: !flashOn)
self.updateFlashButton()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if self.scanner.isScanning() {
self.scanner.stopScanning()
}
MTBBarcodeScanner.requestCameraPermission { (success : Bool) -> Void in
if success {
self.startScan()
} else {
self.showNoCameraAccessAlert()
}
}
}
func cancel() {
self.dismiss(animated: true, completion: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.scanner.stopScanning()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if self.flashOn {
self.toggleFlash(to: false)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
fileprivate func startScan() {
do {
try self.scanner.startScanning(resultBlock: {[weak self] results in
if let code = results?.first {
self?.scanner.stopScanning()
if let strongSelf = self {
self?.delegate?.barcodeScannerViewController(strongSelf, didScanBarcodeWithResult: code.stringValue)
self?.dismiss(animated: true, completion: nil)
}
}
})
} catch {
}
}
fileprivate func showNoCameraAccessAlert() {
let alertController = UIAlertController(title: "Camera access denied", message: "Camera access has been disabled for this application. To turn camera access back on, please go to the iOS settings application.", preferredStyle: .alert);
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
_ = self.navigationController?.popViewController(animated: true)
}))
self.present(alertController, animated: true, completion: nil)
}
}