RoomMembers: change the API again..

This commit is contained in:
ganfra 2023-04-28 15:04:33 +02:00
parent 4b9f2fdae0
commit 23a7b871f7
12 changed files with 109 additions and 73 deletions

View file

@ -17,6 +17,7 @@
package io.element.android.features.roomdetails.impl
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
@ -33,7 +34,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.getDmMemberFlow
import io.element.android.libraries.matrix.ui.room.directRoomMember
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -54,14 +55,14 @@ class RoomDetailsPresenter @Inject constructor(
val error = remember {
mutableStateOf<RoomDetailsError?>(null)
}
LaunchedEffect(Unit) {
room.updateMembers()
}
val membersState by room.membersStateFlow.collectAsState()
val memberCount by getMemberCount(membersState)
val dmMemberState by room.getDmMemberFlow()
.collectAsState(initial = null, context = coroutineDispatchers.computation)
val roomMemberDetailsPresenter = roomMemberDetailsPresenter(dmMemberState)
val roomType = getRoomType(dmMemberState)
val dmMember by room.directRoomMember()
val roomMemberDetailsPresenter = roomMemberDetailsPresenter(dmMember)
val roomType = getRoomType(dmMember)
fun handleEvents(event: RoomDetailsEvent) {
when (event) {
@ -119,9 +120,9 @@ class RoomDetailsPresenter @Inject constructor(
derivedStateOf {
when (membersState) {
MatrixRoomMembersState.Unknown -> Async.Uninitialized
MatrixRoomMembersState.Pending -> Async.Loading()
is MatrixRoomMembersState.Pending -> Async.Loading(prevState = membersState.prevRoomMembers?.size)
is MatrixRoomMembersState.Error -> Async.Failure(membersState.failure, prevState = membersState.prevRoomMembers?.size)
is MatrixRoomMembersState.Ready -> Async.Success(membersState.roomMembers.size)
is MatrixRoomMembersState.Error -> Async.Failure(membersState.failure)
}
}
}

View file

@ -117,7 +117,7 @@ fun RoomDetailsView(
}
if (state.roomType is RoomDetailsType.Room) {
val memberCount = (state.memberCount as? Async.Success<Int>)?.state
val memberCount = state.memberCount.dataOrNull()
MembersSection(
memberCount = memberCount,
isLoading = state.memberCount.isLoading(),

View file

@ -18,7 +18,6 @@ package io.element.android.features.roomdetails.impl.members
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import io.element.android.features.userlist.api.SelectionMode
@ -30,14 +29,9 @@ import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.getMemberFlow
import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Named
@ -74,6 +68,5 @@ class RoomMemberListPresenter @Inject constructor(
userListState = userListState,
)
}
}

View file

@ -41,6 +41,7 @@ class RoomUserListDataSource @Inject constructor(
.dropWhile { it !is MatrixRoomMembersState.Ready }
.first()
.roomMembers()
.orEmpty()
val filteredMembers = if (query.isBlank()) {
roomMembers
} else {

View file

@ -17,8 +17,8 @@
package io.element.android.features.roomdetails.impl.members.details
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
@ -33,9 +33,10 @@ import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.getMemberFlow
import io.element.android.libraries.matrix.ui.room.roomMember
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
class RoomMemberDetailsPresenter @AssistedInject constructor(
private val client: MatrixClient,
@ -51,11 +52,14 @@ class RoomMemberDetailsPresenter @AssistedInject constructor(
override fun present(): RoomMemberDetailsState {
val coroutineScope = rememberCoroutineScope()
var confirmationDialog by remember { mutableStateOf<ConfirmationDialog?>(null) }
val roomMember by room.getMemberFlow(roomMemberId).collectAsState(initial = null)
val isBlocked = remember(roomMember?.isIgnored) {
val roomMember by room.roomMember(roomMemberId)
// the room member is not really live...
val isBlocked = remember {
mutableStateOf(roomMember?.isIgnored.orFalse())
}
LaunchedEffect(Unit) {
room.updateMembers()
}
fun handleEvents(event: RoomMemberDetailsEvents) {
when (event) {

View file

@ -96,6 +96,7 @@ class RoomDetailsPresenterTests {
room.givenRoomMembersState(MatrixRoomMembersState.Ready(emptyList()))
val finalState = awaitItem()
Truth.assertThat(finalState.memberCount).isEqualTo(Async.Success(0))
cancelAndIgnoreRemainingEvents()
}
}
@ -129,12 +130,7 @@ class RoomDetailsPresenterTests {
presenter.present()
}.test {
val initialState = awaitItem()
// It's not configured yet in the first iteration
Truth.assertThat(initialState.roomType).isEqualTo(RoomDetailsType.Room)
// Once updated, the RoomDetailsType becomes 'Dm'
val updatedState = awaitItem()
Truth.assertThat(updatedState.roomType).isEqualTo(RoomDetailsType.Dm(otherRoomMember))
Truth.assertThat(initialState.roomType).isEqualTo(RoomDetailsType.Dm(otherRoomMember))
cancelAndIgnoreRemainingEvents()
}

View file

@ -26,6 +26,7 @@ import io.element.android.features.roomdetails.aRoomMember
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
@ -37,12 +38,13 @@ class RoomMemberDetailsPresenterTests {
@Test
fun `present - returns the room member's data, then updates it if needed`() = runTest {
val roomMember = aRoomMember(displayName = "Alice")
val room = aMatrixRoom().apply {
givenUserDisplayNameResult(Result.success("A custom name"))
givenUserAvatarUrlResult(Result.success("A custom avatar"))
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
}
val roomMember = aRoomMember(displayName = "Alice")
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
@ -60,12 +62,13 @@ class RoomMemberDetailsPresenterTests {
@Test
fun `present - will recover when retrieving room member details fails`() = runTest {
val roomMember = aRoomMember(displayName = "Alice")
val room = aMatrixRoom().apply {
givenUserDisplayNameResult(Result.failure(Throwable()))
givenUserAvatarUrlResult(Result.failure(Throwable()))
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
}
val roomMember = aRoomMember(displayName = "Alice")
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
@ -79,12 +82,13 @@ class RoomMemberDetailsPresenterTests {
@Test
fun `present - will fallback to original data if the updated data is null`() = runTest {
val roomMember = aRoomMember(displayName = "Alice")
val room = aMatrixRoom().apply {
givenUserDisplayNameResult(Result.success(null))
givenUserAvatarUrlResult(Result.success(null))
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
}
val roomMember = aRoomMember(displayName = "Alice")
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
@ -100,7 +104,7 @@ class RoomMemberDetailsPresenterTests {
fun `present - BlockUser needing confirmation displays confirmation dialog`() = runTest {
val room = aMatrixRoom()
val roomMember = aRoomMember()
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
@ -121,7 +125,7 @@ class RoomMemberDetailsPresenterTests {
fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest {
val room = aMatrixRoom()
val roomMember = aRoomMember()
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
@ -138,7 +142,7 @@ class RoomMemberDetailsPresenterTests {
fun `present - UnblockUser needing confirmation displays confirmation dialog`() = runTest {
val room = aMatrixRoom()
val roomMember = aRoomMember()
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {