Merge remote-tracking branch 'origin/develop' into misc/cjs/create-join-design-feedback

This commit is contained in:
Chris Smith 2023-06-01 13:26:27 +01:00
commit fb147f78b0
200 changed files with 3116 additions and 353 deletions

View file

@ -16,10 +16,9 @@
package io.element.android.libraries.usersearch.api
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.coroutines.flow.Flow
interface UserRepository {
suspend fun search(query: String): Flow<List<MatrixUser>>
suspend fun search(query: String): Flow<List<UserSearchResult>>
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.usersearch.api
import io.element.android.libraries.matrix.api.user.MatrixUser
data class UserSearchResult(
val matrixUser: MatrixUser,
val isUnresolved: Boolean = false,
)

View file

@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.core.UserId
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 kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
@ -33,24 +34,26 @@ class MatrixUserRepository @Inject constructor(
private val dataSource: UserListDataSource
) : UserRepository {
override suspend fun search(query: String): Flow<List<MatrixUser>> = flow {
override suspend fun search(query: String): Flow<List<UserSearchResult>> = flow {
// Manually add a fake result with the matrixId, if any
val isUserId = MatrixPatterns.isUserId(query)
if (isUserId) {
emit(listOf(MatrixUser(UserId(query))))
emit(listOf(UserSearchResult(MatrixUser(UserId(query)))))
}
if (query.length >= MINIMUM_SEARCH_LENGTH) {
// Debounce
delay(DEBOUNCE_TIME_MILLIS)
val results = dataSource.search(query, MAXIMUM_SEARCH_RESULTS).toMutableList()
val results = dataSource.search(query, MAXIMUM_SEARCH_RESULTS).map { UserSearchResult(it) }.toMutableList()
// If the query is a user ID and the result doesn't contain that user ID, query the profile information explicitly
if (isUserId && results.none { it.userId.value == query }) {
val getProfileResult: MatrixUser? = dataSource.getProfile(UserId(query))
val profile = getProfileResult ?: MatrixUser(UserId(query))
results.add(0, profile)
if (isUserId && results.none { it.matrixUser.userId.value == query }) {
results.add(
0,
dataSource.getProfile(UserId(query))
?.let { UserSearchResult(it) }
?: UserSearchResult(MatrixUser(UserId(query)), isUnresolved = true))
}
emit(results)

View file

@ -23,6 +23,7 @@ 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_NAME
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
import io.element.android.libraries.usersearch.api.UserSearchResult
import io.element.android.libraries.usersearch.test.FakeUserListDataSource
import kotlinx.coroutines.test.runTest
import org.junit.Test
@ -63,7 +64,7 @@ internal class MatrixUserRepositoryTest {
val result = repository.search("some query")
result.test {
assertThat(awaitItem()).isEqualTo(aMatrixUserList())
assertThat(awaitItem()).isEqualTo(aMatrixUserList().toUserSearchResults())
awaitComplete()
}
}
@ -76,7 +77,7 @@ internal class MatrixUserRepositoryTest {
val result = repository.search(A_USER_ID.value)
result.test {
assertThat(awaitItem()).isEqualTo(listOf(MatrixUser(userId = A_USER_ID)))
assertThat(awaitItem()).isEqualTo(listOf(placeholderResult()))
skipItems(1)
awaitComplete()
}
@ -93,7 +94,7 @@ internal class MatrixUserRepositoryTest {
result.test {
skipItems(1)
assertThat(awaitItem()).isEqualTo(searchResults)
assertThat(awaitItem()).isEqualTo(searchResults.toUserSearchResults())
awaitComplete()
}
}
@ -112,13 +113,13 @@ internal class MatrixUserRepositoryTest {
result.test {
skipItems(1)
assertThat(awaitItem()).isEqualTo(listOf(userProfile) + searchResults)
assertThat(awaitItem()).isEqualTo((listOf(userProfile) + searchResults).toUserSearchResults())
awaitComplete()
}
}
@Test
fun `search - just shows id if profile can't be loaded`() = runTest {
fun `search - returns unresolved user if profile can't be loaded`() = runTest {
val searchResults = aMatrixUserListWithoutUserId(A_USER_ID)
val dataSource = FakeUserListDataSource()
@ -130,11 +131,15 @@ internal class MatrixUserRepositoryTest {
result.test {
skipItems(1)
assertThat(awaitItem()).isEqualTo(listOf(MatrixUser(userId = A_USER_ID)) + searchResults)
assertThat(awaitItem()).isEqualTo(listOf(placeholderResult(isUnresolved = true)) + searchResults.toUserSearchResults())
awaitComplete()
}
}
private fun aMatrixUserListWithoutUserId(userId: UserId) = aMatrixUserList().filterNot { it.userId == userId }
private fun List<MatrixUser>.toUserSearchResults() = map { UserSearchResult(it) }
private fun placeholderResult(id: UserId = A_USER_ID, isUnresolved: Boolean = false) = UserSearchResult(MatrixUser(id), isUnresolved = isUnresolved)
}

View file

@ -16,8 +16,8 @@
package io.element.android.libraries.usersearch.test
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.usersearch.api.UserRepository
import io.element.android.libraries.usersearch.api.UserSearchResult
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
@ -26,14 +26,14 @@ class FakeUserRepository : UserRepository {
var providedQuery: String? = null
private set
private val flow = MutableSharedFlow<List<MatrixUser>>()
private val flow = MutableSharedFlow<List<UserSearchResult>>()
override suspend fun search(query: String): Flow<List<MatrixUser>> {
override suspend fun search(query: String): Flow<List<UserSearchResult>> {
providedQuery = query
return flow
}
suspend fun emitResult(result: List<MatrixUser>) {
suspend fun emitResult(result: List<UserSearchResult>) {
flow.emit(result)
}