diff --git a/changelog.d/2172.bugfix b/changelog.d/2172.bugfix new file mode 100644 index 0000000000..14f34666b9 --- /dev/null +++ b/changelog.d/2172.bugfix @@ -0,0 +1 @@ +Fix no indication that user list is loading when inviting to room. diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt index bc562627cc..c047a60018 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt @@ -35,6 +35,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import io.element.android.libraries.designsystem.components.async.AsyncLoading import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.SearchBar import io.element.android.libraries.designsystem.theme.components.SearchBarResultState @@ -49,6 +50,7 @@ import kotlinx.collections.immutable.ImmutableList fun SearchUserBar( query: String, state: SearchBarResultState>, + showLoader: Boolean, selectedUsers: ImmutableList, active: Boolean, isMultiSelectionEnabled: Boolean, @@ -99,6 +101,11 @@ fun SearchUserBar( ) } }, + contentSuffix = { + if (showLoader) { + AsyncLoading() + } + }, resultState = state, resultHandler = { users -> LazyColumn(state = columnState) { diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt index 45d898577f..b13d682250 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt @@ -48,6 +48,7 @@ fun UserListView( state = state.searchResults, selectedUsers = state.selectedUsers, active = state.isSearchActive, + showLoader = state.showSearchLoader, isMultiSelectionEnabled = state.isMultiSelectionEnabled, showBackButton = showBackButton, onActiveChanged = { state.eventSink(UserListEvents.OnSearchActiveChanged(it)) }, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt index 867fdc9a60..a843570fe5 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt @@ -34,6 +34,8 @@ import io.element.android.libraries.usersearch.api.UserRepository import io.element.android.libraries.usersearch.api.UserSearchResult import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach class DefaultUserListPresenter @AssistedInject constructor( @Assisted val args: UserListPresenterArgs, @@ -57,18 +59,21 @@ class DefaultUserListPresenter @AssistedInject constructor( val selectedUsers by userListDataStore.selectedUsers().collectAsState(emptyList()) var searchQuery by rememberSaveable { mutableStateOf("") } var searchResults: SearchBarResultState> by remember { - mutableStateOf(SearchBarResultState.NotSearching()) + mutableStateOf(SearchBarResultState.Initial()) } + var showSearchLoader by remember { mutableStateOf(false) } LaunchedEffect(searchQuery) { - searchResults = SearchBarResultState.NotSearching() - - userRepository.search(searchQuery).collect { + searchResults = SearchBarResultState.Initial() + showSearchLoader = false + userRepository.search(searchQuery).onEach { state -> + showSearchLoader = state.isSearching searchResults = when { - it.isEmpty() -> SearchBarResultState.NoResults() - else -> SearchBarResultState.Results(it.toImmutableList()) + state.results.isEmpty() && state.isSearching -> SearchBarResultState.Initial() + state.results.isEmpty() && !state.isSearching -> SearchBarResultState.NoResultsFound() + else -> SearchBarResultState.Results(state.results.toImmutableList()) } - } + }.launchIn(this) } return UserListState( @@ -76,6 +81,7 @@ class DefaultUserListPresenter @AssistedInject constructor( searchResults = searchResults, selectedUsers = selectedUsers.toImmutableList(), isSearchActive = isSearchActive, + showSearchLoader = showSearchLoader, selectionMode = args.selectionMode, eventSink = { event -> when (event) { diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt index 60a5bea506..a27191881e 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt @@ -24,6 +24,7 @@ import kotlinx.collections.immutable.ImmutableList data class UserListState( val searchQuery: String, val searchResults: SearchBarResultState>, + val showSearchLoader: Boolean, val selectedUsers: ImmutableList, val isSearchActive: Boolean, val selectionMode: SelectionMode, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt index 31d1f6953a..4685bb47e3 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt @@ -51,17 +51,19 @@ open class UserListStateProvider : PreviewParameterProvider { aUserListState().copy( isSearchActive = true, searchQuery = "something-with-no-results", - searchResults = SearchBarResultState.NoResults() + searchResults = SearchBarResultState.NoResultsFound() ), + aUserListState().copy(isSearchActive = true, searchQuery = "someone", selectionMode = SelectionMode.Single), ) } fun aUserListState() = UserListState( isSearchActive = false, searchQuery = "", - searchResults = SearchBarResultState.NotSearching(), + searchResults = SearchBarResultState.Initial(), selectedUsers = persistentListOf(), selectionMode = SelectionMode.Single, + showSearchLoader = false, eventSink = {} ) diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTests.kt index a591a7a8e9..d1c82120b9 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTests.kt @@ -24,6 +24,7 @@ import io.element.android.libraries.designsystem.theme.components.SearchBarResul import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.libraries.usersearch.api.UserSearchResult +import io.element.android.libraries.usersearch.api.UserSearchResultState import io.element.android.libraries.usersearch.test.FakeUserRepository import io.element.android.tests.testutils.WarmUpRule import kotlinx.collections.immutable.persistentListOf @@ -55,7 +56,7 @@ class DefaultUserListPresenterTests { assertThat(initialState.isMultiSelectionEnabled).isFalse() assertThat(initialState.isSearchActive).isFalse() assertThat(initialState.selectedUsers).isEmpty() - assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.NotSearching::class.java) + assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) } } @@ -76,7 +77,7 @@ class DefaultUserListPresenterTests { assertThat(initialState.isMultiSelectionEnabled).isTrue() assertThat(initialState.isSearchActive).isFalse() assertThat(initialState.selectedUsers).isEmpty() - assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.NotSearching::class.java) + assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) } } @@ -131,25 +132,38 @@ class DefaultUserListPresenterTests { val initialState = awaitItem() initialState.eventSink(UserListEvents.UpdateSearchQuery("alice")) - assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.NotSearching::class.java) + assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(userRepository.providedQuery).isEqualTo("alice") skipItems(2) // When the user repository emits a result, it's copied to the state - userRepository.emitResult(listOf(UserSearchResult(aMatrixUser()))) - assertThat(awaitItem().searchResults).isEqualTo( - SearchBarResultState.Results( - persistentListOf(UserSearchResult(aMatrixUser())) - ) + val result = UserSearchResultState( + results = listOf(UserSearchResult(aMatrixUser())), + isSearching = false, ) - - // When the user repository emits another result, it replaces the previous value - userRepository.emitResult(aMatrixUserList().map { UserSearchResult(it) }) - assertThat(awaitItem().searchResults).isEqualTo( - SearchBarResultState.Results( - aMatrixUserList().map { UserSearchResult(it) } + userRepository.emitState(result) + awaitItem().also { state -> + assertThat(state.searchResults).isEqualTo( + SearchBarResultState.Results( + persistentListOf(UserSearchResult(aMatrixUser())) + ) ) + assertThat(state.showSearchLoader).isFalse() + } + // When the user repository emits another result, it replaces the previous value + val newResult = UserSearchResultState( + results = aMatrixUserList().map { UserSearchResult(it) }, + isSearching = false, ) + userRepository.emitState(newResult) + awaitItem().also { state -> + assertThat(state.searchResults).isEqualTo( + SearchBarResultState.Results( + aMatrixUserList().map { UserSearchResult(it) } + ) + ) + assertThat(state.showSearchLoader).isFalse() + } } } @@ -170,13 +184,13 @@ class DefaultUserListPresenterTests { val initialState = awaitItem() initialState.eventSink(UserListEvents.UpdateSearchQuery("alice")) - assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.NotSearching::class.java) + assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(userRepository.providedQuery).isEqualTo("alice") skipItems(2) // When the results list is empty, the state is set to NoResults - userRepository.emitResult(emptyList()) - assertThat(awaitItem().searchResults).isInstanceOf(SearchBarResultState.NoResults::class.java) + userRepository.emitState(UserSearchResultState(results = emptyList(), isSearching = false)) + assertThat(awaitItem().searchResults).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt index d211a5089a..f7c4363613 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt @@ -37,6 +37,8 @@ import io.element.android.libraries.usersearch.api.UserRepository import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.withContext import javax.inject.Inject @@ -50,16 +52,22 @@ class RoomInviteMembersPresenter @Inject constructor( override fun present(): RoomInviteMembersState { val roomMembers = remember { mutableStateOf>>(AsyncData.Loading()) } val selectedUsers = remember { mutableStateOf>(persistentListOf()) } - val searchResults = remember { mutableStateOf>>(SearchBarResultState.NotSearching()) } + val searchResults = remember { mutableStateOf>>(SearchBarResultState.Initial()) } var searchQuery by rememberSaveable { mutableStateOf("") } var searchActive by rememberSaveable { mutableStateOf(false) } + var showSearchLoader = rememberSaveable { mutableStateOf(false) } LaunchedEffect(Unit) { fetchMembers(roomMembers) } - LaunchedEffect(searchQuery, roomMembers) { - performSearch(searchResults, roomMembers, selectedUsers, searchQuery) + performSearch( + searchResults = searchResults, + roomMembers = roomMembers, + selectedUsers = selectedUsers, + showSearchLoader = showSearchLoader, + searchQuery = searchQuery + ) } return RoomInviteMembersState( @@ -68,6 +76,7 @@ class RoomInviteMembersPresenter @Inject constructor( searchQuery = searchQuery, isSearchActive = searchActive, searchResults = searchResults.value, + showSearchLoader = showSearchLoader.value, eventSink = { when (it) { is RoomInviteMembersEvents.OnSearchActiveChanged -> { @@ -117,16 +126,19 @@ class RoomInviteMembersPresenter @Inject constructor( searchResults: MutableState>>, roomMembers: MutableState>>, selectedUsers: MutableState>, + showSearchLoader: MutableState, searchQuery: String, ) = withContext(coroutineDispatchers.io) { - searchResults.value = SearchBarResultState.NotSearching() - + searchResults.value = SearchBarResultState.Initial() + showSearchLoader.value = false val joinedMembers = roomMembers.value.dataOrNull().orEmpty() - userRepository.search(searchQuery).collect { + userRepository.search(searchQuery).onEach { state -> + showSearchLoader.value = state.isSearching searchResults.value = when { - it.isEmpty() -> SearchBarResultState.NoResults() - else -> SearchBarResultState.Results(it.map { result -> + state.results.isEmpty() && state.isSearching -> SearchBarResultState.Initial() + state.results.isEmpty() && !state.isSearching -> SearchBarResultState.NoResultsFound() + else -> SearchBarResultState.Results(state.results.map { result -> val existingMembership = joinedMembers.firstOrNull { j -> j.userId == result.matrixUser.userId }?.membership val isJoined = existingMembership == RoomMembershipState.JOIN val isInvited = existingMembership == RoomMembershipState.INVITE @@ -139,7 +151,7 @@ class RoomInviteMembersPresenter @Inject constructor( ) }.toImmutableList()) } - } + }.launchIn(this) } private suspend fun fetchMembers(roomMembers: MutableState>>) { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt index 16436debf0..84fb1b0986 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt @@ -23,6 +23,7 @@ import kotlinx.collections.immutable.ImmutableList data class RoomInviteMembersState( val canInvite: Boolean, val searchQuery: String, + val showSearchLoader: Boolean, val searchResults: SearchBarResultState>, val selectedUsers: ImmutableList, val isSearchActive: Boolean, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt index f44d518fb5..ca4e4ac7d2 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt @@ -32,7 +32,7 @@ internal class RoomInviteMembersStateProvider : PreviewParameterProvider> = SearchBarResultState.NotSearching(), + searchResults: SearchBarResultState> = SearchBarResultState.Initial(), selectedUsers: ImmutableList = persistentListOf(), isSearchActive: Boolean = false, + showSearchLoader: Boolean = false, ): RoomInviteMembersState { return RoomInviteMembersState( canInvite = canInvite, @@ -80,6 +92,7 @@ private fun aRoomInviteMembersState( searchResults = searchResults, selectedUsers = selectedUsers, isSearchActive = isSearchActive, + showSearchLoader = showSearchLoader, eventSink = {}, ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt index 6c19b45686..e40e624afc 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt @@ -50,6 +50,7 @@ import io.element.android.libraries.matrix.ui.components.SelectedUsersList import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.designsystem.components.async.AsyncLoading import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.ImmutableList @@ -86,6 +87,7 @@ fun RoomInviteMembersView( RoomInviteMembersSearchBar( modifier = Modifier.fillMaxWidth(), query = state.searchQuery, + showLoader = state.showSearchLoader, selectedUsers = state.selectedUsers, state = state.searchResults, active = state.isSearchActive, @@ -139,6 +141,7 @@ private fun RoomInviteMembersTopBar( private fun RoomInviteMembersSearchBar( query: String, state: SearchBarResultState>, + showLoader: Boolean, selectedUsers: ImmutableList, active: Boolean, onActiveChanged: (Boolean) -> Unit, @@ -167,6 +170,11 @@ private fun RoomInviteMembersSearchBar( }, showBackButton = false, resultState = state, + contentSuffix = { + if (showLoader) { + AsyncLoading() + } + }, resultHandler = { results -> Text( text = stringResource(id = CommonStrings.common_search_results), diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt index 649d2d8482..0f66f7db4c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt @@ -47,7 +47,7 @@ class RoomMemberListPresenter @Inject constructor( var roomMembers by remember { mutableStateOf>(AsyncData.Loading()) } var searchQuery by rememberSaveable { mutableStateOf("") } var searchResults by remember { - mutableStateOf>(SearchBarResultState.NotSearching()) + mutableStateOf>(SearchBarResultState.Initial()) } var isSearchActive by rememberSaveable { mutableStateOf(false) } @@ -71,10 +71,10 @@ class RoomMemberListPresenter @Inject constructor( LaunchedEffect(searchQuery) { withContext(coroutineDispatchers.io) { searchResults = if (searchQuery.isEmpty()) { - SearchBarResultState.NotSearching() + SearchBarResultState.Initial() } else { val results = roomMemberListDataSource.search(searchQuery).groupBy { it.membership } - if (results.isEmpty()) SearchBarResultState.NoResults() + if (results.isEmpty()) SearchBarResultState.NoResultsFound() else SearchBarResultState.Results( RoomMembers( invited = results.getOrDefault(RoomMembershipState.INVITE, emptyList()).toImmutableList(), diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt index a9e4037c3c..5d9549808c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt @@ -53,14 +53,14 @@ internal class RoomMemberListStateProvider : PreviewParameterProvider = AsyncData.Uninitialized, - searchResults: SearchBarResultState = SearchBarResultState.NotSearching(), + searchResults: SearchBarResultState = SearchBarResultState.Initial(), ) = RoomMemberListState( roomMembers = roomMembers, searchQuery = "", diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt index 9763ed280b..0d2201342f 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt @@ -29,14 +29,17 @@ import io.element.android.libraries.designsystem.theme.components.SearchBarResul import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState +import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.libraries.usersearch.api.UserSearchResult +import io.element.android.libraries.usersearch.api.UserSearchResultState import io.element.android.libraries.usersearch.test.FakeUserRepository import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -63,7 +66,7 @@ internal class RoomInviteMembersPresenterTest { }.test { val initialState = awaitItem() - assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.NotSearching::class.java) + assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() assertThat(initialState.canInvite).isFalse() assertThat(initialState.searchQuery).isEmpty() @@ -94,7 +97,7 @@ internal class RoomInviteMembersPresenterTest { } @Test - fun `present - performs search and handles no results`() = runTest { + fun `present - performs search and handles empty result list`() = runTest { val repository = FakeUserRepository() val presenter = RoomInviteMembersPresenter( userRepository = repository, @@ -105,17 +108,18 @@ internal class RoomInviteMembersPresenterTest { presenter.present() }.test { val initialState = awaitItem() - skipItems(1) - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) - skipItems(1) - assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitResult(emptyList()) - skipItems(1) - - val resultState = awaitItem() - assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.NoResults::class.java) + repository.emitState(UserSearchResultState(results = emptyList(), isSearching = true)) + consumeItemsUntilPredicate { it.showSearchLoader }.last().also { state -> + assertThat(state.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) + assertThat(state.showSearchLoader).isTrue() + } + repository.emitState(results = emptyList(), isSearching = false) + consumeItemsUntilPredicate { !it.showSearchLoader }.last().also { state -> + assertThat(state.searchResults).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) + assertThat(state.showSearchLoader).isFalse() + } } } @@ -137,7 +141,7 @@ internal class RoomInviteMembersPresenterTest { skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitResult(aMatrixUserList().map { UserSearchResult(it) }) + repository.emitStateWithUsers(users = aMatrixUserList()) skipItems(1) val resultState = awaitItem() @@ -189,7 +193,7 @@ internal class RoomInviteMembersPresenterTest { skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitResult(aMatrixUserList().map { UserSearchResult(it) }) + repository.emitStateWithUsers(users = aMatrixUserList()) skipItems(1) val resultState = awaitItem() @@ -250,7 +254,7 @@ internal class RoomInviteMembersPresenterTest { assertThat(repository.providedQuery).isEqualTo("some query") val unresolvedUser = UserSearchResult(aMatrixUser(id = A_USER_ID.value), isUnresolved = true) - repository.emitResult(listOf(unresolvedUser) + aMatrixUserList().map { UserSearchResult(it) }) + repository.emitState(listOf(unresolvedUser) + aMatrixUserList().map { UserSearchResult(it) }) skipItems(1) val resultState = awaitItem() @@ -318,7 +322,7 @@ internal class RoomInviteMembersPresenterTest { skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitResult((aMatrixUserList() + selectedUser).map { UserSearchResult(it) }) + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) skipItems(2) val resultState = awaitItem() @@ -358,7 +362,7 @@ internal class RoomInviteMembersPresenterTest { skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") - repository.emitResult((aMatrixUserList() + selectedUser).map { UserSearchResult(it) }) + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) skipItems(2) // And then a user is toggled @@ -381,6 +385,27 @@ internal class RoomInviteMembersPresenterTest { } } + private suspend fun FakeUserRepository.emitStateWithUsers( + users: List, + isSearching: Boolean = false + ) { + emitState( + results = users.map { UserSearchResult(it) }, + isSearching = isSearching, + ) + } + + private suspend fun FakeUserRepository.emitState( + results: List, + isSearching: Boolean = false + ) { + val state = UserSearchResultState( + results = results, + isSearching = isSearching + ) + emitState(state) + } + private fun TestScope.createDataSource( matrixRoom: MatrixRoom = aMatrixRoom().apply { givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt index 1b5ae74765..f08976a8cb 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt @@ -55,7 +55,7 @@ class RoomMemberListPresenterTests { val initialState = awaitItem() assertThat(initialState.roomMembers).isInstanceOf(AsyncData.Loading::class.java) assertThat(initialState.searchQuery).isEmpty() - assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.NotSearching::class.java) + assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() val loadedState = awaitItem() assertThat(loadedState.roomMembers).isInstanceOf(AsyncData.Success::class.java) @@ -92,7 +92,7 @@ class RoomMemberListPresenterTests { val searchQueryUpdatedState = awaitItem() assertThat(searchQueryUpdatedState.searchQuery).isEqualTo("something") val searchSearchResultDelivered = awaitItem() - assertThat(searchSearchResultDelivered.searchResults).isInstanceOf(SearchBarResultState.NoResults::class.java) + assertThat(searchSearchResultDelivered.searchResults).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) } } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt index 7e208b88d9..d32d7de685 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SearchBar.kt @@ -59,7 +59,7 @@ fun SearchBar( modifier: Modifier = Modifier, enabled: Boolean = true, showBackButton: Boolean = true, - resultState: SearchBarResultState = SearchBarResultState.NotSearching(), + resultState: SearchBarResultState = SearchBarResultState.Initial(), shape: Shape = SearchBarDefaults.inputFieldShape, tonalElevation: Dp = SearchBarDefaults.TonalElevation, windowInsets: WindowInsets = SearchBarDefaults.windowInsets, @@ -129,7 +129,7 @@ fun SearchBar( resultHandler(resultState.results) } - is SearchBarResultState.NoResults -> { + is SearchBarResultState.NoResultsFound -> { // No results found, show a message Spacer(Modifier.size(80.dp)) @@ -184,10 +184,10 @@ object ElementSearchBarDefaults { @Immutable sealed interface SearchBarResultState { /** No search results are available yet (e.g. because the user hasn't entered a search term). */ - class NotSearching : SearchBarResultState + class Initial : SearchBarResultState /** The search has completed, but no results were found. */ - class NoResults : SearchBarResultState + class NoResultsFound : SearchBarResultState /** The search has completed, and some matching users were found. */ data class Results(val results: T) : SearchBarResultState @@ -199,7 +199,7 @@ internal fun SearchBarInactivePreview() = ElementThemedPreview { ContentToPrevie @Preview(group = PreviewGroup.Search) @Composable -internal fun SearchBarActiveEmptyQueryPreview() = ElementThemedPreview { +internal fun SearchBarActiveNoneQueryPreview() = ElementThemedPreview { ContentToPreview( query = "", active = true, @@ -231,7 +231,7 @@ internal fun SearchBarActiveWithNoResultsPreview() = ElementThemedPreview { ContentToPreview( query = "search term", active = true, - resultState = SearchBarResultState.NoResults(), + resultState = SearchBarResultState.NoResultsFound(), ) } @@ -257,16 +257,15 @@ internal fun SearchBarActiveWithContentPreview() = ElementThemedPreview { .background(color = Color.Blue) .fillMaxWidth() ) - }, - resultHandler = { - Text( - text = "Results go here", - modifier = Modifier - .background(color = Color.Green) - .fillMaxWidth() - ) } - ) + ) { + Text( + text = "Results go here", + modifier = Modifier + .background(color = Color.Green) + .fillMaxWidth() + ) + } } @OptIn(ExperimentalMaterial3Api::class) @@ -275,7 +274,7 @@ private fun ContentToPreview( query: String = "", active: Boolean = false, showBackButton: Boolean = true, - resultState: SearchBarResultState = SearchBarResultState.NotSearching(), + resultState: SearchBarResultState = SearchBarResultState.Initial(), contentPrefix: @Composable ColumnScope.() -> Unit = {}, contentSuffix: @Composable ColumnScope.() -> Unit = {}, resultHandler: @Composable ColumnScope.(String) -> Unit = {}, 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 16cd7b813d..8535031c16 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 @@ -51,7 +51,7 @@ class RoomSelectPresenter @AssistedInject constructor( var selectedRooms by remember { mutableStateOf(persistentListOf()) } var query by remember { mutableStateOf("") } var isSearchActive by remember { mutableStateOf(false) } - var results: SearchBarResultState> by remember { mutableStateOf(SearchBarResultState.NotSearching()) } + var results: SearchBarResultState> by remember { mutableStateOf(SearchBarResultState.Initial()) } val summaries by client.roomListService.allRooms.summaries.collectAsState() @@ -64,7 +64,7 @@ class RoomSelectPresenter @AssistedInject constructor( results = if (filteredSummaries.isNotEmpty()) { SearchBarResultState.Results(filteredSummaries) } else { - SearchBarResultState.NoResults() + SearchBarResultState.NoResultsFound() } } diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt index d06e0be6d6..032dc4a8d0 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt @@ -48,7 +48,7 @@ open class RoomSelectStateProvider : PreviewParameterProvider { } private fun aRoomSelectState( - resultState: SearchBarResultState> = SearchBarResultState.NotSearching(), + resultState: SearchBarResultState> = SearchBarResultState.Initial(), query: String = "", isSearchActive: Boolean = false, selectedRooms: ImmutableList = persistentListOf(), diff --git a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt index 88ae560bb2..ec85358ebd 100644 --- a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt +++ b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTests.kt @@ -45,11 +45,11 @@ class RoomSelectPresenterTests { }.test { val initialState = awaitItem() assertThat(initialState.selectedRooms).isEmpty() - assertThat(initialState.resultState).isInstanceOf(SearchBarResultState.NotSearching::class.java) + assertThat(initialState.resultState).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() // Search is run automatically val searchState = awaitItem() - assertThat(searchState.resultState).isInstanceOf(SearchBarResultState.NoResults::class.java) + assertThat(searchState.resultState).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) } } @@ -85,7 +85,7 @@ class RoomSelectPresenterTests { initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained")) assertThat(awaitItem().query).isEqualTo("string not contained") - assertThat(awaitItem().resultState).isInstanceOf(SearchBarResultState.NoResults::class.java) + assertThat(awaitItem().resultState).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) } } diff --git a/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserRepository.kt b/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserRepository.kt index 03e9952c92..ed019fc5a5 100644 --- a/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserRepository.kt +++ b/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserRepository.kt @@ -20,5 +20,5 @@ import kotlinx.coroutines.flow.Flow interface UserRepository { - suspend fun search(query: String): Flow> + fun search(query: String): Flow } diff --git a/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserSearchResult.kt b/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserSearchResult.kt index e67a7af46f..2410b58d05 100644 --- a/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserSearchResult.kt +++ b/libraries/usersearch/api/src/main/kotlin/io/element/android/libraries/usersearch/api/UserSearchResult.kt @@ -22,3 +22,8 @@ data class UserSearchResult( val matrixUser: MatrixUser, val isUnresolved: Boolean = false, ) + +data class UserSearchResultState( + val results: List, + val isSearching: Boolean, +) diff --git a/libraries/usersearch/impl/src/main/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepository.kt b/libraries/usersearch/impl/src/main/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepository.kt index 0714528836..fa09a5ce9a 100644 --- a/libraries/usersearch/impl/src/main/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepository.kt +++ b/libraries/usersearch/impl/src/main/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepository.kt @@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.usersearch.api.UserListDataSource import io.element.android.libraries.usersearch.api.UserRepository import io.element.android.libraries.usersearch.api.UserSearchResult +import io.element.android.libraries.usersearch.api.UserSearchResultState import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow @@ -36,34 +37,43 @@ class MatrixUserRepository @Inject constructor( private val dataSource: UserListDataSource ) : UserRepository { - override suspend fun search(query: String): Flow> = flow { - // If the search term is a MXID that's not ours, we'll show a 'fake' result for that user, then update it when we get search results. + override fun search(query: String): Flow = flow { val shouldQueryProfile = MatrixPatterns.isUserId(query) && !client.isMe(UserId(query)) - if (shouldQueryProfile) { - emit(listOf(UserSearchResult(MatrixUser(UserId(query))))) + val shouldFetchSearchResults = query.length >= MINIMUM_SEARCH_LENGTH + // If the search term is a MXID that's not ours, we'll show a 'fake' result for that user, then update it when we get search results. + val fakeSearchResult = if (shouldQueryProfile) { + UserSearchResult(MatrixUser(UserId(query))) + } else { + null } + if (shouldQueryProfile || shouldFetchSearchResults) { + emit(UserSearchResultState(isSearching = shouldFetchSearchResults, results = listOfNotNull(fakeSearchResult))) + } + if (shouldFetchSearchResults) { + val results = fetchSearchResults(query, shouldQueryProfile) + emit(results) + } + } - if (query.length >= MINIMUM_SEARCH_LENGTH) { - // Debounce - delay(DEBOUNCE_TIME_MILLIS) - - val results = dataSource - .search(query, MAXIMUM_SEARCH_RESULTS) - .filter { !client.isMe(it.userId) } - .map { UserSearchResult(it) } - .toMutableList() - - // If the query is another user's MXID and the result doesn't contain that user ID, query the profile information explicitly - if (shouldQueryProfile && results.none { it.matrixUser.userId.value == query }) { - results.add( - 0, - dataSource.getProfile(UserId(query)) - ?.let { UserSearchResult(it) } - ?: UserSearchResult(MatrixUser(UserId(query)), isUnresolved = true)) - } + private suspend fun fetchSearchResults(query: String, shouldQueryProfile: Boolean): UserSearchResultState { + // Debounce + delay(DEBOUNCE_TIME_MILLIS) + val results = dataSource + .search(query, MAXIMUM_SEARCH_RESULTS) + .filter { !client.isMe(it.userId) } + .map { UserSearchResult(it) } + .toMutableList() - emit(results) + // If the query is another user's MXID and the result doesn't contain that user ID, query the profile information explicitly + if (shouldQueryProfile && results.none { it.matrixUser.userId.value == query }) { + results.add( + 0, + dataSource.getProfile(UserId(query)) + ?.let { UserSearchResult(it) } + ?: UserSearchResult(MatrixUser(UserId(query)), isUnresolved = true)) } + + return UserSearchResultState(results = results, isSearching = false) } companion object { diff --git a/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepositoryTest.kt b/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepositoryTest.kt index 621274bef5..e775547efc 100644 --- a/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepositoryTest.kt +++ b/libraries/usersearch/impl/src/test/kotlin/io/element/android/libraries/usersearch/impl/MatrixUserRepositoryTest.kt @@ -54,7 +54,14 @@ internal class MatrixUserRepositoryTest { val result = repository.search("some query") result.test { - assertThat(awaitItem()).isEmpty() + awaitItem().also { + assertThat(it.isSearching).isTrue() + assertThat(it.results).isEmpty() + } + awaitItem().also { + assertThat(it.isSearching).isFalse() + assertThat(it.results).isEmpty() + } awaitComplete() } } @@ -68,7 +75,14 @@ internal class MatrixUserRepositoryTest { val result = repository.search("some query") result.test { - assertThat(awaitItem()).isEqualTo(aMatrixUserList().toUserSearchResults()) + awaitItem().also { + assertThat(it.isSearching).isTrue() + assertThat(it.results).isEmpty() + } + awaitItem().also { + assertThat(it.isSearching).isFalse() + assertThat(it.results).isEqualTo(aMatrixUserList().toUserSearchResults()) + } awaitComplete() } } @@ -81,9 +95,11 @@ internal class MatrixUserRepositoryTest { val result = repository.search(A_USER_ID.value) result.test { - assertThat(awaitItem()).isEqualTo(listOf(placeholderResult())) - skipItems(1) - awaitComplete() + awaitItem().also { + assertThat(it.isSearching).isTrue() + assertThat(it.results).isEqualTo(listOf(placeholderResult())) + } + cancelAndConsumeRemainingEvents() } } @@ -95,8 +111,11 @@ internal class MatrixUserRepositoryTest { val result = repository.search(SESSION_ID.value) result.test { - assertThat(awaitItem()).isEmpty() - awaitComplete() + awaitItem().also { + assertThat(it.isSearching).isTrue() + assertThat(it.results).isEmpty() + } + cancelAndConsumeRemainingEvents() } } @@ -110,7 +129,8 @@ internal class MatrixUserRepositoryTest { val result = repository.search("some text") result.test { - assertThat(awaitItem()).isEqualTo(aMatrixUserList().toUserSearchResults()) + skipItems(1) + assertThat(awaitItem().results).isEqualTo(aMatrixUserList().toUserSearchResults()) awaitComplete() } } @@ -126,7 +146,7 @@ internal class MatrixUserRepositoryTest { result.test { skipItems(1) - assertThat(awaitItem()).isEqualTo(searchResults.toUserSearchResults()) + assertThat(awaitItem().results).isEqualTo(searchResults.toUserSearchResults()) awaitComplete() } } @@ -145,7 +165,7 @@ internal class MatrixUserRepositoryTest { result.test { skipItems(1) - assertThat(awaitItem()).isEqualTo((listOf(userProfile) + searchResults).toUserSearchResults()) + assertThat(awaitItem().results).isEqualTo((listOf(userProfile) + searchResults).toUserSearchResults()) awaitComplete() } } @@ -163,7 +183,8 @@ internal class MatrixUserRepositoryTest { val result = repository.search(SESSION_ID.value) result.test { - assertThat(awaitItem()).isEqualTo(searchResults.toUserSearchResults()) + skipItems(1) + assertThat(awaitItem().results).isEqualTo(searchResults.toUserSearchResults()) awaitComplete() } } @@ -181,7 +202,7 @@ internal class MatrixUserRepositoryTest { result.test { skipItems(1) - assertThat(awaitItem()).isEqualTo(listOf(placeholderResult(isUnresolved = true)) + searchResults.toUserSearchResults()) + assertThat(awaitItem().results).isEqualTo(listOf(placeholderResult(isUnresolved = true)) + searchResults.toUserSearchResults()) awaitComplete() } } diff --git a/libraries/usersearch/test/src/main/kotlin/io/element/android/libraries/usersearch/test/FakeUserRepository.kt b/libraries/usersearch/test/src/main/kotlin/io/element/android/libraries/usersearch/test/FakeUserRepository.kt index 0911d86b36..3ca2320a26 100644 --- a/libraries/usersearch/test/src/main/kotlin/io/element/android/libraries/usersearch/test/FakeUserRepository.kt +++ b/libraries/usersearch/test/src/main/kotlin/io/element/android/libraries/usersearch/test/FakeUserRepository.kt @@ -17,7 +17,7 @@ package io.element.android.libraries.usersearch.test import io.element.android.libraries.usersearch.api.UserRepository -import io.element.android.libraries.usersearch.api.UserSearchResult +import io.element.android.libraries.usersearch.api.UserSearchResultState import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -26,15 +26,15 @@ class FakeUserRepository : UserRepository { var providedQuery: String? = null private set - private val flow = MutableSharedFlow>() + private val flow = MutableSharedFlow() - override suspend fun search(query: String): Flow> { + override fun search(query: String): Flow { providedQuery = query return flow } - suspend fun emitResult(result: List) { - flow.emit(result) + suspend fun emitState(state: UserSearchResultState) { + flow.emit(state) } } diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_8,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d81d496d15 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Day-2_3_null_8,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4731f36d3ee1331c0767ad27d4286feca266deabfd55960a89b0e823925b30f2 +size 7646 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_8,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..573ab912c2 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.createroom.impl.components_UserListView_null_UserListView-Night-2_4_null_8,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae2119fa8d67dc6787a3cf86ada1259a4ff941d1d9a55936d5ee84e71e42ac72 +size 7217 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.invite_RoomInviteMembers_null_RoomInviteMembers-Day-1_2_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.invite_RoomInviteMembers_null_RoomInviteMembers-Day-1_2_null_7,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d7964f155e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.invite_RoomInviteMembers_null_RoomInviteMembers-Day-1_2_null_7,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62baff22557bc9b130c87b64b45a53b0209390ecfe11d16e1b31868a5a264cf3 +size 31956 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.invite_RoomInviteMembers_null_RoomInviteMembers-Night-1_3_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.invite_RoomInviteMembers_null_RoomInviteMembers-Night-1_3_null_7,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ee60e0fc83 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.invite_RoomInviteMembers_null_RoomInviteMembers-Night-1_3_null_7,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b5645d81ef1ed73241ec2183f8d5b4cf4cd7510fc8804a26719842e8ed4bc7f +size 29891 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_SearchBarActiveEmptyQuery_null_Searchviews_SearchBarActiveEmptyQuery_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_SearchBarActiveNoneQuery_null_Searchviews_SearchBarActiveNoneQuery_0_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_SearchBarActiveEmptyQuery_null_Searchviews_SearchBarActiveEmptyQuery_0_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.theme.components_SearchBarActiveNoneQuery_null_Searchviews_SearchBarActiveNoneQuery_0_null,NEXUS_5,1.0,en].png