Search for users to start a new DM. (#376)

Search for users to start a new DM.

Hooks up the create room UI to the matrix client to get
search results. Searches are debounced for 500ms and
only executed when 3 or more characters are entered.

Wrap the result state so we can distinguish between
"no results because we haven't searched yet" and
"no results because the API returned nothing", and
add a "No results found" message in the UI for the
latter case.

Closes #95
This commit is contained in:
Chris Smith 2023-05-03 14:26:31 +01:00 committed by GitHub
parent c411faa93d
commit 99f571b4eb
48 changed files with 432 additions and 71 deletions

View file

@ -17,17 +17,37 @@
package io.element.android.features.createroom.impl
import io.element.android.features.userlist.api.UserListDataSource
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.usersearch.MatrixUserProfile
import io.element.android.libraries.matrix.ui.model.MatrixUser
import javax.inject.Inject
// TODO this is empty as we currently don't have an endpoint to perform user search
class AllMatrixUsersDataSource @Inject constructor() : UserListDataSource {
class AllMatrixUsersDataSource @Inject constructor(
private val client: MatrixClient
) : UserListDataSource {
override suspend fun search(query: String): List<MatrixUser> {
return emptyList()
val res = client.searchUsers(query, MAX_SEARCH_RESULTS)
return res.getOrNull()?.results?.map(::toMatrixUser).orEmpty()
}
override suspend fun getProfile(userId: UserId): MatrixUser? {
// TODO hook up to matrix client
return null
}
private fun toMatrixUser(matrixUserProfile: MatrixUserProfile) = MatrixUser(
id = matrixUserProfile.userId,
username = matrixUserProfile.displayName,
avatarData = AvatarData(
id = matrixUserProfile.userId.value,
name = matrixUserProfile.displayName,
url = matrixUserProfile.avatarUrl,
)
)
companion object {
private const val MAX_SEARCH_RESULTS = 5L
}
}

View file

@ -19,6 +19,7 @@ package io.element.android.features.createroom.impl.addpeople
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.userlist.api.SelectionMode
import io.element.android.features.userlist.api.UserListState
import io.element.android.features.userlist.api.UserSearchResultState
import io.element.android.features.userlist.api.aListOfSelectedUsers
import io.element.android.features.userlist.api.aUserListState
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
@ -29,13 +30,13 @@ open class AddPeopleUserListStateProvider : PreviewParameterProvider<UserListSta
get() = sequenceOf(
aUserListState(),
aUserListState().copy(
searchResults = aMatrixUserList().toImmutableList(),
searchResults = UserSearchResultState.Results(aMatrixUserList().toImmutableList()),
selectedUsers = aListOfSelectedUsers(),
isSearchActive = false,
selectionMode = SelectionMode.Multiple,
),
aUserListState().copy(
searchResults = aMatrixUserList().toImmutableList(),
searchResults = UserSearchResultState.Results(aMatrixUserList().toImmutableList()),
selectedUsers = aListOfSelectedUsers(),
isSearchActive = true,
selectionMode = SelectionMode.Multiple,

View file

@ -21,11 +21,11 @@ import dagger.Binds
import dagger.Module
import io.element.android.features.createroom.impl.AllMatrixUsersDataSource
import io.element.android.features.userlist.api.UserListDataSource
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SessionScope
import javax.inject.Named
@Module
@ContributesTo(AppScope::class)
@ContributesTo(SessionScope::class)
interface CreateRoomModule {
@Binds

View file

@ -46,7 +46,11 @@ class CreateRoomRootPresenter @Inject constructor(
private val presenter by lazy {
presenterFactory.create(
UserListPresenterArgs(selectionMode = SelectionMode.Single),
UserListPresenterArgs(
selectionMode = SelectionMode.Single,
minimumSearchLength = 3,
searchDebouncePeriodMillis = 500,
),
userListDataSource,
userListDataStore,
)

View file

@ -17,6 +17,7 @@
package io.element.android.features.createroom.impl.root
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.userlist.api.UserSearchResultState
import io.element.android.features.userlist.api.aUserListState
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.ui.components.aMatrixUser
@ -31,7 +32,7 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
userListState = aMatrixUser().let {
aUserListState().copy(
searchQuery = it.id.value,
searchResults = persistentListOf(it),
searchResults = UserSearchResultState.Results(persistentListOf(it)),
selectedUsers = persistentListOf(it),
isSearchActive = true,
)
@ -42,7 +43,7 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
userListState = aMatrixUser().let {
aUserListState().copy(
searchQuery = it.id.value,
searchResults = persistentListOf(it),
searchResults = UserSearchResultState.Results(persistentListOf(it)),
selectedUsers = persistentListOf(it),
isSearchActive = true,
)