RoomListFilters : use kotlin filtering as rust one is slower and has more chance to bust the room list cache.

This commit is contained in:
ganfra 2024-02-27 16:24:54 +01:00
parent 593a94b994
commit bd87e99df1
13 changed files with 278 additions and 112 deletions

View file

@ -83,7 +83,7 @@ class RoomListFiltersPresenter @Inject constructor(
RoomListFilter.Unread -> MatrixRoomListFilter.Unread
RoomListFilter.Favourites -> MatrixRoomListFilter.Favorite
}
}.plus(MatrixRoomListFilter.NonLeft)
}
)
roomListService.allRooms.updateFilter(allRoomsFilter)
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.roomlist.impl.search
import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
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 kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import javax.inject.Inject
private const val PAGE_SIZE = 30
class RoomListSearchDataSource @Inject constructor(
roomListService: RoomListService,
coroutineDispatchers: CoroutineDispatchers,
private val roomSummaryFactory: RoomListRoomSummaryFactory,
) {
private val roomList = roomListService.createRoomList(
pageSize = PAGE_SIZE,
initialFilter = RoomListFilter.None,
source = RoomList.Source.All,
)
val roomSummaries: Flow<PersistentList<RoomListRoomSummary>> = roomList.summaries
.map { roomSummaries ->
roomSummaries
.filterIsInstance<RoomSummary.Filled>()
.map(roomSummaryFactory::create)
.toPersistentList()
}
.flowOn(coroutineDispatchers.computation)
suspend fun setIsActive(isActive: Boolean) = coroutineScope {
if (isActive) {
roomList.loadAllIncrementally(this)
} else {
roomList.reset()
}
}
suspend fun setSearchQuery(searchQuery: String) = coroutineScope {
val filter = if (searchQuery.isBlank()) {
RoomListFilter.None
} else {
RoomListFilter.NormalizedMatchRoomName(searchQuery)
}
roomList.updateFilter(filter)
}
}

View file

@ -21,30 +21,14 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
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.roomlist.impl.datasource.RoomListRoomSummaryFactory
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
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 kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import javax.inject.Inject
private const val PAGE_SIZE = 50
class RoomListSearchPresenter @Inject constructor(
private val roomListService: RoomListService,
private val roomSummaryFactory: RoomListRoomSummaryFactory,
private val coroutineDispatchers: CoroutineDispatchers,
private val dataSource: RoomListSearchDataSource,
) : Presenter<RoomListSearchState> {
@Composable
override fun present(): RoomListSearchState {
@ -54,27 +38,13 @@ class RoomListSearchPresenter @Inject constructor(
var searchQuery by rememberSaveable {
mutableStateOf("")
}
val coroutineScope = rememberCoroutineScope()
val roomList = remember {
roomListService.createRoomList(
coroutineScope = coroutineScope,
pageSize = PAGE_SIZE,
initialFilter = RoomListFilter.all(RoomListFilter.None),
source = RoomList.Source.All,
)
LaunchedEffect(isSearchActive) {
dataSource.setIsActive(isSearchActive)
}
LaunchedEffect(Unit) {
roomList.loadAllIncrementally(this)
}
LaunchedEffect(key1 = searchQuery) {
val filter = if (searchQuery.isBlank()) {
RoomListFilter.all(RoomListFilter.None)
} else {
RoomListFilter.all(RoomListFilter.NonLeft, RoomListFilter.NormalizedMatchRoomName(searchQuery))
}
roomList.updateFilter(filter)
LaunchedEffect(searchQuery) {
dataSource.setSearchQuery(searchQuery)
}
fun handleEvents(event: RoomListSearchEvents) {
@ -92,9 +62,7 @@ class RoomListSearchPresenter @Inject constructor(
}
}
val searchResults by roomList
.rememberMappedSummaries()
.collectAsState(initial = persistentListOf())
val searchResults by dataSource.roomSummaries.collectAsState(initial = persistentListOf())
return RoomListSearchState(
isSearchActive = isSearchActive,
@ -103,16 +71,4 @@ class RoomListSearchPresenter @Inject constructor(
eventSink = ::handleEvents
)
}
@Composable
private fun RoomList.rememberMappedSummaries() = remember {
summaries
.map { roomSummaries ->
roomSummaries
.filterIsInstance<RoomSummary.Filled>()
.map(roomSummaryFactory::create)
.toPersistentList()
}
.flowOn(coroutineDispatchers.computation)
}
}

View file

@ -69,7 +69,6 @@ class RoomListFiltersPresenterTests {
)
val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All
assertThat(roomListCurrentFilter.filters).containsExactly(
MatrixRoomListFilter.NonLeft,
MatrixRoomListFilter.Category.Group,
)
@ -86,9 +85,7 @@ class RoomListFiltersPresenterTests {
RoomListFilter.Favourites,
)
val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All
assertThat(roomListCurrentFilter.filters).containsExactly(
MatrixRoomListFilter.NonLeft,
)
assertThat(roomListCurrentFilter.filters).isEmpty()
}
}
}

View file

@ -79,9 +79,7 @@ class RoomListSearchPresenterTests {
assertThat(
roomListService.allRooms.currentFilter.value
).isEqualTo(
RoomListFilter.all(
RoomListFilter.None,
)
RoomListFilter.None,
)
state.eventSink(RoomListSearchEvents.QueryChanged("Search"))
}
@ -90,10 +88,7 @@ class RoomListSearchPresenterTests {
assertThat(
roomListService.allRooms.currentFilter.value
).isEqualTo(
RoomListFilter.all(
RoomListFilter.NonLeft,
RoomListFilter.NormalizedMatchRoomName("Search")
)
RoomListFilter.NormalizedMatchRoomName("Search")
)
state.eventSink(RoomListSearchEvents.ClearQuery)
}
@ -102,9 +97,7 @@ class RoomListSearchPresenterTests {
assertThat(
roomListService.allRooms.currentFilter.value
).isEqualTo(
RoomListFilter.all(
RoomListFilter.None,
)
RoomListFilter.None,
)
}
}
@ -141,11 +134,13 @@ fun TestScope.createRoomListSearchPresenter(
roomListService: RoomListService = FakeRoomListService(),
): RoomListSearchPresenter {
return RoomListSearchPresenter(
roomListService = roomListService,
roomSummaryFactory = RoomListRoomSummaryFactory(
lastMessageTimestampFormatter = FakeLastMessageTimestampFormatter(),
roomLastMessageFormatter = FakeRoomLastMessageFormatter(),
dataSource = RoomListSearchDataSource(
roomListService = roomListService,
roomSummaryFactory = RoomListRoomSummaryFactory(
lastMessageTimestampFormatter = FakeLastMessageTimestampFormatter(),
roomLastMessageFormatter = FakeRoomLastMessageFormatter(),
),
coroutineDispatchers = testCoroutineDispatchers(),
coroutineDispatchers = testCoroutineDispatchers(),
)
)
}