Merge pull request #6117 from element-hq/feature/fga/room_list_filter_rust

Refactor room list filtering to use Rust SDK
This commit is contained in:
ganfra
2026-02-02 10:58:21 +01:00
committed by GitHub
43 changed files with 648 additions and 613 deletions

View File

@@ -15,4 +15,5 @@ sealed interface AddRoomToSpaceEvent {
data object Save : AddRoomToSpaceEvent
data object ResetSaveAction : AddRoomToSpaceEvent
data object Dismiss : AddRoomToSpaceEvent
data class UpdateSearchVisibleRange(val range: IntRange) : AddRoomToSpaceEvent
}

View File

@@ -58,9 +58,6 @@ class AddRoomToSpacePresenter(
LaunchedEffect(searchQuery.text) {
dataSource.setSearchQuery(searchQuery.text.toString())
}
LaunchedEffect(isSearchActive) {
dataSource.setIsActive(isSearchActive)
}
val suggestions by dataSource.suggestions.collectAsState(initial = persistentListOf())
@@ -111,6 +108,9 @@ class AddRoomToSpacePresenter(
coroutineScope.launch { spaceRoomList.reset() }
}
}
is AddRoomToSpaceEvent.UpdateSearchVisibleRange -> coroutineScope.launch {
dataSource.updateVisibleRange(event.range)
}
}
}

View File

@@ -20,14 +20,13 @@ import io.element.android.libraries.matrix.api.room.recent.getRecentlyVisitedRoo
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.loadAllIncrementally
import io.element.android.libraries.matrix.api.roomlist.updateVisibleRange
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
@@ -58,7 +57,6 @@ class AddRoomToSpaceSearchDataSource(
private val roomList = roomListService.createRoomList(
pageSize = PAGE_SIZE,
initialFilter = RoomListFilter.all(),
source = RoomList.Source.All,
coroutineScope = coroutineScope,
)
@@ -87,7 +85,7 @@ class AddRoomToSpaceSearchDataSource(
}
val roomInfoList: Flow<ImmutableList<SelectRoomInfo>> = combine(
roomList.filteredSummaries,
roomList.summaries,
spaceChildrenFlow,
addedRoomIdsFlow,
) { roomSummaries, childIds, addedIds ->
@@ -109,12 +107,8 @@ class AddRoomToSpaceSearchDataSource(
.toImmutableList()
}.flowOn(coroutineDispatchers.computation)
suspend fun setIsActive(isActive: Boolean) = coroutineScope {
if (isActive) {
roomList.loadAllIncrementally(this)
} else {
roomList.reset()
}
suspend fun updateVisibleRange(visibleRange: IntRange) {
roomList.updateVisibleRange(visibleRange)
}
suspend fun setSearchQuery(searchQuery: String) {

View File

@@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -43,6 +44,7 @@ import io.element.android.libraries.designsystem.theme.components.SearchBar
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.designsystem.utils.OnVisibleRangeChangeEffect
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
@@ -121,6 +123,10 @@ fun AddRoomToSpaceView(
}
},
) { rooms ->
val lazyListState = rememberLazyListState()
OnVisibleRangeChangeEffect(lazyListState) { visibleRange ->
state.eventSink(AddRoomToSpaceEvent.UpdateSearchVisibleRange(visibleRange))
}
LazyColumn {
items(rooms, key = { it.roomId }) { roomInfo ->
RoomListItem(

View File

@@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.roomlist.FakeDynamicRoomList
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList
import io.element.android.libraries.matrix.test.spaces.FakeSpaceService
@@ -116,12 +117,15 @@ class AddRoomToSpacePresenterTest {
@Test
fun `present - searchResults shows Results when rooms available`() = runTest {
val roomListService = FakeRoomListService()
val roomList = FakeDynamicRoomList()
val roomListService = FakeRoomListService(
createRoomListLambda = { roomList }
)
val presenter = createAddRoomToSpacePresenter(roomListService = roomListService)
presenter.test {
awaitItem() // Initial state
// Post rooms to the service
roomListService.postAllRooms(
roomList.summaries.emit(
listOf(
aRoomSummary(
roomId = A_ROOM_ID,
@@ -296,6 +300,29 @@ class AddRoomToSpacePresenterTest {
}
}
@Test
fun `present - UpdateSearchVisibleRange triggers pagination when near end`() = runTest {
val loadMoreLambda = lambdaRecorder<Unit> { }
val roomList = FakeDynamicRoomList(loadMoreLambda = loadMoreLambda)
val roomListService = FakeRoomListService(
createRoomListLambda = { roomList }
)
val presenter = createAddRoomToSpacePresenter(roomListService = roomListService)
presenter.test {
val state = awaitItem()
// Post rooms to simulate loaded content
roomList.summaries.emit(listOf(aRoomSummary()))
advanceUntilIdle()
skipItems(1)
// UpdateSearchVisibleRange should trigger loadMore
state.eventSink(AddRoomToSpaceEvent.UpdateSearchVisibleRange(IntRange(0, 9)))
advanceUntilIdle()
assert(loadMoreLambda).isCalledOnce()
}
}
@Test
fun `present - Dismiss after partial success calls reset`() = runTest {
val resetResult = lambdaRecorder<Result<Unit>> { Result.success(Unit) }

View File

@@ -14,6 +14,7 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.tests.testutils.EnsureNeverCalled
import io.element.android.tests.testutils.EventsRecorder
@@ -99,6 +100,21 @@ class AddRoomToSpaceViewTest {
)
}
}
@Config(qualifiers = "h1024dp")
@Test
fun `displaying search results sends UpdateSearchVisibleRange event`() {
val eventsRecorder = EventsRecorder<AddRoomToSpaceEvent>()
val rooms = aSelectRoomInfoList()
rule.setAddRoomToSpaceView(
anAddRoomToSpaceState(
isSearchActive = true,
searchResults = SearchBarResultState.Results(rooms),
eventSink = eventsRecorder,
),
)
eventsRecorder.assertTrue(0) { it is AddRoomToSpaceEvent.UpdateSearchVisibleRange }
}
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setAddRoomToSpaceView(