Bläddra i källkod

Merge pull request #1692 from deltachat/backup_folder_creation

Import backup improvements
cyBerta 2 år sedan
förälder
incheckning
7ff991cf23

+ 0 - 9
DcCore/DcCore/DC/Wrapper.swift

@@ -555,15 +555,6 @@ public class DcContext {
         dc_imex(contextPointer, what, directory, passphrase)
     }
 
-    public func imexHasBackup(filePath: String) -> String? {
-        var file: String?
-        if let cString = dc_imex_has_backup(contextPointer, filePath) {
-            file = String(cString: cString)
-            dc_str_unref(cString)
-        }
-        return file
-    }
-
     public func isSendingLocationsToChat(chatId: Int) -> Bool {
         return dc_is_sending_locations_to_chat(contextPointer, UInt32(chatId)) == 1
     }

+ 58 - 27
deltachat-ios/Controller/WelcomeViewController.swift

@@ -8,6 +8,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
     private var backupProgressObserver: NSObjectProtocol?
     var progressObserver: NSObjectProtocol?
     var onProgressSuccess: VoidFunction?
+    private var securityScopedResource: NSURL?
 
     private lazy var scrollView: UIScrollView = {
         let scrollView = UIScrollView()
@@ -58,6 +59,12 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
                                action: #selector(moreButtonPressed))
     }()
 
+    private lazy var mediaPicker: MediaPicker? = {
+        let mediaPicker = MediaPicker(navigationController: navigationController)
+        mediaPicker.delegate = self
+        return mediaPicker
+    }()
+
     private var qrCodeReader: QrCodeReaderController?
     weak var progressAlert: UIAlertController?
 
@@ -112,8 +119,13 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
             nc.removeObserver(observer)
             self.progressObserver = nil
         }
+        removeBackupProgressObserver()
+    }
+
+    private func removeBackupProgressObserver() {
         if let backupProgressObserver = self.backupProgressObserver {
-            nc.removeObserver(backupProgressObserver)
+            NotificationCenter.default.removeObserver(backupProgressObserver)
+            self.backupProgressObserver = nil
         }
     }
 
@@ -219,7 +231,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
                 logger.error("Failed to open account database for account \(dcContext.id)")
                 return
             }
-            self.navigationItem.title = "Add encrypted account"
+            self.navigationItem.title = String.localized("add_encrypted_account")
         } catch KeychainError.unhandledError(let message, let status) {
             logger.error("Keychain error. Failed to create encrypted account. \(message). Error status: \(status)")
         } catch {
@@ -254,6 +266,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         let lastSelectedAccountId = UserDefaults.standard.integer(forKey: Constants.Keys.lastSelectedAccountKey)
         if lastSelectedAccountId != 0 {
             _ = dcAccounts.select(id: lastSelectedAccountId)
+            dcAccounts.startIo()
         }
 
         appDelegate.reloadDcContext()
@@ -264,29 +277,14 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         if dcContext.isConfigured() {
             return
         }
-        addProgressHudBackupListener()
-        let documents = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
-        if !documents.isEmpty {
-            logger.info("looking for backup in: \(documents[0])")
-
-            if let file = dcContext.imexHasBackup(filePath: documents[0]) {
-                logger.info("restoring backup: \(file)")
-                showProgressAlert(title: String.localized("import_backup_title"), dcContext: dcContext)
-                dcAccounts.stopIo()
-                dcContext.imex(what: DC_IMEX_IMPORT_BACKUP, directory: file)
-            } else {
-                let alert = UIAlertController(
-                    title: String.localized("import_backup_title"),
-                    message: String.localizedStringWithFormat(
-                        String.localized("import_backup_no_backup_found"),
-                        "➔ Mac-Finder or iTunes ➔ iPhone ➔ " + String.localized("files") + " ➔ Delta Chat"), // iTunes was used up to Maverick 10.4
-                    preferredStyle: .alert)
-                alert.addAction(UIAlertAction(title: String.localized("ok"), style: .cancel))
-                present(alert, animated: true)
-            }
-        } else {
-            logger.error("no documents directory found")
-        }
+        mediaPicker?.showDocumentLibrary(selectFolder: true)
+    }
+
+    private func importBackup(at filepath: String) {
+        logger.info("restoring backup: \(filepath)")
+        showProgressAlert(title: String.localized("import_backup_title"), dcContext: dcContext)
+        dcAccounts.stopIo()
+        dcContext.imex(what: DC_IMEX_IMPORT_BACKUP, directory: filepath)
     }
 
     private func addProgressHudBackupListener() {
@@ -295,14 +293,25 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
             forName: dcNotificationImexProgress,
             object: nil,
             queue: nil
-        ) { notification in
+        ) { [weak self] notification in
+            guard let self = self else { return }
             if let ui = notification.userInfo {
                 if let error = ui["error"] as? Bool, error {
-                    self.dcAccounts.startIo()
+                    if self.dcContext.isConfigured() {
+                        let accountId = self.dcContext.id
+                        _ = self.dcAccounts.remove(id: accountId)
+                        KeychainManager.deleteAccountSecret(id: accountId)
+                        _ = self.dcAccounts.add()
+                        self.dcContext = self.dcAccounts.getSelected()
+                        self.navigationItem.title = String.localized(self.canCancel ? "add_account" : "welcome_desktop")
+                    }
                     self.updateProgressAlert(error: ui["errorMessage"] as? String)
+                    self.stopAccessingSecurityScopedResource()
+                    self.removeBackupProgressObserver()
                 } else if let done = ui["done"] as? Bool, done {
                     self.dcAccounts.startIo()
                     self.updateProgressAlertSuccess(completion: self.handleBackupRestoreSuccess)
+                    self.stopAccessingSecurityScopedResource()
                 } else {
                     self.updateProgressAlertValue(value: ui["progress"] as? Int)
                 }
@@ -385,6 +394,11 @@ extension WelcomeViewController: QrCodeReaderDelegate {
         self.navigationController?.popViewController(animated: true)
         self.qrCodeReader = nil
     }
+
+    private func stopAccessingSecurityScopedResource() {
+        self.securityScopedResource?.stopAccessingSecurityScopedResource()
+        self.securityScopedResource = nil
+    }
 }
 
 // MARK: - WelcomeContentView
@@ -559,3 +573,20 @@ class WelcomeContentView: UIView {
          onImportBackup?()
      }
 }
+
+extension WelcomeViewController: MediaPickerDelegate {
+    func onDocumentSelected(url: NSURL) {
+        // ensure we can access folders outside of the app's sandbox
+        let isSecurityScopedResource = url.startAccessingSecurityScopedResource()
+        if isSecurityScopedResource {
+            securityScopedResource = url
+        }
+
+        if let selectedBackupFilePath = url.relativePath {
+            addProgressHudBackupListener()
+            importBackup(at: selectedBackupFilePath)
+        } else {
+            stopAccessingSecurityScopedResource()
+        }
+    }
+}

+ 17 - 7
deltachat-ios/Helper/MediaPicker.swift

@@ -12,6 +12,9 @@ protocol MediaPickerDelegate: class {
 }
 
 extension MediaPickerDelegate {
+    func onImageSelected(image: UIImage) {
+        logger.debug("image selected")
+    }
     func onImageSelected(url: NSURL) {
         logger.debug("image selected: ", url.path ?? "unknown")
     }
@@ -75,15 +78,22 @@ class MediaPicker: NSObject, UINavigationControllerDelegate {
         }
     }
 
-    func showDocumentLibrary() {
-        // TODO: instead of adding kUTTypeData, we probably should implement a Document provider for webxdc's https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/FileProvider.html#//apple_ref/doc/uid/TP40014214-CH18
+    func showDocumentLibrary(selectFolder: Bool = false) {
         let documentPicker: UIDocumentPickerViewController
-        if #available(iOS 15.0, *) {
-            let types = [UTType.pdf, UTType.text, UTType.rtf, UTType.spreadsheet, UTType.vCard, UTType.zip, UTType.image, UTType.data]
-            documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: types, asCopy: true)
+        if selectFolder {
+            if #available(iOS 15.0, *) {
+                documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.archive], asCopy: false)
+            } else {
+                documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypeArchive] as [String], in: .open)
+            }
         } else {
-            let types = [kUTTypePDF, kUTTypeText, kUTTypeRTF, kUTTypeSpreadsheet, kUTTypeVCard, kUTTypeZipArchive, kUTTypeImage, kUTTypeData]
-            documentPicker = UIDocumentPickerViewController(documentTypes: types as [String], in: .import)
+            if #available(iOS 15.0, *) {
+                let types = [UTType.pdf, UTType.text, UTType.rtf, UTType.spreadsheet, UTType.vCard, UTType.zip, UTType.image, UTType.data]
+                documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: types, asCopy: true)
+            } else {
+                let types = [kUTTypePDF, kUTTypeText, kUTTypeRTF, kUTTypeSpreadsheet, kUTTypeVCard, kUTTypeZipArchive, kUTTypeImage, kUTTypeData]
+                documentPicker = UIDocumentPickerViewController(documentTypes: types as [String], in: .import)
+            }
         }
         documentPicker.delegate = self
         documentPicker.allowsMultipleSelection = false

+ 1 - 0
deltachat-ios/en.lproj/Localizable.strings

@@ -989,3 +989,4 @@
 
 "connectivity_low_data_mode" = "Disabled by system's \"Low Data Mode\".";
 "connectivity_low_power_mode" = "Disabled by system's \"Low Power Mode\".";
+"add_encrypted_account" = "Add encrypted account";

+ 1 - 0
scripts/untranslated.xml

@@ -4,4 +4,5 @@
     <string name ="a11y_connectivity_hint">Double tap to view connectivity details.</string>
     <string name="connectivity_low_data_mode">Disabled by system's \"Low Data Mode\".</string>
     <string name="connectivity_low_power_mode">Disabled by system's \"Low Power Mode\".</string>
+    <string name="add_encrypted_account">Add encrypted account</string>
 </resources>