// // QRScannerVC.swift // Sirani // // Created by Anhar Solehudin on 10/04/19. // Copyright © 2019 Anhar Solehudin. All rights reserved. // import UIKit import AVFoundation class QRScannerVC: UIViewController { // Outlets @IBOutlet weak var scannerView: UIView! @IBOutlet weak var overlayTop: UIView! @IBOutlet weak var overlayLeft: UIView! @IBOutlet weak var overlayRight: UIView! @IBOutlet weak var overlayBottom: UIView! @IBOutlet weak var btnCloseScanner: UIButton! @IBOutlet weak var resultLayout: UIView! @IBOutlet weak var contentLayout: UIView! @IBOutlet weak var lblNoSertifikat: UILabel! @IBOutlet weak var lblTanggalSertifikat: UILabel! @IBOutlet weak var lblPlgId: UILabel! @IBOutlet weak var lblPerusahaan: UILabel! @IBOutlet weak var lblNamaPerangkat: UILabel! @IBOutlet weak var lblMerk: UILabel! @IBOutlet weak var lblModel: UILabel! @IBOutlet weak var lblImei: UILabel! @IBOutlet weak var lblPabrikan: UILabel! @IBOutlet weak var lblNegara: UILabel! @IBOutlet weak var lblAcuan: UILabel! @IBOutlet weak var lblFrek: UILabel! @IBOutlet weak var lblPower: UILabel! @IBOutlet weak var progressLoadingLayout: UIView! @IBOutlet weak var progressLoading: UIActivityIndicatorView! private var captureSession = AVCaptureSession() private var videoPreviewLayer: AVCaptureVideoPreviewLayer? private var qrCodeFrameView: UIView? private var dataCaptured = false private let supportedCodeTypes = [ AVMetadataObject.ObjectType.upce, AVMetadataObject.ObjectType.code39, AVMetadataObject.ObjectType.code39Mod43, AVMetadataObject.ObjectType.code93, AVMetadataObject.ObjectType.code128, AVMetadataObject.ObjectType.ean8, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.aztec, AVMetadataObject.ObjectType.pdf417, AVMetadataObject.ObjectType.itf14, AVMetadataObject.ObjectType.dataMatrix, AVMetadataObject.ObjectType.interleaved2of5, AVMetadataObject.ObjectType.qr ] // Initialize private var presenter: QRScannerPresenter = QRScannerPresenter(siraniApiServices: SiraniApiServices()) // Constant Values private let alertNoConnectionTitle = "Informasi" private let alertNoConnectionMsg = "Sepertinya Anda sedang tidak tersambung pada koneksi internet" private let alertNoConnectionActionYes = "OK" // variables private var loading = false var kode : Int? var isSertifikatNew = false var isSertifikatPublic = false var isLabel = false // View Lifecycles override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } override func viewWillAppear(_ animated: Bool) { AppUtility.lockOrientation(.portrait) if let kode = self.kode { onQrDataAvailable(decodedString: "\(kode)") dataCaptured = true } } override func viewDidLoad() { super.viewDidLoad() contentLayout.layer.borderWidth = 1 contentLayout.layer.borderColor = #colorLiteral(red: 0.0171101559, green: 0.3341715932, blue: 0.704000771, alpha: 1) presenter.attachView(view: self) dataCaptured = false // scanner view // Get the back-facing camera for capturing videos let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back) guard let captureDevice = deviceDiscoverySession.devices.first else { print("Failed to get the camera device") return } do { // Get an instance of the AVCaptureDeviceInput class using the previous device object. let input = try AVCaptureDeviceInput(device: captureDevice) // Set the input device on the capture session. captureSession.addInput(input) // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session. let captureMetadataOutput = AVCaptureMetadataOutput() captureSession.addOutput(captureMetadataOutput) // Set delegate and use the default dispatch queue to execute the call back captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) // captureMetadataOutput.metadataObjectTypes = supportedCodeTypes captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr] } catch { // If any error occurs, simply print it out and don't continue any more. print(error) return } // 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 = scannerView.layer.bounds scannerView.layer.addSublayer(videoPreviewLayer!) // Start video capture. captureSession.startRunning() // bring scanner controller views scannerView.bringSubviewToFront(overlayTop) scannerView.bringSubviewToFront(overlayLeft) scannerView.bringSubviewToFront(overlayRight) scannerView.bringSubviewToFront(overlayBottom) scannerView.bringSubviewToFront(btnCloseScanner) // Initialize QR Code Frame to highlight the QR code qrCodeFrameView = UIView() if let qrCodeFrameView = qrCodeFrameView { qrCodeFrameView.layer.borderColor = UIColor.green.cgColor qrCodeFrameView.layer.borderWidth = 2 scannerView.addSubview(qrCodeFrameView) scannerView.bringSubviewToFront(qrCodeFrameView) } } override func viewWillDisappear(_ animated: Bool) { AppUtility.lockOrientation(.all) } override func viewDidDisappear(_ animated: Bool) { presenter.detachView() } // private function private func loadData(code: String) { if !loading { if ConnectionHelper.isConnectedToNetwork() { presenter.loadData(code: code) } else { showNoConnection() } } } private func onQrDataEmpty() { resultLayout.show() scannerView.hide() DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { self.setEmptyQrCode() } } private func onQrDataAvailable(decodedString: String) { resultLayout.show() scannerView.hide() DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { self.loadData(code: decodedString) } } // Actions @IBAction func onBtnBackTap(_ sender: Any) { if(kode != nil) { if(isSertifikatNew){ performSegue(withIdentifier: "unwindToSertifikatSegueId", sender: self) }else if(isSertifikatPublic){ performSegue(withIdentifier: "unwindToSertifikatPublicSegueId", sender: self) }else if(isLabel){ performSegue(withIdentifier: "unwindToLabelSegueId", sender: self) }else{ performSegue(withIdentifier: "unwindToDaftarSertifikatSegueId", sender: self) } } else { performSegue(withIdentifier: "unwindToScanQrSegueId", sender: self) } } @IBAction func onBtnCloseScannerTap(_ sender: Any) { if(kode != nil) { if(isSertifikatNew){ performSegue(withIdentifier: "unwindToSertifikatSegueId", sender: self) }else if(isSertifikatPublic){ performSegue(withIdentifier: "unwindToSertifikatPublicSegueId", sender: self) }else{ performSegue(withIdentifier: "unwindToDaftarSertifikatSegueId", sender: self) } } else { performSegue(withIdentifier: "unwindToScanQrSegueId", sender: self) } } } extension QRScannerVC: QRScannerViewDelegate { func showNoConnection() { let alertNoConnection = UIAlertController( title: alertNoConnectionTitle, message: alertNoConnectionMsg, preferredStyle: .alert ) alertNoConnection.addAction( UIAlertAction(title: alertNoConnectionActionYes, style: .default, handler: nil) ) self.present(alertNoConnection, animated: true, completion: nil) } func showLoading() { loading = true progressLoading.startAnimating() progressLoadingLayout.show() } func hideLoading() { loading = false progressLoading.stopAnimating() progressLoadingLayout.hide() } func setResulQrCode(resultQrCode: ResultQrCode) { var tglSert = "" if (resultQrCode.lic_date == "null" || resultQrCode.lic_date.isEmpty) { tglSert = "" } else { let inputFormatter = DateFormatter() inputFormatter.dateFormat = "yyyy-MM-dd" let expDateString = String(resultQrCode.lic_date.prefix(10)) if let output = inputFormatter.date(from: expDateString) { let outputFormatter = DateFormatter() outputFormatter.dateFormat = "dd MMMM yyyy" tglSert = outputFormatter.string(from: output) } } lblNoSertifikat.text = resultQrCode.lic_no lblTanggalSertifikat.text = tglSert lblPlgId.text = String(resultQrCode.cust_id) lblPerusahaan.text = resultQrCode.pmh_name lblNamaPerangkat.text = resultQrCode.eqp_name lblMerk.text = resultQrCode.merk lblModel.text = resultQrCode.model lblImei.text = resultQrCode.imei lblPabrikan.text = resultQrCode.mfc_name lblNegara.text = resultQrCode.negara lblAcuan.text = resultQrCode.acuan lblFrek.text = resultQrCode.eqp_frek lblPower.text = resultQrCode.eqp_power } func setEmptyQrCode() { let alertNoConnection = UIAlertController( title: "Informasi", message: "Data tidak ditemukan", preferredStyle: .alert ) alertNoConnection.addAction( UIAlertAction(title: "OK", style: .default, handler: nil) ) self.present(alertNoConnection, animated: true, completion: nil) } } extension QRScannerVC: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { if !dataCaptured { print("TEST SCAN") print(metadataObjects.count) print(metadataObjects) // Check if the metadataObjects array is not nil and it contains at least one object. if metadataObjects.count == 0 { onQrDataEmpty() dataCaptured = true return } // Get the metadata object. let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if supportedCodeTypes.contains(metadataObj.type) { // If the found metadata is equal to the QR code metadata (or barcode) then update the status label's text and set the bounds let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) qrCodeFrameView?.frame = barCodeObject!.bounds if metadataObj.stringValue != nil { if let url = URL(string: metadataObj.stringValue ?? "") { let lic_id = url.lastPathComponent onQrDataAvailable(decodedString: lic_id) dataCaptured = true } } } } } }