From 4fc7bf3d6c458371e9e22f6dcbb4e858abaa2809 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 17 Oct 2022 18:23:12 +0300 Subject: [PATCH] Stop syncing on resign active and start again on resume (#232) --- .../UserSessionFlowCoordinator.swift | 39 +++++++++++++++++- ...erSessionFlowCoordinatorStateMachine.swift | 40 +++++++++++++------ 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/ElementX/Sources/UserSession/UserSessionFlowCoordinator.swift b/ElementX/Sources/UserSession/UserSessionFlowCoordinator.swift index d82c376ed..42d4cafca 100644 --- a/ElementX/Sources/UserSession/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/UserSession/UserSessionFlowCoordinator.swift @@ -38,6 +38,7 @@ class UserSessionFlowCoordinator: Coordinator { self.bugReportService = bugReportService setupStateMachine() + startObservingApplicationState() } func start() { @@ -48,6 +49,7 @@ class UserSessionFlowCoordinator: Coordinator { // MARK: - Private + // swiftlint:disable:next cyclomatic_complexity private func setupStateMachine() { stateMachine.addTransitionHandler { [weak self] context in guard let self else { return } @@ -56,7 +58,7 @@ class UserSessionFlowCoordinator: Coordinator { case (.initial, .start, .homeScreen): self.presentHomeScreen() - case(_, _, .roomScreen(let roomId)): + case(.homeScreen, .showRoomScreen, .roomScreen(let roomId)): self.presentRoomWithIdentifier(roomId) case(.roomScreen(let roomId), .dismissedRoomScreen, .homeScreen): self.tearDownDismissedRoomScreen(roomId) @@ -70,6 +72,10 @@ class UserSessionFlowCoordinator: Coordinator { self.presentSettingsScreen() case (.settingsScreen, .dismissedSettingsScreen, .homeScreen): self.dismissSettingsScreen() + case (_, .resignActive, .suspended): + self.pause() + case (_, .becomeActive, _): + self.resume() default: fatalError("Unknown transition: \(context)") @@ -80,6 +86,17 @@ class UserSessionFlowCoordinator: Coordinator { fatalError("Failed transition with context: \(context)") } } + + private func startObservingApplicationState() { + NotificationCenter.default.addObserver(self, + selector: #selector(applicationWillResignActive), + name: UIApplication.willResignActiveNotification, + object: nil) + NotificationCenter.default.addObserver(self, + selector: #selector(applicationDidBecomeActive), + name: UIApplication.didBecomeActiveNotification, + object: nil) + } private func presentHomeScreen() { userSession.clientProxy.startSync() @@ -272,4 +289,24 @@ class UserSessionFlowCoordinator: Coordinator { navigationRouter.dismissModule() remove(childCoordinator: bugReportCoordinator) } + + // MARK: - Application State + + private func pause() { + userSession.clientProxy.stopSync() + } + + private func resume() { + userSession.clientProxy.startSync() + } + + @objc + private func applicationWillResignActive() { + stateMachine.processEvent(.resignActive) + } + + @objc + private func applicationDidBecomeActive() { + stateMachine.processEvent(.becomeActive) + } } diff --git a/ElementX/Sources/UserSession/UserSessionFlowCoordinatorStateMachine.swift b/ElementX/Sources/UserSession/UserSessionFlowCoordinatorStateMachine.swift index ae9f7f8ba..fb5daa0a7 100644 --- a/ElementX/Sources/UserSession/UserSessionFlowCoordinatorStateMachine.swift +++ b/ElementX/Sources/UserSession/UserSessionFlowCoordinatorStateMachine.swift @@ -35,6 +35,9 @@ class UserSessionFlowCoordinatorStateMachine { /// Showing the settings screen case settingsScreen + + /// Application has been suspended + case suspended } /// Events that can be triggered on the AppCoordinator state machine @@ -57,24 +60,37 @@ class UserSessionFlowCoordinatorStateMachine { case showSettingsScreen /// The settings screen has been dismissed case dismissedSettingsScreen + + /// Application goes into inactive state + case resignActive + /// Application goes into active state + case becomeActive } private let stateMachine: StateMachine + private var stateBeforeSuspension: State = .initial init() { - stateMachine = StateMachine(state: .initial) { machine in - machine.addRoutes(event: .start, transitions: [.initial => .homeScreen]) + stateMachine = StateMachine(state: .initial) + configure() + } - // Transitions with associated values need to be handled through `addRouteMapping` - machine.addRouteMapping { event, fromState, _ in - switch (event, fromState) { - case (.showRoomScreen(let roomId), .homeScreen): - return .roomScreen(roomId: roomId) - case (.dismissedRoomScreen, .roomScreen): - return .homeScreen - default: - return nil - } + private func configure() { + stateMachine.addRoutes(event: .start, transitions: [.initial => .homeScreen]) + + stateMachine.addRouteMapping { event, fromState, _ in + switch (event, fromState) { + case (.showRoomScreen(let roomId), .homeScreen): + return .roomScreen(roomId: roomId) + case (.dismissedRoomScreen, .roomScreen): + return .homeScreen + case (.resignActive, _): + self.stateBeforeSuspension = fromState + return .suspended + case (.becomeActive, .suspended): + return self.stateBeforeSuspension + default: + return nil } } }