diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinator.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinator.swift index bbe5c7d4c..3b6e2824a 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinator.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinator.swift @@ -72,4 +72,8 @@ extension KeyVerificationSelfVerifyWaitCoordinator: KeyVerificationSelfVerifyWai func keyVerificationSelfVerifyWaitViewModelDidCancel(_ viewModel: KeyVerificationSelfVerifyWaitViewModelType) { self.delegate?.keyVerificationSelfVerifyWaitCoordinatorDidCancel(self) } + + func keyVerificationSelfVerifyWaitViewModel(_ coordinator: KeyVerificationSelfVerifyWaitViewModelType, wantsToRecoverSecretsWith secretsRecoveryMode: SecretsRecoveryMode) { + self.delegate?.keyVerificationSelfVerifyWaitCoordinator(self, wantsToRecoverSecretsWith: secretsRecoveryMode) + } } diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinatorType.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinatorType.swift index ee89ae0d0..6c0219c4a 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinatorType.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinatorType.swift @@ -22,6 +22,7 @@ protocol KeyVerificationSelfVerifyWaitCoordinatorDelegate: class { func keyVerificationSelfVerifyWaitCoordinator(_ coordinator: KeyVerificationSelfVerifyWaitCoordinatorType, didAcceptKeyVerificationRequest keyVerificationRequest: MXKeyVerificationRequest) func keyVerificationSelfVerifyWaitCoordinator(_ coordinator: KeyVerificationSelfVerifyWaitCoordinatorType, didAcceptIncomingSASTransaction incomingSASTransaction: MXIncomingSASTransaction) func keyVerificationSelfVerifyWaitCoordinatorDidCancel(_ coordinator: KeyVerificationSelfVerifyWaitCoordinatorType) + func keyVerificationSelfVerifyWaitCoordinator(_ coordinator: KeyVerificationSelfVerifyWaitCoordinatorType, wantsToRecoverSecretsWith secretsRecoveryMode: SecretsRecoveryMode) } /// `KeyVerificationSelfVerifyWaitCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewAction.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewAction.swift index d7144e5e2..77d80ab70 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewAction.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewAction.swift @@ -22,4 +22,5 @@ import Foundation enum KeyVerificationSelfVerifyWaitViewAction { case loadData case cancel + case recoverSecrets } diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard index 7e213fdf2..a854f8878 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard @@ -18,95 +18,166 @@ - - + + - - - - - - - - - - - - - - + + + + + - + - - - + + + + @@ -117,6 +188,9 @@ Riot X for Android + + + @@ -125,7 +199,7 @@ Riot X for Android - - + + diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.swift index f22ce2c2e..d5e5d54d1 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.swift @@ -40,6 +40,11 @@ final class KeyVerificationSelfVerifyWaitViewController: UIViewController { @IBOutlet private weak var additionalInformationLabel: UILabel! + + @IBOutlet private weak var recoverSecretsContainerView: UIView! + @IBOutlet private weak var recoverSecretsButton: RoundedButton! + @IBOutlet private weak var recoverSecretsAdditionalInformationLabel: UILabel! + // MARK: Private private var viewModel: KeyVerificationSelfVerifyWaitViewModelType! @@ -112,6 +117,8 @@ final class KeyVerificationSelfVerifyWaitViewController: UIViewController { self?.cancelButtonAction() } + self.vc_removeBackTitle() + self.navigationItem.rightBarButtonItem = cancelBarButtonItem self.cancelBarButtonItem = cancelBarButtonItem @@ -126,14 +133,16 @@ final class KeyVerificationSelfVerifyWaitViewController: UIViewController { self.mobileClientImageView.image = Asset.Images.smartphone.image.withRenderingMode(.alwaysTemplate) self.additionalInformationLabel.text = VectorL10n.deviceVerificationSelfVerifyWaitAdditionalInformation + + self.recoverSecretsAdditionalInformationLabel.text = VectorL10n.deviceVerificationSelfVerifyWaitRecoverSecretsAdditionalInformation } private func render(viewState: KeyVerificationSelfVerifyWaitViewState) { switch viewState { case .loading: self.renderLoading() - case .loaded(let isNewSignIn): - self.renderLoaded(isNewSignIn: isNewSignIn) + case .loaded(let viewData): + self.renderLoaded(viewData: viewData) case .cancelled(let reason): self.renderCancelled(reason: reason) case .cancelledByMe(let reason): @@ -147,11 +156,32 @@ final class KeyVerificationSelfVerifyWaitViewController: UIViewController { self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) } - private func renderLoaded(isNewSignIn: Bool) { + private func renderLoaded(viewData: KeyVerificationSelfVerifyWaitViewData) { self.activityPresenter.removeCurrentActivityIndicator(animated: true) - self.title = isNewSignIn ? VectorL10n.deviceVerificationSelfVerifyWaitNewSignInTitle : VectorL10n.deviceVerificationSelfVerifyWaitTitle - self.cancelBarButtonItem?.title = isNewSignIn ? VectorL10n.skip : VectorL10n.cancel + self.title = viewData.isNewSignIn ? VectorL10n.deviceVerificationSelfVerifyWaitNewSignInTitle : VectorL10n.deviceVerificationSelfVerifyWaitTitle + self.cancelBarButtonItem?.title = viewData.isNewSignIn ? VectorL10n.skip : VectorL10n.cancel + + let hideRecoverSecrets: Bool + let recoverSecretsButtonTitle: String? + + switch viewData.secretsRecoveryAvailability { + case .notAvailable: + hideRecoverSecrets = true + recoverSecretsButtonTitle = nil + case .available(let secretsRecoveryMode): + hideRecoverSecrets = false + + switch secretsRecoveryMode { + case .passphraseOrKey: + recoverSecretsButtonTitle = VectorL10n.deviceVerificationSelfVerifyWaitRecoverSecretsWithPassphrase + case .onlyKey: + recoverSecretsButtonTitle = VectorL10n.deviceVerificationSelfVerifyWaitRecoverSecretsWithoutPassphrase + } + } + + self.recoverSecretsContainerView.isHidden = hideRecoverSecrets + self.recoverSecretsButton.setTitle(recoverSecretsButtonTitle, for: .normal) } private func renderCancelled(reason: MXTransactionCancelCode) { @@ -184,6 +214,10 @@ final class KeyVerificationSelfVerifyWaitViewController: UIViewController { private func cancelButtonAction() { self.viewModel.process(viewAction: .cancel) } + + @IBAction private func recoverSecretsButtonAction(_ sender: Any) { + self.viewModel.process(viewAction: .recoverSecrets) + } } diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift index f36722f66..034cd5c16 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift @@ -28,6 +28,9 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai private let keyVerificationService: KeyVerificationService private let verificationManager: MXKeyVerificationManager private let isNewSignIn: Bool + private lazy var secretsRecoveryAvailability: SecretsRecoveryAvailability = { + return self.secretsRecoveryAvailability(from: self.session.crypto.recoveryService) + }() private var keyVerificationRequest: MXKeyVerificationRequest? @@ -57,6 +60,12 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai self.loadData() case .cancel: self.cancel() + case .recoverSecrets: + switch self.secretsRecoveryAvailability { + case .notAvailable: + fatalError("Should not happen: When recovery is not available button is hidden") + case .available(let secretsRecoveryMode): self.coordinatorDelegate?.keyVerificationSelfVerifyWaitViewModel(self, wantsToRecoverSecretsWith: secretsRecoveryMode) + } } } @@ -80,11 +89,22 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai }) } +// let recoverySecretsStatus = self.recoveryStatus(from: self.session.crypto.recoveryService) + let viewData = KeyVerificationSelfVerifyWaitViewData(isNewSignIn: self.isNewSignIn, secretsRecoveryAvailability: self.secretsRecoveryAvailability) + self.registerKeyVerificationManagerNewRequestNotification(for: self.verificationManager) - self.update(viewState: .loaded(self.isNewSignIn)) + self.update(viewState: .loaded(viewData)) self.registerTransactionDidStateChangeNotification() } + private func secretsRecoveryAvailability(from recoveryService: MXRecoveryService) -> SecretsRecoveryAvailability { + guard recoveryService.hasRecovery() else { + return .notAvailable + } + let secretsRecoveryMode: SecretsRecoveryMode = recoveryService.usePassphrase() ? .passphraseOrKey : .onlyKey + return .available(secretsRecoveryMode) + } + private func cancel() { self.unregisterKeyVerificationManagerNewRequestNotification() self.cancelKeyVerificationRequest() diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModelType.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModelType.swift index 19b05fe83..c6fc85ff0 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModelType.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModelType.swift @@ -26,6 +26,7 @@ protocol KeyVerificationSelfVerifyWaitViewModelCoordinatorDelegate: class { func keyVerificationSelfVerifyWaitViewModel(_ viewModel: KeyVerificationSelfVerifyWaitViewModelType, didAcceptKeyVerificationRequest keyVerificationRequest: MXKeyVerificationRequest) func keyVerificationSelfVerifyWaitViewModel(_ viewModel: KeyVerificationSelfVerifyWaitViewModelType, didAcceptIncomingSASTransaction incomingSASTransaction: MXIncomingSASTransaction) func keyVerificationSelfVerifyWaitViewModelDidCancel(_ viewModel: KeyVerificationSelfVerifyWaitViewModelType) + func keyVerificationSelfVerifyWaitViewModel(_ viewModel: KeyVerificationSelfVerifyWaitViewModelType, wantsToRecoverSecretsWith secretsRecoveryMode: SecretsRecoveryMode) } /// Protocol describing the view model used by `KeyVerificationSelfVerifyWaitViewController` diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewState.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewState.swift index 8efbea12b..6b244c03b 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewState.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewState.swift @@ -18,10 +18,20 @@ import Foundation +enum SecretsRecoveryAvailability { + case notAvailable + case available(_ mode: SecretsRecoveryMode) +} + +struct KeyVerificationSelfVerifyWaitViewData { + let isNewSignIn: Bool + let secretsRecoveryAvailability: SecretsRecoveryAvailability +} + /// KeyVerificationSelfVerifyWaitViewController view state enum KeyVerificationSelfVerifyWaitViewState { case loading - case loaded(_ isNewSignIn: Bool) + case loaded(_ viewData: KeyVerificationSelfVerifyWaitViewData) case cancelled(MXTransactionCancelCode) case cancelledByMe(MXTransactionCancelCode) case error(Error)