|
@@ -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)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|