Skip to content

Commit

Permalink
#40: Create UserSessionStore and update state machine for session res…
Browse files Browse the repository at this point in the history
…toration.
  • Loading branch information
pixlwave committed Jun 16, 2022
1 parent 8dc5359 commit 211bc63
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 287 deletions.
34 changes: 15 additions & 19 deletions ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
90DF83A6A347F7EE7EDE89EE /* AttributedStringBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */; };
90EB25D13AE6EEF034BDE9D2 /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D52BAA5BADB06E5E8C295D /* Assets.swift */; };
91D3084B285898A80013EF53 /* OnboardingSplashScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D3084A285898A80013EF53 /* OnboardingSplashScreenUITests.swift */; };
91D3084E28589D940013EF53 /* UserSessionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D3084D28589D940013EF53 /* UserSessionStore.swift */; };
93BA4A81B6D893271101F9F0 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 5986E300FC849DEAB2EE7AEB /* Introspect */; };
964B9D2EC38C488C360CE0C9 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B902EA6CD3296B0E10EE432B /* HomeScreen.swift */; };
978BB24F2A5D31EE59EEC249 /* UserSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */; };
Expand Down Expand Up @@ -442,6 +443,7 @@
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
90733775209F4D4D366A268F /* RootRouterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootRouterType.swift; sourceTree = "<group>"; };
91D3084A285898A80013EF53 /* OnboardingSplashScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingSplashScreenUITests.swift; sourceTree = "<group>"; };
91D3084D28589D940013EF53 /* UserSessionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStore.swift; sourceTree = "<group>"; };
92B61C243325DC76D3086494 /* EventBriefFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBriefFactoryProtocol.swift; sourceTree = "<group>"; };
938BD1FCD9E6FF3FCFA7AB4C /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-CN"; path = "zh-CN.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
93B21E72926FACB13A186689 /* ml */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ml; path = ml.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
Expand Down Expand Up @@ -652,13 +654,13 @@
0787F81684E503024BD0C051 /* Services */ = {
isa = PBXGroup;
children = (
AAFDD509929A0CCF8BCE51EB /* Authentication */,
0ED3F5C21537519389C07644 /* BugReport */,
8039515BAA53B7C3275AC64A /* Client */,
79E560F5113ED25D172E550C /* Media */,
40E6246F03D1FE377BC5D963 /* Room */,
82D5AD3EAE3A5C1068A44A88 /* Session */,
FCDF06BDB123505F0334B4F9 /* Timeline */,
91D3084C28589D820013EF53 /* UserSession */,
);
path = Services;
sourceTree = "<group>";
Expand Down Expand Up @@ -726,13 +728,6 @@
path = Resources;
sourceTree = "<group>";
};
298F75357B344DE964106404 /* Login */ = {
isa = PBXGroup;
children = (
);
path = Login;
sourceTree = "<group>";
};
304D3532D4FFC1F0ABC0626E /* ViewFrameReader */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1084,6 +1079,16 @@
path = HTMLParsing;
sourceTree = "<group>";
};
91D3084C28589D820013EF53 /* UserSession */ = {
isa = PBXGroup;
children = (
91D3084D28589D940013EF53 /* UserSessionStore.swift */,
F3BC93D4555571E8B4BC47F9 /* KeychainController.swift */,
956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */,
);
path = UserSession;
sourceTree = "<group>";
};
9413F680ECDFB2B0DDB0DEF2 /* Packages */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1173,16 +1178,6 @@
path = UnitTests;
sourceTree = "<group>";
};
AAFDD509929A0CCF8BCE51EB /* Authentication */ = {
isa = PBXGroup;
children = (
0AD575D36B9F6D1D543305D1 /* AuthenticationCoordinator.swift */,
F3BC93D4555571E8B4BC47F9 /* KeychainController.swift */,
956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */,
);
path = Authentication;
sourceTree = "<group>";
};
AD5FCF9340D670C526AD17E4 /* UI */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1309,7 +1304,7 @@
E74CD7681375AD2EAA34D66B /* Authentication */ = {
isa = PBXGroup;
children = (
298F75357B344DE964106404 /* Login */,
0AD575D36B9F6D1D543305D1 /* AuthenticationCoordinator.swift */,
);
path = Authentication;
sourceTree = "<group>";
Expand Down Expand Up @@ -1842,6 +1837,7 @@
F01DB7DD607015557CD48B33 /* ViewFrameReader.swift in Sources */,
01F4A40C1EDCEC8DC4EC9CFA /* WeakDictionary.swift in Sources */,
77E192BA943B90F9F310CA23 /* WeakDictionaryKeyReference.swift in Sources */,
91D3084E28589D940013EF53 /* UserSessionStore.swift in Sources */,
50391038BC50C8ED9A4D88A0 /* WeakDictionaryReference.swift in Sources */,
7DE5EB4CB2401C672257283C /* WeakKeyDictionary.swift in Sources */,
);
Expand Down
80 changes: 47 additions & 33 deletions ElementX/Sources/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//

import UIKit
import Kingfisher

class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
private let window: UIWindow
Expand All @@ -19,8 +18,7 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {

private let navigationRouter: NavigationRouter

private let keychainController: KeychainControllerProtocol
private let authenticationCoordinator: AuthenticationCoordinator!
private let userSessionStore: UserSessionStore

private var userSession: UserSession!

Expand Down Expand Up @@ -61,14 +59,10 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
fatalError("Should have a valid bundle identifier at this point")
}

keychainController = KeychainController(identifier: bundleIdentifier)
authenticationCoordinator = AuthenticationCoordinator(keychainController: keychainController,
navigationRouter: navigationRouter)
userSessionStore = UserSessionStore(bundleIdentifier: bundleIdentifier)

screenshotDetector = ScreenshotDetector()
screenshotDetector.callback = processScreenshotDetection

authenticationCoordinator.delegate = self

setupStateMachine()

Expand All @@ -84,7 +78,8 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
}

func start() {
stateMachine.processEvent(.start)
self.window.makeKeyAndVisible()
stateMachine.processEvent(userSessionStore.hasSessions ? .startWithExistingSession : .startWithAuthentication)
}

// MARK: - AuthenticationCoordinatorDelegate
Expand All @@ -93,16 +88,14 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
stateMachine.processEvent(.attemptedSignIn)
}

func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didFailWithError error: AuthenticationCoordinatorError) {
stateMachine.processEvent(.failedSigningIn)
}

func authenticationCoordinatorDidSetupClientProxy(_ authenticationCoordinator: AuthenticationCoordinator) {
func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didLoginWithSession userSession: UserSession) {
self.userSession = userSession
remove(childCoordinator: authenticationCoordinator)
stateMachine.processEvent(.succeededSigningIn)
}

func authenticationCoordinatorDidTearDownClientProxy(_ authenticationCoordinator: AuthenticationCoordinator) {
stateMachine.processEvent(.succeededSigningOut)
func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didFailWithError error: AuthenticationCoordinatorError) {
stateMachine.processEvent(.failedSigningIn)
}

// MARK: - Private
Expand All @@ -111,27 +104,36 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
private func setupStateMachine() {
stateMachine.addTransitionHandler { [weak self] context in
guard let self = self else { return }

switch (context.fromState, context.event, context.toState) {
case (.initial, .start, .signedOut):
self.window.makeKeyAndVisible()
self.authenticationCoordinator.start()
case (.initial, .startWithAuthentication, .signedOut):
self.showAuthentication()
case (.signedOut, .attemptedSignIn, .signingIn):
self.showLoadingIndicator()
case (.signingIn, .failedSigningIn, .signedOut):
self.hideLoadingIndicator()
self.showLoginErrorToast()
case (.signingIn, .succeededSigningIn, .signedIn):
case (.signingIn, .succeededSigningIn, .homeScreen):
self.hideLoadingIndicator()
self.presentHomeScreen()

case (.initial, .startWithExistingSession, .restoringSession):
self.showLoadingIndicator()
self.restoreUserSession()
case (.restoringSession, .failedRestoringSession, .signedOut):
self.hideLoadingIndicator()
self.showLoginErrorToast()
case (.restoringSession, .succeededRestoringSession, .homeScreen):
self.hideLoadingIndicator()
self.setupUserSession()
case (.signedIn, .showHomeScreen, .homeScreen):
self.presentHomeScreen()

case(_, _, .roomScreen(let roomId)):
self.presentRoomWithIdentifier(roomId)
case(.roomScreen, .dismissedRoomScreen, .homeScreen):
self.tearDownDismissedRoomScreen()
case (_, .attemptSignOut, .signingOut):
self.authenticationCoordinator.logout()
self.userSessionStore.logout(userSession: self.userSession)
self.stateMachine.processEvent(.succeededSigningOut)
case (.signingOut, .succeededSigningOut, .signedOut):
self.tearDownUserSession()
case (.signingOut, .failedSigningOut, _):
Expand All @@ -151,15 +153,26 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
}
// swiftlint:enable cyclomatic_complexity

private func setupUserSession() {
guard let clientProxy = authenticationCoordinator.clientProxy else {
fatalError("User session should be setup at this point")
private func restoreUserSession() {
Task {
switch await userSessionStore.restoreUserSession() {
case .success(let userSession):
self.userSession = userSession
stateMachine.processEvent(.succeededRestoringSession)
case .failure:
MXLog.error("Failed to restore an existing session.")
stateMachine.processEvent(.failedRestoringSession)
}
}
}

private func showAuthentication() {
let coordinator = AuthenticationCoordinator(userSessionStore: userSessionStore,
navigationRouter: navigationRouter)
coordinator.delegate = self

userSession = .init(clientProxy: clientProxy,
mediaProvider: MediaProvider(clientProxy: clientProxy, imageCache: ImageCache.default))

stateMachine.processEvent(.showHomeScreen)
add(childCoordinator: coordinator)
coordinator.start()
}

private func tearDownUserSession() {
Expand All @@ -170,7 +183,8 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
userSession = nil

mainNavigationController.setViewControllers([splashViewController], animated: false)
authenticationCoordinator.start()

showAuthentication()
}

private func presentHomeScreen() {
Expand Down Expand Up @@ -259,7 +273,7 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
}

private func showLoadingIndicator() {
loadingIndicator = indicatorPresenter.present(.loading(label: "Loading", isInteractionBlocking: true))
loadingIndicator = indicatorPresenter.present(.loading(label: ElementL10n.loading, isInteractionBlocking: true))
}

private func hideLoadingIndicator() {
Expand Down
31 changes: 19 additions & 12 deletions ElementX/Sources/AppCoordinatorStateMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class AppCoordinatorStateMachine {
case signedOut
/// Processing sign in request
case signingIn
/// Successfully signed in
case signedIn
/// Opening an existing session.
case restoringSession
/// Showing the home screen
case homeScreen
/// Showing the settings screen
Expand All @@ -33,22 +33,29 @@ class AppCoordinatorStateMachine {

/// Events that can be triggered on the AppCoordinator state machine
enum Event: EventType {
/// Start AppCoordinator flows, move from initial
case start
/// Start the `AppCoordinator` by showing authentication.
case startWithAuthentication
/// A sign in request has been started
case attemptedSignIn
/// Signing it succeeded
/// Signing in succeeded
case succeededSigningIn
/// Signing in failed
case failedSigningIn
/// Request home screen presentation
case showHomeScreen

/// Start the `AppCoordinator` by restoring an existing account.
case startWithExistingSession
/// Restoring session succeeded.
case succeededRestoringSession
/// Restoring session failed.
case failedRestoringSession

/// Request sign out
case attemptSignOut
/// Signing out succeeded
case succeededSigningOut
/// Signing out failed
case failedSigningOut

/// Request presentation for a particular room
/// - Parameter roomId:the room identifier
case showRoomScreen(roomId: String)
Expand All @@ -64,14 +71,14 @@ class AppCoordinatorStateMachine {

init() {
stateMachine = StateMachine(state: .initial) { machine in
machine.addRoutes(event: .start, transitions: [ .initial => .signedOut ])

machine.addRoutes(event: .startWithAuthentication, transitions: [ .initial => .signedOut ])
machine.addRoutes(event: .attemptedSignIn, transitions: [ .signedOut => .signingIn ])

machine.addRoutes(event: .succeededSigningIn, transitions: [ .signingIn => .signedIn ])
machine.addRoutes(event: .succeededSigningIn, transitions: [ .signingIn => .homeScreen ])
machine.addRoutes(event: .failedSigningIn, transitions: [ .signingIn => .signedOut ])

machine.addRoutes(event: .showHomeScreen, transitions: [ .signedIn => .homeScreen ])
machine.addRoutes(event: .startWithExistingSession, transitions: [ .initial => .restoringSession ])
machine.addRoutes(event: .succeededRestoringSession, transitions: [ .restoringSession => .homeScreen ])
machine.addRoutes(event: .failedRestoringSession, transitions: [ .restoringSession => .signedOut ])

machine.addRoutes(event: .attemptSignOut, transitions: [ .homeScreen => .signingOut ])

Expand Down
Loading

0 comments on commit 211bc63

Please sign in to comment.