Merge pull request #4215 from element-hq/feature/bma/airGappedSdk
Let the SDK provide the "network is available information"
This commit is contained in:
commit
34862d70ab
20 changed files with 86 additions and 74 deletions
|
|
@ -19,8 +19,6 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
|
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
|
||||||
import im.vector.app.features.analytics.plan.UserProperties
|
import im.vector.app.features.analytics.plan.UserProperties
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||||
|
|
@ -29,6 +27,8 @@ import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.isOnline
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||||
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
|
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
|
||||||
|
|
@ -46,7 +46,7 @@ private val pusherTag = LoggerTag("Pusher", LoggerTag.PushLoggerTag)
|
||||||
|
|
||||||
class LoggedInPresenter @Inject constructor(
|
class LoggedInPresenter @Inject constructor(
|
||||||
private val matrixClient: MatrixClient,
|
private val matrixClient: MatrixClient,
|
||||||
private val networkMonitor: NetworkMonitor,
|
private val syncService: SyncService,
|
||||||
private val pushService: PushService,
|
private val pushService: PushService,
|
||||||
private val sessionVerificationService: SessionVerificationService,
|
private val sessionVerificationService: SessionVerificationService,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
|
|
@ -76,10 +76,10 @@ class LoggedInPresenter @Inject constructor(
|
||||||
.launchIn(this)
|
.launchIn(this)
|
||||||
}
|
}
|
||||||
val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState()
|
val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState()
|
||||||
val networkStatus by networkMonitor.connectivity.collectAsState()
|
val isOnline by syncService.isOnline().collectAsState()
|
||||||
val showSyncSpinner by remember {
|
val showSyncSpinner by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
networkStatus == NetworkStatus.Online && syncIndicator == RoomListService.SyncIndicator.Show
|
isOnline && syncIndicator == RoomListService.SyncIndicator.Show
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var forceNativeSlidingSyncMigration by remember { mutableStateOf(false) }
|
var forceNativeSlidingSyncMigration by remember { mutableStateOf(false) }
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,12 @@
|
||||||
package io.element.android.appnav.loggedin
|
package io.element.android.appnav.loggedin
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.di.SingleIn
|
import io.element.android.libraries.di.SingleIn
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
|
@ -27,7 +28,7 @@ const val SEND_QUEUES_RETRY_DELAY_MILLIS = 500L
|
||||||
@SingleIn(SessionScope::class)
|
@SingleIn(SessionScope::class)
|
||||||
class SendQueues @Inject constructor(
|
class SendQueues @Inject constructor(
|
||||||
private val matrixClient: MatrixClient,
|
private val matrixClient: MatrixClient,
|
||||||
private val networkMonitor: NetworkMonitor,
|
private val syncService: SyncService,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Launches the send queues retry mechanism in the given [coroutineScope].
|
* Launches the send queues retry mechanism in the given [coroutineScope].
|
||||||
|
|
@ -36,12 +37,12 @@ class SendQueues @Inject constructor(
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
fun launchIn(coroutineScope: CoroutineScope) {
|
fun launchIn(coroutineScope: CoroutineScope) {
|
||||||
combine(
|
combine(
|
||||||
networkMonitor.connectivity,
|
syncService.syncState,
|
||||||
matrixClient.sendQueueDisabledFlow(),
|
matrixClient.sendQueueDisabledFlow(),
|
||||||
) { networkStatus, _ -> networkStatus }
|
) { syncState, _ -> syncState }
|
||||||
.debounce(SEND_QUEUES_RETRY_DELAY_MILLIS)
|
.debounce(SEND_QUEUES_RETRY_DELAY_MILLIS)
|
||||||
.onEach { networkStatus ->
|
.onEach { syncState ->
|
||||||
if (networkStatus == NetworkStatus.Online) {
|
if (syncState == SyncState.Running) {
|
||||||
matrixClient.setAllSendQueuesEnabled(enabled = true)
|
matrixClient.setAllSendQueuesEnabled(enabled = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@ import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
|
||||||
import io.element.android.appnav.room.joined.LoadingRoomNodeView
|
import io.element.android.appnav.room.joined.LoadingRoomNodeView
|
||||||
import io.element.android.appnav.room.joined.LoadingRoomState
|
import io.element.android.appnav.room.joined.LoadingRoomState
|
||||||
import io.element.android.features.joinroom.api.JoinRoomEntryPoint
|
import io.element.android.features.joinroom.api.JoinRoomEntryPoint
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
|
||||||
import io.element.android.features.roomaliasesolver.api.RoomAliasResolverEntryPoint
|
import io.element.android.features.roomaliasesolver.api.RoomAliasResolverEntryPoint
|
||||||
import io.element.android.features.roomdirectory.api.RoomDescription
|
import io.element.android.features.roomdirectory.api.RoomDescription
|
||||||
import io.element.android.libraries.architecture.BackstackView
|
import io.element.android.libraries.architecture.BackstackView
|
||||||
|
|
@ -50,6 +48,8 @@ import io.element.android.libraries.matrix.api.getRoomInfoFlow
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.isOnline
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
|
@ -68,7 +68,7 @@ class RoomFlowNode @AssistedInject constructor(
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
private val joinRoomEntryPoint: JoinRoomEntryPoint,
|
private val joinRoomEntryPoint: JoinRoomEntryPoint,
|
||||||
private val roomAliasResolverEntryPoint: RoomAliasResolverEntryPoint,
|
private val roomAliasResolverEntryPoint: RoomAliasResolverEntryPoint,
|
||||||
private val networkMonitor: NetworkMonitor,
|
private val syncService: SyncService,
|
||||||
private val membershipObserver: RoomMembershipObserver,
|
private val membershipObserver: RoomMembershipObserver,
|
||||||
) : BaseFlowNode<RoomFlowNode.NavTarget>(
|
) : BaseFlowNode<RoomFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
|
|
@ -211,10 +211,10 @@ class RoomFlowNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadingNode(buildContext: BuildContext) = node(buildContext) { modifier ->
|
private fun loadingNode(buildContext: BuildContext) = node(buildContext) { modifier ->
|
||||||
val networkStatus by networkMonitor.connectivity.collectAsState()
|
val isOnline by syncService.isOnline().collectAsState()
|
||||||
LoadingRoomNodeView(
|
LoadingRoomNodeView(
|
||||||
state = LoadingRoomState.Loading,
|
state = LoadingRoomState.Loading,
|
||||||
hasNetworkConnection = networkStatus == NetworkStatus.Online,
|
hasNetworkConnection = isOnline,
|
||||||
onBackClick = { navigateUp() },
|
onBackClick = { navigateUp() },
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.appnav.room.RoomNavigationTarget
|
import io.element.android.appnav.room.RoomNavigationTarget
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
|
||||||
import io.element.android.libraries.architecture.BackstackView
|
import io.element.android.libraries.architecture.BackstackView
|
||||||
import io.element.android.libraries.architecture.BaseFlowNode
|
import io.element.android.libraries.architecture.BaseFlowNode
|
||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
|
|
@ -37,6 +35,8 @@ import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
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.SyncService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.isOnline
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
@ -48,7 +48,7 @@ class JoinedRoomFlowNode @AssistedInject constructor(
|
||||||
@Assisted val buildContext: BuildContext,
|
@Assisted val buildContext: BuildContext,
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory,
|
loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory,
|
||||||
private val networkMonitor: NetworkMonitor,
|
private val syncService: SyncService,
|
||||||
) :
|
) :
|
||||||
BaseFlowNode<JoinedRoomFlowNode.NavTarget>(
|
BaseFlowNode<JoinedRoomFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
|
|
@ -114,10 +114,10 @@ class JoinedRoomFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
private fun loadingNode(buildContext: BuildContext, onBackClick: () -> Unit) = node(buildContext) { modifier ->
|
private fun loadingNode(buildContext: BuildContext, onBackClick: () -> Unit) = node(buildContext) { modifier ->
|
||||||
val loadingRoomState by loadingRoomStateStateFlow.collectAsState()
|
val loadingRoomState by loadingRoomStateStateFlow.collectAsState()
|
||||||
val networkStatus by networkMonitor.connectivity.collectAsState()
|
val isOnline by syncService.isOnline().collectAsState()
|
||||||
LoadingRoomNodeView(
|
LoadingRoomNodeView(
|
||||||
state = loadingRoomState,
|
state = loadingRoomState,
|
||||||
hasNetworkConnection = networkStatus == NetworkStatus.Online,
|
hasNetworkConnection = isOnline,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onBackClick = onBackClick
|
onBackClick = onBackClick
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,13 @@ import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
|
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
|
||||||
import im.vector.app.features.analytics.plan.UserProperties
|
import im.vector.app.features.analytics.plan.UserProperties
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
|
||||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
|
|
@ -29,6 +28,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
||||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||||
|
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||||
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
||||||
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
|
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
|
||||||
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
|
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
|
||||||
|
|
@ -73,7 +73,7 @@ class LoggedInPresenterTest {
|
||||||
@Test
|
@Test
|
||||||
fun `present - show sync spinner`() = runTest {
|
fun `present - show sync spinner`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomListService = FakeRoomListService()
|
||||||
val presenter = createLoggedInPresenter(roomListService, NetworkStatus.Online)
|
val presenter = createLoggedInPresenter(roomListService, SyncState.Running)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -94,7 +94,7 @@ class LoggedInPresenterTest {
|
||||||
val encryptionService = FakeEncryptionService()
|
val encryptionService = FakeEncryptionService()
|
||||||
val presenter = LoggedInPresenter(
|
val presenter = LoggedInPresenter(
|
||||||
matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService),
|
matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService),
|
||||||
networkMonitor = FakeNetworkMonitor(NetworkStatus.Online),
|
syncService = FakeSyncService(initialSyncState = SyncState.Running),
|
||||||
pushService = FakePushService(),
|
pushService = FakePushService(),
|
||||||
sessionVerificationService = verificationService,
|
sessionVerificationService = verificationService,
|
||||||
analyticsService = analyticsService,
|
analyticsService = analyticsService,
|
||||||
|
|
@ -574,7 +574,7 @@ class LoggedInPresenterTest {
|
||||||
|
|
||||||
private fun TestScope.createLoggedInPresenter(
|
private fun TestScope.createLoggedInPresenter(
|
||||||
roomListService: RoomListService = FakeRoomListService(),
|
roomListService: RoomListService = FakeRoomListService(),
|
||||||
networkStatus: NetworkStatus = NetworkStatus.Offline,
|
syncState: SyncState = SyncState.Running,
|
||||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||||
sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
|
sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
|
||||||
encryptionService: EncryptionService = FakeEncryptionService(),
|
encryptionService: EncryptionService = FakeEncryptionService(),
|
||||||
|
|
@ -584,7 +584,7 @@ class LoggedInPresenterTest {
|
||||||
): LoggedInPresenter {
|
): LoggedInPresenter {
|
||||||
return LoggedInPresenter(
|
return LoggedInPresenter(
|
||||||
matrixClient = matrixClient,
|
matrixClient = matrixClient,
|
||||||
networkMonitor = FakeNetworkMonitor(networkStatus),
|
syncService = FakeSyncService(initialSyncState = syncState),
|
||||||
pushService = pushService,
|
pushService = pushService,
|
||||||
sessionVerificationService = sessionVerificationService,
|
sessionVerificationService = sessionVerificationService,
|
||||||
analyticsService = analyticsService,
|
analyticsService = analyticsService,
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@
|
||||||
|
|
||||||
package io.element.android.appnav.loggedin
|
package io.element.android.appnav.loggedin
|
||||||
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
|
||||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
|
||||||
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.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
|
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||||
import io.element.android.tests.testutils.lambda.assert
|
import io.element.android.tests.testutils.lambda.assert
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
|
|
@ -25,8 +25,8 @@ import org.junit.Test
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class SendQueuesTest {
|
class SendQueuesTest {
|
||||||
private val matrixClient = FakeMatrixClient()
|
private val matrixClient = FakeMatrixClient()
|
||||||
private val networkMonitor = FakeNetworkMonitor()
|
private val syncService = FakeSyncService(initialSyncState = SyncState.Running)
|
||||||
private val sut = SendQueues(matrixClient, networkMonitor)
|
private val sut = SendQueues(matrixClient, syncService)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test network status online and sending queue failed`() = runTest {
|
fun `test network status online and sending queue failed`() = runTest {
|
||||||
|
|
@ -53,13 +53,13 @@ class SendQueuesTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test network status offline and sending queue failed`() = runTest {
|
fun `test sync state offline and sending queue failed`() = runTest {
|
||||||
val sendQueueDisabledFlow = MutableSharedFlow<RoomId>(replay = 1)
|
val sendQueueDisabledFlow = MutableSharedFlow<RoomId>(replay = 1)
|
||||||
|
|
||||||
val setAllSendQueuesEnabledLambda = lambdaRecorder { _: Boolean -> }
|
val setAllSendQueuesEnabledLambda = lambdaRecorder { _: Boolean -> }
|
||||||
matrixClient.sendQueueDisabledFlow = sendQueueDisabledFlow
|
matrixClient.sendQueueDisabledFlow = sendQueueDisabledFlow
|
||||||
matrixClient.setAllSendQueuesEnabledLambda = setAllSendQueuesEnabledLambda
|
matrixClient.setAllSendQueuesEnabledLambda = setAllSendQueuesEnabledLambda
|
||||||
networkMonitor.connectivity.value = NetworkStatus.Offline
|
syncService.emitSyncState(SyncState.Offline)
|
||||||
val setRoomSendQueueEnabledLambda = lambdaRecorder { _: Boolean -> }
|
val setRoomSendQueueEnabledLambda = lambdaRecorder { _: Boolean -> }
|
||||||
val room = FakeMatrixRoom(
|
val room = FakeMatrixRoom(
|
||||||
setSendQueueEnabledLambda = setRoomSendQueueEnabledLambda
|
setSendQueueEnabledLambda = setRoomSendQueueEnabledLambda
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import io.element.android.tests.testutils.lambda.value
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.cancelAndJoin
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
|
@ -82,7 +81,7 @@ class CallScreenPresenterTest {
|
||||||
@Test
|
@Test
|
||||||
fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest {
|
fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest {
|
||||||
val sendCallNotificationIfNeededLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
val sendCallNotificationIfNeededLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||||
val syncService = FakeSyncService(MutableStateFlow(SyncState.Running))
|
val syncService = FakeSyncService(SyncState.Running)
|
||||||
val fakeRoom = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda)
|
val fakeRoom = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda)
|
||||||
val client = FakeMatrixClient(syncService = syncService).apply {
|
val client = FakeMatrixClient(syncService = syncService).apply {
|
||||||
givenGetRoomResult(A_ROOM_ID, fakeRoom)
|
givenGetRoomResult(A_ROOM_ID, fakeRoom)
|
||||||
|
|
@ -247,9 +246,8 @@ class CallScreenPresenterTest {
|
||||||
fun `present - automatically starts the Matrix client sync when on RoomCall`() = runTest {
|
fun `present - automatically starts the Matrix client sync when on RoomCall`() = runTest {
|
||||||
val navigator = FakeCallScreenNavigator()
|
val navigator = FakeCallScreenNavigator()
|
||||||
val widgetDriver = FakeMatrixWidgetDriver()
|
val widgetDriver = FakeMatrixWidgetDriver()
|
||||||
val syncStateFlow = MutableStateFlow(SyncState.Idle)
|
|
||||||
val startSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
val startSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||||
val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply {
|
val syncService = FakeSyncService(SyncState.Idle).apply {
|
||||||
this.startSyncLambda = startSyncLambda
|
this.startSyncLambda = startSyncLambda
|
||||||
}
|
}
|
||||||
val matrixClient = FakeMatrixClient(syncService = syncService)
|
val matrixClient = FakeMatrixClient(syncService = syncService)
|
||||||
|
|
@ -276,9 +274,8 @@ class CallScreenPresenterTest {
|
||||||
fun `present - automatically stops the Matrix client sync on dispose`() = runTest {
|
fun `present - automatically stops the Matrix client sync on dispose`() = runTest {
|
||||||
val navigator = FakeCallScreenNavigator()
|
val navigator = FakeCallScreenNavigator()
|
||||||
val widgetDriver = FakeMatrixWidgetDriver()
|
val widgetDriver = FakeMatrixWidgetDriver()
|
||||||
val syncStateFlow = MutableStateFlow(SyncState.Running)
|
|
||||||
val stopSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
val stopSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||||
val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply {
|
val syncService = FakeSyncService(SyncState.Running).apply {
|
||||||
this.stopSyncLambda = stopSyncLambda
|
this.stopSyncLambda = stopSyncLambda
|
||||||
}
|
}
|
||||||
val matrixClient = FakeMatrixClient(syncService = syncService)
|
val matrixClient = FakeMatrixClient(syncService = syncService)
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,6 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
||||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
|
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
|
||||||
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerState
|
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerState
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
|
||||||
import io.element.android.features.roomcall.api.RoomCallState
|
import io.element.android.features.roomcall.api.RoomCallState
|
||||||
import io.element.android.libraries.androidutils.clipboard.ClipboardHelper
|
import io.element.android.libraries.androidutils.clipboard.ClipboardHelper
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
|
@ -72,6 +70,8 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
|
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.isOnline
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||||
import io.element.android.libraries.matrix.ui.messages.reply.map
|
import io.element.android.libraries.matrix.ui.messages.reply.map
|
||||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||||
|
|
@ -98,7 +98,7 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
private val readReceiptBottomSheetPresenter: Presenter<ReadReceiptBottomSheetState>,
|
private val readReceiptBottomSheetPresenter: Presenter<ReadReceiptBottomSheetState>,
|
||||||
private val pinnedMessagesBannerPresenter: Presenter<PinnedMessagesBannerState>,
|
private val pinnedMessagesBannerPresenter: Presenter<PinnedMessagesBannerState>,
|
||||||
private val roomCallStatePresenter: Presenter<RoomCallState>,
|
private val roomCallStatePresenter: Presenter<RoomCallState>,
|
||||||
private val networkMonitor: NetworkMonitor,
|
private val syncService: SyncService,
|
||||||
private val snackbarDispatcher: SnackbarDispatcher,
|
private val snackbarDispatcher: SnackbarDispatcher,
|
||||||
private val dispatchers: CoroutineDispatchers,
|
private val dispatchers: CoroutineDispatchers,
|
||||||
private val clipboardHelper: ClipboardHelper,
|
private val clipboardHelper: ClipboardHelper,
|
||||||
|
|
@ -170,7 +170,7 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
showReinvitePrompt = !hasDismissedInviteDialog && composerState.textEditorState.hasFocus() && room.isDm && room.activeMemberCount == 1L
|
showReinvitePrompt = !hasDismissedInviteDialog && composerState.textEditorState.hasFocus() && room.isDm && room.activeMemberCount == 1L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
|
val isOnline by syncService.isOnline().collectAsState()
|
||||||
|
|
||||||
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
|
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
|
||||||
|
|
||||||
|
|
@ -220,7 +220,7 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
customReactionState = customReactionState,
|
customReactionState = customReactionState,
|
||||||
reactionSummaryState = reactionSummaryState,
|
reactionSummaryState = reactionSummaryState,
|
||||||
readReceiptBottomSheetState = readReceiptBottomSheetState,
|
readReceiptBottomSheetState = readReceiptBottomSheetState,
|
||||||
hasNetworkConnection = networkConnectionStatus == NetworkStatus.Online,
|
hasNetworkConnection = isOnline,
|
||||||
snackbarMessage = snackbarMessage,
|
snackbarMessage = snackbarMessage,
|
||||||
showReinvitePrompt = showReinvitePrompt,
|
showReinvitePrompt = showReinvitePrompt,
|
||||||
inviteProgress = inviteProgress.value,
|
inviteProgress = inviteProgress.value,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.pinned
|
package io.element.android.features.messages.impl.pinned
|
||||||
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.core.coroutine.mapState
|
import io.element.android.libraries.core.coroutine.mapState
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
|
|
@ -15,6 +14,7 @@ import io.element.android.libraries.di.SingleIn
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -31,7 +31,7 @@ import javax.inject.Inject
|
||||||
@SingleIn(RoomScope::class)
|
@SingleIn(RoomScope::class)
|
||||||
class PinnedEventsTimelineProvider @Inject constructor(
|
class PinnedEventsTimelineProvider @Inject constructor(
|
||||||
private val room: MatrixRoom,
|
private val room: MatrixRoom,
|
||||||
private val networkMonitor: NetworkMonitor,
|
private val syncService: SyncService,
|
||||||
private val featureFlagService: FeatureFlagService,
|
private val featureFlagService: FeatureFlagService,
|
||||||
) : TimelineProvider {
|
) : TimelineProvider {
|
||||||
private val _timelineStateFlow: MutableStateFlow<AsyncData<Timeline>> =
|
private val _timelineStateFlow: MutableStateFlow<AsyncData<Timeline>> =
|
||||||
|
|
@ -63,9 +63,9 @@ class PinnedEventsTimelineProvider @Inject constructor(
|
||||||
private suspend fun onActive() = coroutineScope {
|
private suspend fun onActive() = coroutineScope {
|
||||||
combine(
|
combine(
|
||||||
featureFlagService.isFeatureEnabledFlow(FeatureFlags.PinnedEvents),
|
featureFlagService.isFeatureEnabledFlow(FeatureFlags.PinnedEvents),
|
||||||
networkMonitor.connectivity
|
syncService.syncState,
|
||||||
) { isEnabled, _ ->
|
) { isEnabled, _ ->
|
||||||
// do not use connectivity here as data can be loaded from cache, it's just to trigger retry if needed
|
// do not use syncState here as data can be loaded from cache, it's just to trigger retry if needed
|
||||||
isEnabled
|
isEnabled
|
||||||
}
|
}
|
||||||
.onEach { isFeatureEnabled ->
|
.onEach { isFeatureEnabled ->
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI
|
||||||
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
|
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
|
||||||
import io.element.android.features.messages.impl.voicemessages.composer.aVoiceMessageComposerState
|
import io.element.android.features.messages.impl.voicemessages.composer.aVoiceMessageComposerState
|
||||||
import io.element.android.features.messages.test.timeline.FakeHtmlConverterProvider
|
import io.element.android.features.messages.test.timeline.FakeHtmlConverterProvider
|
||||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
|
||||||
import io.element.android.features.roomcall.api.aStandByCallState
|
import io.element.android.features.roomcall.api.aStandByCallState
|
||||||
import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper
|
import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
|
@ -72,6 +71,7 @@ import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||||
|
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||||
import io.element.android.libraries.matrix.test.timeline.aTimelineItemDebugInfo
|
import io.element.android.libraries.matrix.test.timeline.aTimelineItemDebugInfo
|
||||||
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
|
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
|
||||||
|
|
@ -1187,7 +1187,7 @@ class MessagesPresenterTest {
|
||||||
identityChangeStatePresenter = { anIdentityChangeState() },
|
identityChangeStatePresenter = { anIdentityChangeState() },
|
||||||
pinnedMessagesBannerPresenter = { aLoadedPinnedMessagesBannerState() },
|
pinnedMessagesBannerPresenter = { aLoadedPinnedMessagesBannerState() },
|
||||||
roomCallStatePresenter = { aStandByCallState() },
|
roomCallStatePresenter = { aStandByCallState() },
|
||||||
networkMonitor = FakeNetworkMonitor(),
|
syncService = FakeSyncService(),
|
||||||
snackbarDispatcher = SnackbarDispatcher(),
|
snackbarDispatcher = SnackbarDispatcher(),
|
||||||
navigator = navigator,
|
navigator = navigator,
|
||||||
clipboardHelper = clipboardHelper,
|
clipboardHelper = clipboardHelper,
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,11 @@ package io.element.android.features.messages.impl.pinned.banner
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
|
||||||
import io.element.android.libraries.eventformatter.test.FakePinnedMessagesBannerFormatter
|
import io.element.android.libraries.eventformatter.test.FakePinnedMessagesBannerFormatter
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
|
||||||
|
|
@ -22,6 +21,7 @@ import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
||||||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2
|
import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||||
|
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||||
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
||||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||||
|
|
@ -186,12 +186,12 @@ class PinnedMessagesBannerPresenterTest {
|
||||||
formatLambda = { event -> "${event.content}" }
|
formatLambda = { event -> "${event.content}" }
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
networkMonitor: NetworkMonitor = FakeNetworkMonitor(),
|
syncService: SyncService = FakeSyncService(),
|
||||||
isFeatureEnabled: Boolean = true,
|
isFeatureEnabled: Boolean = true,
|
||||||
): PinnedMessagesBannerPresenter {
|
): PinnedMessagesBannerPresenter {
|
||||||
val timelineProvider = PinnedEventsTimelineProvider(
|
val timelineProvider = PinnedEventsTimelineProvider(
|
||||||
room = room,
|
room = room,
|
||||||
networkMonitor = networkMonitor,
|
syncService = syncService,
|
||||||
featureFlagService = FakeFeatureFlagService(
|
featureFlagService = FakeFeatureFlagService(
|
||||||
initialState = mapOf(FeatureFlags.PinnedEvents.key to isFeatureEnabled)
|
initialState = mapOf(FeatureFlags.PinnedEvents.key to isFeatureEnabled)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,12 @@ import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactoryC
|
||||||
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
|
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
|
@ -29,6 +28,7 @@ import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||||
|
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||||
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
||||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||||
|
|
@ -293,13 +293,13 @@ class PinnedMessagesListPresenterTest {
|
||||||
private fun TestScope.createPinnedMessagesListPresenter(
|
private fun TestScope.createPinnedMessagesListPresenter(
|
||||||
navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(),
|
navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(),
|
||||||
room: MatrixRoom = FakeMatrixRoom(),
|
room: MatrixRoom = FakeMatrixRoom(),
|
||||||
networkMonitor: NetworkMonitor = FakeNetworkMonitor(),
|
syncService: SyncService = FakeSyncService(),
|
||||||
isFeatureEnabled: Boolean = true,
|
isFeatureEnabled: Boolean = true,
|
||||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||||
): PinnedMessagesListPresenter {
|
): PinnedMessagesListPresenter {
|
||||||
val timelineProvider = PinnedEventsTimelineProvider(
|
val timelineProvider = PinnedEventsTimelineProvider(
|
||||||
room = room,
|
room = room,
|
||||||
networkMonitor = networkMonitor,
|
syncService = syncService,
|
||||||
featureFlagService = FakeFeatureFlagService(
|
featureFlagService = FakeFeatureFlagService(
|
||||||
initialState = mapOf(FeatureFlags.PinnedEvents.key to isFeatureEnabled)
|
initialState = mapOf(FeatureFlags.PinnedEvents.key to isFeatureEnabled)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@ import io.element.android.features.invite.api.response.InviteData
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
import io.element.android.features.leaveroom.api.LeaveRoomState
|
||||||
import io.element.android.features.logout.api.direct.DirectLogoutState
|
import io.element.android.features.logout.api.direct.DirectLogoutState
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
|
||||||
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
|
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
|
||||||
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
|
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
|
||||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||||
|
|
@ -51,6 +49,8 @@ import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.isOnline
|
||||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
||||||
|
|
@ -76,7 +76,7 @@ private const val SUBSCRIBE_TO_VISIBLE_ROOMS_DEBOUNCE_IN_MILLIS = 300L
|
||||||
|
|
||||||
class RoomListPresenter @Inject constructor(
|
class RoomListPresenter @Inject constructor(
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
private val networkMonitor: NetworkMonitor,
|
private val syncService: SyncService,
|
||||||
private val snackbarDispatcher: SnackbarDispatcher,
|
private val snackbarDispatcher: SnackbarDispatcher,
|
||||||
private val leaveRoomPresenter: Presenter<LeaveRoomState>,
|
private val leaveRoomPresenter: Presenter<LeaveRoomState>,
|
||||||
private val roomListDataSource: RoomListDataSource,
|
private val roomListDataSource: RoomListDataSource,
|
||||||
|
|
@ -98,7 +98,7 @@ class RoomListPresenter @Inject constructor(
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val leaveRoomState = leaveRoomPresenter.present()
|
val leaveRoomState = leaveRoomPresenter.present()
|
||||||
val matrixUser = client.userProfile.collectAsState()
|
val matrixUser = client.userProfile.collectAsState()
|
||||||
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
|
val isOnline by syncService.isOnline().collectAsState()
|
||||||
val filtersState = filtersPresenter.present()
|
val filtersState = filtersPresenter.present()
|
||||||
val searchState = searchPresenter.present()
|
val searchState = searchPresenter.present()
|
||||||
val acceptDeclineInviteState = acceptDeclineInvitePresenter.present()
|
val acceptDeclineInviteState = acceptDeclineInvitePresenter.present()
|
||||||
|
|
@ -158,7 +158,7 @@ class RoomListPresenter @Inject constructor(
|
||||||
matrixUser = matrixUser.value,
|
matrixUser = matrixUser.value,
|
||||||
showAvatarIndicator = showAvatarIndicator,
|
showAvatarIndicator = showAvatarIndicator,
|
||||||
snackbarMessage = snackbarMessage,
|
snackbarMessage = snackbarMessage,
|
||||||
hasNetworkConnection = networkConnectionStatus == NetworkStatus.Online,
|
hasNetworkConnection = isOnline,
|
||||||
contextMenu = contextMenu.value,
|
contextMenu = contextMenu.value,
|
||||||
leaveRoomState = leaveRoomState,
|
leaveRoomState = leaveRoomState,
|
||||||
filtersState = filtersState,
|
filtersState = filtersState,
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@ import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
import io.element.android.features.leaveroom.api.LeaveRoomState
|
||||||
import io.element.android.features.leaveroom.api.aLeaveRoomState
|
import io.element.android.features.leaveroom.api.aLeaveRoomState
|
||||||
import io.element.android.features.logout.api.direct.aDirectLogoutState
|
import io.element.android.features.logout.api.direct.aDirectLogoutState
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
|
||||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
|
||||||
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
|
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
|
||||||
import io.element.android.features.roomlist.impl.datasource.aRoomListRoomSummaryFactory
|
import io.element.android.features.roomlist.impl.datasource.aRoomListRoomSummaryFactory
|
||||||
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
|
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
|
||||||
|
|
@ -48,6 +46,7 @@ import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
@ -84,7 +83,6 @@ import io.element.android.tests.testutils.test
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.advanceTimeBy
|
import kotlinx.coroutines.test.advanceTimeBy
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -202,7 +200,7 @@ class RoomListPresenterTest {
|
||||||
val encryptionService = FakeEncryptionService().apply {
|
val encryptionService = FakeEncryptionService().apply {
|
||||||
emitRecoveryState(RecoveryState.INCOMPLETE)
|
emitRecoveryState(RecoveryState.INCOMPLETE)
|
||||||
}
|
}
|
||||||
val syncService = FakeSyncService(MutableStateFlow(SyncState.Running))
|
val syncService = FakeSyncService(initialSyncState = SyncState.Running)
|
||||||
val presenter = createRoomListPresenter(
|
val presenter = createRoomListPresenter(
|
||||||
client = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService, syncService = syncService),
|
client = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService, syncService = syncService),
|
||||||
)
|
)
|
||||||
|
|
@ -233,7 +231,7 @@ class RoomListPresenterTest {
|
||||||
sessionVerificationService = FakeSessionVerificationService().apply {
|
sessionVerificationService = FakeSessionVerificationService().apply {
|
||||||
emitNeedsSessionVerification(false)
|
emitNeedsSessionVerification(false)
|
||||||
},
|
},
|
||||||
syncService = FakeSyncService(MutableStateFlow(SyncState.Running)),
|
syncService = FakeSyncService(initialSyncState = SyncState.Running),
|
||||||
)
|
)
|
||||||
val presenter = createRoomListPresenter(
|
val presenter = createRoomListPresenter(
|
||||||
client = matrixClient,
|
client = matrixClient,
|
||||||
|
|
@ -633,7 +631,7 @@ class RoomListPresenterTest {
|
||||||
|
|
||||||
private fun TestScope.createRoomListPresenter(
|
private fun TestScope.createRoomListPresenter(
|
||||||
client: MatrixClient = FakeMatrixClient(),
|
client: MatrixClient = FakeMatrixClient(),
|
||||||
networkMonitor: NetworkMonitor = FakeNetworkMonitor(),
|
syncService: SyncService = FakeSyncService(),
|
||||||
snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
|
snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
|
||||||
leaveRoomState: LeaveRoomState = aLeaveRoomState(),
|
leaveRoomState: LeaveRoomState = aLeaveRoomState(),
|
||||||
dateFormatter: DateFormatter = FakeDateFormatter(),
|
dateFormatter: DateFormatter = FakeDateFormatter(),
|
||||||
|
|
@ -647,7 +645,7 @@ class RoomListPresenterTest {
|
||||||
notificationCleaner: NotificationCleaner = FakeNotificationCleaner(),
|
notificationCleaner: NotificationCleaner = FakeNotificationCleaner(),
|
||||||
) = RoomListPresenter(
|
) = RoomListPresenter(
|
||||||
client = client,
|
client = client,
|
||||||
networkMonitor = networkMonitor,
|
syncService = syncService,
|
||||||
snackbarDispatcher = snackbarDispatcher,
|
snackbarDispatcher = snackbarDispatcher,
|
||||||
leaveRoomPresenter = { leaveRoomState },
|
leaveRoomPresenter = { leaveRoomState },
|
||||||
roomListDataSource = RoomListDataSource(
|
roomListDataSource = RoomListDataSource(
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.sync
|
package io.element.android.libraries.matrix.api.sync
|
||||||
|
|
||||||
|
import io.element.android.libraries.core.coroutine.mapState
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
interface SyncService {
|
interface SyncService {
|
||||||
|
|
@ -25,3 +26,5 @@ interface SyncService {
|
||||||
*/
|
*/
|
||||||
val syncState: StateFlow<SyncState>
|
val syncState: StateFlow<SyncState>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun SyncService.isOnline(): StateFlow<Boolean> = syncState.mapState { it != SyncState.Offline }
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ class RustMatrixClientFactory @Inject constructor(
|
||||||
|
|
||||||
val syncService = client.syncService()
|
val syncService = client.syncService()
|
||||||
.withUtdHook(UtdTracker(analyticsService))
|
.withUtdHook(UtdTracker(analyticsService))
|
||||||
|
.withOfflineMode()
|
||||||
.finish()
|
.finish()
|
||||||
|
|
||||||
return RustMatrixClient(
|
return RustMatrixClient(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
|
|
@ -45,6 +46,11 @@ object SessionMatrixModule {
|
||||||
return matrixClient.roomListService
|
return matrixClient.roomListService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun providesSyncService(matrixClient: MatrixClient): SyncService {
|
||||||
|
return matrixClient.syncService()
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesEncryptionService(matrixClient: MatrixClient): EncryptionService {
|
fun providesEncryptionService(matrixClient: MatrixClient): EncryptionService {
|
||||||
return matrixClient.encryptionService()
|
return matrixClient.encryptionService()
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,6 @@ import org.matrix.rustcomponents.sdk.UnableToDecryptDelegate
|
||||||
|
|
||||||
class FakeRustSyncServiceBuilder : SyncServiceBuilder(NoPointer) {
|
class FakeRustSyncServiceBuilder : SyncServiceBuilder(NoPointer) {
|
||||||
override suspend fun withUtdHook(delegate: UnableToDecryptDelegate): SyncServiceBuilder = this
|
override suspend fun withUtdHook(delegate: UnableToDecryptDelegate): SyncServiceBuilder = this
|
||||||
|
override fun withOfflineMode(): SyncServiceBuilder = this
|
||||||
override suspend fun finish(): SyncService = FakeRustSyncService()
|
override suspend fun finish(): SyncService = FakeRustSyncService()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
class FakeSyncService(
|
class FakeSyncService(
|
||||||
syncStateFlow: MutableStateFlow<SyncState> = MutableStateFlow(SyncState.Idle)
|
initialSyncState: SyncState = SyncState.Idle,
|
||||||
) : SyncService {
|
) : SyncService {
|
||||||
|
private val syncStateFlow: MutableStateFlow<SyncState> = MutableStateFlow(initialSyncState)
|
||||||
|
|
||||||
var startSyncLambda: () -> Result<Unit> = { Result.success(Unit) }
|
var startSyncLambda: () -> Result<Unit> = { Result.success(Unit) }
|
||||||
override suspend fun startSync(): Result<Unit> {
|
override suspend fun startSync(): Result<Unit> {
|
||||||
return startSyncLambda()
|
return startSyncLambda()
|
||||||
|
|
@ -26,4 +28,8 @@ class FakeSyncService(
|
||||||
}
|
}
|
||||||
|
|
||||||
override val syncState: StateFlow<SyncState> = syncStateFlow
|
override val syncState: StateFlow<SyncState> = syncStateFlow
|
||||||
|
|
||||||
|
suspend fun emitSyncState(syncState: SyncState) {
|
||||||
|
syncStateFlow.emit(syncState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ import org.junit.Test
|
||||||
|
|
||||||
class SyncOnNotifiableEventTest {
|
class SyncOnNotifiableEventTest {
|
||||||
private val timelineItems = MutableStateFlow<List<MatrixTimelineItem>>(emptyList())
|
private val timelineItems = MutableStateFlow<List<MatrixTimelineItem>>(emptyList())
|
||||||
private val syncStateFlow = MutableStateFlow(SyncState.Idle)
|
|
||||||
private val startSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
private val startSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||||
private val stopSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
private val stopSyncLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||||
private val subscribeToSyncLambda = lambdaRecorder<Unit> { }
|
private val subscribeToSyncLambda = lambdaRecorder<Unit> { }
|
||||||
|
|
@ -49,7 +48,7 @@ class SyncOnNotifiableEventTest {
|
||||||
liveTimeline = liveTimeline,
|
liveTimeline = liveTimeline,
|
||||||
subscribeToSyncLambda = subscribeToSyncLambda
|
subscribeToSyncLambda = subscribeToSyncLambda
|
||||||
)
|
)
|
||||||
private val syncService = FakeSyncService(syncStateFlow).also {
|
private val syncService = FakeSyncService(SyncState.Idle).also {
|
||||||
it.startSyncLambda = startSyncLambda
|
it.startSyncLambda = startSyncLambda
|
||||||
it.stopSyncLambda = stopSyncLambda
|
it.stopSyncLambda = stopSyncLambda
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +114,7 @@ class SyncOnNotifiableEventTest {
|
||||||
timelineItems.emit(
|
timelineItems.emit(
|
||||||
listOf(MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem()))
|
listOf(MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem()))
|
||||||
)
|
)
|
||||||
syncStateFlow.emit(SyncState.Running)
|
syncService.emitSyncState(SyncState.Running)
|
||||||
sut(notifiableEvent)
|
sut(notifiableEvent)
|
||||||
|
|
||||||
assert(startSyncLambda).isCalledOnce()
|
assert(startSyncLambda).isCalledOnce()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue