浏览代码

integrated qrReader

nayooti 5 年之前
父节点
当前提交
36e52553c8
共有 1 个文件被更改,包括 186 次插入6 次删除
  1. 186 6
      deltachat-ios/Controller/QRPageController.swift

+ 186 - 6
deltachat-ios/Controller/QRPageController.swift

@@ -4,6 +4,8 @@ import DcCore
 class QRPageController: UIPageViewController {
 class QRPageController: UIPageViewController {
 
 
     private let dcContext: DcContext
     private let dcContext: DcContext
+    weak var coordinator: QrViewCoordinator?
+    var secureJoinObserver: Any?
 
 
     var selectedIndex: Int = 0
     var selectedIndex: Int = 0
 
 
@@ -12,10 +14,10 @@ class QRPageController: UIPageViewController {
         return controller
         return controller
     }()
     }()
 
 
-    private lazy var qrCameraController: UIViewController = {
-        let vc = UIViewController()
-        vc.view.backgroundColor = .green
-        return vc
+    private lazy var qrCodeReaderController: QrCodeReaderController = {
+        let qrReader = QrCodeReaderController()
+        qrReader.delegate = self
+        return qrReader
     }()
     }()
 
 
     private lazy var qrSegmentControl: UISegmentedControl = {
     private lazy var qrSegmentControl: UISegmentedControl = {
@@ -25,6 +27,22 @@ class QRPageController: UIPageViewController {
         return control
         return control
     }()
     }()
 
 
+    private lazy var progressAlert: UIAlertController = {
+        var title = String.localized("one_moment")+"\n\n"
+        let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
+
+        let rect = CGRect(x: 0, y: 0, width: 25, height: 25)
+        let activityIndicator = UIActivityIndicatorView(frame: rect)
+        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
+        activityIndicator.style = .gray
+
+        alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .default, handler: { _ in
+            self.dcContext.stopOngoingProcess()
+            self.dismiss(animated: true, completion: nil)
+        }))
+        return alert
+    }()
+
     init(dcContext: DcContext) {
     init(dcContext: DcContext) {
         self.dcContext = dcContext
         self.dcContext = dcContext
         super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
         super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
@@ -53,7 +71,7 @@ class QRPageController: UIPageViewController {
         if sender.selectedSegmentIndex == 0 {
         if sender.selectedSegmentIndex == 0 {
             setViewControllers([qrController], direction: .reverse, animated: true, completion: nil)
             setViewControllers([qrController], direction: .reverse, animated: true, completion: nil)
         } else {
         } else {
-            setViewControllers([qrCameraController], direction: .forward, animated: true, completion: nil)
+            setViewControllers([qrCodeReaderController], direction: .forward, animated: true, completion: nil)
         }
         }
     }
     }
 }
 }
@@ -69,7 +87,7 @@ extension QRPageController: UIPageViewControllerDataSource, UIPageViewController
 
 
     func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
     func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
         if viewController is QrViewController {
         if viewController is QrViewController {
-            return qrCameraController
+            return qrCodeReaderController
         }
         }
         return nil
         return nil
     }
     }
@@ -84,3 +102,165 @@ extension QRPageController: UIPageViewControllerDataSource, UIPageViewController
         }
         }
     }
     }
 }
 }
+
+// MARK: - QRCodeDelegate
+extension QRPageController: QrCodeReaderDelegate {
+
+    func handleQrCode(_ code: String) {
+        qrCodeReaderController.dismiss(animated: true) {
+            self.processQrCode(code)
+        }
+    }
+
+    private func processQrCode(_ code: String) {
+        let qrParsed: DcLot = self.dcContext.checkQR(qrCode: code)
+        let state = Int32(qrParsed.state)
+        switch state {
+        case DC_QR_ASK_VERIFYCONTACT:
+            let nameAndAddress = DcContact(id: qrParsed.id).nameNAddr
+            joinSecureJoin(alertMessage: String.localizedStringWithFormat(String.localized("ask_start_chat_with"), nameAndAddress), code: code)
+
+        case DC_QR_ASK_VERIFYGROUP:
+            let groupName = qrParsed.text1 ?? "ErrGroupName"
+            joinSecureJoin(alertMessage: String.localizedStringWithFormat(String.localized("qrscan_ask_join_group"), groupName), code: code)
+
+        case DC_QR_FPR_WITHOUT_ADDR:
+            let msg = String.localized("qrscan_no_addr_found") + "\n\n" +
+                String.localized("qrscan_fingerprint_label") + ":\n" + (qrParsed.text1 ?? "")
+            let alert = UIAlertController(title: msg, message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
+            present(alert, animated: true, completion: nil)
+
+        case DC_QR_FPR_MISMATCH:
+            let nameAndAddress = DcContact(id: qrParsed.id).nameNAddr
+            let msg = String.localizedStringWithFormat(String.localized("qrscan_fingerprint_mismatch"), nameAndAddress)
+            let alert = UIAlertController(title: msg, message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
+            present(alert, animated: true, completion: nil)
+
+        case DC_QR_ADDR, DC_QR_FPR_OK:
+            let nameAndAddress = DcContact(id: qrParsed.id).nameNAddr
+            let msg = String.localizedStringWithFormat(String.localized(state==DC_QR_ADDR ? "ask_start_chat_with" : "qrshow_x_verified"), nameAndAddress)
+            let alert = UIAlertController(title: msg, message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: String.localized("start_chat"), style: .default, handler: { _ in
+                let chatId = self.dcContext.createChatByContactId(contactId: qrParsed.id)
+                self.coordinator?.showChat(chatId: chatId)
+            }))
+            alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .default, handler: nil))
+            present(alert, animated: true, completion: nil)
+
+        case DC_QR_TEXT:
+            let msg = String.localizedStringWithFormat(String.localized("qrscan_contains_text"), qrParsed.text1 ?? "")
+            let alert = UIAlertController(title: msg, message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
+            present(alert, animated: true, completion: nil)
+
+        case DC_QR_URL:
+            let url = qrParsed.text1 ?? ""
+            let msg = String.localizedStringWithFormat(String.localized("qrscan_contains_url"), url)
+            let alert = UIAlertController(title: msg, message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: String.localized("open"), style: .default, handler: { _ in
+                if let url = URL(string: url) {
+                    UIApplication.shared.open(url)
+                }
+            }))
+            alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .default, handler: nil))
+            present(alert, animated: true, completion: nil)
+
+        case DC_QR_ACCOUNT:
+            let alert = UIAlertController(title: String.localized("qraccount_use_on_new_install"), message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default))
+            present(alert, animated: true)
+
+        default:
+            var msg = String.localizedStringWithFormat(String.localized("qrscan_contains_text"), code)
+            if state == DC_QR_ERROR {
+                if let errorMsg = qrParsed.text1 {
+                    msg = errorMsg + "\n\n" + msg
+                }
+            }
+            let alert = UIAlertController(title: msg, message: nil, preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
+            present(alert, animated: true, completion: nil)
+        }
+    }
+
+    private func joinSecureJoin(alertMessage: String, code: String) {
+        let alert = UIAlertController(title: alertMessage,
+                                      message: nil,
+                                      preferredStyle: .alert)
+        alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .default, handler: nil))
+        alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: { _ in
+            alert.dismiss(animated: true, completion: nil)
+            self.showProgressAlert()
+            // execute blocking secure join in background
+            DispatchQueue.global(qos: .background).async {
+                self.addSecureJoinProgressListener()
+                self.dcContext.lastErrorString = nil
+                let chatId = self.dcContext.joinSecurejoin(qrCode: code)
+                let errorString = self.dcContext.lastErrorString
+                self.removeSecureJoinProgressListener()
+
+                DispatchQueue.main.async {
+                    self.progressAlert.dismiss(animated: true, completion: nil)
+                    if chatId != 0 {
+                        self.coordinator?.showChat(chatId: chatId)
+                    } else if errorString != nil {
+                        self.showErrorAlert(error: errorString!)
+                    }
+                }
+            }
+        }))
+        present(alert, animated: true, completion: nil)
+    }
+
+    private func showProgressAlert() {
+        self.present(self.progressAlert, animated: true, completion: {
+            let rect = CGRect(x: 10, y: 10, width: 20, height: 20)
+            let progressView = UIActivityIndicatorView(frame: rect)
+            progressView.tintColor = .blue
+            progressView.startAnimating()
+            progressView.translatesAutoresizingMaskIntoConstraints = false
+            self.progressAlert.view.addSubview(progressView)
+            self.progressAlert.view.addConstraints([
+                progressView.constraintCenterXTo(self.progressAlert.view),
+                progressView.constraintAlignTopTo(self.progressAlert.view, paddingTop: 45)
+            ])
+        })
+    }
+
+    private func showErrorAlert(error: String) {
+        let alert = UIAlertController(title: String.localized("error"), message: error, preferredStyle: .alert)
+        alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: { _ in
+            alert.dismiss(animated: true, completion: nil)
+        }))
+    }
+
+    private func addSecureJoinProgressListener() {
+        let nc = NotificationCenter.default
+        secureJoinObserver = nc.addObserver(
+            forName: dcNotificationSecureJoinerProgress,
+            object: nil,
+            queue: nil
+        ) { notification in
+            print("secure join: ", notification)
+            if let ui = notification.userInfo {
+                if ui["progress"] as? Int == 400 {
+                    if let contactId = ui["contact_id"] as? Int {
+                        self.progressAlert.message = String.localizedStringWithFormat(
+                            String.localized("qrscan_x_verified_introduce_myself"),
+                            DcContact(id: contactId).nameNAddr)
+                    }
+                }
+            }
+        }
+    }
+
+    private func removeSecureJoinProgressListener() {
+        let nc = NotificationCenter.default
+        if let secureJoinObserver = self.secureJoinObserver {
+            nc.removeObserver(secureJoinObserver)
+        }
+    }
+
+}