diff --git a/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinator.swift b/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinator.swift new file mode 100644 index 000000000..c3328a6e5 --- /dev/null +++ b/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinator.swift @@ -0,0 +1,171 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +@objcMembers +final class SecureKeyBackupSetupCoordinator: SecureKeyBackupSetupCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private let navigationRouter: NavigationRouterType + private let recoveryService: MXRecoveryService + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: SecureKeyBackupSetupCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController()) + self.recoveryService = session.crypto.recoveryService + } + + // MARK: - Public methods + + func start() { + let rootViewController = self.createIntro() + self.navigationRouter.setRootModule(rootViewController) + } + + func toPresentable() -> UIViewController { + return self.navigationRouter.toPresentable() + } + + // MARK: - Private methods + + private func createIntro() -> SecureKeyBackupSetupIntroViewController { + let introViewController = SecureKeyBackupSetupIntroViewController.instantiate() + introViewController.delegate = self + return introViewController + } + + private func showSetupKey(passphrase: String? = nil) { + let coordinator = SecretsSetupRecoveryKeyCoordinator(recoveryService: self.recoveryService, passphrase: passphrase) + coordinator.delegate = self + coordinator.start() + + self.add(childCoordinator: coordinator) + self.navigationRouter.push(coordinator, animated: true) { [weak self] in + self?.remove(childCoordinator: coordinator) + } + } + + private func showSetupPassphrase() { + let coordinator = SecretsSetupRecoveryPassphraseCoordinator(passphraseInput: .new) + coordinator.delegate = self + coordinator.start() + + self.add(childCoordinator: coordinator) + self.navigationRouter.push(coordinator, animated: true) { [weak self] in + self?.remove(childCoordinator: coordinator) + } + } + + private func showSetupPassphraseConfirmation(with passphrase: String) { + let coordinator = SecretsSetupRecoveryPassphraseCoordinator(passphraseInput: .confirm(passphrase)) + coordinator.delegate = self + coordinator.start() + + self.add(childCoordinator: coordinator) + self.navigationRouter.push(coordinator, animated: true) { [weak self] in + self?.remove(childCoordinator: coordinator) + } + } + + private func showCancelAlert() { + let alertController = UIAlertController(title: VectorL10n.secureKeyBackupSetupCancelAlertTitle, + message: VectorL10n.secureKeyBackupSetupCancelAlertMessage, + preferredStyle: .alert) + + alertController.addAction(UIAlertAction(title: VectorL10n.continue, style: .cancel, handler: { action in + })) + + alertController.addAction(UIAlertAction(title: VectorL10n.keyBackupSetupSkipAlertSkipAction, style: .default, handler: { action in + self.delegate?.secureKeyBackupSetupCoordinatorDidCancel(self) + })) + + self.navigationRouter.present(alertController, animated: true) + } + + private func didCancel(showSkipAlert: Bool = true) { + if showSkipAlert { + self.showCancelAlert() + } else { + self.delegate?.secureKeyBackupSetupCoordinatorDidCancel(self) + } + } + + private func didComplete() { + self.delegate?.secureKeyBackupSetupCoordinatorDidComplete(self) + } +} + +// MARK: - SecureKeyBackupSetupIntroViewControllerDelegate +extension SecureKeyBackupSetupCoordinator: SecureKeyBackupSetupIntroViewControllerDelegate { + + func secureKeyBackupSetupIntroViewControllerDidTapUseKey(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) { + self.showSetupKey() + } + + func secureKeyBackupSetupIntroViewControllerDidTapUsePassphrase(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) { + self.showSetupPassphrase() + } + + func secureKeyBackupSetupIntroViewControllerDidCancel(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) { + self.didCancel() + } +} + +// MARK: - SecretsSetupRecoveryKeyCoordinatorDelegate +extension SecureKeyBackupSetupCoordinator: SecretsSetupRecoveryKeyCoordinatorDelegate { + + func secretsSetupRecoveryKeyCoordinatorDidComplete(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) { + self.didComplete() + } + + func secretsSetupRecoveryKeyCoordinatorDidFailed(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) { + self.didCancel(showSkipAlert: false) + } + + func secretsSetupRecoveryKeyCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) { + self.didCancel() + } +} + +// MARK: - SecretsSetupRecoveryPassphraseCoordinatorDelegate +extension SecureKeyBackupSetupCoordinator: SecretsSetupRecoveryPassphraseCoordinatorDelegate { + + func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didEnterNewPassphrase passphrase: String) { + self.showSetupPassphraseConfirmation(with: passphrase) + } + + func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didConfirmPassphrase passphrase: String) { + self.showSetupKey(passphrase: passphrase) + } + + func secretsSetupRecoveryPassphraseCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType) { + self.didCancel() + } +} diff --git a/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinatorBridgePresenter.swift b/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinatorBridgePresenter.swift new file mode 100644 index 000000000..4e69e3a8d --- /dev/null +++ b/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinatorBridgePresenter.swift @@ -0,0 +1,88 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +@objc protocol SecureKeyBackupSetupCoordinatorBridgePresenterDelegate { + func secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorBridgePresenter) + func secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidCancel(_ coordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorBridgePresenter) +} + +/// SecureKeyBackupSetupCoordinatorBridgePresenter enables to start SecureKeyBackupSetupCoordinator from a view controller. +/// This bridge is used while waiting for global usage of coordinator pattern. +@objcMembers +final class SecureKeyBackupSetupCoordinatorBridgePresenter: NSObject { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + private var coordinator: SecureKeyBackupSetupCoordinator? + + // MARK: Public + + weak var delegate: SecureKeyBackupSetupCoordinatorBridgePresenterDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + super.init() + } + + // MARK: - Public + + // NOTE: Default value feature is not compatible with Objective-C. + // func present(from viewController: UIViewController, animated: Bool) { + // self.present(from: viewController, animated: animated) + // } + + func present(from viewController: UIViewController, animated: Bool) { + let secureKeyBackupSetupCoordinator = SecureKeyBackupSetupCoordinator(session: self.session) + secureKeyBackupSetupCoordinator.delegate = self + viewController.present(secureKeyBackupSetupCoordinator.toPresentable(), animated: animated, completion: nil) + secureKeyBackupSetupCoordinator.start() + + self.coordinator = secureKeyBackupSetupCoordinator + } + + func dismiss(animated: Bool, completion: (() -> Void)?) { + guard let coordinator = self.coordinator else { + return + } + coordinator.toPresentable().dismiss(animated: animated) { + self.coordinator = nil + + if let completion = completion { + completion() + } + } + } +} + +// MARK: - SecureKeyBackupSetupCoordinatorDelegate +extension SecureKeyBackupSetupCoordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorDelegate { + func secureKeyBackupSetupCoordinatorDidComplete(_ coordinator: SecureKeyBackupSetupCoordinatorType) { + self.delegate?.secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidComplete(self) + } + + func secureKeyBackupSetupCoordinatorDidCancel(_ coordinator: SecureKeyBackupSetupCoordinatorType) { + self.delegate?.secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidCancel(self) + } +} diff --git a/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinatorType.swift b/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinatorType.swift new file mode 100644 index 000000000..0c51a497d --- /dev/null +++ b/Riot/Modules/KeyBackup/SecureSetup/SecureKeyBackupSetupCoordinatorType.swift @@ -0,0 +1,29 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +protocol SecureKeyBackupSetupCoordinatorDelegate: class { + func secureKeyBackupSetupCoordinatorDidComplete(_ coordinator: SecureKeyBackupSetupCoordinatorType) + func secureKeyBackupSetupCoordinatorDidCancel(_ coordinator: SecureKeyBackupSetupCoordinatorType) +} + +/// `SecureKeyBackupSetupCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow. +protocol SecureKeyBackupSetupCoordinatorType: Coordinator, Presentable { + var delegate: SecureKeyBackupSetupCoordinatorDelegate? { get } +}