diff --git a/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift b/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift index d525348690..fca50e7b02 100644 --- a/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift +++ b/DuckDuckGo/SyncSettingsViewController+SyncDelegate.swift @@ -61,23 +61,25 @@ extension SyncSettingsViewController: SyncManagementViewModelDelegate { self.refreshDevices() navigationController?.topViewController?.dismiss(animated: true, completion: showRecoveryPDF) } catch { - handleError(SyncError.unableToSync, error: error) + handleError(SyncError.unableToSyncToServer, error: error) } } } @MainActor - func handleError(_ type: SyncError, error: Error) { + func handleError(_ type: SyncError, error: Error?) { let alertController = UIAlertController( title: type.title, - message: type.description + "\n" + error.localizedDescription, + message: [type.description, error?.localizedDescription].compactMap({ $0 }).joined(separator: "\n"), preferredStyle: .alert) let okAction = UIAlertAction(title: UserText.syncPausedAlertOkButton, style: .default, handler: nil) alertController.addAction(okAction) - if type == .unableToSync { - // Give time to the is syncing view to appear + if type == .unableToSyncToServer || + type == .unableToSyncWithDevice || + type == .unableToMergeTwoAccounts { + // Gives time to the is syncing view to appear DispatchQueue.main.asyncAfter(deadline: .now() + 1) { self.dismissPresentedViewController { [weak self] in self?.present(alertController, animated: true, completion: nil) @@ -283,12 +285,14 @@ private class PortraitNavigationController: UINavigationController { } enum SyncError { - case unableToSync - case unableToGetDevices + case unableToSyncToServer + case unableToSyncWithDevice + case unableToMergeTwoAccounts case unableToUpdateDeviceName case unableToTurnSyncOff case unableToDeleteData case unableToRemoveDevice + case unableToCreateRecoveryPdf var title: String { return UserText.syncErrorAlertTitle @@ -296,10 +300,12 @@ enum SyncError { var description: String { switch self { - case .unableToSync: - return UserText.unableToSyncDescription - case .unableToGetDevices: - return UserText.unableToGetDevicesDescription + case .unableToSyncToServer: + return UserText.unableToSyncToServerDescription + case .unableToSyncWithDevice: + return UserText.unableToSyncWithOtherDeviceDescription + case .unableToMergeTwoAccounts: + return UserText.unableToMergeTwoAccountsErrorDescription case .unableToUpdateDeviceName: return UserText.unableToUpdateDeviceNameDescription case .unableToTurnSyncOff: @@ -308,6 +314,8 @@ enum SyncError { return UserText.unableToDeleteDataDescription case .unableToRemoveDevice: return UserText.unableToRemoveDeviceDescription + case .unableToCreateRecoveryPdf: + return UserText.unableToCreateRecoveryPDF } } } diff --git a/DuckDuckGo/SyncSettingsViewController.swift b/DuckDuckGo/SyncSettingsViewController.swift index 4a72c25aba..86cb9f8b95 100644 --- a/DuckDuckGo/SyncSettingsViewController.swift +++ b/DuckDuckGo/SyncSettingsViewController.swift @@ -248,7 +248,7 @@ extension SyncSettingsViewController: ScanOrPasteCodeViewModelDelegate { self.startPolling() return self.connector?.code } catch { - self.handleError(SyncError.unableToSync, error: error) + self.handleError(SyncError.unableToSyncToServer, error: error) return nil } } @@ -274,34 +274,45 @@ extension SyncSettingsViewController: ScanOrPasteCodeViewModelDelegate { return } } catch { - handleError(SyncError.unableToSync, error: error) + handleError(SyncError.unableToSyncWithDevice, error: error) } } } func syncCodeEntered(code: String) async -> Bool { var shouldShowSyncEnabled = true - do { - guard let syncCode = try? SyncCode.decodeBase64String(code) else { - return false - } - if let recoveryKey = syncCode.recovery { - dismissPresentedViewController() - showPreparingSync() + guard let syncCode = try? SyncCode.decodeBase64String(code) else { + return false + } + if let recoveryKey = syncCode.recovery { + dismissPresentedViewController() + showPreparingSync() + do { try await loginAndShowDeviceConnected(recoveryKey: recoveryKey) return true - } else if let connectKey = syncCode.connect { - dismissPresentedViewController() - showPreparingSync() - if syncService.account == nil { + } catch { + if self.rootView.model.isSyncEnabled { + handleError(.unableToMergeTwoAccounts, error: nil) + } else { + handleError(.unableToSyncToServer, error: error) + } + } + } else if let connectKey = syncCode.connect { + dismissPresentedViewController() + showPreparingSync() + if syncService.account == nil { + do { try await syncService.createAccount(deviceName: deviceName, deviceType: deviceType) Pixel.fire(pixel: .syncSignupConnect, includedParameters: [.appVersion]) self.dismissVCAndShowRecoveryPDF() shouldShowSyncEnabled = false rootView.model.syncEnabled(recoveryCode: recoveryCode) + } catch { + handleError(.unableToSyncToServer, error: error) } + } + do { try await syncService.transmitRecoveryKey(connectKey) - self.rootView.model.$devices .removeDuplicates() .dropFirst() @@ -312,12 +323,11 @@ extension SyncSettingsViewController: ScanOrPasteCodeViewModelDelegate { self.dismissVCAndShowRecoveryPDF() } }.store(in: &cancellables) - - return true + } catch { + handleError(.unableToSyncWithDevice, error: error) } - } catch { - handleError(SyncError.unableToSync, error: error) + return true } return false } diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 88f5f98999..78896b9e00 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -860,13 +860,15 @@ But if you *do* want a peek under the hood, you can find more information about static let syncCredentialsPausedAlertDescription = NSLocalizedString("alert.sync-credentials-paused-description", value: "You have exceeded the passwords sync limit. Try deleting some passwords. Until this is resolved your passwords will not be backed up.", comment: "Description for alert shown when sync credentials paused for too many items") public static let syncPausedAlertOkButton = NSLocalizedString("alert.sync-paused-alert-ok-button", value: "OK", comment: "Confirmation button in alert") public static let syncPausedAlertLearnMoreButton = NSLocalizedString("alert.sync-paused-alert-learn-more-button", value: "Learn More", comment: "Learn more button in alert") - public static let syncErrorAlertTitle = NSLocalizedString("alert.sync-error", value: "Sync Error", comment: "Title for sync error alert") - public static let unableToSyncDescription = NSLocalizedString("alert.unable-to-sync-description", value: "Unable to sync.", comment: "Description for unable to sync error") - public static let unableToGetDevicesDescription = NSLocalizedString("alert.unable-to-get-devices-description", value: "Unable to retrieve the list of connected devices.", comment: "Description for unable to get devices error") - public static let unableToUpdateDeviceNameDescription = NSLocalizedString("alert.unable-to-update-device-name-description", value: "Unable to update the name of the device.", comment: "Description for unable to update device name error") - public static let unableToTurnSyncOffDescription = NSLocalizedString("alert.unable-to-turn-sync-off-description", value: "Unable to turn sync off.", comment: "Description for unable to turn sync off error") + public static let syncErrorAlertTitle = NSLocalizedString("alert.sync-error", value: "Sync & Backup Error", comment: "Title for sync error alert") + public static let unableToSyncToServerDescription = NSLocalizedString("alert.unable-to-sync-to-server-description", value: "Unable to connect to the server.", comment: "Description for unable to sync to server error") + public static let unableToSyncWithOtherDeviceDescription = NSLocalizedString("alert.unable-to-sync-with-other-device-description", value: "Unable to Sync with another device.", comment: "Description for unable to sync with another device error") + public static let unableToMergeTwoAccountsErrorDescription = NSLocalizedString("alert.unable-to-merge-two-accounts-description", value: "To pair these devices, turn off Sync & Backup on one device then tap \"Sync with Another Device\" on the other device.", comment: "Description for unable to merge two accounts error") + public static let unableToUpdateDeviceNameDescription = NSLocalizedString("alert.unable-to-update-device-name-description", value: "Unable to update the device name.", comment: "Description for unable to update device name error") + public static let unableToTurnSyncOffDescription = NSLocalizedString("alert.unable-to-turn-sync-off-description", value: "Unable to turn Sync & Backup off.", comment: "Description for unable to turn sync off error") public static let unableToDeleteDataDescription = NSLocalizedString("alert.unable-to-delete-data-description", value: "Unable to delete data on the server.", comment: "Description for unable to delete data error") - public static let unableToRemoveDeviceDescription = NSLocalizedString("alert.unable-to-remove-device-description", value: "Unable to remove the specified device from the synchronized devices.", comment: "Description for unable to remove device error") + public static let unableToRemoveDeviceDescription = NSLocalizedString("alert.unable-to-remove-device-description", value: "Unable to remove this device from Sync & Backup.", comment: "Description for unable to remove device error") + public static let unableToCreateRecoveryPDF = NSLocalizedString("alert.unable-to-create-recovery-pdf-description", value: "Unable to create the recovery PDF. ", comment: "Description for unable to create recovery pdf error") static let syncPausedTitle = NSLocalizedString("sync.warning.sync.paused", value: "Sync & Backup is Paused", comment: "Title of the warning message") static let syncUnavailableMessage = NSLocalizedString("sync.warning.data.syncing.disabled", value: "Sorry, but Sync & Backup is currently unavailable. Please try again later.", comment: "Data syncing unavailable warning message") static let syncUnavailableMessageUpgradeRequired = NSLocalizedString("sync.warning.data.syncing.disabled.upgrade.required", value: "Sorry, but Sync & Backup is no longer available in this app version. Please update DuckDuckGo to the latest version to continue.", comment: "Data syncing unavailable warning message") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 692c00ba01..dbbc366d23 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -140,7 +140,7 @@ "alert.sync-credentials-paused-title" = "Passwords Sync is Paused"; /* Title for sync error alert */ -"alert.sync-error" = "Sync Error"; +"alert.sync-error" = "Sync & Backup Error"; /* Learn more button in alert */ "alert.sync-paused-alert-learn-more-button" = "Learn More"; @@ -163,23 +163,29 @@ /* Save Favorite action */ "alert.title.save.favorite" = "Save Favorite"; +/* Description for unable to create recovery pdf error */ +"alert.unable-to-create-recovery-pdf-description" = "Unable to create the recovery PDF. "; + /* Description for unable to delete data error */ "alert.unable-to-delete-data-description" = "Unable to delete data on the server."; -/* Description for unable to get devices error */ -"alert.unable-to-get-devices-description" = "Unable to retrieve the list of connected devices."; +/* Description for unable to merge two accounts error */ +"alert.unable-to-merge-two-accounts-description" = "To pair these devices, turn off Sync & Backup on one device then tap \"Sync with Another Device\" on the other device."; /* Description for unable to remove device error */ -"alert.unable-to-remove-device-description" = "Unable to remove the specified device from the synchronized devices."; +"alert.unable-to-remove-device-description" = "Unable to remove this device from Sync & Backup."; + +/* Description for unable to sync to server error */ +"alert.unable-to-sync-to-server-description" = "Unable to connect to the server."; -/* Description for unable to sync error */ -"alert.unable-to-sync-description" = "Unable to sync."; +/* Description for unable to sync with another device error */ +"alert.unable-to-sync-with-other-device-description" = "Unable to Sync with another device."; /* Description for unable to turn sync off error */ -"alert.unable-to-turn-sync-off-description" = "Unable to turn sync off."; +"alert.unable-to-turn-sync-off-description" = "Unable to turn Sync & Backup off."; /* Description for unable to update device name error */ -"alert.unable-to-update-device-name-description" = "Unable to update the name of the device."; +"alert.unable-to-update-device-name-description" = "Unable to update the device name."; /* Shown on authentication screen */ "app.authentication.unlock" = "Unlock DuckDuckGo.";