Added logout option, room list on home screen, made various methods asynchronous,

This commit is contained in:
Stefan Ceriu
2022-02-22 09:18:46 +02:00
parent d90738e1e4
commit b53efb4869
12 changed files with 522 additions and 71 deletions
@@ -15,6 +15,9 @@ enum AuthenticationCoordinatorError: Error {
}
protocol AuthenticationCoordinatorDelegate: AnyObject {
func authenticationCoordinatorDidStartLoading(_ authenticationCoordinator: AuthenticationCoordinator)
func authenticationCoordinatorDidSetupUserSession(_ authenticationCoordinator: AuthenticationCoordinator)
func authenticationCoordinatorDidTearDownUserSession(_ authenticationCoordinator: AuthenticationCoordinator)
@@ -40,19 +43,46 @@ class AuthenticationCoordinator: Coordinator {
}
func start() {
delegate?.authenticationCoordinatorDidStartLoading(self)
let availableRestoreTokens = keychainController.restoreTokens()
guard let usernameTokenTuple = availableRestoreTokens.first else {
startNewLoginFlow()
startNewLoginFlow { result in
switch result {
case .success:
self.delegate?.authenticationCoordinatorDidSetupUserSession(self)
case .failure(let error):
self.delegate?.authenticationCoordinator(self, didFailWithError: error)
MXLog.error("Failed logging in user with error: \(error)")
}
}
return
}
restorePreviousLogin(usernameTokenTuple)
restorePreviousLogin(usernameTokenTuple) { [weak self] result in
guard let self = self else { return }
switch result {
case .success:
self.delegate?.authenticationCoordinatorDidSetupUserSession(self)
case .failure(let error):
self.delegate?.authenticationCoordinator(self, didFailWithError: error)
MXLog.error("Failed restoring login with error: \(error)")
}
}
}
func logout() {
keychainController.removeAllTokens()
userSession = nil
delegate?.authenticationCoordinatorDidTearDownUserSession(self)
}
// MARK: - Private
private func startNewLoginFlow() {
private func startNewLoginFlow(_ completion: @escaping (Result<(), AuthenticationCoordinatorError>) -> Void) {
let parameters = LoginScreenCoordinatorParameters()
let coordinator = LoginScreenCoordinator(parameters: parameters)
@@ -63,16 +93,18 @@ class AuthenticationCoordinator: Coordinator {
switch result {
case .login(let result):
do {
self.setupUserSessionForClient(try loginNewClient(basePath: self.baseDirectoryPathForUsername(result.username),
username: result.username,
password: result.password))
self.login(username: result.username, password: result.password) { [weak self] result in
guard let self = self else { return }
switch result {
case .success:
completion(.success(()))
case .failure(let error):
completion(.failure(error))
}
self.remove(childCoordinator: coordinator)
self.navigationRouter.dismissModule()
} catch {
self.delegate?.authenticationCoordinator(self, didFailWithError: .failedLoggingIn)
MXLog.error("Failed logging in user with error: \(error)")
}
}
}
@@ -83,13 +115,42 @@ class AuthenticationCoordinator: Coordinator {
coordinator.start()
}
private func restorePreviousLogin(_ usernameTokenTuple: (username: String, token: String)) {
do {
setupUserSessionForClient(try loginWithToken(basePath: baseDirectoryPathForUsername(usernameTokenTuple.username),
restoreToken: usernameTokenTuple.token))
} catch {
delegate?.authenticationCoordinator(self, didFailWithError: .failedRestoringLogin)
MXLog.error("Failed restoring login with error: \(error)")
private func login(username: String, password: String, completion: @escaping (Result<Void, AuthenticationCoordinatorError>) -> Void) {
DispatchQueue.global(qos: .background).async { [weak self] in
guard let self = self else { return }
do {
self.setupUserSessionForClient(try loginNewClient(basePath: self.baseDirectoryPathForUsername(username),
username: username,
password: password))
DispatchQueue.main.async {
completion(.success(()))
}
} catch {
DispatchQueue.main.async {
completion(.failure(.failedLoggingIn))
}
}
}
}
private func restorePreviousLogin(_ usernameTokenTuple: (username: String, token: String), completion: @escaping (Result<Void, AuthenticationCoordinatorError>) -> Void) {
DispatchQueue.global(qos: .background).async { [weak self] in
guard let self = self else { return }
do {
self.setupUserSessionForClient(try loginWithToken(basePath: self.baseDirectoryPathForUsername(usernameTokenTuple.username),
restoreToken: usernameTokenTuple.token))
DispatchQueue.main.async {
completion(.success(()))
}
} catch {
DispatchQueue.main.async {
completion(.failure(.failedRestoringLogin))
}
}
}
}
@@ -106,7 +167,6 @@ class AuthenticationCoordinator: Coordinator {
}
userSession = UserSession(client: client)
delegate?.authenticationCoordinatorDidSetupUserSession(self)
}
private func baseDirectoryPathForUsername(_ username: String) -> String {
@@ -38,6 +38,7 @@ struct LoginScreen: View {
.padding(.horizontal, 8.0)
.navigationTitle("Login")
.navigationBarTitleDisplayMode(.inline)
.navigationViewStyle(StackNavigationViewStyle())
}
}
}
@@ -7,33 +7,41 @@
import Foundation
import MatrixRustSDK
import Combine
import UIKit
class UserSession {
enum UserSessionCallback {
case updatedData
}
enum UserSessionError: Error {
case failedRetrievingAvatar
}
class UserSession: ClientDelegate {
private let client: Client
let callbacks = PassthroughSubject<UserSessionCallback, Never>()
init(client: Client) {
self.client = client
if !client.hasFirstSynced() {
MXLog.info("Started initial sync")
client.startSync()
MXLog.info("Finished intial sync")
client.startSync(delegate: self)
}
}
func roomList() -> [RoomModel] {
client.conversations().compactMap { room in
do {
return RoomModel(displayName: try room.displayName())
} catch {
MXLog.error("Failed retrieving room info with error: \(error)")
return nil
}
var userIdentifier: String {
do {
return try client.userId()
} catch {
MXLog.error("Failed retrieving room info with error: \(error)")
return "Unknown user identifier"
}
}
var displayName: String? {
var userDisplayName: String? {
do {
return try client.displayName()
} catch {
@@ -41,4 +49,42 @@ class UserSession {
return nil
}
}
func getUserAvatar(_ completion: @escaping (Result<UIImage?, Error>) -> Void) {
DispatchQueue.global(qos: .background).async {
do {
let avatarData = try self.client.avatar()
DispatchQueue.main.async {
completion(.success(UIImage(data: Data(bytes: avatarData, count: avatarData.count))))
}
} catch {
MXLog.error("Failed retrieving room name with error: \(error)")
DispatchQueue.main.async {
completion(.failure(UserSessionError.failedRetrievingAvatar))
}
}
}
}
func getRoomList(_ completion: @escaping ([RoomModel]) -> Void) {
DispatchQueue.global(qos: .background).async {
let conversations = self.client.conversations()
let rooms = conversations.map {
return RoomModel(room: $0)
}
DispatchQueue.main.async {
completion(rooms)
}
}
}
// MARK: ClientDelegate
func didReceiveSyncUpdate() {
DispatchQueue.main.async {
self.callbacks.send(.updatedData)
}
}
}