Skip to content

Instantly share code, notes, and snippets.

@yaakovgamliel
Last active October 3, 2019 08:23
Show Gist options
  • Save yaakovgamliel/6174c787e9afe2afe07229b51fbe83af to your computer and use it in GitHub Desktop.
Save yaakovgamliel/6174c787e9afe2afe07229b51fbe83af to your computer and use it in GitHub Desktop.
//
// OverlayViewController.swift
// pos
//
//
import UIKit
import Core
import MicroBlink
import DropDown
class RecognizerProvider {
var pdf417Recognizer : MBPdf417Recognizer?
var barcodeRecognizer : MBBarcodeRecognizer?
func controller(transaction: OngoingTransaction) -> UIViewController? {
guard let license = VaultStore().storedVault(key: ApiKeys.microblink_v4_9) else {
Loggly.client.send(events: ["event": "failed_to_load_mb_sdk"])
return nil
}
Loggly.client.send(events: ["event": "starting_mb_sdk"])
MBMicroblinkSDK.sharedInstance().setLicenseKey(license)
/** Create barcode recognizer */
self.barcodeRecognizer = MBBarcodeRecognizer()
self.barcodeRecognizer?.scanQrCode = true
self.pdf417Recognizer = MBPdf417Recognizer()
self.pdf417Recognizer?.scanUncertain = true
/** Crate recognizer collection */
let recognizerList = [self.pdf417Recognizer!, self.barcodeRecognizer!]
let recognizerCollection = MBRecognizerCollection(recognizers: recognizerList)
/** Create your overlay view controller */
let customOverlayViewController = OverlayViewController.instantiate(transaction: transaction)
/** This has to be called for custom controller */
customOverlayViewController.reconfigureRecognizers(recognizerCollection)
/** Create recognizer view controller with wanted overlay view controller */
return MBViewControllerFactory.recognizerRunnerViewController(
withOverlayViewController: customOverlayViewController)
}
}
class OverlayViewModel {
func userMock() -> Bool {
return AppEnvironment.current.mock
}
func patchCustomerState(customer: Customer, state: State) -> Customer {
var patched = Customer.create().update(from: customer)
patched.addressDetails = nil
patched.drivingLicenseState = Defaults.nonApplicableState
return patched
}
func needsStatePatching(customer: Customer) -> Bool {
let address = customer.addressDetails
if address?.state?.rawValue.isEmpty == true || address?.state == nil {
return true
}
return false
}
}
//class OverlayViewController: MBCustomOverlayViewController, LifetimeTrackable {
class OverlayViewController: MBCustomOverlayViewController {
let viewModel = OverlayViewModel()
@IBOutlet weak var scannerMockButton: UIButton!
@IBOutlet var cameraOverlayView: ScannerCameraOverlayView!
@IBOutlet weak var resumeScanningLabel: UILabel!
@IBOutlet weak var labelTitle: UILabel!
@IBOutlet weak var hintLabel: UILabel!
@IBOutlet weak var hintButton: HintActionButton!
@IBOutlet weak var cameraHelpImageView: UIImageView!
@IBOutlet weak var manualDetailsButton: UIButton!
@IBOutlet weak var resumeScannningButton: UIButton!
fileprivate lazy var phoneVerificationController = CustomerPhoneVerificationViewController.instantiate()
fileprivate var transaction: OngoingTransaction?
fileprivate var idleTimer: Timer = Timer()
fileprivate var dlDetected: Bool = false
deinit {
print("[*] Unloading ............. \(self.description)")
}
internal static func instantiate(transaction: OngoingTransaction) -> OverlayViewController {
let vc = Storyboard.scanner.instantiate(OverlayViewController.self)
vc.transaction = transaction
return vc
}
internal static func instantiate() -> OverlayViewController {
return Storyboard.scanner.instantiate(OverlayViewController.self)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
EventReporter.shared.breadcrumbs(message: "\(self.description) init")
}
override func viewDidLoad() {
super.viewDidLoad()
super.scanningRecognizerRunnerViewControllerDelegate = self
setupUI()
manualEntrySetup()
setupIdleTimer()
//Handle here manual entry button timer
phoneVerificationController.customerVerificationDelegate = self
let resumeBtn = UIButton.init(frame: resumeScanningLabel.bounds)
resumeBtn.sizeToFit()
resumeBtn.addTarget(self, action: #selector(awakeScanner), for: .touchUpInside)
cameraHelpImageView.addSubview(resumeBtn)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
#if SELFAPPLY
SelfApplicationHelper.shared.screenMark.isHidden = false
#endif
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
idleTimer.invalidate()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
scanningRecognizerRunnerViewControllerDelegate = nil
recognizerRunnerViewControllerDelegate = nil
recognizerRunnerViewController = nil
}
private func setupIdleTimer() {
idleTimer = Timer.scheduledTimer(
timeInterval: 60.0,
target: self,
selector: #selector(idleActiveCamera),
userInfo: nil,
repeats: false
)
}
fileprivate func restartScannerIfNeed() {
if recognizerRunnerViewController?.isCameraPaused() == true {
recognizerRunnerViewController?.resumeCamera()
}
if recognizerRunnerViewController?.isScanningPaused() == true {
recognizerRunnerViewController?.resumeScanningAndResetState(true)
resumeScanningLabel.isHidden = true
}
}
func setupUI() {
navigationController?.setColorMode(mode: .blue)
self.navigationController?.setClearBackground()
self.resumeScanningLabel.isHidden = true
cameraOverlayView.alpha = 0.4
cameraOverlayView.backgroundColor = .black
if viewModel.userMock() {
scannerMockButton.isHidden = false
}
#if SELFAPPLY
SelfApplicationHelper.shared.screenMark.isHidden = false
#endif
}
@objc func idleActiveCamera() {
recognizerRunnerViewController?.pauseScanning()
self.resumeScanningLabel.isHidden = false
}
func handleLicenseExpiration(presenter: UIViewController) {
guard let state = transaction?.retailer?.addressDetails?.state else {
return
}
self.failureAlert(title: Messages.expirationTitle(),
message: Messages.driverLicenseExpiration(state: state.rawValue))?
.present(with: presenter)
}
func failureAlert(title: String, message: String) -> GeneralAlert? {
return GeneralAlert.with(title: title,
body: message,
cancelAction: { self.navigateBack() })
}
}
extension OverlayViewController: MBScanningRecognizerRunnerViewControllerDelegate {
func recognizerRunnerViewController(_ recognizerRunnerViewController: UIViewController & MBRecognizerRunnerViewController,
didFinishScanningWith state: MBRecognizerResultState) {
SunbitUIEventNotifier().resetTimerNotification()
if dlDetected { return }
if state == MBRecognizerResultState.valid {
DispatchQueue.main.sync { [weak self] in
guard let s = self else { return }
s.recognizerRunnerViewController?.pauseScanning()
s.recognizerRunnerViewController?.pauseCamera()
for recognizer in s.recognizerCollection.recognizerList where
recognizer.baseResult?.resultState == MBRecognizerResultState.valid && recognizer is MBPdf417Recognizer {
let pdf417Recognizer = recognizer as? MBPdf417Recognizer
if let rawData = pdf417Recognizer?.result.stringData {
s.dlDetected = true
s.talkToService(rawData: rawData)
}
}
}
}
}
func talkToService(rawData: String) {
<to talk to our servers>
}
}
extension OverlayViewController {
@IBAction func hintButtonTouched(sender: Any?) {
if hintLabel.alpha == 0.0 {
fadeInHint()
} else {
fadeOutHint()
}
}
@IBAction func resumeScanningTouched(_ sender: Any) {
awakeScanner()
setupIdleTimer()
}
private func fadeOutHint() {
UIView.animate(withDuration: 0.3, animations: {
self.hintButton.setTitle("How do I scan?", for: .normal)
self.hintButton.setImage(#imageLiteral(resourceName: "hintScanIcon"), for: .normal)
self.hintLabel.alpha = 0.0
self.cameraHelpImageView.alpha = 0.0
})
}
private func fadeInHint() {
UIView.animate(withDuration: 0.3, animations: {
self.hintButton.setTitle("Cancel", for: .normal)
self.hintButton.setImage(#imageLiteral(resourceName: "selfApplyCancelBtn"), for: .normal)
self.hintLabel.alpha = 1.0
self.cameraHelpImageView.alpha = 1.0
})
}
}
extension OverlayViewController: UserMockDelegate {
@IBAction func userMockTouched(_ sender: UIButton) {
let mockVC = UsersMockController.init(style: .plain)
mockVC.mockControllerDelegate = self
mockVC.modalPresentationStyle = .popover
present(mockVC, animated: true, completion: nil)
let popover = mockVC.popoverPresentationController
popover?.sourceView = self.view
}
func didSelect(customer: Customer?, controller: UITableViewController) {
guard let c = customer else { return }
guard self.transaction != nil else { return }
var mockCustomer = c
mockCustomer.isTest = true
self.transaction?.customer = mockCustomer
controller.dismiss(animated: true, completion: nil)
guard let customer = transaction?.customer else { return }
if viewModel.needsStatePatching(customer: customer) {
guard let retailerState = transaction?.retailer?.addressDetails?.state else { return }
transaction?.customer = viewModel.patchCustomerState(customer: customer, state: retailerState)
navigate()
} else {
navigate()
}
}
func navigate() {
DispatchQueue.main.asyncAfter(deadline: .secondsFromNow(1.0)) { [weak self] in
guard let t = self?.transaction else { return }
POSRouter().route(route: .phoneEmailVerification, transaction: t)
}
}
func navigateBack() {
self.navigationController?.popViewController(animated: true)
}
func navigateToManualFunnel() {
guard let t = transaction else { return }
POSRouter().route(route: .manualDetails, transaction: t)
}
@objc func awakeScanner() {
restartScannerIfNeed()
}
}
struct ManualFunnelStates: Codable {
let states: [String]
}
extension OverlayViewController {
@IBAction func manualEntryButtonTouched(_ sender: UIButton) {
guard let transaction = self.transaction else { return }
phoneVerificationController.viewModel.update(transaction: transaction)
present(phoneVerificationController, animated: true) {
}
}
func manualEntrySetup() {
if transaction?.retailer?.originator != .tab { return }
var displayAfter: Double
if let t = VaultStore.init().storedVault(key: RemoteParameters.manualFunnelShowtime) {
displayAfter = Double(t) ?? Defaults.manualEntryOptionDisplayDelay
} else {
displayAfter = Defaults.manualEntryOptionDisplayDelay
}
DispatchQueue
.main
.asyncAfter(deadline: .secondsFromNow(displayAfter)) { [weak self] in
self?.manualDetailsButton.isEnabled = true
self?.manualDetailsButton.isHidden = false
}
}
}
extension OverlayViewController: CustomerPhoneVerificationDelegate {
func shouldPopPresenterController() {
navigationController?.popViewController(animated: true)
}
func customerPhoneVerificationSucced(transaction: OngoingTransaction) {
self.transaction?.phoneVerification = transaction.phoneVerification
self.transaction?.customer = transaction.purchase?.customer
self.transaction?.purchase = transaction.purchase
navigateToManualFunnel()
}
func customerPhoneVerificationFailed() {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment