Reload room member list when active members count changes (#5129)
This commit is contained in:
parent
955263bee1
commit
2a42a71490
2 changed files with 70 additions and 2 deletions
|
|
@ -38,8 +38,10 @@ import kotlinx.collections.immutable.ImmutableMap
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.collections.immutable.toPersistentMap
|
import kotlinx.collections.immutable.toPersistentMap
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -64,6 +66,11 @@ class RoomMemberListPresenter @Inject constructor(
|
||||||
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
||||||
val canInvite by room.canInviteAsState(syncUpdateFlow.value)
|
val canInvite by room.canInviteAsState(syncUpdateFlow.value)
|
||||||
val roomModerationState = roomMembersModerationPresenter.present()
|
val roomModerationState = roomMembersModerationPresenter.present()
|
||||||
|
val activeRoomMemberCount by produceState(0L) {
|
||||||
|
room.roomInfoFlow.map { it.activeMembersCount }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.collect { value = it }
|
||||||
|
}
|
||||||
|
|
||||||
val roomMemberIdentityStates by produceState(persistentMapOf<UserId, IdentityState>()) {
|
val roomMemberIdentityStates by produceState(persistentMapOf<UserId, IdentityState>()) {
|
||||||
room.roomMemberIdentityStateChange(waitForEncryption = true)
|
room.roomMemberIdentityStateChange(waitForEncryption = true)
|
||||||
|
|
@ -73,8 +80,8 @@ class RoomMemberListPresenter @Inject constructor(
|
||||||
.launchIn(this)
|
.launchIn(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we load the latest data when entering this screen
|
// Update the room members when the screen is loaded or the active member count changes
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(activeRoomMemberCount) {
|
||||||
room.updateMembers()
|
room.updateMembers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,20 @@ import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.coroutines.time.withTimeout
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
class RoomMemberListPresenterTest {
|
class RoomMemberListPresenterTest {
|
||||||
|
|
@ -67,6 +75,59 @@ class RoomMemberListPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `member loading is done automatically when RoomInfo's activeMemberCount changes`() = runTest {
|
||||||
|
val reloadMembersMutex = Mutex()
|
||||||
|
val updateMembersLambda = lambdaRecorder<Unit> {
|
||||||
|
if (reloadMembersMutex.isLocked) {
|
||||||
|
reloadMembersMutex.unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val room = FakeJoinedRoom(
|
||||||
|
baseRoom = FakeBaseRoom(
|
||||||
|
updateMembersResult = updateMembersLambda,
|
||||||
|
canInviteResult = { Result.success(true) }
|
||||||
|
).apply {
|
||||||
|
// Needed to avoid discarding the loaded members as a partial and invalid result
|
||||||
|
givenRoomInfo(aRoomInfo(joinedMembersCount = 2))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val presenter = createPresenter(joinedRoom = room)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
skipItems(1)
|
||||||
|
val initialState = awaitItem()
|
||||||
|
assertThat(initialState.roomMembers.isLoading()).isTrue()
|
||||||
|
room.givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
|
||||||
|
// Skip item while the new members state is processed
|
||||||
|
skipItems(1)
|
||||||
|
val loadedMembersState = awaitItem()
|
||||||
|
assertThat(loadedMembersState.roomMembers.isLoading()).isFalse()
|
||||||
|
assertThat(loadedMembersState.roomMembers.dataOrNull()?.joined).isNotEmpty()
|
||||||
|
|
||||||
|
// Assert no events are emitted only with that change
|
||||||
|
expectNoEvents()
|
||||||
|
|
||||||
|
// This will only progress if the `Room.updateMembers()` function is called, triggered by the RoomInfo change
|
||||||
|
withTimeout(10.seconds) {
|
||||||
|
reloadMembersMutex.withLock {
|
||||||
|
launch { room.givenRoomInfo(aRoomInfo(activeMembersCount = 0L)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the update to be processed
|
||||||
|
skipItems(1)
|
||||||
|
|
||||||
|
// Update the room members state as `Room.updateMembers()` would have done with the actual implementation
|
||||||
|
room.givenRoomMembersState(RoomMembersState.Ready(persistentListOf()))
|
||||||
|
// Wait for another update
|
||||||
|
skipItems(1)
|
||||||
|
// The members should be reloaded now
|
||||||
|
assertThat(awaitItem().roomMembers.dataOrNull()?.joined).isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `open search`() = runTest {
|
fun `open search`() = runTest {
|
||||||
val presenter = createPresenter(
|
val presenter = createPresenter(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue