Encryption Flow Coordinators. (#3471)

* Manage the secure backup screens with flow coordinators.

* Add UI tests for the EncryptionSettingsFlowCoordinator.

* Realise that the settings flow can't reset anymore and remove the sub-flow 🤦‍♂️

* Add UI tests for the EncryptionResetFlowCoordinator.
This commit is contained in:
Doug
2024-11-04 14:22:50 +00:00
committed by GitHub
parent 85e1de2c1c
commit 8e26718d0b
51 changed files with 822 additions and 226 deletions
@@ -11,12 +11,12 @@ import SwiftUI
struct SecureBackupScreenCoordinatorParameters {
let appSettings: AppSettings
let clientProxy: ClientProxyProtocol
weak var navigationStackCoordinator: NavigationStackCoordinator?
let userIndicatorController: UserIndicatorControllerProtocol
}
enum SecureBackupScreenCoordinatorAction {
case requestOIDCAuthorisation(URL)
case manageRecoveryKey
case disableKeyBackup
}
final class SecureBackupScreenCoordinator: CoordinatorProtocol {
@@ -43,53 +43,10 @@ final class SecureBackupScreenCoordinator: CoordinatorProtocol {
guard let self else { return }
switch action {
case .recoveryKey:
let recoveryNavigationStackCoordinator = NavigationStackCoordinator()
let recoveryKeyCoordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: .init(secureBackupController: parameters.clientProxy.secureBackupController,
userIndicatorController: parameters.userIndicatorController,
isModallyPresented: true))
recoveryKeyCoordinator.actions.sink { [weak self] action in
guard let self else { return }
switch action {
case .cancel:
parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
case .recoverySetUp:
showSuccessIndicator(title: L10n.screenRecoveryKeySetupSuccess)
parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
case .recoveryChanged:
showSuccessIndicator(title: L10n.screenRecoveryKeyChangeSuccess)
parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
case .recoveryFixed:
showSuccessIndicator(title: L10n.screenRecoveryKeyConfirmSuccess)
parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
case .resetEncryption:
showEncryptionReset(recoveryNavigationStackCoordinator: recoveryNavigationStackCoordinator)
}
}
.store(in: &cancellables)
recoveryNavigationStackCoordinator.setRootCoordinator(recoveryKeyCoordinator, animated: true)
parameters.navigationStackCoordinator?.setSheetCoordinator(recoveryNavigationStackCoordinator)
case .keyBackup:
let navigationStackCoordinator = NavigationStackCoordinator()
let keyBackupCoordinator = SecureBackupKeyBackupScreenCoordinator(parameters: .init(secureBackupController: parameters.clientProxy.secureBackupController,
userIndicatorController: parameters.userIndicatorController))
keyBackupCoordinator.actions.sink { [weak self] action in
switch action {
case .done:
self?.parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
}
}
.store(in: &cancellables)
navigationStackCoordinator.setRootCoordinator(keyBackupCoordinator, animated: true)
parameters.navigationStackCoordinator?.setSheetCoordinator(navigationStackCoordinator)
case .manageRecoveryKey:
actionsSubject.send(.manageRecoveryKey)
case .disableKeyBackup:
actionsSubject.send(.disableKeyBackup)
}
}
.store(in: &cancellables)
@@ -98,41 +55,4 @@ final class SecureBackupScreenCoordinator: CoordinatorProtocol {
func toPresentable() -> AnyView {
AnyView(SecureBackupScreen(context: viewModel.context))
}
// MARK: - Private
private func showSuccessIndicator(title: String) {
parameters.userIndicatorController.submitIndicator(.init(id: .init(),
type: .modal(progress: .none, interactiveDismissDisabled: false, allowsInteraction: false),
title: title,
iconName: "checkmark",
persistent: false))
}
private func showEncryptionReset(recoveryNavigationStackCoordinator: NavigationStackCoordinator) {
let resetNavigationStackCoordinator = NavigationStackCoordinator()
let coordinator = EncryptionResetScreenCoordinator(parameters: .init(clientProxy: parameters.clientProxy,
navigationStackCoordinator: resetNavigationStackCoordinator,
userIndicatorController: parameters.userIndicatorController))
coordinator.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .cancel:
recoveryNavigationStackCoordinator.setSheetCoordinator(nil)
case .requestOIDCAuthorisation(let url):
actionsSubject.send(.requestOIDCAuthorisation(url))
case .resetFinished:
parameters.navigationStackCoordinator?.setSheetCoordinator(nil) // Dismiss the recovery screen
recoveryNavigationStackCoordinator.setSheetCoordinator(nil)
}
}
.store(in: &cancellables)
resetNavigationStackCoordinator.setRootCoordinator(coordinator)
recoveryNavigationStackCoordinator.setSheetCoordinator(resetNavigationStackCoordinator)
}
}
@@ -8,8 +8,8 @@
import Foundation
enum SecureBackupScreenViewModelAction {
case recoveryKey
case keyBackup
case manageRecoveryKey
case disableKeyBackup
}
struct SecureBackupScreenViewState: BindableState {
@@ -48,7 +48,7 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
override func process(viewAction: SecureBackupScreenViewAction) {
switch viewAction {
case .recoveryKey:
actionsSubject.send(.recoveryKey)
actionsSubject.send(.manageRecoveryKey)
case .keyStorageToggled(let enable):
let keyBackupState = secureBackupController.keyBackupState.value
switch (keyBackupState, enable) {
@@ -57,7 +57,7 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
enableBackup()
case (.enabled, false):
state.bindings.keyStorageEnabled = keyBackupState.keyStorageToggleState // Reset the toggle in case the user cancels
actionsSubject.send(.keyBackup)
actionsSubject.send(.disableKeyBackup)
default:
break
}
@@ -53,7 +53,13 @@ struct SecureBackupScreen: View {
.accessibilityElement(children: .combine)
})
keyStorageToggle
ListRow(label: .plain(title: L10n.screenChatBackupKeyStorageToggleTitle,
description: context.viewState.keyStorageToggleDescription),
kind: .toggle($context.keyStorageEnabled))
.onChange(of: context.keyStorageEnabled) { _, newValue in
context.send(viewAction: .keyStorageToggled(newValue))
}
.accessibilityIdentifier(A11yIdentifiers.secureBackupScreen.keyStorage)
}
}
@@ -67,15 +73,6 @@ struct SecureBackupScreen: View {
return description
}
private var keyStorageToggle: some View {
ListRow(label: .plain(title: L10n.screenChatBackupKeyStorageToggleTitle,
description: context.viewState.keyStorageToggleDescription),
kind: .toggle($context.keyStorageEnabled))
.onChange(of: context.keyStorageEnabled) { _, newValue in
context.send(viewAction: .keyStorageToggled(newValue))
}
}
private var recoveryKeySection: some View {
Section {
switch context.viewState.recoveryState {
@@ -85,6 +82,7 @@ struct SecureBackupScreen: View {
icon: \.key,
iconAlignment: .top),
kind: .navigationLink { context.send(viewAction: .recoveryKey) })
.accessibilityIdentifier(A11yIdentifiers.secureBackupScreen.recoveryKey)
case .disabled:
ListRow(label: .default(title: L10n.screenChatBackupRecoveryActionSetup,
description: L10n.screenChatBackupRecoveryActionChangeDescription,
@@ -92,10 +90,12 @@ struct SecureBackupScreen: View {
iconAlignment: .top),
details: .icon(BadgeView(size: 10)),
kind: .navigationLink { context.send(viewAction: .recoveryKey) })
.accessibilityIdentifier(A11yIdentifiers.secureBackupScreen.recoveryKey)
case .incomplete:
ListRow(label: .plain(title: L10n.screenChatBackupRecoveryActionConfirm),
details: .icon(BadgeView(size: 10)),
kind: .navigationLink { context.send(viewAction: .recoveryKey) })
.accessibilityIdentifier(A11yIdentifiers.secureBackupScreen.recoveryKey)
default:
ListRow(label: .plain(title: L10n.commonLoading), details: .isWaiting(true), kind: .label)
}