Skip to content

Commit f84aa03

Browse files
committed
Enable Offline mode of the SyncService, so that the sync starts automatically when the network is back.
Also rely on the sync state to render the "Offline" banner.
1 parent f4afda1 commit f84aa03

File tree

20 files changed

+91
-74
lines changed

20 files changed

+91
-74
lines changed

appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import androidx.compose.runtime.rememberCoroutineScope
1919
import androidx.compose.runtime.setValue
2020
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
2121
import im.vector.app.features.analytics.plan.UserProperties
22-
import io.element.android.features.networkmonitor.api.NetworkMonitor
23-
import io.element.android.features.networkmonitor.api.NetworkStatus
2422
import io.element.android.libraries.architecture.AsyncData
2523
import io.element.android.libraries.architecture.Presenter
2624
import io.element.android.libraries.core.log.logger.LoggerTag
@@ -29,6 +27,8 @@ import io.element.android.libraries.matrix.api.encryption.EncryptionService
2927
import io.element.android.libraries.matrix.api.encryption.RecoveryState
3028
import io.element.android.libraries.matrix.api.roomlist.RoomListService
3129
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
30+
import io.element.android.libraries.matrix.api.sync.SyncService
31+
import io.element.android.libraries.matrix.api.sync.isConnected
3232
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
3333
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
3434
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
@@ -46,7 +46,7 @@ private val pusherTag = LoggerTag("Pusher", LoggerTag.PushLoggerTag)
4646

4747
class LoggedInPresenter @Inject constructor(
4848
private val matrixClient: MatrixClient,
49-
private val networkMonitor: NetworkMonitor,
49+
private val syncService: SyncService,
5050
private val pushService: PushService,
5151
private val sessionVerificationService: SessionVerificationService,
5252
private val analyticsService: AnalyticsService,
@@ -76,10 +76,10 @@ class LoggedInPresenter @Inject constructor(
7676
.launchIn(this)
7777
}
7878
val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState()
79-
val networkStatus by networkMonitor.connectivity.collectAsState()
79+
val syncState by syncService.syncState.collectAsState()
8080
val showSyncSpinner by remember {
8181
derivedStateOf {
82-
networkStatus == NetworkStatus.Online && syncIndicator == RoomListService.SyncIndicator.Show
82+
syncState.isConnected() && syncIndicator == RoomListService.SyncIndicator.Show
8383
}
8484
}
8585
var forceNativeSlidingSyncMigration by remember { mutableStateOf(false) }

appnav/src/main/kotlin/io/element/android/appnav/loggedin/SendQueues.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
package io.element.android.appnav.loggedin
99

1010
import androidx.annotation.VisibleForTesting
11-
import io.element.android.features.networkmonitor.api.NetworkMonitor
1211
import io.element.android.features.networkmonitor.api.NetworkStatus
1312
import io.element.android.libraries.di.SessionScope
1413
import io.element.android.libraries.di.SingleIn
1514
import io.element.android.libraries.matrix.api.MatrixClient
15+
import io.element.android.libraries.matrix.api.sync.SyncService
16+
import io.element.android.libraries.matrix.api.sync.SyncState
1617
import kotlinx.coroutines.CoroutineScope
1718
import kotlinx.coroutines.FlowPreview
1819
import kotlinx.coroutines.flow.combine
@@ -27,7 +28,7 @@ const val SEND_QUEUES_RETRY_DELAY_MILLIS = 500L
2728
@SingleIn(SessionScope::class)
2829
class SendQueues @Inject constructor(
2930
private val matrixClient: MatrixClient,
30-
private val networkMonitor: NetworkMonitor,
31+
private val syncService: SyncService,
3132
) {
3233
/**
3334
* Launches the send queues retry mechanism in the given [coroutineScope].
@@ -36,12 +37,12 @@ class SendQueues @Inject constructor(
3637
@OptIn(FlowPreview::class)
3738
fun launchIn(coroutineScope: CoroutineScope) {
3839
combine(
39-
networkMonitor.connectivity,
40+
syncService.syncState,
4041
matrixClient.sendQueueDisabledFlow(),
41-
) { networkStatus, _ -> networkStatus }
42+
) { syncState, _ -> syncState }
4243
.debounce(SEND_QUEUES_RETRY_DELAY_MILLIS)
43-
.onEach { networkStatus ->
44-
if (networkStatus == NetworkStatus.Online) {
44+
.onEach { syncState ->
45+
if (syncState == SyncState.Running) {
4546
matrixClient.setAllSendQueuesEnabled(enabled = true)
4647
}
4748
}

appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
3030
import io.element.android.appnav.room.joined.LoadingRoomNodeView
3131
import io.element.android.appnav.room.joined.LoadingRoomState
3232
import io.element.android.features.joinroom.api.JoinRoomEntryPoint
33-
import io.element.android.features.networkmonitor.api.NetworkMonitor
34-
import io.element.android.features.networkmonitor.api.NetworkStatus
3533
import io.element.android.features.roomaliasesolver.api.RoomAliasResolverEntryPoint
3634
import io.element.android.features.roomdirectory.api.RoomDescription
3735
import io.element.android.libraries.architecture.BackstackView
@@ -50,6 +48,8 @@ import io.element.android.libraries.matrix.api.getRoomInfoFlow
5048
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
5149
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
5250
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
51+
import io.element.android.libraries.matrix.api.sync.SyncService
52+
import io.element.android.libraries.matrix.api.sync.isConnected
5353
import kotlinx.coroutines.flow.combine
5454
import kotlinx.coroutines.flow.distinctUntilChanged
5555
import kotlinx.coroutines.flow.first
@@ -68,7 +68,7 @@ class RoomFlowNode @AssistedInject constructor(
6868
private val client: MatrixClient,
6969
private val joinRoomEntryPoint: JoinRoomEntryPoint,
7070
private val roomAliasResolverEntryPoint: RoomAliasResolverEntryPoint,
71-
private val networkMonitor: NetworkMonitor,
71+
private val syncService: SyncService,
7272
private val membershipObserver: RoomMembershipObserver,
7373
) : BaseFlowNode<RoomFlowNode.NavTarget>(
7474
backstack = BackStack(
@@ -211,10 +211,10 @@ class RoomFlowNode @AssistedInject constructor(
211211
}
212212

213213
private fun loadingNode(buildContext: BuildContext) = node(buildContext) { modifier ->
214-
val networkStatus by networkMonitor.connectivity.collectAsState()
214+
val syncState by syncService.syncState.collectAsState()
215215
LoadingRoomNodeView(
216216
state = LoadingRoomState.Loading,
217-
hasNetworkConnection = networkStatus == NetworkStatus.Online,
217+
hasNetworkConnection = syncState.isConnected(),
218218
onBackClick = { navigateUp() },
219219
modifier = modifier,
220220
)

appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomFlowNode.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ import dagger.assisted.Assisted
2828
import dagger.assisted.AssistedInject
2929
import io.element.android.anvilannotations.ContributesNode
3030
import io.element.android.appnav.room.RoomNavigationTarget
31-
import io.element.android.features.networkmonitor.api.NetworkMonitor
32-
import io.element.android.features.networkmonitor.api.NetworkStatus
3331
import io.element.android.libraries.architecture.BackstackView
3432
import io.element.android.libraries.architecture.BaseFlowNode
3533
import io.element.android.libraries.architecture.NodeInputs
3634
import io.element.android.libraries.architecture.createNode
3735
import io.element.android.libraries.architecture.inputs
3836
import io.element.android.libraries.di.SessionScope
3937
import io.element.android.libraries.matrix.api.core.RoomId
38+
import io.element.android.libraries.matrix.api.sync.SyncService
39+
import io.element.android.libraries.matrix.api.sync.isConnected
4040
import kotlinx.coroutines.flow.distinctUntilChanged
4141
import kotlinx.coroutines.flow.launchIn
4242
import kotlinx.coroutines.flow.map
@@ -48,7 +48,7 @@ class JoinedRoomFlowNode @AssistedInject constructor(
4848
@Assisted val buildContext: BuildContext,
4949
@Assisted plugins: List<Plugin>,
5050
loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory,
51-
private val networkMonitor: NetworkMonitor,
51+
private val syncService: SyncService,
5252
) :
5353
BaseFlowNode<JoinedRoomFlowNode.NavTarget>(
5454
backstack = BackStack(
@@ -114,10 +114,10 @@ class JoinedRoomFlowNode @AssistedInject constructor(
114114

115115
private fun loadingNode(buildContext: BuildContext, onBackClick: () -> Unit) = node(buildContext) { modifier ->
116116
val loadingRoomState by loadingRoomStateStateFlow.collectAsState()
117-
val networkStatus by networkMonitor.connectivity.collectAsState()
117+
val syncState by syncService.syncState.collectAsState()
118118
LoadingRoomNodeView(
119119
state = loadingRoomState,
120-
hasNetworkConnection = networkStatus == NetworkStatus.Online,
120+
hasNetworkConnection = syncState.isConnected(),
121121
modifier = modifier,
122122
onBackClick = onBackClick
123123
)

appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ import app.cash.turbine.test
1414
import com.google.common.truth.Truth.assertThat
1515
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
1616
import im.vector.app.features.analytics.plan.UserProperties
17-
import io.element.android.features.networkmonitor.api.NetworkStatus
18-
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
1917
import io.element.android.libraries.matrix.api.MatrixClient
2018
import io.element.android.libraries.matrix.api.core.SessionId
2119
import io.element.android.libraries.matrix.api.encryption.EncryptionService
2220
import io.element.android.libraries.matrix.api.encryption.RecoveryState
2321
import io.element.android.libraries.matrix.api.roomlist.RoomListService
2422
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
23+
import io.element.android.libraries.matrix.api.sync.SyncState
2524
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
2625
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
2726
import io.element.android.libraries.matrix.test.AN_EXCEPTION
2827
import io.element.android.libraries.matrix.test.A_SESSION_ID
2928
import io.element.android.libraries.matrix.test.FakeMatrixClient
3029
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
3130
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
31+
import io.element.android.libraries.matrix.test.sync.FakeSyncService
3232
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
3333
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
3434
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
@@ -73,7 +73,7 @@ class LoggedInPresenterTest {
7373
@Test
7474
fun `present - show sync spinner`() = runTest {
7575
val roomListService = FakeRoomListService()
76-
val presenter = createLoggedInPresenter(roomListService, NetworkStatus.Online)
76+
val presenter = createLoggedInPresenter(roomListService, SyncState.Running)
7777
moleculeFlow(RecompositionMode.Immediate) {
7878
presenter.present()
7979
}.test {
@@ -94,7 +94,7 @@ class LoggedInPresenterTest {
9494
val encryptionService = FakeEncryptionService()
9595
val presenter = LoggedInPresenter(
9696
matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService),
97-
networkMonitor = FakeNetworkMonitor(NetworkStatus.Online),
97+
syncService = FakeSyncService(initialSyncState = SyncState.Running),
9898
pushService = FakePushService(),
9999
sessionVerificationService = verificationService,
100100
analyticsService = analyticsService,
@@ -574,7 +574,7 @@ class LoggedInPresenterTest {
574574

575575
private fun TestScope.createLoggedInPresenter(
576576
roomListService: RoomListService = FakeRoomListService(),
577-
networkStatus: NetworkStatus = NetworkStatus.Offline,
577+
syncState: SyncState = SyncState.Running,
578578
analyticsService: AnalyticsService = FakeAnalyticsService(),
579579
sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
580580
encryptionService: EncryptionService = FakeEncryptionService(),
@@ -584,7 +584,7 @@ class LoggedInPresenterTest {
584584
): LoggedInPresenter {
585585
return LoggedInPresenter(
586586
matrixClient = matrixClient,
587-
networkMonitor = FakeNetworkMonitor(networkStatus),
587+
syncService = FakeSyncService(initialSyncState = syncState),
588588
pushService = pushService,
589589
sessionVerificationService = sessionVerificationService,
590590
analyticsService = analyticsService,

appnav/src/test/kotlin/io/element/android/appnav/loggedin/SendQueuesTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
package io.element.android.appnav.loggedin
99

10-
import io.element.android.features.networkmonitor.api.NetworkStatus
11-
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
1210
import io.element.android.libraries.matrix.api.core.RoomId
11+
import io.element.android.libraries.matrix.api.sync.SyncState
1312
import io.element.android.libraries.matrix.test.FakeMatrixClient
1413
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
14+
import io.element.android.libraries.matrix.test.sync.FakeSyncService
1515
import io.element.android.tests.testutils.lambda.assert
1616
import io.element.android.tests.testutils.lambda.lambdaRecorder
1717
import io.element.android.tests.testutils.lambda.value
@@ -25,8 +25,8 @@ import org.junit.Test
2525
@OptIn(ExperimentalCoroutinesApi::class)
2626
class SendQueuesTest {
2727
private val matrixClient = FakeMatrixClient()
28-
private val networkMonitor = FakeNetworkMonitor()
29-
private val sut = SendQueues(matrixClient, networkMonitor)
28+
private val syncService = FakeSyncService(initialSyncState = SyncState.Running)
29+
private val sut = SendQueues(matrixClient, syncService)
3030

3131
@Test
3232
fun `test network status online and sending queue failed`() = runTest {
@@ -53,13 +53,13 @@ class SendQueuesTest {
5353
}
5454

5555
@Test
56-
fun `test network status offline and sending queue failed`() = runTest {
56+
fun `test sync state offline and sending queue failed`() = runTest {
5757
val sendQueueDisabledFlow = MutableSharedFlow<RoomId>(replay = 1)
5858

5959
val setAllSendQueuesEnabledLambda = lambdaRecorder { _: Boolean -> }
6060
matrixClient.sendQueueDisabledFlow = sendQueueDisabledFlow
6161
matrixClient.setAllSendQueuesEnabledLambda = setAllSendQueuesEnabledLambda
62-
networkMonitor.connectivity.value = NetworkStatus.Offline
62+
syncService.emitSyncState(SyncState.Offline)
6363
val setRoomSendQueueEnabledLambda = lambdaRecorder { _: Boolean -> }
6464
val room = FakeMatrixRoom(
6565
setSendQueueEnabledLambda = setRoomSendQueueEnabledLambda

features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import io.element.android.tests.testutils.lambda.value
4141
import io.element.android.tests.testutils.testCoroutineDispatchers
4242
import kotlinx.coroutines.ExperimentalCoroutinesApi
4343
import kotlinx.coroutines.cancelAndJoin
44-
import kotlinx.coroutines.flow.MutableStateFlow
4544
import kotlinx.coroutines.launch
4645
import kotlinx.coroutines.sync.Mutex
4746
import kotlinx.coroutines.test.TestScope
@@ -82,7 +81,7 @@ class CallScreenPresenterTest {
8281
@Test
8382
fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest {
8483
val sendCallNotificationIfNeededLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
85-
val syncService = FakeSyncService(MutableStateFlow(SyncState.Running))
84+
val syncService = FakeSyncService(SyncState.Running)
8685
val fakeRoom = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda)
8786
val client = FakeMatrixClient(syncService = syncService).apply {
8887
givenGetRoomResult(A_ROOM_ID, fakeRoom)
@@ -247,9 +246,8 @@ class CallScreenPresenterTest {
247246
fun `present - automatically starts the Matrix client sync when on RoomCall`() = runTest {
248247
val navigator = FakeCallScreenNavigator()
249248
val widgetDriver = FakeMatrixWidgetDriver()
250-
val syncStateFlow = MutableStateFlow(SyncState.Idle)
251249
val startSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
252-
val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply {
250+
val syncService = FakeSyncService(SyncState.Idle).apply {
253251
this.startSyncLambda = startSyncLambda
254252
}
255253
val matrixClient = FakeMatrixClient(syncService = syncService)
@@ -276,9 +274,8 @@ class CallScreenPresenterTest {
276274
fun `present - automatically stops the Matrix client sync on dispose`() = runTest {
277275
val navigator = FakeCallScreenNavigator()
278276
val widgetDriver = FakeMatrixWidgetDriver()
279-
val syncStateFlow = MutableStateFlow(SyncState.Running)
280277
val stopSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
281-
val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply {
278+
val syncService = FakeSyncService(SyncState.Running).apply {
282279
this.stopSyncLambda = stopSyncLambda
283280
}
284281
val matrixClient = FakeMatrixClient(syncService = syncService)

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
4747
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
4848
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
4949
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerState
50-
import io.element.android.features.networkmonitor.api.NetworkMonitor
51-
import io.element.android.features.networkmonitor.api.NetworkStatus
5250
import io.element.android.features.roomcall.api.RoomCallState
5351
import io.element.android.libraries.androidutils.clipboard.ClipboardHelper
5452
import io.element.android.libraries.architecture.AsyncData
@@ -72,6 +70,8 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin
7270
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
7371
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
7472
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
73+
import io.element.android.libraries.matrix.api.sync.SyncService
74+
import io.element.android.libraries.matrix.api.sync.isConnected
7575
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
7676
import io.element.android.libraries.matrix.ui.messages.reply.map
7777
import io.element.android.libraries.matrix.ui.model.getAvatarData
@@ -98,7 +98,7 @@ class MessagesPresenter @AssistedInject constructor(
9898
private val readReceiptBottomSheetPresenter: Presenter<ReadReceiptBottomSheetState>,
9999
private val pinnedMessagesBannerPresenter: Presenter<PinnedMessagesBannerState>,
100100
private val roomCallStatePresenter: Presenter<RoomCallState>,
101-
private val networkMonitor: NetworkMonitor,
101+
private val syncService: SyncService,
102102
private val snackbarDispatcher: SnackbarDispatcher,
103103
private val dispatchers: CoroutineDispatchers,
104104
private val clipboardHelper: ClipboardHelper,
@@ -170,7 +170,7 @@ class MessagesPresenter @AssistedInject constructor(
170170
showReinvitePrompt = !hasDismissedInviteDialog && composerState.textEditorState.hasFocus() && room.isDm && room.activeMemberCount == 1L
171171
}
172172
}
173-
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
173+
val syncState by syncService.syncState.collectAsState()
174174

175175
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
176176

@@ -220,7 +220,7 @@ class MessagesPresenter @AssistedInject constructor(
220220
customReactionState = customReactionState,
221221
reactionSummaryState = reactionSummaryState,
222222
readReceiptBottomSheetState = readReceiptBottomSheetState,
223-
hasNetworkConnection = networkConnectionStatus == NetworkStatus.Online,
223+
hasNetworkConnection = syncState.isConnected(),
224224
snackbarMessage = snackbarMessage,
225225
showReinvitePrompt = showReinvitePrompt,
226226
inviteProgress = inviteProgress.value,

0 commit comments

Comments
 (0)