mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
Ensure multiple mandatory verification flows can be ran consecutively (e.g. following encryption resets) (#3722)
* Ensure multiple mandatory verification flows can be ran consecutively (e.g. following encryption resets) * Disabled the back button on the verification screen only when verified and waiting for the security state publisher
This commit is contained in:
parent
4856ffd3b2
commit
97069850f5
@ -38,7 +38,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
enum Event: EventType {
|
||||
case next
|
||||
case nextSkippingIdentityConfimed
|
||||
case nextSkippingIdentityConfirmed
|
||||
}
|
||||
|
||||
private let stateMachine: StateMachine<State, Event>
|
||||
@ -79,6 +79,8 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
stateMachine = .init(state: .initial)
|
||||
|
||||
configureStateMachine()
|
||||
|
||||
// Verification can change as part of the onboarding flow by verifying with
|
||||
// another device, using a recovery key or by resetting one's crypto identity.
|
||||
// It can also happen that onboarding started before it had a chance to update,
|
||||
@ -86,15 +88,14 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
// Handle all those cases here instead of spreading them throughout the code.
|
||||
verificationStateCancellable = userSession.sessionSecurityStatePublisher
|
||||
.map(\.verificationState)
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] value in
|
||||
guard let self,
|
||||
value == .verified,
|
||||
stateMachine.state == .identityConfirmation else { return }
|
||||
|
||||
appSettings.hasRunIdentityConfirmationOnboarding = true
|
||||
stateMachine.tryEvent(.nextSkippingIdentityConfimed)
|
||||
self.verificationStateCancellable = nil
|
||||
stateMachine.tryEvent(.nextSkippingIdentityConfirmed)
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,8 +112,6 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
fatalError("This flow coordinator shouldn't have been started")
|
||||
}
|
||||
|
||||
configureStateMachine()
|
||||
|
||||
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(navigationStackCoordinator, animated: !isNewLogin)
|
||||
|
||||
stateMachine.tryEvent(.next)
|
||||
@ -146,6 +145,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func configureStateMachine() {
|
||||
stateMachine.addRoute(.init(fromState: .finished, toState: .initial))
|
||||
stateMachine.addRouteMapping { [weak self] event, fromState, _ in
|
||||
guard let self else {
|
||||
return nil
|
||||
@ -164,7 +164,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
return .finished
|
||||
|
||||
case (.identityConfirmation, _, _, _, _):
|
||||
if event == .nextSkippingIdentityConfimed {
|
||||
if event == .nextSkippingIdentityConfirmed {
|
||||
// Used when the verification state has updated to verified
|
||||
// after starting the onboarding flow
|
||||
switch (requiresAppLockSetup, requiresAnalyticsSetup, requiresNotificationsSetup) {
|
||||
@ -225,9 +225,18 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
presentNotificationPermissionsScreen()
|
||||
case (_, _, .finished):
|
||||
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(nil)
|
||||
stateMachine.tryState(.initial)
|
||||
case (.finished, _, .initial):
|
||||
break
|
||||
default:
|
||||
fatalError("Unknown transition: \(context)")
|
||||
}
|
||||
|
||||
if let event = context.event {
|
||||
MXLog.info("Transitioning from `\(context.fromState)` to `\(context.toState)` with event `\(event)`")
|
||||
} else {
|
||||
MXLog.info("Transitioning from \(context.fromState)` to `\(context.toState)`")
|
||||
}
|
||||
}
|
||||
|
||||
stateMachine.addErrorHandler { context in
|
||||
@ -251,7 +260,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
presentRecoveryKeyScreen()
|
||||
case .skip:
|
||||
appSettings.hasRunIdentityConfirmationOnboarding = true
|
||||
stateMachine.tryEvent(.nextSkippingIdentityConfimed)
|
||||
stateMachine.tryEvent(.nextSkippingIdentityConfirmed)
|
||||
case .reset:
|
||||
startEncryptionResetFlow()
|
||||
case .logout:
|
||||
|
@ -220,6 +220,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
func attemptStartingOnboarding() {
|
||||
MXLog.info("Attempting to start onboarding")
|
||||
|
||||
if onboardingFlowCoordinator.shouldStart {
|
||||
clearRoute(animated: false)
|
||||
onboardingFlowCoordinator.start()
|
||||
@ -340,7 +342,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
userSession.sessionSecurityStatePublisher
|
||||
.map(\.verificationState)
|
||||
.filter { $0 != .unknown }
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
|
@ -24,6 +24,7 @@ struct SessionVerificationScreen: View {
|
||||
.background()
|
||||
.backgroundStyle(.compound.bgCanvasDefault)
|
||||
.interactiveDismissDisabled()
|
||||
.navigationBarBackButtonHidden(context.viewState.verificationState == .verified)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
@ -47,7 +47,6 @@ class UserSession: UserSessionProtocol {
|
||||
MXLog.info("Session security state changed, verificationState: \($0), recoveryState: \($1)")
|
||||
return SessionSecurityState(verificationState: $0, recoveryState: $1)
|
||||
}
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] value in
|
||||
self?.sessionSecurityStateSubject.send(value)
|
||||
|
Loading…
x
Reference in New Issue
Block a user