misc : remove direct usage of RoomSummary in UI and let RoomSummary use RoomInfo.

This commit is contained in:
ganfra
2024-10-08 21:34:34 +02:00
parent e71a010e22
commit d73b1bad91
47 changed files with 628 additions and 467 deletions

View File

@@ -7,10 +7,10 @@
package io.element.android.libraries.roomselect.impl
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
sealed interface RoomSelectEvents {
data class SetSelectedRoom(val room: RoomSummary) : RoomSelectEvents
data class SetSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvents
// TODO remove to restore multi-selection
data object RemoveSelectedRoom : RoomSelectEvents

View File

@@ -20,7 +20,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
import io.element.android.libraries.roomselect.api.RoomSelectMode
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@@ -36,7 +36,7 @@ class RoomSelectPresenter @AssistedInject constructor(
@Composable
override fun present(): RoomSelectState {
var selectedRooms by remember { mutableStateOf(persistentListOf<RoomSummary>()) }
var selectedRooms by remember { mutableStateOf(persistentListOf<SelectRoomInfo>()) }
var searchQuery by remember { mutableStateOf("") }
var isSearchActive by remember { mutableStateOf(false) }
@@ -48,7 +48,7 @@ class RoomSelectPresenter @AssistedInject constructor(
dataSource.setSearchQuery(searchQuery)
}
val roomSummaryDetailsList by dataSource.roomSummaries.collectAsState(initial = persistentListOf())
val roomSummaryDetailsList by dataSource.roomInfoList.collectAsState(initial = persistentListOf())
val searchResults by remember {
derivedStateOf {

View File

@@ -12,8 +12,8 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.roomlist.RoomList
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.coroutineScope
@@ -38,11 +38,20 @@ class RoomSelectSearchDataSource @Inject constructor(
source = RoomList.Source.All,
)
val roomSummaries: Flow<PersistentList<RoomSummary>> = roomList.filteredSummaries
val roomInfoList: Flow<PersistentList<SelectRoomInfo>> = roomList.filteredSummaries
.map { roomSummaries ->
roomSummaries
.filter { it.currentUserMembership == CurrentUserMembership.JOINED }
.filter { it.info.currentUserMembership == CurrentUserMembership.JOINED }
.distinctBy { it.roomId } // This should be removed once we're sure no duplicate Rooms can be received
.map { roomSummary ->
SelectRoomInfo(
roomId = roomSummary.roomId,
name = roomSummary.info.name,
avatarUrl = roomSummary.info.avatarUrl,
heroes = roomSummary.info.heroes,
canonicalAlias = roomSummary.info.canonicalAlias,
)
}
.toPersistentList()
}
.flowOn(coroutineDispatchers.computation)

View File

@@ -8,15 +8,15 @@
package io.element.android.libraries.roomselect.impl
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
import io.element.android.libraries.roomselect.api.RoomSelectMode
import kotlinx.collections.immutable.ImmutableList
data class RoomSelectState(
val mode: RoomSelectMode,
val resultState: SearchBarResultState<ImmutableList<RoomSummary>>,
val resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>>,
val query: String,
val isSearchActive: Boolean,
val selectedRooms: ImmutableList<RoomSummary>,
val selectedRooms: ImmutableList<SelectRoomInfo>,
val eventSink: (RoomSelectEvents) -> Unit
)

View File

@@ -11,8 +11,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails
import io.element.android.libraries.matrix.ui.components.aSelectRoomInfo
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
import io.element.android.libraries.roomselect.api.RoomSelectMode
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@@ -32,7 +32,7 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
resultState = SearchBarResultState.Results(aRoomSelectRoomList()),
query = "Test",
isSearchActive = true,
selectedRooms = persistentListOf(aRoomSummaryDetails(roomId = RoomId("!room2:domain")))
selectedRooms = aRoomSelectRoomList().subList(0, 1),
),
aRoomSelectState(
mode = RoomSelectMode.Share,
@@ -43,10 +43,10 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
private fun aRoomSelectState(
mode: RoomSelectMode = RoomSelectMode.Forward,
resultState: SearchBarResultState<ImmutableList<RoomSummary>> = SearchBarResultState.Initial(),
resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>> = SearchBarResultState.Initial(),
query: String = "",
isSearchActive: Boolean = false,
selectedRooms: ImmutableList<RoomSummary> = persistentListOf(),
selectedRooms: ImmutableList<SelectRoomInfo> = persistentListOf(),
) = RoomSelectState(
mode = mode,
resultState = resultState,
@@ -57,14 +57,16 @@ private fun aRoomSelectState(
)
private fun aRoomSelectRoomList() = persistentListOf(
aRoomSummaryDetails(),
aRoomSummaryDetails(
aSelectRoomInfo(
roomId = RoomId("!room1:domain"),
name = "Room with name",
),
aSelectRoomInfo(
roomId = RoomId("!room2:domain"),
name = "Room with alias",
canonicalAlias = RoomAlias("#alias:example.org"),
),
aRoomSummaryDetails(
aSelectRoomInfo(
roomId = RoomId("!room3:domain"),
name = null,
),
)

View File

@@ -47,8 +47,8 @@ import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.components.SelectedRoom
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.roomselect.api.RoomSelectMode
import io.element.android.libraries.ui.strings.CommonStrings
@@ -65,13 +65,13 @@ fun RoomSelectView(
modifier: Modifier = Modifier,
) {
@Suppress("UNUSED_PARAMETER")
fun onRoomRemoved(roomSummary: RoomSummary) {
fun onRoomRemoved(roomInfo: SelectRoomInfo) {
// TODO toggle selection when multi-selection is enabled
state.eventSink(RoomSelectEvents.RemoveSelectedRoom)
}
@Composable
fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList<RoomSummary>) {
fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList<SelectRoomInfo>) {
if (isForwarding) return
SelectedRooms(
selectedRooms = selectedRooms,
@@ -185,8 +185,8 @@ fun RoomSelectView(
@Composable
private fun SelectedRooms(
selectedRooms: ImmutableList<RoomSummary>,
onRemoveRoom: (RoomSummary) -> Unit,
selectedRooms: ImmutableList<SelectRoomInfo>,
onRemoveRoom: (SelectRoomInfo) -> Unit,
modifier: Modifier = Modifier,
) {
LazyRow(
@@ -194,29 +194,29 @@ private fun SelectedRooms(
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(32.dp)
) {
items(selectedRooms, key = { it.roomId.value }) { roomSummary ->
SelectedRoom(roomSummary = roomSummary, onRemoveRoom = onRemoveRoom)
items(selectedRooms, key = { it.roomId.value }) { selectRoomInfo ->
SelectedRoom(roomInfo = selectRoomInfo, onRemoveRoom = onRemoveRoom)
}
}
}
@Composable
private fun RoomSummaryView(
summary: RoomSummary,
roomInfo: SelectRoomInfo,
isSelected: Boolean,
onSelection: (RoomSummary) -> Unit,
onSelection: (SelectRoomInfo) -> Unit,
) {
Row(
modifier = Modifier
.clickable { onSelection(summary) }
.clickable { onSelection(roomInfo) }
.fillMaxWidth()
.padding(start = 16.dp, end = 4.dp)
.heightIn(56.dp),
verticalAlignment = Alignment.CenterVertically
) {
CompositeAvatar(
avatarData = summary.getAvatarData(size = AvatarSize.RoomSelectRoomListItem),
heroes = summary.heroes.map { user ->
avatarData = roomInfo.getAvatarData(size = AvatarSize.RoomSelectRoomListItem),
heroes = roomInfo.heroes.map { user ->
user.getAvatarData(size = AvatarSize.RoomSelectRoomListItem)
}.toPersistentList()
)
@@ -228,14 +228,14 @@ private fun RoomSummaryView(
// Name
Text(
style = ElementTheme.typography.fontBodyLgRegular,
text = summary.name ?: stringResource(id = CommonStrings.common_no_room_name),
fontStyle = FontStyle.Italic.takeIf { summary.name == null },
text = roomInfo.name ?: stringResource(id = CommonStrings.common_no_room_name),
fontStyle = FontStyle.Italic.takeIf { roomInfo.name == null },
color = ElementTheme.colors.textPrimary,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
// Alias
summary.canonicalAlias?.let { alias ->
roomInfo.canonicalAlias?.let { alias ->
Text(
text = alias.value,
color = ElementTheme.colors.textSecondary,
@@ -245,7 +245,7 @@ private fun RoomSummaryView(
)
}
}
RadioButton(selected = isSelected, onClick = { onSelection(summary) })
RadioButton(selected = isSelected, onClick = { onSelection(roomInfo) })
}
}

View File

@@ -14,8 +14,10 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.matrix.ui.components.aSelectRoomInfo
import io.element.android.libraries.roomselect.api.RoomSelectMode
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.testCoroutineDispatchers
@@ -58,8 +60,9 @@ class RoomSelectPresenterTest {
@Test
fun `present - update query`() = runTest {
val roomSummary = aRoomSummary()
val roomListService = FakeRoomListService().apply {
postAllRooms(listOf(aRoomSummary()))
postAllRooms(listOf(roomSummary))
}
val presenter = createRoomSelectPresenter(
roomListService = roomListService
@@ -68,19 +71,10 @@ class RoomSelectPresenterTest {
presenter.present()
}.test {
val initialState = awaitItem()
val expectedRoomSummary = aRoomSummary()
val expectedRoomInfo = roomSummary.toSelectRoomInfo()
// Do not compare the lambda because they will be different. So copy the lambda from expectedRoomSummary to result
val result = (awaitItem().resultState as SearchBarResultState.Results).results.map { roomSummary ->
roomSummary.copy(
lastMessage = roomSummary.lastMessage!!.copy(
event = roomSummary.lastMessage!!.event.copy(
debugInfoProvider = expectedRoomSummary.lastMessage!!.event.debugInfoProvider,
messageShieldProvider = expectedRoomSummary.lastMessage!!.event.messageShieldProvider,
)
),
)
}
assertThat(result).isEqualTo(listOf(expectedRoomSummary))
val result = (awaitItem().resultState as SearchBarResultState.Results).results
assertThat(result).isEqualTo(listOf(expectedRoomInfo))
initialState.eventSink(RoomSelectEvents.ToggleSearchActive)
skipItems(1)
initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained"))
@@ -99,8 +93,9 @@ class RoomSelectPresenterTest {
@Test
fun `present - select and remove a room`() = runTest {
val roomSummary = aRoomSummary()
val roomListService = FakeRoomListService().apply {
postAllRooms(listOf(aRoomSummary()))
postAllRooms(listOf(roomSummary))
}
val presenter = createRoomSelectPresenter(
roomListService = roomListService,
@@ -109,9 +104,9 @@ class RoomSelectPresenterTest {
presenter.present()
}.test {
val initialState = awaitItem()
val summary = aRoomSummary()
initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary))
assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary))
val roomInfo = roomSummary.toSelectRoomInfo()
initialState.eventSink(RoomSelectEvents.SetSelectedRoom(roomInfo))
assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(roomInfo))
initialState.eventSink(RoomSelectEvents.RemoveSelectedRoom)
assertThat(awaitItem().selectedRooms).isEmpty()
cancel()
@@ -128,4 +123,12 @@ class RoomSelectPresenterTest {
coroutineDispatchers = testCoroutineDispatchers(),
),
)
private fun RoomSummary.toSelectRoomInfo() = aSelectRoomInfo(
roomId = roomId,
name = info.name,
avatarUrl = info.avatarUrl,
heroes = info.heroes,
canonicalAlias = info.canonicalAlias,
)
}