Create SyncOrchestrator (#4176)
* Create `SyncOrchestrator` to centralise the sync start/stop flow through the whole app: the decision is based on several inputs: sync state, network available, app in foreground, app in call, app needing to sync an event for a notification. * Make network monitor return network connectivity status, not internet connectivity * Don't stop the `SyncService` when network connection is lost, let it fail instead. This prevents an issue when using the offline mode of the SDK, which made the wrong UI states to be shown when the `SyncState` is `Idle` (that is, after the service being manually stopped). * Rename `NetworkStatus.Online/Offline` to `Connected/Disconnected` so they're not easily mistaken with internet connectivity instead
This commit is contained in:
parent
ce1c01e626
commit
3c87fb05b2
44 changed files with 851 additions and 344 deletions
|
|
@ -18,8 +18,28 @@ interface AppForegroundStateService {
|
|||
*/
|
||||
val isInForeground: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Updates to whether the app is in an active call or not will be emitted here.
|
||||
*/
|
||||
val isInCall: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Updates to whether the app is syncing a notification event or not will be emitted here.
|
||||
*/
|
||||
val isSyncingNotificationEvent: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Start observing the foreground state.
|
||||
*/
|
||||
fun start()
|
||||
fun startObservingForeground()
|
||||
|
||||
/**
|
||||
* Update the in-call state.
|
||||
*/
|
||||
fun updateIsInCallState(isInCall: Boolean)
|
||||
|
||||
/**
|
||||
* Update the active state for the syncing notification event flow.
|
||||
*/
|
||||
fun updateIsSyncingNotificationEvent(isSyncingNotificationEvent: Boolean)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,19 +12,27 @@ import androidx.lifecycle.LifecycleEventObserver
|
|||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class DefaultAppForegroundStateService : AppForegroundStateService {
|
||||
private val state = MutableStateFlow(false)
|
||||
override val isInForeground: StateFlow<Boolean> = state
|
||||
override val isInForeground = MutableStateFlow(false)
|
||||
override val isInCall = MutableStateFlow(false)
|
||||
override val isSyncingNotificationEvent = MutableStateFlow(false)
|
||||
|
||||
private val appLifecycle: Lifecycle by lazy { ProcessLifecycleOwner.get().lifecycle }
|
||||
|
||||
override fun start() {
|
||||
override fun startObservingForeground() {
|
||||
appLifecycle.addObserver(lifecycleObserver)
|
||||
}
|
||||
|
||||
private val lifecycleObserver = LifecycleEventObserver { _, _ -> state.value = getCurrentState() }
|
||||
override fun updateIsInCallState(isInCall: Boolean) {
|
||||
this.isInCall.value = isInCall
|
||||
}
|
||||
|
||||
override fun updateIsSyncingNotificationEvent(isSyncingNotificationEvent: Boolean) {
|
||||
this.isSyncingNotificationEvent.value = isSyncingNotificationEvent
|
||||
}
|
||||
|
||||
private val lifecycleObserver = LifecycleEventObserver { _, _ -> isInForeground.value = getCurrentState() }
|
||||
|
||||
private fun getCurrentState(): Boolean = appLifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class DefaultAppNavigationStateService @Inject constructor(
|
|||
|
||||
init {
|
||||
coroutineScope.launch {
|
||||
appForegroundStateService.start()
|
||||
appForegroundStateService.startObservingForeground()
|
||||
appForegroundStateService.isInForeground.collect { isInForeground ->
|
||||
state.getAndUpdate { it.copy(isInForeground = isInForeground) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,19 +9,29 @@ package io.element.android.services.appnavstate.test
|
|||
|
||||
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class FakeAppForegroundStateService(
|
||||
initialValue: Boolean = true,
|
||||
initialForegroundValue: Boolean = true,
|
||||
initialIsInCallValue: Boolean = false,
|
||||
initialIsSyncingNotificationEventValue: Boolean = false
|
||||
) : AppForegroundStateService {
|
||||
private val state = MutableStateFlow(initialValue)
|
||||
override val isInForeground: StateFlow<Boolean> = state
|
||||
override val isInForeground = MutableStateFlow(initialForegroundValue)
|
||||
override val isInCall = MutableStateFlow(initialIsInCallValue)
|
||||
override val isSyncingNotificationEvent = MutableStateFlow(initialIsSyncingNotificationEventValue)
|
||||
|
||||
override fun start() {
|
||||
override fun startObservingForeground() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
fun givenIsInForeground(isInForeground: Boolean) {
|
||||
state.value = isInForeground
|
||||
this.isInForeground.value = isInForeground
|
||||
}
|
||||
|
||||
override fun updateIsInCallState(isInCall: Boolean) {
|
||||
this.isInCall.value = isInCall
|
||||
}
|
||||
|
||||
override fun updateIsSyncingNotificationEvent(isSyncingNotificationEvent: Boolean) {
|
||||
this.isSyncingNotificationEvent.value = isSyncingNotificationEvent
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue