diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListExtensions.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListExtensions.kt index bf57e4295b..2352f82c3b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListExtensions.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListExtensions.kt @@ -57,7 +57,7 @@ fun RoomListInterface.loadingStateFlow(): Flow = internal fun RoomListInterface.entriesFlow( pageSize: Int, initialFilterKind: RoomListEntriesDynamicFilterKind, - onControllerCreated: (RoomListDynamicEntriesController) -> Unit, + onControllerCreated: suspend (RoomListDynamicEntriesController) -> Unit, ): Flow> = callbackFlow { val listener = object : RoomListEntriesListener { @@ -70,9 +70,13 @@ internal fun RoomListInterface.entriesFlow( listener = listener, ) val controller = result.controller() - controller.setFilter(initialFilterKind) - onControllerCreated(controller) - awaitClose { + // Use try/finally rather than awaitClose's block, so that the resources are released even if + // onControllerCreated is cancelled or throws before awaitClose is reached + try { + controller.setFilter(initialFilterKind) + onControllerCreated(controller) + awaitClose() + } finally { result.entriesStream().cancelAndDestroy() controller.destroy() result.destroy() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt index 1d90b07104..c12ddbede8 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt @@ -23,7 +23,6 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import org.matrix.rustcomponents.sdk.RoomListDynamicEntriesController import org.matrix.rustcomponents.sdk.RoomListLoadingState import org.matrix.rustcomponents.sdk.RoomListService import kotlin.coroutines.CoroutineContext @@ -49,7 +48,13 @@ internal class RoomListFactory( val summariesFlow = MutableSharedFlow>(replay = 1, extraBufferCapacity = 1) val processor = RoomSummaryListProcessor(summariesFlow, innerRoomListService, coroutineContext, roomSummaryFactory, analyticsService) var innerRoomList: InnerRoomList? = null - var dynamicController: RoomListDynamicEntriesController? = null + val dynamicRoomList = RustDynamicRoomList( + summaries = summariesFlow, + loadingState = loadingStateFlow, + processor = processor, + pageSize = pageSize, + initialFilter = initialFilter, + ) val firstRoomsTransaction = analyticsService.startTransaction("Load first set of rooms", "innerRoomList.entriesFlow") @@ -60,7 +65,7 @@ internal class RoomListFactory( pageSize = pageSize, initialFilterKind = RoomListFilterMapper.toRustFilter(initialFilter), onControllerCreated = { controller -> - dynamicController = controller + dynamicRoomList.onControllerCreated(controller, initialFilter) } ).onEach { update -> if (!firstRoomsTransaction.isFinished()) { @@ -80,13 +85,7 @@ internal class RoomListFactory( }.invokeOnCompletion { innerRoomList?.destroy() } - return RustDynamicRoomList( - summaries = summariesFlow, - loadingState = loadingStateFlow, - processor = processor, - pageSize = pageSize, - dynamicController = { dynamicController } - ) + return dynamicRoomList } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustDynamicRoomList.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustDynamicRoomList.kt index 0d7b2394b3..5161b3d13a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustDynamicRoomList.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustDynamicRoomList.kt @@ -24,37 +24,58 @@ internal class RustDynamicRoomList( override val loadingState: MutableStateFlow, private val processor: RoomSummaryListProcessor, override val pageSize: Int, - private val dynamicController: () -> RoomListDynamicEntriesController?, + initialFilter: RoomListFilter, private val addPagesCount: Int = DEFAULT_ADD_PAGES_COUNT ) : DynamicRoomList { private val mutex = Mutex() + // The controller is created asynchronously, once the entries of the room list are observed + private var dynamicController: RoomListDynamicEntriesController? = null + + // The last requested filter, so that it can be applied when the controller is created + private var currentFilter: RoomListFilter = initialFilter + + /** + * To be called when the controller is created. The controller already has the initial filter set, so apply the filter + * only if it has been updated in the meantime. + */ + suspend fun onControllerCreated(controller: RoomListDynamicEntriesController, initialFilter: RoomListFilter) { + mutex.withLock { + dynamicController = controller + if (currentFilter != initialFilter) { + controller.applyFilter(currentFilter) + } + } + } + override suspend fun rebuildSummaries() { processor.rebuildRoomSummaries() } override suspend fun updateFilter(filter: RoomListFilter) { mutex.withLock { - dynamicController()?.let { controller -> - // Reset pagination when filter changes - controller.resetToOnePage() - val rustFilter = RoomListFilterMapper.toRustFilter(filter) - controller.setFilter(rustFilter) - // Then preload some pages - controller.addPages(addPagesCount) - } + currentFilter = filter + dynamicController?.applyFilter(filter) } } + private fun RoomListDynamicEntriesController.applyFilter(filter: RoomListFilter) { + // Reset pagination when filter changes + resetToOnePage() + setFilter(RoomListFilterMapper.toRustFilter(filter)) + // Then preload some pages + addPages(addPagesCount) + } + override suspend fun loadMore() { mutex.withLock { - dynamicController()?.addPages(addPagesCount) + dynamicController?.addPages(addPagesCount) } } override suspend fun reset() { mutex.withLock { - dynamicController()?.resetToOnePage() + dynamicController?.resetToOnePage() } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiRoomListDynamicEntriesController.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiRoomListDynamicEntriesController.kt new file mode 100644 index 0000000000..9a80841069 --- /dev/null +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiRoomListDynamicEntriesController.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.fixtures.fakes + +import org.matrix.rustcomponents.sdk.NoHandle +import org.matrix.rustcomponents.sdk.RoomListDynamicEntriesController +import org.matrix.rustcomponents.sdk.RoomListEntriesDynamicFilterKind + +class FakeFfiRoomListDynamicEntriesController : RoomListDynamicEntriesController(NoHandle) { + val filters = mutableListOf() + + override fun setFilter(kind: RoomListEntriesDynamicFilterKind): Boolean { + filters.add(kind) + return true + } + + override fun resetToOnePage() = Unit + + override fun addOnePage() = Unit +} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustDynamicRoomListTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustDynamicRoomListTest.kt new file mode 100644 index 0000000000..fc2686f882 --- /dev/null +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustDynamicRoomListTest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.roomlist + +import com.google.common.truth.Truth.assertThat +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.RoomSummary +import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiRoomListDynamicEntriesController +import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiRoomListService +import io.element.android.services.analytics.test.FakeAnalyticsService +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class RustDynamicRoomListTest { + @Test + fun `updateFilter before the controller is created applies the filter when it is created`() = runTest { + val sut = createRustDynamicRoomList() + sut.updateFilter(RoomListFilter.NormalizedMatchRoomName("query")) + val controller = FakeFfiRoomListDynamicEntriesController() + sut.onControllerCreated(controller, initialFilter = RoomListFilter.all()) + assertThat(controller.filters).containsExactly(RoomListFilterMapper.toRustFilter(RoomListFilter.NormalizedMatchRoomName("query"))) + } + + @Test + fun `when the filter is not updated, the controller filter is not changed when it is created`() = runTest { + val sut = createRustDynamicRoomList() + val controller = FakeFfiRoomListDynamicEntriesController() + sut.onControllerCreated(controller, initialFilter = RoomListFilter.all()) + assertThat(controller.filters).isEmpty() + } + + @Test + fun `updateFilter after the controller is created applies the filter`() = runTest { + val sut = createRustDynamicRoomList() + val controller = FakeFfiRoomListDynamicEntriesController() + sut.onControllerCreated(controller, initialFilter = RoomListFilter.all()) + sut.updateFilter(RoomListFilter.NormalizedMatchRoomName("query")) + assertThat(controller.filters).containsExactly(RoomListFilterMapper.toRustFilter(RoomListFilter.NormalizedMatchRoomName("query"))) + } + + private fun TestScope.createRustDynamicRoomList(): RustDynamicRoomList { + val summaries = MutableSharedFlow>(replay = 1) + return RustDynamicRoomList( + summaries = summaries, + loadingState = MutableStateFlow(RoomList.LoadingState.NotLoaded), + processor = RoomSummaryListProcessor( + summaries, + FakeFfiRoomListService(), + coroutineContext = StandardTestDispatcher(testScheduler), + roomSummaryFactory = RoomSummaryFactory(), + analyticsService = FakeAnalyticsService(), + ), + pageSize = 10, + initialFilter = RoomListFilter.all(), + ) + } +} diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvent.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvent.kt index 0f7baecf12..d08bce5026 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvent.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvent.kt @@ -13,7 +13,6 @@ import io.element.android.libraries.matrix.ui.model.SelectRoomInfo sealed interface RoomSelectEvent { data class ToggleSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvent - data object ToggleSearchActive : RoomSelectEvent data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvent data object ToggleAccountListExpanded : RoomSelectEvent data class SelectAccount(val sessionId: SessionId) : RoomSelectEvent diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt index 3de9d22ba8..9229718f10 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.roomselect.impl -import androidx.compose.foundation.text.input.clearText import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -63,7 +62,6 @@ class RoomSelectPresenter( override fun present(): RoomSelectState { var selectedRooms by remember { mutableStateOf(persistentListOf()) } val queryState = rememberTextFieldState() - var isSearchActive by remember { mutableStateOf(false) } var isAccountListExpanded by remember { mutableStateOf(false) } var selectedSessionId by remember { mutableStateOf(initialSessionId) } val sessions by remember { sessionStore.sessionsFlow() }.collectAsState(initial = emptyList()) @@ -136,7 +134,7 @@ class RoomSelectPresenter( derivedStateOf { when { roomSummaryDetailsList.isNotEmpty() -> SearchBarResultState.Results(roomSummaryDetailsList.toImmutableList()) - isSearchActive -> SearchBarResultState.NoResultsFound + queryState.text.isNotBlank() -> SearchBarResultState.NoResultsFound else -> SearchBarResultState.Initial } } @@ -152,13 +150,11 @@ class RoomSelectPresenter( selectedRooms.adding(event.room) } } - RoomSelectEvent.ToggleSearchActive -> isSearchActive = !isSearchActive RoomSelectEvent.ToggleAccountListExpanded -> isAccountListExpanded = !isAccountListExpanded is RoomSelectEvent.SelectAccount -> { selectedSessionId = event.sessionId - // The selected rooms and the search query are specific to the session + // The selected rooms are specific to the session. The search query is kept, and applied to the rooms of the new session. selectedRooms = persistentListOf() - queryState.clearText() isAccountListExpanded = false } is RoomSelectEvent.UpdateVisibleRange -> coroutineScope.launch { @@ -172,7 +168,6 @@ class RoomSelectPresenter( maxNumberOfRooms = maxNumberOfRooms, resultState = searchResults, searchQuery = queryState, - isSearchActive = isSearchActive, selectedRooms = selectedRooms, selectedAccount = selectedAccount, hasRoomListError = hasRoomListError, diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt index 7af7b28ddf..7ec5fdf0a6 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt @@ -20,7 +20,6 @@ data class RoomSelectState( val maxNumberOfRooms: Int, val resultState: SearchBarResultState>, val searchQuery: TextFieldState, - val isSearchActive: Boolean, val selectedRooms: ImmutableList, val selectedAccount: MatrixUser, /** diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStatePreviewParam.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStatePreviewParam.kt index 0c46c652ef..440179e55d 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStatePreviewParam.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStatePreviewParam.kt @@ -26,17 +26,15 @@ open class RoomSelectStatePreviewParam : PreviewParameterProvider get() = sequenceOf( aRoomSelectState(), - aRoomSelectState(searchQuery = "Test", isSearchActive = true), + aRoomSelectState(searchQuery = "Test", resultState = SearchBarResultState.NoResultsFound), aRoomSelectState(resultState = SearchBarResultState.Results(aRoomSelectRoomList())), aRoomSelectState( resultState = SearchBarResultState.Results(aRoomSelectRoomList()), searchQuery = "Test", - isSearchActive = true, ), aRoomSelectState( resultState = SearchBarResultState.Results(aRoomSelectRoomList()), searchQuery = "Test", - isSearchActive = true, selectedRooms = aRoomSelectRoomList().subList(0, 1), ), aRoomSelectState( @@ -76,7 +74,6 @@ internal fun aRoomSelectState( maxNumberOfRooms: Int = 10, resultState: SearchBarResultState> = SearchBarResultState.Initial, searchQuery: String = "", - isSearchActive: Boolean = false, selectedRooms: ImmutableList = persistentListOf(), selectedAccount: MatrixUser = MatrixUser(UserId("@alice:example.org")), hasRoomListError: Boolean = false, @@ -88,7 +85,6 @@ internal fun aRoomSelectState( maxNumberOfRooms = maxNumberOfRooms, resultState = resultState, searchQuery = TextFieldState(initialText = searchQuery), - isSearchActive = isSearchActive, selectedRooms = selectedRooms, selectedAccount = selectedAccount, hasRoomListError = hasRoomListError, diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt index a201faaa3d..dcae5b9f87 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.roomselect.impl import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.animate import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn @@ -24,18 +25,23 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.widthIn 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.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf @@ -46,9 +52,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -70,8 +78,8 @@ import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.ListItem import io.element.android.libraries.designsystem.theme.components.ListSectionHeader import io.element.android.libraries.designsystem.theme.components.Scaffold -import io.element.android.libraries.designsystem.theme.components.SearchBar import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.designsystem.theme.components.SearchField 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 @@ -123,10 +131,8 @@ fun RoomSelectView( } var canHandleBack by remember { mutableStateOf(true) } - fun onBackButton(state: RoomSelectState) { - if (state.isSearchActive) { - state.eventSink(RoomSelectEvent.ToggleSearchActive) - } else if (canHandleBack) { + fun onBackButton() { + if (canHandleBack) { canHandleBack = false onDismiss() } @@ -134,16 +140,34 @@ fun RoomSelectView( BackHandler( enabled = canHandleBack, - onBack = { onBackButton(state) } + onBack = ::onBackButton, ) + val searchQuery = state.searchQuery.text.toString() // Use a new list state when the selected account changes, so that the list of rooms is scrolled to the top val lazyListState = key(state.selectedAccount.userId) { rememberLazyListState() } + // Scroll the list of rooms to the top when the search query changes + LaunchedEffect(lazyListState, searchQuery) { + lazyListState.scrollToItem(0) + } // Hide the account switch section when the room list is scrolled up, and show it again as soon as it is scrolled down. // Use a new state when the selected account changes, so that the section is fully displayed again. val accountSwitchScrollBehavior = key(state.selectedAccount.userId) { TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) } + // Collapse the account switch section when the user starts searching. It can be displayed again by scrolling down. + val isSearching = searchQuery.isNotBlank() + LaunchedEffect(isSearching) { + if (isSearching) { + val topAppBarState = accountSwitchScrollBehavior.state + animate( + initialValue = topAppBarState.heightOffset, + targetValue = topAppBarState.heightOffsetLimit, + ) { value, _ -> + topAppBarState.heightOffset = value + } + } + } OnVisibleRangeChangeEffect(lazyListState) { visibleRange -> state.eventSink(RoomSelectEvent.UpdateVisibleRange(visibleRange)) } @@ -159,7 +183,7 @@ fun RoomSelectView( navigationIcon = { BackButton( enabled = canHandleBack, - onClick = { onBackButton(state) } + onClick = ::onBackButton, ) }, actions = { @@ -179,89 +203,60 @@ fun RoomSelectView( .consumeWindowInsets(paddingValues) .then( // Only when the account switch section is displayed, else its unknown height would consume all the scroll events - if (state.showAccountSwitch && !state.isSearchActive) { + if (state.showAccountSwitch) { Modifier.nestedScroll(accountSwitchScrollBehavior.nestedScrollConnection) } else { Modifier } ) ) { - SearchBar( + SearchField( + state = state.searchQuery, modifier = Modifier .fillMaxWidth() .padding( WindowInsets.safeDrawing .only(WindowInsetsSides.Horizontal) .asPaddingValues() - ), - placeHolderTitle = stringResource(CommonStrings.action_search), - queryState = state.searchQuery, - active = state.isSearchActive, - onActiveChange = { state.eventSink(RoomSelectEvent.ToggleSearchActive) }, - resultState = state.resultState, - showBackButton = false, - ) { summaries -> - LazyColumn( - state = lazyListState, - contentPadding = lazyColumnContentPadding, - ) { - if (summaries.isNotEmpty()) { - item { - ListSectionHeader( - title = stringResource(CommonStrings.common_header_rooms), - hasDivider = false, - ) - } - } - item { - SelectedRoomsHelper( - selectedRooms = state.selectedRooms, - showVerticalSpace = false, - ) - } - items(summaries, key = { it.roomId.value }) { roomSummary -> - RoomSummaryView( - roomSummary, - isSelected = state.selectedRooms.any { it.roomId == roomSummary.roomId }, - onSelection = { roomSummary -> - state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomSummary)) - }, - canBeSelected = state.canSelectMoreRooms, - ) - } + ) + .padding(horizontal = 16.dp, vertical = 8.dp), + placeholder = stringResource(CommonStrings.action_search), + ) + if (state.showAccountSwitch) { + // Keep this space outside the collapsing section, so that the section does not touch the search field when it is collapsing + Spacer(modifier = Modifier.height(8.dp)) + TopAppBarScrollBehaviorLayout(scrollBehavior = accountSwitchScrollBehavior) { + AccountSwitchSection( + selectedAccount = state.selectedAccount, + otherAccounts = state.otherAccounts, + isExpanded = state.isAccountListExpanded, + onToggleExpand = { state.eventSink(RoomSelectEvent.ToggleAccountListExpanded) }, + onSelectAccount = { state.eventSink(RoomSelectEvent.SelectAccount(it)) }, + ) } } - - if (!state.isSearchActive) { - if (state.showAccountSwitch) { - // Keep this space outside the collapsing section, so that the section does not touch the search bar when it is collapsing - Spacer(modifier = Modifier.height(8.dp)) - TopAppBarScrollBehaviorLayout(scrollBehavior = accountSwitchScrollBehavior) { - AccountSwitchSection( - selectedAccount = state.selectedAccount, - otherAccounts = state.otherAccounts, - isExpanded = state.isAccountListExpanded, - onToggleExpand = { state.eventSink(RoomSelectEvent.ToggleAccountListExpanded) }, - onSelectAccount = { state.eventSink(RoomSelectEvent.SelectAccount(it)) }, - ) - } - } - SelectedRoomsHelper( - selectedRooms = state.selectedRooms, - // showVerticalSpace only if there is no other accounts - showVerticalSpace = !state.showAccountSwitch, - ) - if (state.hasRoomListError) { - RoomListError() - } else if (state.resultState is SearchBarResultState.Results) { + SelectedRoomsHelper( + selectedRooms = state.selectedRooms, + // showVerticalSpace only if there is no other accounts + showVerticalSpace = !state.showAccountSwitch, + ) + when { + state.hasRoomListError -> RoomListError() + state.resultState is SearchBarResultState.NoResultsFound -> NoResultsView(searchQuery = searchQuery) + state.resultState is SearchBarResultState.Results -> { LazyColumn( state = lazyListState, contentPadding = lazyColumnContentPadding, ) { if (state.resultState.results.isNotEmpty()) { item { + val headerText = if (searchQuery.isBlank()) { + stringResource(CommonStrings.common_header_rooms) + } else { + stringResource(CommonStrings.common_results_for, searchQuery) + } ListSectionHeader( - title = stringResource(CommonStrings.common_header_rooms), + title = headerText, hasDivider = false, ) } @@ -278,11 +273,45 @@ fun RoomSelectView( } } } + else -> Unit } } } } +@Composable +private fun NoResultsView( + searchQuery: String, +) { + Column( + modifier = Modifier + .fillMaxSize() + // Scrollable, so that the account switch section can be displayed again by scrolling down + .verticalScroll(rememberScrollState()) + .padding(horizontal = 24.dp, vertical = 40.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + Text( + text = stringResource(CommonStrings.common_no_results), + modifier = Modifier + .semantics { + heading() + }, + textAlign = TextAlign.Center, + style = ElementTheme.typography.fontHeadingMdBold, + color = ElementTheme.colors.textPrimary, + ) + Text( + text = stringResource(CommonStrings.common_no_results_for, searchQuery), + modifier = Modifier.widthIn(max = 300.dp), + textAlign = TextAlign.Center, + style = ElementTheme.typography.fontBodyMdRegular, + color = ElementTheme.colors.textSecondary, + ) + } +} + @Composable private fun RoomListError() { IconTitleSubtitleMolecule( diff --git a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt index 0694cc27f0..2d04d28dc4 100644 --- a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt +++ b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt @@ -59,7 +59,6 @@ class RoomSelectPresenterTest { val initialState = awaitItem() assertThat(initialState.selectedRooms).isEmpty() assertThat(initialState.resultState).isInstanceOf(SearchBarResultState.Initial::class.java) - assertThat(initialState.isSearchActive).isFalse() assertThat(initialState.maxNumberOfRooms).isEqualTo(10) assertThat(initialState.canSelectMoreRooms).isTrue() assertThat(initialState.selectedAccount).isEqualTo(MatrixUser(A_SESSION_ID)) @@ -264,6 +263,33 @@ class RoomSelectPresenterTest { } } + @Test + fun `present - select another account keeps the search query and applies it to the rooms of this account`() = runTest { + val roomList2 = FakeDynamicRoomList(summaries = MutableStateFlow(listOf(aRoomSummary(roomId = A_ROOM_ID_2)))) + val roomListServices = mapOf( + A_SESSION_ID to FakeRoomListService(createRoomListLambda = { FakeDynamicRoomList(summaries = MutableStateFlow(listOf(aRoomSummary()))) }), + A_SESSION_ID_2 to FakeRoomListService(createRoomListLambda = { roomList2 }), + ) + val presenter = createRoomSelectPresenter( + mode = RoomSelectMode.Share, + sessionStore = aSessionStoreWithTwoAccounts(), + matrixClientProvider = FakeMatrixClientProvider { sessionId -> + Result.success(FakeMatrixClient(sessionId = sessionId, roomListService = roomListServices.getValue(sessionId))) + }, + ) + presenter.test { + val state = awaitLastSequentialItem() + state.searchQuery.setTextAndPlaceCursorAtEnd("query") + state.eventSink(RoomSelectEvent.SelectAccount(A_SESSION_ID_2)) + val finalState = consumeItemsUntilPredicate { + it.selectedAccount.userId == A_SESSION_ID_2 && it.resultState is SearchBarResultState.Results + }.last() + assertThat(finalState.searchQuery.text.toString()).isEqualTo("query") + assertThat(finalState.showAccountSwitch).isTrue() + assertThat(roomList2.currentFilter.value).isEqualTo(RoomListFilter.NormalizedMatchRoomName("query")) + } + } + @Test fun `present - forward mode with several accounts does not show the account switch`() = runTest { val presenter = createRoomSelectPresenter( @@ -284,18 +310,6 @@ class RoomSelectPresenterTest { ), ) - @Test - fun `present - toggle search active`() = runTest { - val presenter = createRoomSelectPresenter() - presenter.test { - val initialState = awaitItem() - initialState.eventSink(RoomSelectEvent.ToggleSearchActive) - assertThat(awaitItem().isSearchActive).isTrue() - initialState.eventSink(RoomSelectEvent.ToggleSearchActive) - assertThat(awaitItem().isSearchActive).isFalse() - } - } - @Test fun `present - update query`() = runTest { val roomSummary = aRoomSummary() @@ -314,8 +328,6 @@ class RoomSelectPresenterTest { // 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 assertThat(result).isEqualTo(listOf(expectedRoomInfo)) - initialState.eventSink(RoomSelectEvent.ToggleSearchActive) - skipItems(1) initialState.searchQuery.setTextAndPlaceCursorAtEnd("string not contained") assertThat( roomList.currentFilter.value diff --git a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectViewTest.kt b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectViewTest.kt index 71284e6ec5..3f60508816 100644 --- a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectViewTest.kt +++ b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectViewTest.kt @@ -155,6 +155,17 @@ class RoomSelectViewTest : RobolectricTest() { onNodeWithText("Room 0").assertIsNotDisplayed() } + @Test + fun `a message is displayed when no room matches the search query`() = runAndroidComposeUiTest { + setRoomSelectView( + aRoomSelectState( + searchQuery = "Test", + resultState = SearchBarResultState.NoResultsFound, + ), + ) + onNodeWithText(activity!!.getString(CommonStrings.common_no_results)).assertIsDisplayed() + } + @Test fun `an error is displayed instead of the rooms if they cannot be loaded`() = runAndroidComposeUiTest { setRoomSelectView( diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 0eeb366d72..d2cf805c69 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -335,6 +335,7 @@ Reason: %1$s." "Mute" "Name" "%1$s (%2$s)" + "There are no results for ā€œ%1$sā€. Try a new search term." "No results" "No room name" "No space name" @@ -381,6 +382,7 @@ Reason: %1$s." "Replying to %1$s" "Report a problem" "Report submitted" + "Results for ā€œ%1$sā€" "Rich text editor" "Role" "Room" diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_0_en.png index ed28276533..df5eb341fb 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf1e3ce457d2e28ee929ade5bfc1abfc0a62ef2dc8443824300d15f78e843b75 -size 11233 +oid sha256:9dad60d90d63d832243181f9eb3517a1ad15817bba3a0686e3c275a489d42921 +size 12363 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_1_en.png index eacac1fc43..a4d55009a3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90452c32320a3eaad1c520885c487dc6242e1333f2084940c85e8f4060940b1e -size 9166 +oid sha256:27198b09382c662a0fd3b35ede7afa185ffea636f4fbfd236b00163169baa4c5 +size 21598 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png index 7ac7728536..f7c327daab 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96da17f60cf84b6e5052d9753e3e81fc6f27e1ca78bbadb4501c9e4c864b6eeb -size 34329 +oid sha256:83c813b6e07f8b22ade72dbec568417c7ed7b15aba661ecc0c59d67b9b962a26 +size 35361 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png index 48e6dbced5..06ae089b98 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da7a0e6c7ed39c6d1c8f900e32d6139da70333bac1356b017148f68ea7c1dcbf -size 32126 +oid sha256:fab8e57274220f8261e4650c227aeae92fc8994300285148a96ed844b0d7d8ea +size 36277 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png index 19362d4a71..679cea54de 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c234a4c6b0c3219e4cfc6330601b15f7dc1db385b4024c18bd7f3376c27f7122 -size 36112 +oid sha256:15a9aeba4a79ce52622bcb1761483603b415d34a14017390ecc481df59d6b640 +size 39922 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png index ce8da40ea2..b6628b455d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:512f9d0246ac666d024395672ef7ff33473a40d2fe261bc84b70c1bb4381a1bd -size 33822 +oid sha256:adb459b531ec73c8d0ec33ff7a1d55685f4829458588998c021b737743584d88 +size 34886 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_6_en.png index 16a6ac408f..ed4d758af3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea0a573af47011a6f19ecc304d4cbb78522a1e6c41a353923425aeb7c8ea8e07 -size 37392 +oid sha256:66f4c2db94fa0e1230d46f4afb132a31053d6bbf66d876c7a2d71415c9d50a64 +size 38470 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_7_en.png index d17e9a0c3d..ab906e63cf 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06a3b2ffff122289becfa847e8ff4979987ba17aeab85e2c6d277f0d2234878a -size 44276 +oid sha256:a2dd9df048447b7cc742e81fa3e8436a4494b953132cb77e0614261c0e0ae3c8 +size 45326 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_8_en.png index 718c7d031a..3e5a59a127 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:454810b015c969009fd610b5b0141a892f68234147b87724d5dad0a0d7b5aab3 -size 48658 +oid sha256:aafa2a411ed5dbc23948f70ac2745883ed5824a7148fc0e9344deac2d69fafca +size 49763 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_9_en.png index 2625c34346..76829c2224 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2e2d9e7c6b7b866b610df385ff5c7a61a5bb716efd4479f9a7f07e4c61e69487 -size 37335 +oid sha256:1013a91d529084a8f65776c2b097be3409d49344bf45c6f5634179e61d21aac4 +size 38419 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_0_en.png index 149038c4f5..760d0f8033 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71b4ecc3a18de7be9eb8ef453852f6f9a5c44ae8edb0a14cdf09a4a240c3faab -size 10703 +oid sha256:757573392dec052edf0ed522a344edca4777075ede316ae3fe757ec72ae47a03 +size 11757 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_1_en.png index 9287ee04f3..7178aae2c0 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e4a4c20eb92cf93d5e7a76973b46863ed79b32e36c9d970b311b9681a382b23 -size 8957 +oid sha256:476aecd18345c3f0049a3cf455b3d0c6d9799774772cfc7044708a7eefdeec1c +size 20845 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png index c4d89d3fb0..20787d9daf 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f472811552d7499bd0acd7c929224a643957816cb4122c1a95ceaf5a7b32f1f3 -size 34198 +oid sha256:210355754bec4be43cc9a183c2125a0baf1de282cd8d1e88e85919c326159e4c +size 35225 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png index 60b3f75e62..20273cb08a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d722f376b5cc87f8a11be2d42347fbf90f31b04699f9ec6373ed068454545372 -size 32336 +oid sha256:091fb942406728012bb8d95f17465166c92d2506b11703198fb75211865bf28d +size 36138 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png index c27956224c..bc19519280 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f45a3dff7b5b669c643394ba12e0df55344ff76177030d1ae1de57275c57c4c6 -size 36401 +oid sha256:207c51ecd3b0b39d20e4d54631aa2160120ba4711f121626f6ee56a00765b7fc +size 39859 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png index 0c2e69b595..62ebafd5df 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c402aa3102e2f31c8b9ec911fdfeddd626d65032973f3f5753b2117a90118edb -size 33636 +oid sha256:000e055f5b9cb2c002b4879977aee3d85bedf377794c74aa18f65527ff34ee43 +size 34657 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_6_en.png index 8d1929baf4..75c8fef6bb 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54d3269f34abec26529050d7a89b581bdc3d5d1e20980d63993a08e73ec7a655 -size 37244 +oid sha256:03678c2b6caca9a63811717ba48d823924c855fa9b5b350eea6f6b942d3820d5 +size 38245 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_7_en.png index 267a25e404..cd2b8e2a8f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e37a74fe450f9f150963f0099d25d51b5fca93905ebf24dd243e703344eec2d7 -size 44540 +oid sha256:152d862155867306be3bbede1b1734b6c76465bc0baabf77fd9b6af462ef99e8 +size 45521 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_8_en.png index 075b7ea1ed..d93ab616e8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0cd1e2aba9e07a10237b310359f1011434ac4d55fe68acc79bf2f83461fbb88 -size 48843 +oid sha256:dae86fa884bb76b3f88a76d07894490e7779c1d73bc218de3f26f5e5c22b4680 +size 49785 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_9_en.png index 9dc7466680..1374addcb3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a327f4c2c4e3204a14a4ee601a1ddb784354a921525825868e0273f5c941f595 -size 36987 +oid sha256:389b46a2546a221927a0b9f632b10e347fd30fa088b7d26dd0f8a844b981e110 +size 37997