Kaynağa Gözat

Merge pull request #1640 from deltachat/register-for-dc-account-scheme

register for `dcaccount:` scheme
cyBerta 2 yıl önce
ebeveyn
işleme
34e9e7d7c7

+ 0 - 1
CHANGELOG.md

@@ -14,7 +14,6 @@
 * update translations, revise english source
 * update to core90
 
-
 ## v1.31.0 Testflight
 2022-07
 

+ 9 - 4
deltachat-ios/AppDelegate.swift

@@ -187,16 +187,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         // }
 
         switch url.scheme?.lowercased() {
+        case "dcaccount":
+            appCoordinator.handleQRCode(url.absoluteString)
+            return true
         case "openpgp4fpr":
             // Hack to format url properly
             let urlString = url.absoluteString
                            .replacingOccurrences(of: "openpgp4fpr", with: "OPENPGP4FPR", options: .literal, range: nil)
                            .replacingOccurrences(of: "%23", with: "#", options: .literal, range: nil)
 
-            self.appCoordinator.handleQRCode(urlString)
+            appCoordinator.handleQRCode(urlString)
             return true
         case "mailto":
-            return self.appCoordinator.handleMailtoURL(url)
+            return appCoordinator.handleMailtoURL(url)
         default:
             return false
         }
@@ -579,7 +582,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         }
     }
 
-    func reloadDcContext() {
+    /// - Parameters:
+    ///   - accountCode: optional string representation of dcaccounts: url, used to setup a new account
+    func reloadDcContext(accountCode: String? = nil) {
         setStockTranslations()
         locationManager.reloadDcContext()
         notificationManager.reloadDcContext()
@@ -588,7 +593,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         if dcAccounts.getSelected().isConfigured() {
             appCoordinator.resetTabBarRootViewControllers()
         } else {
-            appCoordinator.presentWelcomeController()
+            appCoordinator.presentWelcomeController(accountCode: accountCode)
         }
     }
 

+ 9 - 7
deltachat-ios/Controller/QrPageController.swift

@@ -3,6 +3,7 @@ import DcCore
 
 class QrPageController: UIPageViewController {
     private let dcContext: DcContext
+    private let dcAccounts: DcAccounts
     var progressObserver: NSObjectProtocol?
     var qrCodeReaderController: QrCodeReaderController?
 
@@ -38,8 +39,9 @@ class QrPageController: UIPageViewController {
         return control
     }()
 
-    init(dcContext: DcContext) {
-        self.dcContext = dcContext
+    init(dcAccounts: DcAccounts) {
+        self.dcAccounts = dcAccounts
+        self.dcContext = dcAccounts.getSelected()
         super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
     }
 
@@ -184,11 +186,11 @@ extension QrPageController: QrCodeReaderDelegate {
             let nameAndAddress = dcContext.getContact(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("cancel"), style: .default, handler: nil))
             alert.addAction(UIAlertAction(title: String.localized("start_chat"), style: .default, handler: { _ in
                 let chatId = self.dcContext.createChatByContactId(contactId: qrParsed.id)
                 self.showChat(chatId: chatId)
             }))
-            alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .default, handler: nil))
             present(alert, animated: true, completion: nil)
 
         case DC_QR_TEXT:
@@ -201,18 +203,18 @@ extension QrPageController: QrCodeReaderDelegate {
             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("cancel"), style: .default, handler: nil))
             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)
+            if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
+                appDelegate.appCoordinator.presentWelcomeController(accountCode: code)
+            }
 
         case DC_QR_WEBRTC_INSTANCE:
             guard let domain = qrParsed.text1 else { return }

+ 48 - 23
deltachat-ios/Controller/WelcomeViewController.swift

@@ -4,6 +4,7 @@ import DcCore
 class WelcomeViewController: UIViewController, ProgressAlertHandler {
     private var dcContext: DcContext
     private let dcAccounts: DcAccounts
+    private let accountCode: String?
     private var backupProgressObserver: NSObjectProtocol?
     var progressObserver: NSObjectProtocol?
     var onProgressSuccess: VoidFunction?
@@ -41,7 +42,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
     }()
 
     private lazy var cancelButton: UIBarButtonItem = {
-        return UIBarButtonItem(title: String.localized("cancel"), style: .plain, target: self, action: #selector(cancelButtonPressed))
+        return UIBarButtonItem(title: String.localized("cancel"), style: .plain, target: self, action: #selector(cancelAccountCreation))
     }()
 
     private lazy var moreButton: UIBarButtonItem = {
@@ -60,9 +61,10 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
     private var qrCodeReader: QrCodeReaderController?
     weak var progressAlert: UIAlertController?
 
-    init(dcAccounts: DcAccounts) {
+    init(dcAccounts: DcAccounts, accountCode: String? = nil) {
         self.dcAccounts = dcAccounts
         self.dcContext = dcAccounts.getSelected()
+        self.accountCode = accountCode
         super.init(nibName: nil, bundle: nil)
         self.navigationItem.title = String.localized(canCancel ? "add_account" : "welcome_desktop")
         onProgressSuccess = { [weak self] in
@@ -89,6 +91,9 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
             navigationItem.leftBarButtonItem = cancelButton
         }
         navigationItem.rightBarButtonItem = moreButton
+        if let accountCode = accountCode {
+            handleQrCode(accountCode)
+        }
     }
 
     override func viewDidLayoutSubviews() {
@@ -149,15 +154,23 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         let accountId = dcAccounts.getSelected().id
 
         if accountId != 0 {
-            self.dcContext = dcAccounts.get(id: accountId)
-            let success = dcContext.setConfigFromQR(qrCode: qrCode)
-            if success {
-                addProgressAlertListener(dcAccounts: dcAccounts, progressName: dcNotificationConfigureProgress, onSuccess: handleLoginSuccess)
-                showProgressAlert(title: String.localized("login_header"), dcContext: dcContext)
-                dcAccounts.stopIo()
-                dcContext.configure()
-            } else {
-                accountCreationErrorAlert()
+            dcContext = dcAccounts.get(id: accountId)
+            addProgressAlertListener(dcAccounts: self.dcAccounts,
+                                     progressName: dcNotificationConfigureProgress,
+                                     onSuccess: self.handleLoginSuccess)
+            showProgressAlert(title: String.localized("login_header"), dcContext: self.dcContext)
+            DispatchQueue.global().async { [weak self] in
+                guard let self = self else { return }
+                let success = self.dcContext.setConfigFromQR(qrCode: qrCode)
+                DispatchQueue.main.async {
+                    if success {
+                        self.dcAccounts.stopIo()
+                        self.dcContext.configure()
+                    } else {
+                        self.updateProgressAlert(error: self.dcContext.lastErrorString,
+                                                 completion: self.accountCode != nil ? self.cancelAccountCreation : nil)
+                    }
+                }
             }
         }
     }
@@ -182,13 +195,6 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         }
     }
 
-    private func accountCreationErrorAlert() {
-        let title = dcContext.lastErrorString
-        let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
-        alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default))
-        present(alert, animated: true)
-    }
-
     @objc private func moreButtonPressed() {
         let alert = UIAlertController(title: "Encrypted Account (experimental)",
                                       message: "Do you want to encrypt your account database? This cannot be undone.",
@@ -231,7 +237,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         self.navigationController?.pushViewController(accountSetupController, animated: true)
     }
 
-    @objc private func cancelButtonPressed() {
+    @objc private func cancelAccountCreation() {
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
         // take a bit care on account removal:
         // remove only openend and unconfigured and make sure, there is another account
@@ -316,7 +322,9 @@ extension WelcomeViewController: QrCodeReaderDelegate {
     }
 
     private func confirmAccountCreationAlert(accountDomain domain: String, qrCode: String) {
-        let title = String.localizedStringWithFormat(String.localized("qraccount_ask_create_and_login"), domain)
+        let title = String.localizedStringWithFormat(
+            String.localized(dcAccounts.getAll().count > 1 ? "qraccount_ask_create_and_login_another" : "qraccount_ask_create_and_login"),
+            domain)
         let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
 
         let okAction = UIAlertAction(
@@ -333,13 +341,23 @@ extension WelcomeViewController: QrCodeReaderDelegate {
             title: String.localized("cancel"),
             style: .cancel,
             handler: { [weak self] _ in
-                self?.dismissQRReader()
+                guard let self = self else { return }
+                self.dismissQRReader()
+                // if an injected accountCode exists, the WelcomeViewController was only opened to handle that
+                // cancelling the action should also dismiss the whole controller
+                if self.accountCode != nil {
+                    self.cancelAccountCreation()
+                }
             }
         )
 
         alert.addAction(okAction)
         alert.addAction(qrCancelAction)
-        qrCodeReader?.present(alert, animated: true)
+        if qrCodeReader != nil {
+            qrCodeReader?.present(alert, animated: true)
+        } else {
+            self.present(alert, animated: true)
+        }
     }
 
     private func qrErrorAlert() {
@@ -349,7 +367,14 @@ extension WelcomeViewController: QrCodeReaderDelegate {
             title: String.localized("ok"),
             style: .default,
             handler: { [weak self] _ in
-                self?.qrCodeReader?.startSession()
+                guard let self = self else { return }
+                if self.accountCode != nil {
+                    // if an injected accountCode exists, the WelcomeViewController was only opened to handle that
+                    // if the action failed the whole controller should be dismissed
+                    self.cancelAccountCreation()
+                } else {
+                    self.qrCodeReader?.startSession()
+                }
             }
         )
         alert.addAction(okAction)

+ 13 - 9
deltachat-ios/Coordinator/AppCoordinator.swift

@@ -33,7 +33,7 @@ class AppCoordinator {
     }()
 
     private func createQrNavigationController() -> UINavigationController {
-        let root = QrPageController(dcContext: dcAccounts.getSelected())
+        let root = QrPageController(dcAccounts: dcAccounts)
         let nav = UINavigationController(rootViewController: root)
         let settingsImage = UIImage(named: "qr_code")
         nav.tabBarItem = UITabBarItem(title: String.localized("qr_code"), image: settingsImage, tag: qrTab)
@@ -131,13 +131,17 @@ class AppCoordinator {
         RelayHelper.shared.finishMailto()
         return false
     }
-    
+
     func handleQRCode(_ code: String) {
-        showTab(index: qrTab)
-        if let navController = self.tabBarController.selectedViewController as? UINavigationController,
-           let topViewController = navController.topViewController,
-            let qrPageController = topViewController as? QrPageController {
-            qrPageController.handleQrCode(code)
+        if code.lowercased().starts(with: "dcaccount:") {
+            presentWelcomeController(accountCode: code)
+        } else {
+            showTab(index: qrTab)
+            if let navController = self.tabBarController.selectedViewController as? UINavigationController,
+               let topViewController = navController.topViewController,
+                let qrPageController = topViewController as? QrPageController {
+                qrPageController.handleQrCode(code)
+            }
         }
     }
 
@@ -155,8 +159,8 @@ class AppCoordinator {
         UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17, weight: .semibold)]
     }
 
-    func presentWelcomeController() {
-        loginNavController.setViewControllers([WelcomeViewController(dcAccounts: dcAccounts)], animated: true)
+    func presentWelcomeController(accountCode: String? = nil) {
+        loginNavController.setViewControllers([WelcomeViewController(dcAccounts: dcAccounts, accountCode: accountCode)], animated: true)
         window.rootViewController = loginNavController
         window.makeKeyAndVisible()
 

+ 5 - 3
deltachat-ios/Handler/ProgressAlertHandler.swift

@@ -6,7 +6,7 @@ protocol ProgressAlertHandler: UIViewController {
     var progressObserver: NSObjectProtocol? { get set } // set to nil in viewDidDisappear
     func showProgressAlert(title: String, dcContext: DcContext)
     func updateProgressAlertValue(value: Int?)
-    func updateProgressAlert(error: String?)
+    func updateProgressAlert(error: String?, completion: VoidFunction?)
     func updateProgressAlertSuccess(completion: VoidFunction?)
     func addProgressAlertListener(dcAccounts: DcAccounts, progressName: Notification.Name, onSuccess: @escaping VoidFunction)
 }
@@ -39,7 +39,7 @@ extension ProgressAlertHandler {
         }
     }
 
-    func updateProgressAlert(error message: String?) {
+    func updateProgressAlert(error message: String?, completion onComplete: VoidFunction? = nil) {
         DispatchQueue.main.async(execute: {
             // CAVE: show the new alert in the dismiss-done-handler of the previous one -
             // otherwise we get the error "Attempt to present <UIAlertController: ...> while a presentation is in progress."
@@ -47,7 +47,9 @@ extension ProgressAlertHandler {
             // (when animated is true, that works also sequentially, however better not rely on that, also we do not want an animation here)
             self.progressAlert?.dismiss(animated: false) {
                 let errorAlert = UIAlertController(title: String.localized("error"), message: message, preferredStyle: .alert)
-                errorAlert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
+                errorAlert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: { _ in
+                    onComplete?()
+                }))
                 // sometimes error messages are not shown and we get the same error as above
                 // as a workaround we disable animated here as well
                 self.present(errorAlert, animated: false, completion: nil)

+ 1 - 0
deltachat-ios/Info.plist

@@ -29,6 +29,7 @@
 			<array>
 				<string>chat.delta</string>
 				<string>openpgp4fpr</string>
+				<string>dcaccount</string>
 			</array>
 		</dict>
 		<dict>