mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Add developer option for clearing the application cache (#852)
* Add developer option for clearing the application cache * Tweaks following code review
This commit is contained in:
@@ -159,6 +159,8 @@ class AppCoordinator: AppCoordinatorProtocol {
|
|||||||
self.logout(isSoft: isSoft)
|
self.logout(isSoft: isSoft)
|
||||||
case (.signingOut, .completedSigningOut(let isSoft), .signedOut):
|
case (.signingOut, .completedSigningOut(let isSoft), .signedOut):
|
||||||
self.presentSplashScreen(isSoftLogout: isSoft)
|
self.presentSplashScreen(isSoftLogout: isSoft)
|
||||||
|
case (.signedIn, .clearCache, .initial):
|
||||||
|
clearCache()
|
||||||
default:
|
default:
|
||||||
fatalError("Unknown transition: \(context)")
|
fatalError("Unknown transition: \(context)")
|
||||||
}
|
}
|
||||||
@@ -238,6 +240,8 @@ class AppCoordinator: AppCoordinatorProtocol {
|
|||||||
switch action {
|
switch action {
|
||||||
case .signOut:
|
case .signOut:
|
||||||
self?.stateMachine.processEvent(.signOut(isSoft: false))
|
self?.stateMachine.processEvent(.signOut(isSoft: false))
|
||||||
|
case .clearCache:
|
||||||
|
self?.stateMachine.processEvent(.clearCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,6 +432,25 @@ class AppCoordinator: AppCoordinatorProtocol {
|
|||||||
storedAppRoute = appRoute
|
storedAppRoute = appRoute
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func clearCache() {
|
||||||
|
showLoadingIndicator()
|
||||||
|
|
||||||
|
defer {
|
||||||
|
hideLoadingIndicator()
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationRootCoordinator.setRootCoordinator(SplashScreenCoordinator())
|
||||||
|
|
||||||
|
userSession.clientProxy.stopSync()
|
||||||
|
userSessionFlowCoordinator?.stop()
|
||||||
|
|
||||||
|
userSessionStore.clearCacheFor(userSession: userSession)
|
||||||
|
|
||||||
|
tearDownUserSession()
|
||||||
|
|
||||||
|
stateMachine.processEvent(.startWithExistingSession)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - AuthenticationCoordinatorDelegate
|
// MARK: - AuthenticationCoordinatorDelegate
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ class AppCoordinatorStateMachine {
|
|||||||
case signOut(isSoft: Bool)
|
case signOut(isSoft: Bool)
|
||||||
/// Signing out completed
|
/// Signing out completed
|
||||||
case completedSigningOut(isSoft: Bool)
|
case completedSigningOut(isSoft: Bool)
|
||||||
|
|
||||||
|
/// Request cache clearing
|
||||||
|
case clearCache
|
||||||
}
|
}
|
||||||
|
|
||||||
private let stateMachine: StateMachine<State, Event>
|
private let stateMachine: StateMachine<State, Event>
|
||||||
@@ -71,6 +74,8 @@ class AppCoordinatorStateMachine {
|
|||||||
stateMachine.addRoutes(event: .startWithExistingSession, transitions: [.initial => .restoringSession])
|
stateMachine.addRoutes(event: .startWithExistingSession, transitions: [.initial => .restoringSession])
|
||||||
stateMachine.addRoutes(event: .createdUserSession, transitions: [.restoringSession => .signedIn])
|
stateMachine.addRoutes(event: .createdUserSession, transitions: [.restoringSession => .signedIn])
|
||||||
stateMachine.addRoutes(event: .failedRestoringSession, transitions: [.restoringSession => .signedOut])
|
stateMachine.addRoutes(event: .failedRestoringSession, transitions: [.restoringSession => .signedOut])
|
||||||
|
|
||||||
|
stateMachine.addRoutes(event: .clearCache, transitions: [.signedIn => .initial])
|
||||||
|
|
||||||
// Transitions with associated values need to be handled through `addRouteMapping`
|
// Transitions with associated values need to be handled through `addRouteMapping`
|
||||||
stateMachine.addRouteMapping { event, fromState, _ in
|
stateMachine.addRouteMapping { event, fromState, _ in
|
||||||
|
|||||||
+13
-1
@@ -16,11 +16,23 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
enum DeveloperOptionsScreenCoordinatorAction {
|
||||||
|
case clearCache
|
||||||
|
}
|
||||||
|
|
||||||
final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol {
|
final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol {
|
||||||
private let viewModel: DeveloperOptionsScreenViewModelProtocol
|
private var viewModel: DeveloperOptionsScreenViewModelProtocol
|
||||||
|
|
||||||
|
var callback: ((DeveloperOptionsScreenCoordinatorAction) -> Void)?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
viewModel = DeveloperOptionsScreenViewModel()
|
viewModel = DeveloperOptionsScreenViewModel()
|
||||||
|
viewModel.callback = { [weak self] action in
|
||||||
|
switch action {
|
||||||
|
case .clearCache:
|
||||||
|
self?.callback?(.clearCache)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toPresentable() -> AnyView {
|
func toPresentable() -> AnyView {
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum DeveloperOptionsScreenViewModelAction { }
|
enum DeveloperOptionsScreenViewModelAction {
|
||||||
|
case clearCache
|
||||||
|
}
|
||||||
|
|
||||||
struct DeveloperOptionsScreenViewState: BindableState {
|
struct DeveloperOptionsScreenViewState: BindableState {
|
||||||
var bindings: DeveloperOptionsScreenViewStateBindings
|
var bindings: DeveloperOptionsScreenViewStateBindings
|
||||||
@@ -34,4 +36,5 @@ enum DeveloperOptionsScreenViewAction {
|
|||||||
case changedStartChatFlowEnabled
|
case changedStartChatFlowEnabled
|
||||||
case changedStartChatUserSuggestionsEnabled
|
case changedStartChatUserSuggestionsEnabled
|
||||||
case changedInvitesFlowEnabled
|
case changedInvitesFlowEnabled
|
||||||
|
case clearCache
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, Deve
|
|||||||
ServiceLocator.shared.settings.startChatUserSuggestionsEnabled = state.bindings.startChatUserSuggestionsEnabled
|
ServiceLocator.shared.settings.startChatUserSuggestionsEnabled = state.bindings.startChatUserSuggestionsEnabled
|
||||||
case .changedInvitesFlowEnabled:
|
case .changedInvitesFlowEnabled:
|
||||||
ServiceLocator.shared.settings.invitesFlowEnabled = state.bindings.invitesFlowEnabled
|
ServiceLocator.shared.settings.invitesFlowEnabled = state.bindings.invitesFlowEnabled
|
||||||
|
case .clearCache:
|
||||||
|
callback?(.clearCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,9 +59,16 @@ struct DeveloperOptionsScreen: View {
|
|||||||
Text("🥳")
|
Text("🥳")
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
}
|
}
|
||||||
.buttonStyle(FormButtonStyle())
|
|
||||||
}
|
}
|
||||||
.formSectionStyle()
|
|
||||||
|
Section {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
context.send(viewAction: .clearCache)
|
||||||
|
} label: {
|
||||||
|
Text("Clear cache")
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.overlay(effectsView)
|
.overlay(effectsView)
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ struct SettingsScreenCoordinatorParameters {
|
|||||||
enum SettingsScreenCoordinatorAction {
|
enum SettingsScreenCoordinatorAction {
|
||||||
case dismiss
|
case dismiss
|
||||||
case logout
|
case logout
|
||||||
|
case clearCache
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SettingsScreenCoordinator: CoordinatorProtocol {
|
final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||||
@@ -114,6 +115,14 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
|||||||
|
|
||||||
private func presentDeveloperOptions() {
|
private func presentDeveloperOptions() {
|
||||||
let coordinator = DeveloperOptionsScreenCoordinator()
|
let coordinator = DeveloperOptionsScreenCoordinator()
|
||||||
|
|
||||||
|
coordinator.callback = { [weak self] action in
|
||||||
|
switch action {
|
||||||
|
case .clearCache:
|
||||||
|
self?.callback?(.clearCache)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
parameters.navigationStackCoordinator?.push(coordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import SwiftUI
|
|||||||
|
|
||||||
enum UserSessionFlowCoordinatorAction {
|
enum UserSessionFlowCoordinatorAction {
|
||||||
case signOut
|
case signOut
|
||||||
|
case clearCache
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserSessionFlowCoordinator: CoordinatorProtocol {
|
class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||||
@@ -304,6 +305,8 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
|||||||
case .logout:
|
case .logout:
|
||||||
self.navigationSplitCoordinator.setSheetCoordinator(nil)
|
self.navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||||
self.callback?(.signOut)
|
self.callback?(.signOut)
|
||||||
|
case .clearCache:
|
||||||
|
self.callback?(.clearCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import MatrixRustSDK
|
|||||||
class UserSessionStore: UserSessionStoreProtocol {
|
class UserSessionStore: UserSessionStoreProtocol {
|
||||||
private let keychainController: KeychainControllerProtocol
|
private let keychainController: KeychainControllerProtocol
|
||||||
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
||||||
|
private let cachesFolderName = "matrix-sdk-state"
|
||||||
|
|
||||||
/// Whether or not there are sessions in the store.
|
/// Whether or not there are sessions in the store.
|
||||||
var hasSessions: Bool { !keychainController.restorationTokens().isEmpty }
|
var hasSessions: Bool { !keychainController.restorationTokens().isEmpty }
|
||||||
@@ -90,6 +91,11 @@ class UserSessionStore: UserSessionStoreProtocol {
|
|||||||
deleteSessionDirectory(for: userID)
|
deleteSessionDirectory(for: userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearCacheFor(userSession: UserSessionProtocol) {
|
||||||
|
let userID = userSession.clientProxy.userID
|
||||||
|
deleteCachesFolder(for: userID)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func buildUserSessionWithClient(_ clientProxy: ClientProxyProtocol) -> UserSessionProtocol {
|
private func buildUserSessionWithClient(_ clientProxy: ClientProxyProtocol) -> UserSessionProtocol {
|
||||||
@@ -140,9 +146,15 @@ class UserSessionStore: UserSessionStoreProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func deleteSessionDirectory(for userID: String) {
|
private func deleteSessionDirectory(for userID: String) {
|
||||||
// Rust sanitises the user ID replacing invalid characters with an _
|
do {
|
||||||
let sanitisedUserID = userID.replacingOccurrences(of: ":", with: "_")
|
try FileManager.default.removeItem(at: basePath(for: userID))
|
||||||
let url = baseDirectory.appendingPathComponent(sanitisedUserID)
|
} catch {
|
||||||
|
MXLog.failure("Failed deleting the session data: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func deleteCachesFolder(for userID: String) {
|
||||||
|
let url = basePath(for: userID).appendingPathComponent(cachesFolderName)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(at: url)
|
try FileManager.default.removeItem(at: url)
|
||||||
@@ -150,4 +162,11 @@ class UserSessionStore: UserSessionStoreProtocol {
|
|||||||
MXLog.failure("Failed deleting the session data: \(error)")
|
MXLog.failure("Failed deleting the session data: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#warning("We should move this and the caches folder path to the rust side")
|
||||||
|
private func basePath(for userID: String) -> URL {
|
||||||
|
// Rust sanitises the user ID replacing invalid characters with an _
|
||||||
|
let sanitisedUserID = userID.replacingOccurrences(of: ":", with: "_")
|
||||||
|
return baseDirectory.appendingPathComponent(sanitisedUserID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,4 +45,7 @@ protocol UserSessionStoreProtocol {
|
|||||||
|
|
||||||
/// Logs out of the specified session.
|
/// Logs out of the specified session.
|
||||||
func logout(userSession: UserSessionProtocol)
|
func logout(userSession: UserSessionProtocol)
|
||||||
|
|
||||||
|
/// Clears our all the matrix sdk state data for the specified session
|
||||||
|
func clearCacheFor(userSession: UserSessionProtocol)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user