// // ScannerController.swift // Befund // // Created by Artur Savitskiy on 29.08.22. // Copyright © 2022 MVZ Dr. Stein und Kollegen. All rights reserved. // import AVFoundation import UIKit class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { var captureSession: AVCaptureSession! var previewLayer: AVCaptureVideoPreviewLayer! var scanFailed: Bool = false var laborIsSelected: Bool = false private var isBarcodeScan = false @IBOutlet weak var btnBack: UIButton! enum CameraAutorizationStatus{ case None case Autorized case Declined } public static func InitScannerController( scanSampleID: Bool) -> ScannerViewController { let storyboard = UIStoryboard(name: "Main", bundle: nil) let scanController = storyboard.instantiateViewController(identifier: "ScannerController") as ScannerViewController scanController.isBarcodeScan = scanSampleID return scanController } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.gray } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let status = self.checkCameraAutorizationStatus() if ( status == CameraAutorizationStatus.Declined) { failedWithAlert() } else if (status == CameraAutorizationStatus.Autorized) { StartCapture() } } private func StartCapture() { if (captureSession == nil) { captureSession = AVCaptureSession() guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { failed() return } let videoInput: AVCaptureDeviceInput do { videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice) } catch { failed() return } if (captureSession.canAddInput(videoInput)) { captureSession.addInput(videoInput) } else { failed() return } let metadataOutput = AVCaptureMetadataOutput() if (captureSession.canAddOutput(metadataOutput)) { captureSession.addOutput(metadataOutput) metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) if (isBarcodeScan) { metadataOutput.metadataObjectTypes = [.code128, .code39, .code39Mod43, .code93, .ean13, .ean8, .interleaved2of5, .itf14, .pdf417, .upce] } else { metadataOutput.metadataObjectTypes = [.qr] } } else { failed() return } previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.frame = view.layer.bounds previewLayer.videoGravity = .resizeAspectFill view.layer.addSublayer(previewLayer) btnBack.superview?.bringSubviewToFront(btnBack); } if (captureSession?.isRunning == false) { captureSession.startRunning() } } func checkCameraAutorizationStatus() -> CameraAutorizationStatus { switch AVCaptureDevice.authorizationStatus(for: .video) { case .authorized: return CameraAutorizationStatus.Autorized case .notDetermined: AVCaptureDevice.requestAccess(for: .video) { granted in if granted { DispatchQueue.main.async { self.StartCapture() } } else { DispatchQueue.main.async { self.return2MainWindow() } } } return CameraAutorizationStatus.None case .denied: return CameraAutorizationStatus.Declined case .restricted: return CameraAutorizationStatus.Declined @unknown default: return CameraAutorizationStatus.Declined } } func failed() { scanFailed = true captureSession = nil failedWithAlert() } func failedWithAlert() { let ac = UIAlertController(title: Core.Lang.Get(key: "LBL_SCAN_NOT_SUPPORTED"), message: Core.Lang.Get(key: "MSG_SCAN_NOT_SUPPORTED"), preferredStyle: .alert) ac.addAction(UIAlertAction(title: "OK", style: .default, handler: failedWithAlertOk)) let settingsAction = UIAlertAction(title: "Einstellungen", style: .default, handler: OpenSettings) ac.addAction(settingsAction) self.present(ac, animated: true, completion: nil) } func OpenSettings(alert: UIAlertAction!) { guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else { return } if (UIApplication.shared.canOpenURL(settingsUrl)){ UIApplication.shared.open(settingsUrl) } } func failedWithAlertOk(alert: UIAlertAction!) { #if DEBUG if (isBarcodeScan) { self.foundBarcode(code: "123456789ABCDE") } else { self.found(code: "befund://labor?id=LIS_SIMULATOR") } //self.found(code: "befund://labor?id=LABOR_MOENCHENGLADBACH") #endif if (!laborIsSelected) { self.return2MainWindow() } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if (captureSession?.isRunning == true) { captureSession.stopRunning() } } func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { captureSession.stopRunning() if let metadataObject = metadataObjects.first { guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return } guard let stringValue = readableObject.stringValue else { return } AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) if (isBarcodeScan) { foundBarcode(code: stringValue) } else { found(code: stringValue) } } dismiss(animated: true) } func found(code: String) { if(code.count>0) { let posIndex = code.range(of: "id=")!.lowerBound let index = code.distance(from: code.startIndex, to: posIndex) let substr = code.dropFirst(index) let labID = substr.replacingOccurrences(of: "id=", with: "") let labor = Core.Models.Labor.GetLaborByName(id: labID) if (labor.id.count>0) { self.SelectLabor(labor: labor) self.return2MainWindow() } } } func foundBarcode(code: String) { if(code.count>0) { ViewController.currentlySelectedBarcode = code self.return2MainWindow() } } func SelectLabor(labor: Core.Models.Labor) { var settings = Core.Models.Settings.loadFromFile(atPath: Core.System.SettingsPath()) if (settings == nil) { settings = Core.Models.Settings() } settings!.labor = labor laborIsSelected = settings!.save(atPath: Core.System.SettingsPath()) } @IBAction func goBack(_ sender: Any) { self.return2MainWindow() } private func return2MainWindow() { self.view.endEditing(true) self.dismiss(animated: true, completion: nil) } override var prefersStatusBarHidden: Bool { return true } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } }