RoomList: try syncing when network is back and inError state
This commit is contained in:
parent
1185dbd276
commit
bb4f61fe12
6 changed files with 45 additions and 17 deletions
|
|
@ -22,7 +22,9 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import coil.Coil
|
import coil.Coil
|
||||||
import com.bumble.appyx.core.composable.Children
|
import com.bumble.appyx.core.composable.Children
|
||||||
import com.bumble.appyx.core.lifecycle.subscribe
|
import com.bumble.appyx.core.lifecycle.subscribe
|
||||||
|
|
@ -43,6 +45,8 @@ import io.element.android.appnav.loggedin.LoggedInNode
|
||||||
import io.element.android.features.analytics.api.AnalyticsEntryPoint
|
import io.element.android.features.analytics.api.AnalyticsEntryPoint
|
||||||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||||
import io.element.android.features.invitelist.api.InviteListEntryPoint
|
import io.element.android.features.invitelist.api.InviteListEntryPoint
|
||||||
|
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||||
|
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||||
import io.element.android.features.preferences.api.PreferencesEntryPoint
|
import io.element.android.features.preferences.api.PreferencesEntryPoint
|
||||||
import io.element.android.features.roomlist.api.RoomListEntryPoint
|
import io.element.android.features.roomlist.api.RoomListEntryPoint
|
||||||
import io.element.android.features.verifysession.api.VerifySessionEntryPoint
|
import io.element.android.features.verifysession.api.VerifySessionEntryPoint
|
||||||
|
|
@ -59,13 +63,17 @@ import io.element.android.libraries.di.AppScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.MAIN_SPACE
|
import io.element.android.libraries.matrix.api.core.MAIN_SPACE
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import io.element.android.libraries.matrix.ui.di.MatrixUIBindings
|
import io.element.android.libraries.matrix.ui.di.MatrixUIBindings
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.debounce
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@ContributesNode(AppScope::class)
|
@ContributesNode(AppScope::class)
|
||||||
|
|
@ -81,6 +89,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
private val inviteListEntryPoint: InviteListEntryPoint,
|
private val inviteListEntryPoint: InviteListEntryPoint,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
private val coroutineScope: CoroutineScope,
|
private val coroutineScope: CoroutineScope,
|
||||||
|
private val networkMonitor: NetworkMonitor,
|
||||||
snackbarDispatcher: SnackbarDispatcher,
|
snackbarDispatcher: SnackbarDispatcher,
|
||||||
) : BackstackNode<LoggedInFlowNode.NavTarget>(
|
) : BackstackNode<LoggedInFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
|
|
@ -162,6 +171,27 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
loggedInFlowProcessor.stopObserving()
|
loggedInFlowProcessor.stopObserving()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
observeSyncStateAndNetworkStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeSyncStateAndNetworkStatus() {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
combine(
|
||||||
|
syncService.syncState.debounce(100),
|
||||||
|
networkMonitor.connectivity
|
||||||
|
) { syncState, networkStatus ->
|
||||||
|
syncState == SyncState.InError && networkStatus == NetworkStatus.Online
|
||||||
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.collect { restartSync ->
|
||||||
|
if (restartSync) {
|
||||||
|
syncService.startSync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface NavTarget : Parcelable {
|
sealed interface NavTarget : Parcelable {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -81,6 +82,7 @@ class NetworkMonitorImpl @Inject constructor(
|
||||||
connectivityManager.unregisterNetworkCallback(callback)
|
connectivityManager.unregisterNetworkCallback(callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
.debounce(300)
|
.debounce(300)
|
||||||
.stateIn(appCoroutineScope, SharingStarted.WhileSubscribed(), connectivityManager.activeNetworkStatus())
|
.stateIn(appCoroutineScope, SharingStarted.WhileSubscribed(), connectivityManager.activeNetworkStatus())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ interface SyncService {
|
||||||
fun stopSync()
|
fun stopSync()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Flow of [SyncState]. Will be updated as soon as the current [SyncState] changes.
|
||||||
*/
|
*/
|
||||||
fun syncState(): StateFlow<SyncState>
|
val syncState: StateFlow<SyncState>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ class RustMatrixClient constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
client.setDelegate(clientDelegate)
|
client.setDelegate(clientDelegate)
|
||||||
syncService.syncState()
|
syncService.syncState
|
||||||
.onEach { syncState ->
|
.onEach { syncState ->
|
||||||
if (syncState == SyncState.Syncing) {
|
if (syncState == SyncState.Syncing) {
|
||||||
onSlidingSyncUpdate()
|
onSlidingSyncUpdate()
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.impl.room.roomListStateFlow
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
@ -46,13 +47,10 @@ class RustSyncService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun syncState(): StateFlow<SyncState> {
|
override val syncState: StateFlow<SyncState> =
|
||||||
return roomListService
|
roomListService
|
||||||
.roomListStateFlow()
|
.roomListStateFlow()
|
||||||
.map(RoomListState::toSyncState)
|
.map(RoomListState::toSyncState)
|
||||||
.onEach { syncState ->
|
.distinctUntilChanged()
|
||||||
Timber.d("OnSyncState updated = $syncState")
|
.stateIn(sessionCoroutineScope, SharingStarted.WhileSubscribed(), SyncState.Idle)
|
||||||
}
|
|
||||||
.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, SyncState.Idle)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,21 +23,19 @@ import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
class FakeSyncService : SyncService {
|
class FakeSyncService : SyncService {
|
||||||
|
|
||||||
private val syncState = MutableStateFlow(SyncState.Idle)
|
private val syncStateFlow = MutableStateFlow(SyncState.Idle)
|
||||||
|
|
||||||
fun simulateError() {
|
fun simulateError() {
|
||||||
syncState.value = SyncState.InError
|
syncStateFlow.value = SyncState.InError
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startSync() {
|
override fun startSync() {
|
||||||
syncState.value = SyncState.Syncing
|
syncStateFlow.value = SyncState.Syncing
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stopSync() {
|
override fun stopSync() {
|
||||||
syncState.value = SyncState.Terminated
|
syncStateFlow.value = SyncState.Terminated
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun syncState(): StateFlow<SyncState> {
|
override val syncState: StateFlow<SyncState> = syncStateFlow
|
||||||
return syncState
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue