Last active
October 3, 2019 08:23
-
-
Save yaakovgamliel/6174c787e9afe2afe07229b51fbe83af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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