Files
checker/ios/Runner/ScannerViewController.swift
Ivan Murashov c576c138b6 Menu for ios
2018-04-25 22:35:13 +03:00

435 lines
16 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import UIKit
import Flutter
import DropDown
import ZXingObjC
@objc class ScannerViewController: UIViewController, ZXCaptureDelegate, UITextFieldDelegate {
enum AppLocale {
case ru
case en
}
enum ButtonState {
case card
case phone
var icon: UIImage {
switch self {
case .card: return UIImage(named: "card")!
case .phone: return UIImage(named: "phone")!
}
}
var searchType: String {
switch self {
case .card: return "card"
case .phone: return "phone"
}
}
}
var captureSizeTransform: CGAffineTransform?
var buttonState: ButtonState = .card
var platformChannel: FlutterMethodChannel?
var strings = [String:String]()
let scanRectView = UIView()
let header = UIView()
let textField = UITextField()
let settingsButton = UIButton(type: .system)
let searchType = UIButton(type: .system)
let dropDown = DropDown()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
init(strings: [String: String]) {
super.init(nibName: nil, bundle: nil)
strings.forEach { (k,v) in self.strings[k] = v }
}
func getInputHint() -> String {
switch self.buttonState {
case .card: return strings["enter_manual"]!
case .phone: return strings["enter_phone"]!
}
}
func getErrorText() -> String {
switch self.buttonState {
case .card: return strings["user_card_not_found"]!
case .phone: return strings["user_phone_not_found"]!
}
}
func setButtonState() {
switch self.buttonState {
case .card: self.buttonState = .phone
case .phone: self.buttonState = .card
}
}
let capture: ZXCapture = ZXCapture()
override func viewDidLoad() {
super.viewDidLoad()
view.layer.addSublayer((capture.layer)!)
view.addSubview(scanRectView)
view.addSubview(header)
view.bringSubview(toFront: header)
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(ScannerViewController.hideKeyboard)))
initCamera()
initSearchTypeButton()
initTextFIeld()
initSettingsButton()
initDropDown()
initHeader()
}
private func initCamera() {
capture.camera = capture.back()
capture.focusMode = .continuousAutoFocus
}
private func initHeader() {
header.addSubview(textField)
header.addSubview(searchType)
header.addSubview(settingsButton)
}
private func initTextFIeld() {
textField.delegate = self
textField.placeholder = self.getInputHint()
}
private func initSearchTypeButton() {
searchType.setImage(self.buttonState.icon, for: .normal)
searchType.addTarget(self, action: #selector(ScannerViewController.buttonTouch), for: .touchUpInside)
}
private func initDropDown() {
dropDown.anchorView = settingsButton
dropDown.dataSource = [strings["settings"]!, strings["faq"]!]
dropDown.selectionAction = { (index: Int, item: String) in
if index == 0 {
self.platformChannel?.invokeMethod("settings", arguments: nil)
} else if index == 1 {
self.platformChannel?.invokeMethod("faq", arguments: nil)
}
self.dismiss(animated: false)
}
}
private func initSettingsButton() {
settingsButton.setImage(UIImage(named: "more")!, for: .normal)
settingsButton.addTarget(self, action: #selector(ScannerViewController.settingsTouch), for: .touchUpInside)
}
func hideKeyboard() {
view.endEditing(false)
}
func buttonTouch() {
setButtonState()
searchType.setImage(self.buttonState.icon, for: .normal)
textField.placeholder = self.getInputHint()
}
func settingsTouch() {
dropDown.show()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
header.backgroundColor = UIColor.white
textField.borderStyle = .roundedRect
capture.delegate = self
applyOrientation()
}
// TODO: Вынести эту копипасту в методы, когда будет время
override func viewWillLayoutSubviews() {
// TODO: Надо бы уйти от констант, переписать на отступы какие-нибудь
scanRectView.frame = view.bounds
header.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 56)
searchType.frame = CGRect(x: 8, y: 26, width: 20, height: 20)
textField.frame = CGRect(x: searchType.frame.maxX + 8, y: 21, width: view.frame.size.width - searchType.frame.maxX - 48, height: 30)
settingsButton.frame = CGRect(x: view.frame.size.width - 30, y: 26, width: 20, height: 20)
var path = UIBezierPath()
path.move(to: CGPoint(x: 32, y: view.frame.size.height / 2))
path.addLine(to: CGPoint(x: view.frame.size.width - 32, y: view.frame.size.height / 2))
var shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 2
view.layer.addSublayer(shapeLayer)
path = UIBezierPath()
path.move(to: CGPoint(x: 32, y: (view.frame.size.height / 2) - 32))
path.addLine(to: CGPoint(x: 32, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: 64, y: (view.frame.size.height / 2) - 64))
path.move(to: CGPoint(x: view.frame.size.width - 64, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: view.frame.size.width - 32, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: view.frame.size.width - 32, y: (view.frame.size.height / 2) - 32))
path.move(to: CGPoint(x: 32, y: (view.frame.size.height / 2) + 32))
path.addLine(to: CGPoint(x: 32, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: 64, y: (view.frame.size.height / 2) + 64))
path.move(to: CGPoint(x: view.frame.size.width - 32, y: (view.frame.size.height / 2) + 32))
path.addLine(to: CGPoint(x: view.frame.size.width - 32, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: view.frame.size.width - 64, y: (view.frame.size.height / 2) + 64))
shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 2
view.layer.addSublayer(shapeLayer)
path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 56))
path.addLine(to: CGPoint(x: view.frame.size.width, y: 56))
path.addLine(to: CGPoint(x: view.frame.size.width, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: 0, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: 0, y: 56))
path.close()
shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5).cgColor
view.layer.addSublayer(shapeLayer)
path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: 32, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: 32, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: 0, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: 0, y: (view.frame.size.height / 2) - 64))
path.close()
shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5).cgColor
view.layer.addSublayer(shapeLayer)
path = UIBezierPath()
path.move(to: CGPoint(x: view.frame.size.width, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: view.frame.size.width - 32, y: (view.frame.size.height / 2) - 64))
path.addLine(to: CGPoint(x: view.frame.size.width - 32, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: view.frame.size.width, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: view.frame.size.width, y: (view.frame.size.height / 2) - 64))
path.close()
shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5).cgColor
view.layer.addSublayer(shapeLayer)
path = UIBezierPath()
path.move(to: CGPoint(x: view.frame.size.width, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: 0, y: (view.frame.size.height / 2) + 64))
path.addLine(to: CGPoint(x: 0, y: view.frame.size.height))
path.addLine(to: CGPoint(x: view.frame.size.width, y: view.frame.size.height))
path.addLine(to: CGPoint(x: view.frame.size.width, y: (view.frame.size.height / 2) + 64))
path.close()
shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5).cgColor
view.layer.addSublayer(shapeLayer)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print("User from manual input: \(textField.text!)")
sendResult(textField.text!)
return true
}
func sendResult(_ str: String) {
platformChannel?.invokeMethod("findUser", arguments: [str, buttonState.searchType], result: { (result: Any?) in
if result is FlutterError {
print("Result is nil (ios code)");
self.showErrorAlert(str)
} else {
print("Result is not nil (ios code)");
self.dismiss(animated: true) {
self.platformChannel?.invokeMethod("purchase", arguments: [result, str])
}
}
})
}
func showErrorAlert(_ str: String) {
let alertController = UIAlertController(
title: strings["error"]!,
message: String(format: self.getErrorText(), str),
preferredStyle: UIAlertControllerStyle.alert
)
alertController.addAction(UIAlertAction(title: strings["dismiss"]!, style: UIAlertActionStyle.default,handler: nil))
self.present(alertController, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
deinit {
capture.layer.removeFromSuperlayer()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: {(_ context: UIViewControllerTransitionCoordinatorContext) -> Void in
}, completion: {(_ context: UIViewControllerTransitionCoordinatorContext) -> Void in
self.applyOrientation()
})
}
func applyOrientation() {
print("APPLY ORIENTATION")
let orientation: UIInterfaceOrientation = UIApplication.shared.statusBarOrientation
var scanRectRotation: Float
var captureRotation: Float
switch orientation {
case .portrait:
captureRotation = 0
scanRectRotation = 90
case .landscapeLeft:
captureRotation = 90
scanRectRotation = 180
case .landscapeRight:
captureRotation = 270
scanRectRotation = 0
case .portraitUpsideDown:
captureRotation = 180
scanRectRotation = 270
default:
captureRotation = 0
scanRectRotation = 90
}
applyRectOfInterest(orientation)
let transform = CGAffineTransform(rotationAngle: CGFloat(captureRotation / 180 * .pi))
capture.transform = transform
capture.rotation = CGFloat(scanRectRotation)
capture.layer.frame = view.frame
}
func applyRectOfInterest(_ orientation: UIInterfaceOrientation) {
var scaleVideo: CGFloat
var scaleVideoX: CGFloat
var scaleVideoY: CGFloat
var videoSizeX: CGFloat
var videoSizeY: CGFloat
var transformedVideoRect: CGRect = scanRectView.frame
videoSizeX = 720
videoSizeY = 1280
if UIInterfaceOrientationIsPortrait(orientation) {
scaleVideoX = view.frame.size.width / videoSizeX
scaleVideoY = view.frame.size.height / videoSizeY
scaleVideo = max(scaleVideoX, scaleVideoY)
if scaleVideoX > scaleVideoY {
transformedVideoRect.origin.y += (scaleVideo * videoSizeY - view.frame.size.height) / 2
}
else {
transformedVideoRect.origin.x += (scaleVideo * videoSizeX - view.frame.size.width) / 2
}
}
else {
scaleVideoX = view.frame.size.width / videoSizeY
scaleVideoY = view.frame.size.height / videoSizeX
scaleVideo = max(scaleVideoX, scaleVideoY)
if scaleVideoX > scaleVideoY {
transformedVideoRect.origin.y += (scaleVideo * videoSizeX - view.frame.size.height) / 2
}
else {
transformedVideoRect.origin.x += (scaleVideo * videoSizeY - view.frame.size.width) / 2
}
}
captureSizeTransform = CGAffineTransform(scaleX: 1 / scaleVideo, y: 1 / scaleVideo)
capture.scanRect = transformedVideoRect.applying(captureSizeTransform!)
}
// MARK: - Private Methods
func barcodeFormat(toString format: ZXBarcodeFormat) -> String {
switch format {
case kBarcodeFormatAztec:
return "Aztec"
case kBarcodeFormatCodabar:
return "CODABAR"
case kBarcodeFormatCode39:
return "Code 39"
case kBarcodeFormatCode93:
return "Code 93"
case kBarcodeFormatCode128:
return "Code 128"
case kBarcodeFormatDataMatrix:
return "Data Matrix"
case kBarcodeFormatEan8:
return "EAN-8"
case kBarcodeFormatEan13:
return "EAN-13"
case kBarcodeFormatITF:
return "ITF"
case kBarcodeFormatPDF417:
return "PDF417"
case kBarcodeFormatQRCode:
return "QR Code"
case kBarcodeFormatRSS14:
return "RSS 14"
case kBarcodeFormatRSSExpanded:
return "RSS Expanded"
case kBarcodeFormatUPCA:
return "UPCA"
case kBarcodeFormatUPCE:
return "UPCE"
case kBarcodeFormatUPCEANExtension:
return "UPC/EAN extension"
default:
return "Unknown"
}
}
// MARK: - ZXCaptureDelegate Methods
func captureResult(_ capture: ZXCapture, result: ZXResult) {
let inverse: CGAffineTransform = captureSizeTransform!.inverted()
var points = [AnyHashable]()
var location = ""
for resultPoint in result.resultPoints {
let p = resultPoint as! ZXResultPoint
let cgPoint = CGPoint(x: CGFloat(p.x), y: CGFloat(p.y))
var transformedPoint: CGPoint = cgPoint.applying(inverse)
transformedPoint = scanRectView.convert(transformedPoint, to: scanRectView.window)
let windowPointValue = NSValue(cgPoint: transformedPoint)
location = "\(location) (\(transformedPoint.x), \(transformedPoint.y))"
points.append(windowPointValue)
}
print("User from scanner: \(result.text)")
sendResult(result.text)
print(result.text)
self.capture.stop()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(2 * Double(NSEC_PER_SEC)) / Double(NSEC_PER_SEC), execute: {() -> Void in
self.capture.start()
})
}
}