Bläddra i källkod

Merge pull request #1286 from deltachat/use-multiple-accounts

add basic switch-account controls
bjoern 4 år sedan
förälder
incheckning
1dd6c6035e

+ 14 - 10
DcCore/DcCore/DC/Wrapper.swift

@@ -8,6 +8,7 @@ public class DcAccounts {
     /// The ID is created in the apple developer portal and can be changed there.
     let applicationGroupIdentifier = "group.chat.delta.ios"
     var accountsPointer: OpaquePointer?
+    public var logger: Logger?
 
     public init() {
     }
@@ -28,7 +29,7 @@ public class DcAccounts {
 
     public func get(id: Int) -> DcContext {
         let contextPointer = dc_accounts_get_account(accountsPointer, UInt32(id))
-        return DcContext(contextPointer: contextPointer)
+        return DcContext(contextPointer: contextPointer, logger: logger)
     }
 
     public func getAll() -> [Int] {
@@ -38,7 +39,7 @@ public class DcAccounts {
 
     public func getSelected() -> DcContext {
         let cPtr = dc_accounts_get_selected_account(accountsPointer)
-        return DcContext(contextPointer: cPtr)
+        return DcContext(contextPointer: cPtr, logger: logger)
     }
 
     // call maybeNetwork() from a worker thread.
@@ -64,10 +65,6 @@ public class DcAccounts {
         return dc_accounts_remove_account(accountsPointer, UInt32(id)) == 1
     }
 
-    public func importAccount(filePath: String) -> Int {
-        return Int(dc_accounts_import_account(accountsPointer, filePath))
-    }
-
     public func getEventEmitter() -> DcAccountsEventEmitter {
         let eventEmitterPointer = dc_accounts_get_event_emitter(accountsPointer)
         return DcAccountsEventEmitter(eventEmitterPointer: eventEmitterPointer)
@@ -99,11 +96,9 @@ public class DcContext {
     public var lastWarningString: String = "" // temporary thing to get a grip on some weird errors
     public var maxConfigureProgress: Int = 0 // temporary thing to get a grip on some weird errors
 
-    public init() {
-    }
-
-    public init(contextPointer: OpaquePointer?) {
+    public init(contextPointer: OpaquePointer?, logger: Logger?) {
         self.contextPointer = contextPointer
+        self.logger = logger
     }
     
     deinit {
@@ -538,6 +533,15 @@ public class DcContext {
         set { setConfig("displayname", newValue) }
     }
 
+    public var displaynameAndAddr: String {
+        var ret = addr ?? ""
+        if let displayname = displayname {
+            ret = "\(displayname) (\(ret))"
+        }
+        ret += configured ? "" : " (not configured)"
+        return ret.trimmingCharacters(in: .whitespaces)
+    }
+
     public var selfstatus: String? {
         get { return getConfig("selfstatus") }
         set { setConfig("selfstatus", newValue) }

+ 1 - 1
DcShare/Controller/ShareViewController.swift

@@ -77,8 +77,8 @@ class ShareViewController: SLComposeServiceViewController {
     }
 
     override func presentationAnimationDidFinish() {
+        dcAccounts.logger = logger
         dcAccounts.openDatabase()
-        dcContext.logger = self.logger
         isAccountConfigured = dcContext.isConfigured()
         if isAccountConfigured {
             if #available(iOSApplicationExtension 13.0, *) {

+ 1 - 1
deltachat-ios/AppDelegate.swift

@@ -56,12 +56,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         console.format = "$DHH:mm:ss.SSS$d $C$L$c $M" // see https://docs.swiftybeaver.com/article/20-custom-format
         logger.addDestination(console)
 
+        dcAccounts.logger = DcLogger()
         dcAccounts.openDatabase()
         migrateToDcAccounts()
         if dcAccounts.getAll().isEmpty, dcAccounts.add() == 0 {
            fatalError("Could not initialize a new account.")
         }
-        dcAccounts.getSelected().logger = DcLogger()
         logger.info("➡️ didFinishLaunchingWithOptions")
 
         window = UIWindow(frame: UIScreen.main.bounds)

+ 0 - 50
deltachat-ios/Controller/AccountSetupController.swift

@@ -26,7 +26,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
     private let tagSmtpPasswordCell = 10
     private let tagSmtpSecurityCell = 11
     private let tagCertCheckCell = 12
-    private let tagDeleteAccountCell = 13
     private let tagRestoreCell = 14
     private let tagViewLogCell = 15
 
@@ -46,7 +45,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
     let advancedSection = 200
     let restoreSection = 300
     let folderSection = 400
-    let dangerSection = 500
     private var sections = [Int]()
 
     private lazy var basicSectionCells: [UITableViewCell] = [emailCell, passwordCell]
@@ -66,7 +64,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
         viewLogCell
     ]
     private lazy var folderCells: [UITableViewCell] = [inboxWatchCell, sentboxWatchCell, mvboxWatchCell, sendCopyToSelfCell, mvboxMoveCell]
-    private lazy var dangerCells: [UITableViewCell] = [deleteAccountCell]
     private let editView: Bool
     private var advancedSectionShowing: Bool = false
     private var providerInfoShowing: Bool = false
@@ -115,14 +112,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
         return cell
     }()
 
-    private lazy var deleteAccountCell: ActionCell = {
-        let cell = ActionCell(frame: .zero)
-        cell.actionTitle = String.localized("delete_account")
-        cell.actionColor = UIColor.red
-        cell.tag = tagDeleteAccountCell
-        return cell
-    }()
-
     lazy var advancedShowCell: UITableViewCell = {
         let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("menu_advanced")
@@ -345,7 +334,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
         self.sections.append(advancedSection)
         if editView {
             self.sections.append(folderSection)
-            self.sections.append(dangerSection)
         } else {
             self.sections.append(restoreSection)
         }
@@ -412,8 +400,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
             return restoreCells.count
         } else if sections[section] == folderSection {
             return folderCells.count
-        } else if sections[section] == dangerSection {
-            return dangerCells.count
         } else {
             return advancedSectionShowing ? advancedSectionCells.count : 1
         }
@@ -424,8 +410,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
             return String.localized("login_header")
         } else if sections[section] == folderSection {
             return String.localized("pref_imap_folder_handling")
-        } else if sections[section] == dangerSection {
-            return String.localized("danger")
         } else {
             return nil
         }
@@ -469,8 +453,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
             return restoreCells[row]
         } else if sections[section] == folderSection {
             return folderCells[row]
-        } else if sections[section] == dangerSection {
-            return dangerCells[row]
         } else {
             return advancedSectionCells[row]
         }
@@ -489,9 +471,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
         case tagRestoreCell:
             tableView.reloadData() // otherwise the disclosureIndicator may stay selected
             restoreBackup()
-        case tagDeleteAccountCell:
-            tableView.deselectRow(at: indexPath, animated: false)
-            deleteAccount()
         case tagAdvancedCell:
             toggleAdvancedSection()
         case tagImapSecurityCell:
@@ -764,35 +743,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
 
     }
 
-    private func deleteAccount() {
-        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
-            return
-        }
-
-        let alert = UIAlertController(
-            title: String.localized("delete_account_ask"),
-            message: nil,
-            preferredStyle: .safeActionSheet)
-
-        alert.addAction(UIAlertAction(title: String.localized("delete_account"), style: .destructive, handler: { [weak self] _ in
-            guard let self = self else { return }
-            appDelegate.locationManager.disableLocationStreamingInAllChats()
-            self.dcAccounts.stopIo()
-            _ = self.dcAccounts.remove(id: self.dcAccounts.getSelected().id)
-            if let firstAccountId = self.dcAccounts.getAll().first {
-                _ = self.dcAccounts.select(id: firstAccountId)
-            } else {
-                let accountId = self.dcAccounts.add()
-                _ = self.dcAccounts.select(id: accountId)
-            }
-            appDelegate.reloadDcContext()
-            appDelegate.installEventHandler()
-            self.dcAccounts.maybeStartIo()
-        }))
-        alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel))
-        present(alert, animated: true, completion: nil)
-    }
-
     private func handleLoginSuccess() {
         // used when login hud successfully went through
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }

+ 70 - 1
deltachat-ios/Controller/SettingsController.swift

@@ -24,6 +24,7 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
         case help = 10
         case autodel = 11
         case mediaQuality = 12
+        case switchAccount = 13
     }
 
     private var dcContext: DcContext
@@ -168,6 +169,14 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
         return cell
     }()
 
+    private lazy var switchAccountCell: ActionCell = {
+        let cell = ActionCell()
+        cell.tag = CellTags.switchAccount.rawValue
+        cell.actionTitle = String.localized("switch_account")
+        cell.selectionStyle = .default
+        return cell
+    }()
+
     private lazy var helpCell: ActionCell = {
         let cell = ActionCell()
         cell.tag = CellTags.help.rawValue
@@ -183,7 +192,7 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
         let profileSection = SectionConfigs(
             headerTitle: String.localized("pref_profile_info_headline"),
             footerTitle: nil,
-            cells: [profileCell]
+            cells: [profileCell, switchAccountCell]
         )
         let preferencesSection = SectionConfigs(
             headerTitle: String.localized("pref_chats_and_media"),
@@ -291,6 +300,7 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
         case .sendAutocryptMessage: sendAutocryptSetupMessage()
         case .exportBackup: createBackup()
         case .advanced: showAdvancedDialog()
+        case .switchAccount: showSwitchAccountMenu()
         case .help: showHelp()
         }
     }
@@ -420,6 +430,65 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
         present(alert, animated: true, completion: nil)
     }
 
+    private func presentError(message: String) {
+        let error = UIAlertController(title: nil, message: message, preferredStyle: .alert)
+        error.addAction(UIAlertAction(title: String.localized("ok"), style: .cancel))
+        present(error, animated: true)
+    }
+
+    private func showSwitchAccountMenu() {
+        let accountIds = dcAccounts.getAll()
+        let selectedAccountId = dcAccounts.getSelected().id
+        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
+
+        // switch account
+        let menu = UIAlertController(title: String.localized("switch_account"), message: nil, preferredStyle: .safeActionSheet)
+        for accountId in accountIds {
+            let account = dcAccounts.get(id: accountId)
+            var title = account.displaynameAndAddr
+            title = (selectedAccountId==accountId ? "✔︎ " : "") + title
+            menu.addAction(UIAlertAction(title: title, style: .default, handler: { [weak self] _ in
+                guard let self = self else { return }
+                _ = self.dcAccounts.select(id: accountId)
+                appDelegate.reloadDcContext()
+            }))
+        }
+
+        // add account
+        menu.addAction(UIAlertAction(title: String.localized("add_account"), style: .default, handler: { [weak self] _ in
+            guard let self = self else { return }
+            _ = self.dcAccounts.add()
+            appDelegate.reloadDcContext()
+        }))
+
+        // delete account
+        menu.addAction(UIAlertAction(title: String.localized("delete_account"), style: .default, handler: { [weak self] _ in
+            let confirm1 = UIAlertController(title: String.localized("delete_account_ask"), message: nil, preferredStyle: .safeActionSheet)
+            confirm1.addAction(UIAlertAction(title: String.localized("delete_account"), style: .destructive, handler: { [weak self] _ in
+                guard let self = self else { return }
+                let account = self.dcAccounts.get(id: selectedAccountId)
+                let confirm2 = UIAlertController(title: account.displaynameAndAddr,
+                    message: String.localized("forget_login_confirmation_desktop"), preferredStyle: .alert)
+                confirm2.addAction(UIAlertAction(title: String.localized("delete"), style: .destructive, handler: { [weak self] _ in
+                    guard let self = self else { return }
+                    appDelegate.locationManager.disableLocationStreamingInAllChats()
+                    _ = self.dcAccounts.remove(id: selectedAccountId)
+                    if self.dcAccounts.getAll().isEmpty {
+                        _ = self.dcAccounts.add()
+                    }
+                    appDelegate.reloadDcContext()
+                }))
+                confirm2.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel))
+                self.present(confirm2, animated: true, completion: nil)
+            }))
+            confirm1.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel))
+            self?.present(confirm1, animated: true, completion: nil)
+        }))
+
+        menu.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: nil))
+        present(menu, animated: true, completion: nil)
+    }
+
     private func startImex(what: Int32) {
         let documents = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
         if !documents.isEmpty {

+ 30 - 1
deltachat-ios/Controller/WelcomeViewController.swift

@@ -38,6 +38,15 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         return view
     }()
 
+    private lazy var canCancel: Bool = {
+        // "cancel" removes selected unconfigured account, so there needs to be at least one other account
+        return dcAccounts.getAll().count >= 2
+    }()
+
+    private lazy var cancelButton: UIBarButtonItem = {
+        return UIBarButtonItem(title: String.localized("cancel"), style: .plain, target: self, action: #selector(cancelButtonPressed))
+    }()
+
     private var qrCodeReader: QrCodeReaderController?
     weak var progressAlert: UIAlertController?
 
@@ -45,7 +54,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         self.dcAccounts = dcAccounts
         self.dcContext = dcAccounts.getSelected()
         super.init(nibName: nil, bundle: nil)
-        self.navigationItem.title = String.localized("welcome_desktop")
+        self.navigationItem.title = String.localized(canCancel ? "add_account" : "welcome_desktop")
         onProgressSuccess = { [weak self] in
             guard let self = self else { return }
             let profileInfoController = ProfileInfoViewController(context: self.dcContext)
@@ -66,6 +75,9 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
     override func viewDidLoad() {
         super.viewDidLoad()
         setupSubviews()
+        if canCancel {
+            navigationItem.leftBarButtonItem = cancelButton
+        }
     }
 
     override func viewDidLayoutSubviews() {
@@ -143,6 +155,23 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default))
         present(alert, animated: true)
     }
+
+    @objc private func cancelButtonPressed() {
+        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
+
+        // take a bit care on account removal:
+        // remove only unconfigured and make sure, there is another account
+        // (normally, both checks are not needed, however, some resilience wrt future program-flow-changes seems to be reasonable here)
+        let selectedAccount = dcAccounts.getSelected()
+        if !selectedAccount.isConfigured() {
+            _ = dcAccounts.remove(id: selectedAccount.id)
+            if self.dcAccounts.getAll().isEmpty {
+                _ = self.dcAccounts.add()
+            }
+        }
+
+        appDelegate.reloadDcContext()
+    }
 }
 
 extension WelcomeViewController: QrCodeReaderDelegate {