Let SearchBar/SearchField use TextFieldState
This commit is contained in:
parent
87619e50e8
commit
fa1b32f0ba
48 changed files with 197 additions and 298 deletions
|
|
@ -13,6 +13,5 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
|||
|
||||
sealed interface DefaultInvitePeopleEvents : InvitePeopleEvents {
|
||||
data class ToggleUser(val user: MatrixUser) : DefaultInvitePeopleEvents
|
||||
data class UpdateSearchQuery(val query: String) : DefaultInvitePeopleEvents
|
||||
data class OnSearchActiveChanged(val active: Boolean) : DefaultInvitePeopleEvents
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
package io.element.android.features.invitepeople.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
|
||||
import androidx.compose.runtime.MutableState
|
||||
|
|
@ -80,7 +82,7 @@ class DefaultInvitePeoplePresenter(
|
|||
val roomMembers = remember { mutableStateOf<AsyncData<ImmutableList<RoomMember>>>(AsyncData.Loading()) }
|
||||
val selectedUsers = remember { mutableStateOf<ImmutableList<MatrixUser>>(persistentListOf()) }
|
||||
val searchResults = remember { mutableStateOf<SearchBarResultState<ImmutableList<InvitableUser>>>(SearchBarResultState.Initial()) }
|
||||
var searchQuery by rememberSaveable { mutableStateOf("") }
|
||||
val queryState = rememberTextFieldState()
|
||||
var searchActive by rememberSaveable { mutableStateOf(false) }
|
||||
val showSearchLoader = rememberSaveable { mutableStateOf(false) }
|
||||
val sendInvitesAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) }
|
||||
|
|
@ -129,6 +131,7 @@ class DefaultInvitePeoplePresenter(
|
|||
fetchMembers(it, roomMembers)
|
||||
}
|
||||
}
|
||||
val searchQuery = queryState.text.toString()
|
||||
LaunchedEffect(searchQuery, roomMembers) {
|
||||
performSearch(
|
||||
searchResults = searchResults,
|
||||
|
|
@ -143,11 +146,9 @@ class DefaultInvitePeoplePresenter(
|
|||
when (event) {
|
||||
is DefaultInvitePeopleEvents.OnSearchActiveChanged -> {
|
||||
searchActive = event.active
|
||||
searchQuery = ""
|
||||
}
|
||||
|
||||
is DefaultInvitePeopleEvents.UpdateSearchQuery -> {
|
||||
searchQuery = event.query
|
||||
if (!event.active) {
|
||||
queryState.clearText()
|
||||
}
|
||||
}
|
||||
|
||||
is DefaultInvitePeopleEvents.ToggleUser -> {
|
||||
|
|
@ -162,7 +163,7 @@ class DefaultInvitePeoplePresenter(
|
|||
}
|
||||
is InvitePeopleEvents.CloseSearch -> {
|
||||
searchActive = false
|
||||
searchQuery = ""
|
||||
queryState.clearText()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -171,7 +172,7 @@ class DefaultInvitePeoplePresenter(
|
|||
room = room.map { },
|
||||
canInvite = selectedUsers.value.isNotEmpty() && !sendInvitesAction.value.isLoading(),
|
||||
selectedUsers = selectedUsers.value,
|
||||
searchQuery = searchQuery,
|
||||
searchQuery = queryState,
|
||||
isSearchActive = searchActive,
|
||||
searchResults = searchResults.value,
|
||||
showSearchLoader = showSearchLoader.value,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package io.element.android.features.invitepeople.impl
|
||||
|
||||
import androidx.compose.foundation.text.input.TextFieldState
|
||||
import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
||||
import io.element.android.features.invitepeople.api.InvitePeopleState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
|
|
@ -19,7 +20,7 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
data class DefaultInvitePeopleState(
|
||||
val room: AsyncData<Unit>,
|
||||
override val canInvite: Boolean,
|
||||
val searchQuery: String,
|
||||
val searchQuery: TextFieldState,
|
||||
val showSearchLoader: Boolean,
|
||||
val searchResults: SearchBarResultState<ImmutableList<InvitableUser>>,
|
||||
val selectedUsers: ImmutableList<MatrixUser>,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package io.element.android.features.invitepeople.impl
|
||||
|
||||
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.architecture.AsyncData
|
||||
|
|
@ -108,7 +109,7 @@ private fun aDefaultInvitePeopleState(
|
|||
return DefaultInvitePeopleState(
|
||||
room = room,
|
||||
canInvite = canInvite,
|
||||
searchQuery = searchQuery,
|
||||
searchQuery = TextFieldState(initialText = searchQuery),
|
||||
searchResults = searchResults,
|
||||
selectedUsers = selectedUsers,
|
||||
isSearchActive = isSearchActive,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.text.input.TextFieldState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -90,7 +91,7 @@ private fun InvitePeopleContentView(
|
|||
|
||||
InvitePeopleSearchBar(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
query = state.searchQuery,
|
||||
queryState = state.searchQuery,
|
||||
showLoader = state.showSearchLoader,
|
||||
selectedUsers = state.selectedUsers,
|
||||
state = state.searchResults,
|
||||
|
|
@ -102,7 +103,6 @@ private fun InvitePeopleContentView(
|
|||
)
|
||||
)
|
||||
},
|
||||
onTextChange = { state.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery(it)) },
|
||||
onToggleUser = ::toggleUser,
|
||||
)
|
||||
|
||||
|
|
@ -149,20 +149,18 @@ private fun InvitePeopleContentView(
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun InvitePeopleSearchBar(
|
||||
query: String,
|
||||
queryState: TextFieldState,
|
||||
state: SearchBarResultState<ImmutableList<InvitableUser>>,
|
||||
showLoader: Boolean,
|
||||
selectedUsers: ImmutableList<MatrixUser>,
|
||||
active: Boolean,
|
||||
onActiveChange: (Boolean) -> Unit,
|
||||
onTextChange: (String) -> Unit,
|
||||
onToggleUser: (MatrixUser) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
placeHolderTitle: String = stringResource(CommonStrings.common_search_for_someone),
|
||||
) {
|
||||
SearchBar(
|
||||
query = query,
|
||||
onQueryChange = onTextChange,
|
||||
queryState = queryState,
|
||||
active = active,
|
||||
onActiveChange = onActiveChange,
|
||||
modifier = modifier,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package io.element.android.features.invitepeople.impl
|
||||
|
||||
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
|
||||
import app.cash.turbine.ReceiveTurbine
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
||||
|
|
@ -68,7 +69,7 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java)
|
||||
assertThat(initialState.isSearchActive).isFalse()
|
||||
assertThat(initialState.canInvite).isFalse()
|
||||
assertThat(initialState.searchQuery).isEmpty()
|
||||
assertThat(initialState.searchQuery.text.toString()).isEmpty()
|
||||
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
|
|
@ -85,15 +86,15 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.OnSearchActiveChanged(true))
|
||||
|
||||
val resultState = awaitItem()
|
||||
val resultState = awaitItemAsDefault()
|
||||
assertThat(resultState.isSearchActive).isTrue()
|
||||
resultState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query"))
|
||||
assertThat(awaitItemAsDefault().searchQuery).isEqualTo("some query")
|
||||
resultState.searchQuery.setTextAndPlaceCursorAtEnd("some query")
|
||||
assertThat(awaitItemAsDefault().searchQuery.text.toString()).isEqualTo("some query")
|
||||
resultState.eventSink(InvitePeopleEvents.CloseSearch)
|
||||
skipItems(2)
|
||||
awaitItemAsDefault().also {
|
||||
assertThat(it.isSearchActive).isFalse()
|
||||
assertThat(it.searchQuery).isEmpty()
|
||||
assertThat(it.searchQuery.text.toString()).isEmpty()
|
||||
}
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
|
|
@ -107,8 +108,8 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query"))
|
||||
val initialState = awaitItemAsDefault()
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("some query")
|
||||
assertThat(repository.providedQuery).isEqualTo("some query")
|
||||
repository.emitState(UserSearchResultState(results = emptyList(), isSearching = true))
|
||||
skipItems(3)
|
||||
|
|
@ -132,10 +133,10 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val initialState = awaitItemAsDefault()
|
||||
skipItems(1)
|
||||
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query"))
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("some query")
|
||||
skipItems(1)
|
||||
|
||||
assertThat(repository.providedQuery).isEqualTo("some query")
|
||||
|
|
@ -185,10 +186,10 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
coroutineDispatchers = coroutineDispatchers,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val initialState = awaitItemAsDefault()
|
||||
skipItems(1)
|
||||
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query"))
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("some query")
|
||||
skipItems(1)
|
||||
|
||||
assertThat(repository.providedQuery).isEqualTo("some query")
|
||||
|
|
@ -245,10 +246,10 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
)
|
||||
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val initialState = awaitItemAsDefault()
|
||||
skipItems(1)
|
||||
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query"))
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("some query")
|
||||
skipItems(1)
|
||||
|
||||
assertThat(repository.providedQuery).isEqualTo("some query")
|
||||
|
|
@ -312,14 +313,14 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val initialState = awaitItemAsDefault()
|
||||
skipItems(1)
|
||||
|
||||
val selectedUser = aMatrixUser()
|
||||
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser))
|
||||
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query"))
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("some query")
|
||||
skipItems(1)
|
||||
|
||||
assertThat(repository.providedQuery).isEqualTo("some query")
|
||||
|
|
@ -350,13 +351,13 @@ internal class DefaultInvitePeoplePresenterTest {
|
|||
coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val initialState = awaitItemAsDefault()
|
||||
skipItems(1)
|
||||
|
||||
val selectedUser = aMatrixUser()
|
||||
|
||||
// Given a query is made
|
||||
initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query"))
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("some query")
|
||||
skipItems(1)
|
||||
|
||||
assertThat(repository.providedQuery).isEqualTo("some query")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue