Let SearchBar/SearchField use TextFieldState

This commit is contained in:
ganfra 2026-01-22 16:34:22 +01:00
parent 87619e50e8
commit fa1b32f0ba
48 changed files with 197 additions and 298 deletions

View file

@ -12,7 +12,6 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
sealed interface ChangeRolesEvent {
data object ToggleSearchActive : ChangeRolesEvent
data class QueryChanged(val query: String?) : ChangeRolesEvent
data class UserSelectionToggled(val matrixUser: MatrixUser) : ChangeRolesEvent
data object Save : ChangeRolesEvent
data object Exit : ChangeRolesEvent

View file

@ -8,6 +8,7 @@
package io.element.android.features.rolesandpermissions.impl.roles
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
@ -68,7 +69,7 @@ class ChangeRolesPresenter(
@Composable
override fun present(): ChangeRolesState {
var query by rememberSaveable { mutableStateOf<String?>(null) }
val queryState = rememberTextFieldState()
var searchActive by rememberSaveable { mutableStateOf(false) }
var searchResults by remember {
mutableStateOf<SearchBarResultState<MembersByRole>>(SearchBarResultState.Initial())
@ -105,9 +106,10 @@ class ChangeRolesPresenter(
val roomMemberState by room.membersStateFlow.collectAsState()
// Update search results for every query change
val query = queryState.text.toString()
LaunchedEffect(query, roomMemberState) {
val results = dataSource
.search(query.orEmpty())
.search(query)
.groupedByRole()
searchResults = if (results.isEmpty()) {
@ -136,9 +138,6 @@ class ChangeRolesPresenter(
is ChangeRolesEvent.ToggleSearchActive -> {
searchActive = !searchActive
}
is ChangeRolesEvent.QueryChanged -> {
query = event.query
}
is ChangeRolesEvent.UserSelectionToggled -> {
val newList = selectedUsers.value.toMutableList()
val index = newList.indexOfFirst { it.userId == event.matrixUser.userId }
@ -188,7 +187,7 @@ class ChangeRolesPresenter(
}
return ChangeRolesState(
role = role,
query = query,
searchQuery = queryState,
isSearchActive = searchActive,
searchResults = searchResults,
selectedUsers = selectedUsers.value,

View file

@ -8,6 +8,7 @@
package io.element.android.features.rolesandpermissions.impl.roles
import androidx.compose.foundation.text.input.TextFieldState
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.core.UserId
@ -19,7 +20,7 @@ import kotlinx.collections.immutable.toImmutableList
data class ChangeRolesState(
val role: RoomMember.Role,
val query: String?,
val searchQuery: TextFieldState,
val isSearchActive: Boolean,
val searchResults: SearchBarResultState<MembersByRole>,
val selectedUsers: ImmutableList<MatrixUser>,

View file

@ -8,6 +8,7 @@
package io.element.android.features.rolesandpermissions.impl.roles
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
@ -34,8 +35,8 @@ class ChangeRolesStateProvider : PreviewParameterProvider<ChangeRolesState> {
aChangeRolesStateWithSelectedUsers().copy(
selectedUsers = aMatrixUserList().take(2).toImmutableList(),
),
aChangeRolesStateWithSelectedUsers().copy(
query = "Alice",
aChangeRolesState(
searchQuery = "Alice",
isSearchActive = true,
searchResults = SearchBarResultState.Results(
MembersByRole(
@ -44,6 +45,8 @@ class ChangeRolesStateProvider : PreviewParameterProvider<ChangeRolesState> {
)
),
selectedUsers = aMatrixUserList().take(1).toImmutableList(),
hasPendingChanges = true,
canRemoveMember = { it != UserId("@alice:server.org") },
),
aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.ConfirmingCancellation),
aChangeRolesStateWithSelectedUsers().copy(savingState = ConfirmingModifyingAdmins),
@ -59,7 +62,7 @@ class ChangeRolesStateProvider : PreviewParameterProvider<ChangeRolesState> {
internal fun aChangeRolesState(
role: RoomMember.Role = RoomMember.Role.Admin,
query: String? = null,
searchQuery: String = "",
isSearchActive: Boolean = false,
searchResults: SearchBarResultState<MembersByRole> = SearchBarResultState.NoResultsFound(),
selectedUsers: ImmutableList<MatrixUser> = persistentListOf(),
@ -69,7 +72,7 @@ internal fun aChangeRolesState(
eventSink: (ChangeRolesEvent) -> Unit = {},
) = ChangeRolesState(
role = role,
query = query,
searchQuery = TextFieldState(initialText = searchQuery),
isSearchActive = isSearchActive,
searchResults = searchResults,
selectedUsers = selectedUsers,

View file

@ -118,8 +118,7 @@ fun ChangeRolesView(
.fillMaxWidth()
.padding(bottom = 16.dp),
placeHolderTitle = stringResource(CommonStrings.common_search_for_someone),
query = state.query.orEmpty(),
onQueryChange = { state.eventSink(ChangeRolesEvent.QueryChanged(it)) },
queryState = state.searchQuery,
active = state.isSearchActive,
onActiveChange = { state.eventSink(ChangeRolesEvent.ToggleSearchActive) },
resultState = state.searchResults,

View file

@ -8,6 +8,7 @@
package io.element.android.features.rolesandpermissions.impl.roles
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.RoomModeration
import io.element.android.features.rolesandpermissions.impl.RoomMemberListDataSource
@ -49,7 +50,7 @@ class ChangeRolesPresenterTest {
presenter.test {
with(awaitItem()) {
assertThat(role).isEqualTo(RoomMember.Role.Admin)
assertThat(query).isNull()
assertThat(searchQuery.text.toString()).isEmpty()
assertThat(isSearchActive).isFalse()
assertThat(searchResults).isInstanceOf(SearchBarResultState.Initial::class.java)
assertThat(selectedUsers).isEmpty()
@ -206,7 +207,7 @@ class ChangeRolesPresenterTest {
}
@Test
fun `present - QueryChanged produces new results`() = runTest {
fun `present - updating query produces new results`() = runTest {
val room = FakeJoinedRoom().apply {
givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList()))
}
@ -219,7 +220,7 @@ class ChangeRolesPresenterTest {
assertThat(initialResults?.moderators).hasSize(1)
assertThat(initialResults?.admins).hasSize(1)
initialState.eventSink(ChangeRolesEvent.QueryChanged("Alice"))
initialState.searchQuery.setTextAndPlaceCursorAtEnd("Alice")
skipItems(1)
val searchResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results

View file

@ -76,7 +76,7 @@ class ChangeRolesViewTest {
),
)
rule.pressBackKey()
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit))
eventsRecorder.assertSingle(ChangeRolesEvent.Exit)
}
@Test
@ -89,7 +89,7 @@ class ChangeRolesViewTest {
),
)
rule.pressBack()
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit))
eventsRecorder.assertSingle(ChangeRolesEvent.Exit)
}
@Test
@ -102,7 +102,7 @@ class ChangeRolesViewTest {
),
)
rule.clickOn(CommonStrings.action_save)
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Save))
eventsRecorder.assertSingle(ChangeRolesEvent.Save)
}
@Test
@ -115,7 +115,7 @@ class ChangeRolesViewTest {
),
)
rule.clickOn(CommonStrings.action_save)
eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged("")))
eventsRecorder.assertEmpty()
}
@Test
@ -238,12 +238,7 @@ class ChangeRolesViewTest {
label = contentDescription,
useUnmergedTree = true,
).performClick()
eventsRecorder.assertList(
listOf(
ChangeRolesEvent.QueryChanged(""),
ChangeRolesEvent.UserSelectionToggled(userToDeselect),
)
)
eventsRecorder.assertSingle(ChangeRolesEvent.UserSelectionToggled(userToDeselect))
}
@Test
@ -262,12 +257,7 @@ class ChangeRolesViewTest {
)
// Select the user from the user list
rule.onNodeWithText("Carol").performClick()
eventsRecorder.assertList(
listOf(
ChangeRolesEvent.QueryChanged(""),
ChangeRolesEvent.UserSelectionToggled(userToSelect),
)
)
eventsRecorder.assertSingle(ChangeRolesEvent.UserSelectionToggled(userToSelect))
}
@Test
@ -288,12 +278,7 @@ class ChangeRolesViewTest {
text = "Bob",
useUnmergedTree = true,
)[1].performClick()
eventsRecorder.assertList(
listOf(
ChangeRolesEvent.QueryChanged(""),
ChangeRolesEvent.UserSelectionToggled(userToSelect),
)
)
eventsRecorder.assertSingle(ChangeRolesEvent.UserSelectionToggled(userToSelect))
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setChangeRolesContent(