Various fixes (#437)

* Fix information leaking on RoomSummaryDetails logging

* Prevent crashes when force quitting the application

* Cleanup crash detected alert presentation and exposed home screen view model actions

* Fixes #340 - Wait for logout confirmation before changing the app state

* Add changelogs

* Fix unit tests

* Add missing softLogout logout handling
This commit is contained in:
Stefan Ceriu
2023-01-11 15:10:26 +02:00
committed by GitHub
parent 99e7f76ca0
commit 357d493e5a
11 changed files with 82 additions and 52 deletions
@@ -85,6 +85,11 @@ class AppCoordinator: AppCoordinatorProtocol {
} }
func start() { func start() {
guard stateMachine.state == .initial else {
MXLog.error("Received a start request when already started")
return
}
stateMachine.processEvent(userSessionStore.hasSessions ? .startWithExistingSession : .startWithAuthentication) stateMachine.processEvent(userSessionStore.hasSessions ? .startWithExistingSession : .startWithAuthentication)
} }
@@ -255,21 +260,27 @@ class AppCoordinator: AppCoordinatorProtocol {
deobserveUserSessionChanges() deobserveUserSessionChanges()
if !isSoftLogout { guard !isSoftLogout else {
Task { stateMachine.processEvent(.completedSigningOut)
// first log out from the server return
_ = await userSession.clientProxy.logout()
// regardless of the result, clear user data
userSessionStore.logout(userSession: userSession)
userSession = nil
notificationManager?.delegate = nil
notificationManager = nil
}
} }
// complete logging out Task {
stateMachine.processEvent(.completedSigningOut) showLoadingIndicator()
// first log out from the server
_ = await userSession.clientProxy.logout()
// regardless of the result, clear user data
userSessionStore.logout(userSession: userSession)
userSession = nil
notificationManager?.delegate = nil
notificationManager = nil
stateMachine.processEvent(.completedSigningOut)
hideLoadingIndicator()
}
} }
private func presentSplashScreen(isSoftLogout: Bool = false) { private func presentSplashScreen(isSoftLogout: Bool = false) {
@@ -61,6 +61,10 @@ class AppCoordinatorStateMachine {
private let stateMachine: StateMachine<State, Event> private let stateMachine: StateMachine<State, Event>
var state: AppCoordinatorStateMachine.State {
stateMachine.state
}
init() { init() {
stateMachine = StateMachine(state: .initial) stateMachine = StateMachine(state: .initial)
configure() configure()
@@ -25,7 +25,7 @@ struct HomeScreenCoordinatorParameters {
} }
enum HomeScreenCoordinatorAction { enum HomeScreenCoordinatorAction {
case presentRoomScreen(roomIdentifier: String) case presentRoom(roomIdentifier: String)
case presentSettingsScreen case presentSettingsScreen
case presentFeedbackScreen case presentFeedbackScreen
case presentSessionVerificationScreen case presentSessionVerificationScreen
@@ -50,12 +50,18 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
guard let self else { return } guard let self else { return }
switch action { switch action {
case .selectRoom(let roomIdentifier): case .presentRoom(let roomIdentifier):
self.callback?(.presentRoomScreen(roomIdentifier: roomIdentifier)) self.callback?(.presentRoom(roomIdentifier: roomIdentifier))
case .userMenu(let action): case .presentFeedbackScreen:
self.processUserMenuAction(action) self.callback?(.presentFeedbackScreen)
case .verifySession: case .presentSettingsScreen:
self.callback?(.presentSettingsScreen)
case .presentInviteFriendsScreen:
self.presentInviteFriends()
case .presentSessionVerificationScreen:
self.callback?(.presentSessionVerificationScreen) self.callback?(.presentSessionVerificationScreen)
case .signOut:
self.callback?(.signOut)
} }
} }
} }
@@ -63,15 +69,11 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
// MARK: - Public // MARK: - Public
func start() { func start() {
#if !DEBUG
if parameters.bugReportService.crashedLastRun { if parameters.bugReportService.crashedLastRun {
viewModel.presentAlert( viewModel.presentCrashedLastRunAlert()
AlertInfo(id: UUID(),
title: ElementL10n.sendBugReportAppCrashed,
primaryButton: .init(title: ElementL10n.no, action: nil),
secondaryButton: .init(title: ElementL10n.yes) { [weak self] in
self?.callback?(.presentFeedbackScreen)
}))
} }
#endif
} }
func toPresentable() -> AnyView { func toPresentable() -> AnyView {
@@ -80,19 +82,6 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
// MARK: - Private // MARK: - Private
private func processUserMenuAction(_ action: HomeScreenViewUserMenuAction) {
switch action {
case .settings:
callback?(.presentSettingsScreen)
case .inviteFriends:
presentInviteFriends()
case .feedback:
callback?(.presentFeedbackScreen)
case .signOut:
callback?(.signOut)
}
}
private func presentInviteFriends() { private func presentInviteFriends() {
parameters.navigationStackCoordinator.setSheetCoordinator(InviteFriendsCoordinator(userId: parameters.userSession.userID)) parameters.navigationStackCoordinator.setSheetCoordinator(InviteFriendsCoordinator(userId: parameters.userSession.userID))
} }
@@ -18,9 +18,12 @@ import Foundation
import UIKit import UIKit
enum HomeScreenViewModelAction { enum HomeScreenViewModelAction {
case selectRoom(roomIdentifier: String) case presentRoom(roomIdentifier: String)
case userMenu(action: HomeScreenViewUserMenuAction) case presentSessionVerificationScreen
case verifySession case presentSettingsScreen
case presentInviteFriendsScreen
case presentFeedbackScreen
case signOut
} }
enum HomeScreenViewUserMenuAction { enum HomeScreenViewUserMenuAction {
@@ -112,6 +112,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
// MARK: - Public // MARK: - Public
// swiftlint:disable:next cyclomatic_complexity
override func process(viewAction: HomeScreenViewAction) async { override func process(viewAction: HomeScreenViewAction) async {
switch viewAction { switch viewAction {
case .loadRoomData(let roomIdentifier): case .loadRoomData(let roomIdentifier):
@@ -119,11 +120,20 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
loadDataForRoomIdentifier(roomIdentifier) loadDataForRoomIdentifier(roomIdentifier)
} }
case .selectRoom(let roomIdentifier): case .selectRoom(let roomIdentifier):
callback?(.selectRoom(roomIdentifier: roomIdentifier)) callback?(.presentRoom(roomIdentifier: roomIdentifier))
case .userMenu(let action): case .userMenu(let action):
callback?(.userMenu(action: action)) switch action {
case .feedback:
callback?(.presentFeedbackScreen)
case .settings:
callback?(.presentSettingsScreen)
case .inviteFriends:
callback?(.presentInviteFriendsScreen)
case .signOut:
callback?(.signOut)
}
case .verifySession: case .verifySession:
callback?(.verifySession) callback?(.presentSessionVerificationScreen)
case .skipSessionVerification: case .skipSessionVerification:
state.showSessionVerificationBanner = false state.showSessionVerificationBanner = false
case .updatedVisibleItemIdentifiers(let identifiers): case .updatedVisibleItemIdentifiers(let identifiers):
@@ -131,8 +141,13 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
} }
} }
func presentAlert(_ alertInfo: AlertInfo<UUID>) { func presentCrashedLastRunAlert() {
state.bindings.alertInfo = alertInfo state.bindings.alertInfo = AlertInfo(id: UUID(),
title: ElementL10n.sendBugReportAppCrashed,
primaryButton: .init(title: ElementL10n.no, action: nil),
secondaryButton: .init(title: ElementL10n.yes) { [weak self] in
self?.callback?(.presentFeedbackScreen)
})
} }
// MARK: - Private // MARK: - Private
@@ -23,5 +23,5 @@ protocol HomeScreenViewModelProtocol {
var context: HomeScreenViewModelType.Context { get } var context: HomeScreenViewModelType.Context { get }
func presentAlert(_ alert: AlertInfo<UUID>) func presentCrashedLastRunAlert()
} }
@@ -25,3 +25,9 @@ struct RoomSummaryDetails {
let lastMessageTimestamp: Date? let lastMessageTimestamp: Date?
let unreadNotificationCount: UInt let unreadNotificationCount: UInt
} }
extension RoomSummaryDetails: CustomStringConvertible {
var description: String {
"id: \"\(id)\", isDirect: \"\(isDirect)\", unreadNotificationCount: \"\(unreadNotificationCount)\""
}
}
@@ -125,7 +125,7 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
guard let self else { return } guard let self else { return }
switch action { switch action {
case .presentRoomScreen(let roomIdentifier): case .presentRoom(let roomIdentifier):
self.stateMachine.processEvent(.selectRoom(roomId: roomIdentifier)) self.stateMachine.processEvent(.selectRoom(roomId: roomIdentifier))
case .presentSettingsScreen: case .presentSettingsScreen:
self.stateMachine.processEvent(.showSettingsScreen) self.stateMachine.processEvent(.showSettingsScreen)
@@ -35,7 +35,7 @@ class HomeScreenViewModelTests: XCTestCase {
var selectedRoomId = "" var selectedRoomId = ""
viewModel.callback = { result in viewModel.callback = { result in
switch result { switch result {
case .selectRoom(let roomId): case .presentRoom(let roomId):
correctResult = true correctResult = true
selectedRoomId = roomId selectedRoomId = roomId
default: default:
@@ -53,8 +53,8 @@ class HomeScreenViewModelTests: XCTestCase {
var correctResult = false var correctResult = false
viewModel.callback = { result in viewModel.callback = { result in
switch result { switch result {
case .userMenu(let action): case .presentSettingsScreen:
correctResult = action == .settings correctResult = true
default: default:
break break
} }
+1
View File
@@ -0,0 +1 @@
Wait for logout confirmation before changing the app state
+1
View File
@@ -0,0 +1 @@
Prevent crash popups when force quitting the application