Browse Source

Room directory : fix pagination and add empty state.

pull/2620/head
ganfra 6 months ago
parent
commit
e4c7118428
  1. 1
      features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryEvents.kt
  2. 23
      features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenter.kt
  3. 75
      features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt
  4. 4
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomdirectory/RoomDirectoryList.kt
  5. 18
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RoomDirectorySearchProcessor.kt
  6. 30
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt

1
features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryEvents.kt

@ -22,5 +22,4 @@ sealed interface RoomDirectoryEvents { @@ -22,5 +22,4 @@ sealed interface RoomDirectoryEvents {
data class Search(val query: String) : RoomDirectoryEvents
data object LoadMore : RoomDirectoryEvents
data class JoinRoom(val roomId: RoomId) : RoomDirectoryEvents
data class SearchActiveChange(val isActive: Boolean) : RoomDirectoryEvents
}

23
features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenter.kt

@ -26,14 +26,11 @@ import androidx.compose.runtime.remember @@ -26,14 +26,11 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import io.element.android.features.roomdirectory.impl.root.model.RoomDescriptionUiModel
import io.element.android.features.roomdirectory.impl.root.model.toUiModel
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
@ -76,9 +73,6 @@ class RoomDirectoryPresenter @Inject constructor( @@ -76,9 +73,6 @@ class RoomDirectoryPresenter @Inject constructor(
is RoomDirectoryEvents.Search -> {
searchQuery = event.query
}
is RoomDirectoryEvents.SearchActiveChange -> {
}
}
}
@ -90,23 +84,6 @@ class RoomDirectoryPresenter @Inject constructor( @@ -90,23 +84,6 @@ class RoomDirectoryPresenter @Inject constructor(
)
}
@Composable
private fun searchResults(
filteredRooms: ImmutableList<RoomDescriptionUiModel>,
hasMoreToLoad: Boolean,
isSearchActive: Boolean,
): SearchBarResultState<ImmutableList<RoomDescriptionUiModel>> {
return if (!isSearchActive) {
SearchBarResultState.Initial()
} else {
if (filteredRooms.isEmpty() && !hasMoreToLoad) {
SearchBarResultState.NoResultsFound()
} else {
SearchBarResultState.Results(filteredRooms)
}
}
}
@Composable
private fun RoomDirectoryList.collectItemsAsState() = remember {
items.map { list ->

75
features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package io.element.android.features.roomdirectory.impl.root
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
@ -26,6 +27,7 @@ import androidx.compose.foundation.layout.fillMaxWidth @@ -26,6 +27,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.KeyboardActions
@ -33,6 +35,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api @@ -33,6 +35,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TextFieldColors
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -49,6 +52,7 @@ import io.element.android.libraries.designsystem.components.button.BackButton @@ -49,6 +52,7 @@ import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.Scaffold
@ -77,8 +81,8 @@ fun RoomDirectoryView( @@ -77,8 +81,8 @@ fun RoomDirectoryView(
state.eventSink(RoomDirectoryEvents.JoinRoom(roomId))
},
modifier = Modifier
.padding(padding)
.consumeWindowInsets(padding)
.padding(padding)
.consumeWindowInsets(padding)
)
}
)
@ -119,7 +123,10 @@ private fun RoomDirectoryContent( @@ -119,7 +123,10 @@ private fun RoomDirectoryContent(
)
RoomDirectoryRoomList(
roomDescriptions = state.roomDescriptions,
displayLoadMoreIndicator = state.displayLoadMoreIndicator,
displayEmptyState = state.displayEmptyState,
onResultClicked = onResultClicked,
onReachedLoadMore = { state.eventSink(RoomDirectoryEvents.LoadMore) },
)
}
}
@ -127,18 +134,52 @@ private fun RoomDirectoryContent( @@ -127,18 +134,52 @@ private fun RoomDirectoryContent(
@Composable
private fun RoomDirectoryRoomList(
roomDescriptions: ImmutableList<RoomDescriptionUiModel>,
displayLoadMoreIndicator: Boolean,
displayEmptyState: Boolean,
onResultClicked: (RoomId) -> Unit,
onReachedLoadMore: () -> Unit,
modifier: Modifier = Modifier,
) {
LazyColumn(
modifier = modifier,
) {
LazyColumn(modifier = modifier) {
items(roomDescriptions) { roomDescription ->
RoomDirectoryRoomRow(
roomDescription = roomDescription,
onClick = onResultClicked,
)
}
if (displayEmptyState) {
item {
Text(
text = stringResource(id = CommonStrings.common_no_results),
style = ElementTheme.typography.fontBodyLgRegular,
color = ElementTheme.colors.textPlaceholder,
modifier = Modifier.padding(16.dp)
)
}
}
if (displayLoadMoreIndicator) {
item {
LoadMoreIndicator(modifier = Modifier.fillMaxWidth())
LaunchedEffect(Unit) {
onReachedLoadMore()
}
}
}
}
}
@Composable
private fun LoadMoreIndicator(modifier: Modifier = Modifier) {
Box(
modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(8.dp),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(
strokeWidth = 2.dp,
)
}
}
@ -203,14 +244,14 @@ private fun RoomDirectoryRoomRow( @@ -203,14 +244,14 @@ private fun RoomDirectoryRoomRow(
) {
Row(
modifier = modifier
.fillMaxWidth()
.clickable { onClick(roomDescription.roomId) }
.padding(
top = 12.dp,
bottom = 12.dp,
start = 16.dp,
)
.height(IntrinsicSize.Min),
.fillMaxWidth()
.clickable { onClick(roomDescription.roomId) }
.padding(
top = 12.dp,
bottom = 12.dp,
start = 16.dp,
)
.height(IntrinsicSize.Min),
) {
Avatar(
avatarData = roomDescription.avatarData,
@ -218,8 +259,8 @@ private fun RoomDirectoryRoomRow( @@ -218,8 +259,8 @@ private fun RoomDirectoryRoomRow(
)
Column(
modifier = Modifier
.weight(1f)
.padding(start = 16.dp)
.weight(1f)
.padding(start = 16.dp)
) {
Text(
text = roomDescription.name,
@ -241,8 +282,8 @@ private fun RoomDirectoryRoomRow( @@ -241,8 +282,8 @@ private fun RoomDirectoryRoomRow(
text = stringResource(id = CommonStrings.action_join),
color = ElementTheme.colors.textSuccessPrimary,
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(start = 4.dp, end = 12.dp)
.align(Alignment.CenterVertically)
.padding(start = 4.dp, end = 12.dp)
)
} else {
Spacer(modifier = Modifier.width(24.dp))

4
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomdirectory/RoomDirectoryList.kt

@ -19,8 +19,8 @@ package io.element.android.libraries.matrix.api.roomdirectory @@ -19,8 +19,8 @@ package io.element.android.libraries.matrix.api.roomdirectory
import kotlinx.coroutines.flow.Flow
interface RoomDirectoryList {
suspend fun filter(filter: String?, batchSize: Int)
suspend fun loadMore()
suspend fun filter(filter: String?, batchSize: Int): Result<Unit>
suspend fun loadMore(): Result<Unit>
suspend fun hasMoreToLoad(): Boolean
val items: Flow<List<RoomDescription>>
}

18
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RoomDirectorySearchProcessor.kt

@ -42,27 +42,27 @@ class RoomDirectorySearchProcessor( @@ -42,27 +42,27 @@ class RoomDirectorySearchProcessor(
}
}
private suspend fun MutableList<RoomDescription>.applyUpdate(update: RoomDirectorySearchEntryUpdate) {
private fun MutableList<RoomDescription>.applyUpdate(update: RoomDirectorySearchEntryUpdate) {
when (update) {
is RoomDirectorySearchEntryUpdate.Append -> {
val roomSummaries = update.values.map(roomDescriptionMapper::map)
addAll(roomSummaries)
}
is RoomDirectorySearchEntryUpdate.PushBack -> {
val roomSummary = roomDescriptionMapper.map(update.value)
add(roomSummary)
val roomDescription = roomDescriptionMapper.map(update.value)
add(roomDescription)
}
is RoomDirectorySearchEntryUpdate.PushFront -> {
val roomSummary = roomDescriptionMapper.map(update.value)
add(0, roomSummary)
val roomDescription = roomDescriptionMapper.map(update.value)
add(0, roomDescription)
}
is RoomDirectorySearchEntryUpdate.Set -> {
val roomSummary = roomDescriptionMapper.map(update.value)
this[update.index.toInt()] = roomSummary
val roomDescription = roomDescriptionMapper.map(update.value)
this[update.index.toInt()] = roomDescription
}
is RoomDirectorySearchEntryUpdate.Insert -> {
val roomSummary = roomDescriptionMapper.map(update.value)
add(update.index.toInt(), roomSummary)
val roomDescription = roomDescriptionMapper.map(update.value)
add(update.index.toInt(), roomDescription)
}
is RoomDirectorySearchEntryUpdate.Remove -> {
removeAt(update.index.toInt())

30
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt

@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl.roomdirectory @@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl.roomdirectory
import io.element.android.libraries.matrix.api.roomdirectory.RoomDescription
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
@ -32,12 +33,11 @@ import org.matrix.rustcomponents.sdk.RoomDirectorySearch as InnerRoomDirectorySe @@ -32,12 +33,11 @@ import org.matrix.rustcomponents.sdk.RoomDirectorySearch as InnerRoomDirectorySe
class RustRoomDirectoryList(
private val inner: InnerRoomDirectorySearch,
private val sessionCoroutineScope: CoroutineScope,
private val sessionDispatcher: CoroutineDispatcher,
sessionCoroutineScope: CoroutineScope,
sessionDispatcher: CoroutineDispatcher,
) : RoomDirectoryList {
private val _items = MutableSharedFlow<List<RoomDescription>>()
private val _items = MutableSharedFlow<List<RoomDescription>>(replay = 1)
private val processor = RoomDirectorySearchProcessor(_items, sessionDispatcher, RoomDescriptionMapper())
init {
@ -51,12 +51,26 @@ class RustRoomDirectoryList( @@ -51,12 +51,26 @@ class RustRoomDirectoryList(
}
}
override suspend fun filter(filter: String?, batchSize: Int) {
inner.search(filter, batchSize.toUInt())
override suspend fun filter(filter: String?, batchSize: Int): Result<Unit> {
return try {
inner.search(filter = filter, batchSize = batchSize.toUInt())
Result.success(Unit)
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Result.failure(e)
}
}
override suspend fun loadMore() {
inner.nextPage()
override suspend fun loadMore(): Result<Unit> {
return try {
inner.nextPage()
Result.success(Unit)
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Result.failure(e)
}
}
override suspend fun hasMoreToLoad(): Boolean {

Loading…
Cancel
Save