Move and refactor MatrixUser (#381)

Move and refactor MatrixUser

Instead of living in matrixui and having an AvatarData, this can
reside in the matrix module and just have the URL. An extension
method in matrixui can then provide the AvatarData when required.

This removes some small duplication, and pushes the UI-specific
information (i.e., what size of avatar is going to be rendered)
further down the stack. It also aligns the field names with those
used by the rust SDK (e.g. "displayName" instead of "userName").
This commit is contained in:
Chris Smith
2023-05-03 17:30:19 +01:00
committed by GitHub
parent 271c66588a
commit 581c5ab2d2
51 changed files with 125 additions and 215 deletions
@@ -17,11 +17,9 @@
package io.element.android.features.createroom.impl package io.element.android.features.createroom.impl
import io.element.android.features.userlist.api.UserListDataSource 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.MatrixClient
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.usersearch.MatrixUserProfile import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.MatrixUser
import javax.inject.Inject import javax.inject.Inject
class AllMatrixUsersDataSource @Inject constructor( class AllMatrixUsersDataSource @Inject constructor(
@@ -29,7 +27,7 @@ class AllMatrixUsersDataSource @Inject constructor(
) : UserListDataSource { ) : UserListDataSource {
override suspend fun search(query: String): List<MatrixUser> { override suspend fun search(query: String): List<MatrixUser> {
val res = client.searchUsers(query, MAX_SEARCH_RESULTS) val res = client.searchUsers(query, MAX_SEARCH_RESULTS)
return res.getOrNull()?.results?.map(::toMatrixUser).orEmpty() return res.getOrNull()?.results.orEmpty()
} }
override suspend fun getProfile(userId: UserId): MatrixUser? { override suspend fun getProfile(userId: UserId): MatrixUser? {
@@ -37,16 +35,6 @@ class AllMatrixUsersDataSource @Inject constructor(
return null 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 { companion object {
private const val MAX_SEARCH_RESULTS = 5L private const val MAX_SEARCH_RESULTS = 5L
} }
@@ -17,7 +17,7 @@
package io.element.android.features.createroom.impl package io.element.android.features.createroom.impl
import io.element.android.features.createroom.impl.configureroom.RoomPrivacy import io.element.android.features.createroom.impl.configureroom.RoomPrivacy
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@@ -18,7 +18,7 @@ package io.element.android.features.createroom.impl.configureroom
import android.net.Uri import android.net.Uri
import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomConfig
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
sealed interface ConfigureRoomEvents { sealed interface ConfigureRoomEvents {
data class RoomNameChanged(val name: String) : ConfigureRoomEvents data class RoomNameChanged(val name: String) : ConfigureRoomEvents
@@ -89,7 +89,7 @@ class ConfigureRoomPresenter @Inject constructor(
isDirect = false, isDirect = false,
visibility = if (config.privacy == RoomPrivacy.Public) RoomVisibility.PUBLIC else RoomVisibility.PRIVATE, visibility = if (config.privacy == RoomPrivacy.Public) RoomVisibility.PUBLIC else RoomVisibility.PRIVATE,
preset = if (config.privacy == RoomPrivacy.Public) RoomPreset.PUBLIC_CHAT else RoomPreset.PRIVATE_CHAT, preset = if (config.privacy == RoomPrivacy.Public) RoomPreset.PUBLIC_CHAT else RoomPreset.PRIVATE_CHAT,
invite = config.invites.map { it.id }, invite = config.invites.map { it.userId },
avatar = config.avatarUrl, avatar = config.avatarUrl,
) )
matrixClient.createRoom(params).getOrThrow() matrixClient.createRoom(params).getOrThrow()
@@ -16,7 +16,7 @@
package io.element.android.features.createroom.impl.configureroom package io.element.android.features.createroom.impl.configureroom
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
data class ConfigureRoomPresenterArgs( data class ConfigureRoomPresenterArgs(
val selectedUsers: List<MatrixUser>, val selectedUsers: List<MatrixUser>,
@@ -16,7 +16,7 @@
package io.element.android.features.createroom.impl.root package io.element.android.features.createroom.impl.root
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
sealed interface CreateRoomRootEvents { sealed interface CreateRoomRootEvents {
object InvitePeople : CreateRoomRootEvents object InvitePeople : CreateRoomRootEvents
@@ -31,7 +31,7 @@ import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.execute import io.element.android.libraries.architecture.execute
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@@ -65,7 +65,7 @@ class CreateRoomRootPresenter @Inject constructor(
fun startDm(matrixUser: MatrixUser) { fun startDm(matrixUser: MatrixUser) {
startDmAction.value = Async.Uninitialized startDmAction.value = Async.Uninitialized
val existingDM = matrixClient.findDM(matrixUser.id) val existingDM = matrixClient.findDM(matrixUser.userId)
if (existingDM == null) { if (existingDM == null) {
localCoroutineScope.createDM(matrixUser, startDmAction) localCoroutineScope.createDM(matrixUser, startDmAction)
} else { } else {
@@ -90,7 +90,7 @@ class CreateRoomRootPresenter @Inject constructor(
private fun CoroutineScope.createDM(user: MatrixUser, startDmAction: MutableState<Async<RoomId>>) = launch { private fun CoroutineScope.createDM(user: MatrixUser, startDmAction: MutableState<Async<RoomId>>) = launch {
suspend { suspend {
matrixClient.createDM(user.id).getOrThrow() matrixClient.createDM(user.userId).getOrThrow()
}.execute(startDmAction) }.execute(startDmAction)
} }
} }
@@ -31,7 +31,7 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
startDmAction = Async.Loading(), startDmAction = Async.Loading(),
userListState = aMatrixUser().let { userListState = aMatrixUser().let {
aUserListState().copy( aUserListState().copy(
searchQuery = it.id.value, searchQuery = it.userId.value,
searchResults = UserSearchResultState.Results(persistentListOf(it)), searchResults = UserSearchResultState.Results(persistentListOf(it)),
selectedUsers = persistentListOf(it), selectedUsers = persistentListOf(it),
isSearchActive = true, isSearchActive = true,
@@ -42,7 +42,7 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
startDmAction = Async.Failure(Throwable()), startDmAction = Async.Failure(Throwable()),
userListState = aMatrixUser().let { userListState = aMatrixUser().let {
aUserListState().copy( aUserListState().copy(
searchQuery = it.id.value, searchQuery = it.userId.value,
searchResults = UserSearchResultState.Results(persistentListOf(it)), searchResults = UserSearchResultState.Results(persistentListOf(it)),
selectedUsers = persistentListOf(it), selectedUsers = persistentListOf(it),
isSearchActive = true, isSearchActive = true,
@@ -17,16 +17,14 @@
package io.element.android.features.createroom.impl package io.element.android.features.createroom.impl
import com.google.common.truth.Truth import com.google.common.truth.Truth
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.usersearch.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.usersearch.MatrixUserProfile import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_USER_ID 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.A_USER_ID_2
import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.A_USER_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@@ -51,15 +49,15 @@ internal class AllMatrixUsersDataSourceTest {
val results = dataSource.search("test") val results = dataSource.search("test")
Truth.assertThat(results).containsExactly( Truth.assertThat(results).containsExactly(
MatrixUser( MatrixUser(
id = A_USER_ID, userId = A_USER_ID,
username = A_USER_NAME, displayName = A_USER_NAME,
avatarData = AvatarData(id = A_USER_ID.value, name = A_USER_NAME, url = AN_AVATAR_URL) avatarUrl = AN_AVATAR_URL
), ),
MatrixUser( MatrixUser(
id = A_USER_ID_2, userId = A_USER_ID_2,
username = A_USER_NAME, displayName = A_USER_NAME,
avatarData = AvatarData(id = A_USER_ID_2.value, name = A_USER_NAME, url = AN_AVATAR_URL) avatarUrl = AN_AVATAR_URL
) ),
) )
} }
@@ -80,5 +78,5 @@ internal class AllMatrixUsersDataSourceTest {
userId: UserId = A_USER_ID, userId: UserId = A_USER_ID,
displayName: String = A_USER_NAME, displayName: String = A_USER_NAME,
avatarUrl: String = AN_AVATAR_URL avatarUrl: String = AN_AVATAR_URL
) = MatrixUserProfile(userId, displayName, avatarUrl) ) = MatrixUser(userId, displayName, avatarUrl)
} }
@@ -30,10 +30,10 @@ import io.element.android.features.userlist.test.FakeUserListPresenterFactory
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.A_THROWABLE
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@@ -19,7 +19,7 @@ package io.element.android.features.preferences.impl.root
import io.element.android.features.logout.api.LogoutPreferenceState import io.element.android.features.logout.api.LogoutPreferenceState
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
data class PreferencesRootState( data class PreferencesRootState(
val logoutState: LogoutPreferenceState, val logoutState: LogoutPreferenceState,
@@ -32,8 +32,8 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.LargeHeightPreview import io.element.android.libraries.designsystem.preview.LargeHeightPreview
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.MatrixUserProvider import io.element.android.libraries.matrix.ui.components.MatrixUserProvider
import io.element.android.libraries.matrix.ui.model.MatrixUser
import io.element.android.libraries.ui.strings.R as StringR import io.element.android.libraries.ui.strings.R as StringR
@Composable @Composable
@@ -26,9 +26,9 @@ import androidx.compose.ui.unit.dp
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.MatrixUserHeader import io.element.android.libraries.matrix.ui.components.MatrixUserHeader
import io.element.android.libraries.matrix.ui.components.MatrixUserWithNullProvider import io.element.android.libraries.matrix.ui.components.MatrixUserWithNullProvider
import io.element.android.libraries.matrix.ui.model.MatrixUser
@Composable @Composable
fun UserPreferences( fun UserPreferences(
@@ -16,7 +16,7 @@
package io.element.android.features.roomdetails.impl.members package io.element.android.features.roomdetails.impl.members
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
sealed interface RoomMemberListEvents { sealed interface RoomMemberListEvents {
data class SelectUser(val user: MatrixUser) : RoomMemberListEvents data class SelectUser(val user: MatrixUser) : RoomMemberListEvents
@@ -29,7 +29,7 @@ import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -18,8 +18,7 @@ package io.element.android.features.roomdetails.impl.members
import io.element.android.features.userlist.api.UserListState import io.element.android.features.userlist.api.UserListState
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
data class RoomMemberListState( data class RoomMemberListState(
@@ -20,8 +20,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.userlist.api.UserSearchResultState import io.element.android.features.userlist.api.UserSearchResultState
import io.element.android.features.userlist.api.aUserListState import io.element.android.features.userlist.api.aUserListState
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@@ -52,7 +52,7 @@ import io.element.android.libraries.designsystem.theme.components.CircularProgre
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -64,7 +64,7 @@ fun RoomMemberListView(
) { ) {
fun onUserSelected(user: MatrixUser) { fun onUserSelected(user: MatrixUser) {
onMemberSelected(user.id) onMemberSelected(user.userId)
} }
Scaffold( Scaffold(
@@ -19,13 +19,13 @@ package io.element.android.features.roomdetails.impl.members
import io.element.android.features.userlist.api.UserListDataSource import io.element.android.features.userlist.api.UserListDataSource
import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.MatrixRoom 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.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.room.roomMembers
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.room.toMatrixUser
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.coroutines.flow.dropWhile import kotlinx.coroutines.flow.dropWhile
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -50,22 +50,11 @@ class RoomUserListDataSource @Inject constructor(
|| member.displayName?.contains(query, ignoreCase = true).orFalse() || member.displayName?.contains(query, ignoreCase = true).orFalse()
} }
} }
filteredMembers.map(::mapMemberToMatrixUser) filteredMembers.map(RoomMember::toMatrixUser)
} }
override suspend fun getProfile(userId: UserId): MatrixUser? { override suspend fun getProfile(userId: UserId): MatrixUser? {
return null return null
} }
private fun mapMemberToMatrixUser(member: RoomMember): MatrixUser {
return MatrixUser(
id = member.userId,
username = member.displayName,
avatarData = AvatarData(
id = member.userId.value,
name = member.displayName,
url = member.avatarUrl
)
)
}
} }
@@ -27,6 +27,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryPlaceholders import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryPlaceholders
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
@@ -34,17 +35,15 @@ import io.element.android.libraries.core.coroutine.parallelMap
import io.element.android.libraries.core.extensions.orEmpty import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.designsystem.utils.handleSnackbarMessage import io.element.android.libraries.designsystem.utils.handleSnackbarMessage
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomSummary import io.element.android.libraries.matrix.api.room.RoomSummary
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.ui.model.MatrixUser
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.libraries.matrix.api.core.RoomId
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@@ -153,17 +152,10 @@ class RoomListPresenter @Inject constructor(
private fun CoroutineScope.initialLoad(matrixUser: MutableState<MatrixUser?>) = launch { private fun CoroutineScope.initialLoad(matrixUser: MutableState<MatrixUser?>) = launch {
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull() val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
val userDisplayName = client.loadUserDisplayName().getOrNull() val userDisplayName = client.loadUserDisplayName().getOrNull()
val avatarData =
AvatarData(
id = client.sessionId.value,
name = userDisplayName,
url = userAvatarUrl,
size = AvatarSize.SMALL
)
matrixUser.value = MatrixUser( matrixUser.value = MatrixUser(
id = UserId(client.sessionId.value), userId = UserId(client.sessionId.value),
username = userDisplayName ?: client.sessionId.value, displayName = userDisplayName,
avatarData = avatarData, avatarUrl = userAvatarUrl,
) )
} }
@@ -19,7 +19,7 @@ package io.element.android.features.roomlist.impl
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.libraries.designsystem.utils.SnackbarMessage import io.element.android.libraries.designsystem.utils.SnackbarMessage
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@Immutable @Immutable
@@ -23,7 +23,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.utils.SnackbarMessage import io.element.android.libraries.designsystem.utils.SnackbarMessage
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import io.element.android.libraries.ui.strings.R as StringR import io.element.android.libraries.ui.strings.R as StringR
@@ -42,7 +42,7 @@ open class RoomListStateProvider : PreviewParameterProvider<RoomListState> {
} }
internal fun aRoomListState() = RoomListState( internal fun aRoomListState() = RoomListState(
matrixUser = MatrixUser(id = UserId("@id:domain"), username = "User#1", avatarData = AvatarData("@id:domain", "U")), matrixUser = MatrixUser(userId = UserId("@id:domain"), displayName = "User#1"),
roomList = aRoomListRoomSummaryList(), roomList = aRoomListRoomSummaryList(),
filter = "filter", filter = "filter",
filteredRoomList = aRoomListRoomSummaryList(), filteredRoomList = aRoomListRoomSummaryList(),
@@ -27,6 +27,9 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -35,7 +38,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.features.roomlist.impl.R import io.element.android.features.roomlist.impl.R
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@@ -44,7 +46,8 @@ import io.element.android.libraries.designsystem.theme.components.MediumTopAppBa
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.LogCompositions import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag import io.element.android.libraries.testtags.testTag
import io.element.android.libraries.ui.strings.R as StringR import io.element.android.libraries.ui.strings.R as StringR
@@ -107,7 +110,8 @@ private fun DefaultRoomListTopBar(
modifier = Modifier.testTag(TestTags.homeScreenSettings), modifier = Modifier.testTag(TestTags.homeScreenSettings),
onClick = onOpenSettings onClick = onOpenSettings
) { ) {
Avatar(matrixUser.avatarData, contentDescription = stringResource(StringR.string.common_settings)) val avatarData by remember { derivedStateOf { matrixUser.getAvatarData() } }
Avatar(avatarData, contentDescription = stringResource(StringR.string.common_settings))
} }
} }
}, },
@@ -135,7 +139,7 @@ internal fun DefaultRoomListTopBarDarkPreview() = ElementPreviewDark { DefaultRo
@Composable @Composable
private fun DefaultRoomListTopBarPreview() { private fun DefaultRoomListTopBarPreview() {
DefaultRoomListTopBar( DefaultRoomListTopBar(
matrixUser = MatrixUser(UserId("@id:domain"), "Alice", AvatarData("@id:domain", "Alice")), matrixUser = MatrixUser(UserId("@id:domain"), "Alice"),
scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()), scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()),
) )
} }
@@ -60,10 +60,9 @@ class RoomListPresenterTests {
Truth.assertThat(initialState.matrixUser).isNull() Truth.assertThat(initialState.matrixUser).isNull()
val withUserState = awaitItem() val withUserState = awaitItem()
Truth.assertThat(withUserState.matrixUser).isNotNull() Truth.assertThat(withUserState.matrixUser).isNotNull()
Truth.assertThat(withUserState.matrixUser!!.id).isEqualTo(A_USER_ID) Truth.assertThat(withUserState.matrixUser!!.userId).isEqualTo(A_USER_ID)
Truth.assertThat(withUserState.matrixUser!!.username).isEqualTo(A_USER_NAME) Truth.assertThat(withUserState.matrixUser!!.displayName).isEqualTo(A_USER_NAME)
Truth.assertThat(withUserState.matrixUser!!.avatarData.name).isEqualTo(A_USER_NAME) Truth.assertThat(withUserState.matrixUser!!.avatarUrl).isEqualTo(AN_AVATAR_URL)
Truth.assertThat(withUserState.matrixUser!!.avatarData.url).isEqualTo(AN_AVATAR_URL)
} }
} }
@@ -88,8 +87,6 @@ class RoomListPresenterTests {
Truth.assertThat(initialState.matrixUser).isNull() Truth.assertThat(initialState.matrixUser).isNull()
val withUserState = awaitItem() val withUserState = awaitItem()
Truth.assertThat(withUserState.matrixUser).isNotNull() Truth.assertThat(withUserState.matrixUser).isNotNull()
// username fallback to user id value
Truth.assertThat(withUserState.matrixUser!!.username).isEqualTo(A_USER_ID.value)
} }
} }
@@ -17,7 +17,7 @@
package io.element.android.features.userlist.api package io.element.android.features.userlist.api
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
interface UserListDataSource { interface UserListDataSource {
//TODO should probably have a flow //TODO should probably have a flow
@@ -16,7 +16,7 @@
package io.element.android.features.userlist.api package io.element.android.features.userlist.api
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject import javax.inject.Inject
@@ -16,7 +16,7 @@
package io.element.android.features.userlist.api package io.element.android.features.userlist.api
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
sealed interface UserListEvents { sealed interface UserListEvents {
data class UpdateSearchQuery(val query: String) : UserListEvents data class UpdateSearchQuery(val query: String) : UserListEvents
@@ -16,7 +16,7 @@
package io.element.android.features.userlist.api package io.element.android.features.userlist.api
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
data class UserListState( data class UserListState(
@@ -24,9 +24,9 @@ import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.CheckableMatrixUserRow import io.element.android.libraries.matrix.ui.components.CheckableMatrixUserRow
import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.model.MatrixUser
@Composable @Composable
fun SearchMultipleUsersResultItem( fun SearchMultipleUsersResultItem(
@@ -24,9 +24,9 @@ import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.MatrixUserRow import io.element.android.libraries.matrix.ui.components.MatrixUserRow
import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.model.MatrixUser
@Composable @Composable
fun SearchSingleUserResultItem( fun SearchSingleUserResultItem(
@@ -43,7 +43,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.SearchBar import io.element.android.libraries.designsystem.theme.components.SearchBar
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.ui.strings.R import io.element.android.libraries.ui.strings.R
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@@ -128,7 +128,7 @@ fun SearchUserBar(
SearchMultipleUsersResultItem( SearchMultipleUsersResultItem(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
matrixUser = matrixUser, matrixUser = matrixUser,
isUserSelected = selectedUsers.find { it.id == matrixUser.id } != null, isUserSelected = selectedUsers.find { it.userId == matrixUser.userId } != null,
onCheckedChange = { checked -> onCheckedChange = { checked ->
if (checked) { if (checked) {
onUserSelected(matrixUser) onUserSelected(matrixUser)
@@ -40,8 +40,9 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.matrix.ui.model.getBestName
import io.element.android.libraries.ui.strings.R import io.element.android.libraries.ui.strings.R
@@ -55,7 +56,7 @@ fun SelectedUser(
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Avatar(matrixUser.avatarData.copy(size = AvatarSize.Custom(56.dp))) Avatar(matrixUser.getAvatarData(size = AvatarSize.Custom(56.dp)))
Text( Text(
text = matrixUser.getBestName(), text = matrixUser.getBestName(),
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
@@ -33,7 +33,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.features.userlist.api.aListOfSelectedUsers import io.element.android.features.userlist.api.aListOfSelectedUsers
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@Composable @Composable
@@ -29,7 +29,7 @@ import io.element.android.features.userlist.api.UserListState
import io.element.android.features.userlist.api.UserListStateProvider import io.element.android.features.userlist.api.UserListStateProvider
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
@Composable @Composable
fun UserListView( fun UserListView(
@@ -38,7 +38,7 @@ import io.element.android.features.userlist.api.UserSearchResultState
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.core.MatrixPatterns import io.element.android.libraries.matrix.api.core.MatrixPatterns
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -105,7 +105,7 @@ class DefaultUserListPresenter @AssistedInject constructor(
private suspend fun performSearch(query: String): UserSearchResultState { private suspend fun performSearch(query: String): UserSearchResultState {
val isMatrixId = MatrixPatterns.isUserId(query) val isMatrixId = MatrixPatterns.isUserId(query)
val results = userListDataSource.search(query).toMutableList() val results = userListDataSource.search(query).toMutableList()
if (isMatrixId && results.none { it.id.value == query }) { if (isMatrixId && results.none { it.userId.value == query }) {
val getProfileResult: MatrixUser? = userListDataSource.getProfile(UserId(query)) val getProfileResult: MatrixUser? = userListDataSource.getProfile(UserId(query))
val profile = getProfileResult ?: MatrixUser(UserId(query)) val profile = getProfileResult ?: MatrixUser(UserId(query))
results.add(0, profile) results.add(0, profile)
@@ -28,8 +28,8 @@ import io.element.android.features.userlist.api.UserListPresenterArgs
import io.element.android.features.userlist.api.UserSearchResultState import io.element.android.features.userlist.api.UserSearchResultState
import io.element.android.features.userlist.test.FakeUserListDataSource import io.element.android.features.userlist.test.FakeUserListDataSource
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.model.MatrixUser
import io.mockk.coJustRun import io.mockk.coJustRun
import io.mockk.mockkConstructor import io.mockk.mockkConstructor
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@@ -18,7 +18,7 @@ package io.element.android.features.userlist.test
import io.element.android.features.userlist.api.UserListDataSource import io.element.android.features.userlist.api.UserListDataSource
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
class FakeUserListDataSource : UserListDataSource { class FakeUserListDataSource : UserListDataSource {
@@ -16,22 +16,16 @@
package io.element.android.libraries.designsystem.components.avatar package io.element.android.libraries.designsystem.components.avatar
import android.os.Parcelable
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
@Immutable @Immutable
@Parcelize
data class AvatarData( data class AvatarData(
val id: String, val id: String,
val name: String?, val name: String?,
val url: String? = null, val url: String? = null,
@IgnoredOnParcel
val size: AvatarSize = AvatarSize.MEDIUM val size: AvatarSize = AvatarSize.MEDIUM
) : Parcelable { ) {
@IgnoredOnParcel
val initial by lazy { val initial by lazy {
(name?.takeIf { it.isNotBlank() } ?: id) (name?.takeIf { it.isNotBlank() } ?: id)
.let { dn -> .let { dn ->
@@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
import io.element.android.libraries.matrix.api.usersearch.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import java.io.Closeable import java.io.Closeable
@@ -17,6 +17,7 @@
package io.element.android.libraries.matrix.api.room package io.element.android.libraries.matrix.api.room
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser
data class RoomMember( data class RoomMember(
val userId: UserId, val userId: UserId,
@@ -29,6 +30,12 @@ data class RoomMember(
val isIgnored: Boolean, val isIgnored: Boolean,
) )
fun RoomMember.toMatrixUser() = MatrixUser(
userId = userId,
displayName = displayName,
avatarUrl = avatarUrl,
)
enum class RoomMembershipState { enum class RoomMembershipState {
BAN, INVITE, JOIN, KNOCK, LEAVE BAN, INVITE, JOIN, KNOCK, LEAVE
} }
@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.libraries.matrix.api.usersearch package io.element.android.libraries.matrix.api.user
data class MatrixSearchUserResults( data class MatrixSearchUserResults(
val results: List<MatrixUserProfile>, val results: List<MatrixUser>,
val limited: Boolean, val limited: Boolean,
) )
@@ -14,12 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.libraries.matrix.api.usersearch package io.element.android.libraries.matrix.api.user
import android.os.Parcelable
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import kotlinx.parcelize.Parcelize
data class MatrixUserProfile( @Parcelize
data class MatrixUser(
val userId: UserId, val userId: UserId,
val displayName: String?, val displayName: String? = null,
val avatarUrl: String? val avatarUrl: String? = null
) ) : Parcelable
@@ -29,7 +29,7 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
import io.element.android.libraries.matrix.api.usersearch.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.impl.media.RustMediaResolver import io.element.android.libraries.matrix.impl.media.RustMediaResolver
import io.element.android.libraries.matrix.impl.notification.RustNotificationService import io.element.android.libraries.matrix.impl.notification.RustNotificationService
@@ -17,8 +17,8 @@
package io.element.android.libraries.matrix.impl.usersearch package io.element.android.libraries.matrix.impl.usersearch
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.usersearch.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.usersearch.MatrixUserProfile import io.element.android.libraries.matrix.api.user.MatrixUser
import org.matrix.rustcomponents.sdk.SearchUsersResults import org.matrix.rustcomponents.sdk.SearchUsersResults
import org.matrix.rustcomponents.sdk.UserProfile import org.matrix.rustcomponents.sdk.UserProfile
@@ -31,8 +31,8 @@ object UserSearchResultMapper {
) )
} }
private fun mapUserProfile(userProfile: UserProfile): MatrixUserProfile { private fun mapUserProfile(userProfile: UserProfile): MatrixUser {
return MatrixUserProfile( return MatrixUser(
userId = UserId(userProfile.userId), userId = UserId(userProfile.userId),
displayName = userProfile.displayName, displayName = userProfile.displayName,
avatarUrl = userProfile.avatarUrl, avatarUrl = userProfile.avatarUrl,
@@ -27,7 +27,7 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
import io.element.android.libraries.matrix.api.usersearch.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.test.media.FakeMediaResolver import io.element.android.libraries.matrix.test.media.FakeMediaResolver
import io.element.android.libraries.matrix.test.notification.FakeNotificationService import io.element.android.libraries.matrix.test.notification.FakeNotificationService
@@ -1,53 +0,0 @@
/*
* Copyright (c) 2022 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.matrix.ui
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import javax.inject.Inject
class MatrixItemHelper @Inject constructor(
private val client: MatrixClient
) {
/**
* TODO Make username and avatar live...
*/
@OptIn(FlowPreview::class)
fun getCurrentUserData(avatarSize: AvatarSize): Flow<MatrixUser> {
return suspend {
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
val userDisplayName = client.loadUserDisplayName().getOrNull()
val avatarData =
AvatarData(
client.sessionId.value,
userDisplayName,
userAvatarUrl,
avatarSize
)
MatrixUser(
id = client.sessionId,
username = userDisplayName,
avatarData = avatarData,
)
}.asFlow()
}
}
@@ -30,14 +30,14 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Checkbox import io.element.android.libraries.designsystem.theme.components.Checkbox
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
@Composable @Composable
fun CheckableMatrixUserRow( fun CheckableMatrixUserRow(
checked: Boolean, checked: Boolean,
matrixUser: MatrixUser, matrixUser: MatrixUser,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
avatarSize: AvatarSize = matrixUser.avatarData.size, avatarSize: AvatarSize = AvatarSize.MEDIUM,
onCheckedChange: (Boolean) -> Unit = {}, onCheckedChange: (Boolean) -> Unit = {},
enabled: Boolean = true, enabled: Boolean = true,
) { ) {
@@ -38,7 +38,8 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.matrix.ui.model.getBestName
@Composable @Composable
@@ -56,7 +57,7 @@ fun MatrixUserHeader(
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Avatar( Avatar(
matrixUser.avatarData.copy(size = AvatarSize.HUGE), matrixUser.getAvatarData(size = AvatarSize.HUGE),
) )
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
// Name // Name
@@ -69,10 +70,10 @@ fun MatrixUserHeader(
color = MaterialTheme.colorScheme.primary, color = MaterialTheme.colorScheme.primary,
) )
// Id // Id
if (matrixUser.username.isNullOrEmpty().not()) { if (matrixUser.displayName.isNullOrEmpty().not()) {
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text( Text(
text = matrixUser.id.value, text = matrixUser.userId.value,
color = MaterialTheme.colorScheme.secondary, color = MaterialTheme.colorScheme.secondary,
fontSize = 14.sp, fontSize = 14.sp,
maxLines = 1, maxLines = 1,
@@ -17,25 +17,20 @@
package io.element.android.libraries.matrix.ui.components package io.element.android.libraries.matrix.ui.components
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
open class MatrixUserProvider : PreviewParameterProvider<MatrixUser> { open class MatrixUserProvider : PreviewParameterProvider<MatrixUser> {
override val values: Sequence<MatrixUser> override val values: Sequence<MatrixUser>
get() = sequenceOf( get() = sequenceOf(
aMatrixUser(), aMatrixUser(),
aMatrixUser().copy( aMatrixUser().copy(displayName = null),
username = null,
avatarData = anAvatarData().copy(name = null)
),
) )
} }
fun aMatrixUser(id: String = "@id_of_alice:server.org", userName: String = "Alice") = MatrixUser( fun aMatrixUser(id: String = "@id_of_alice:server.org", displayName: String = "Alice") = MatrixUser(
id = UserId(id), userId = UserId(id),
username = userName, displayName = displayName,
avatarData = anAvatarData(id, userName)
) )
fun aMatrixUserList() = listOf( fun aMatrixUserList() = listOf(
@@ -55,10 +50,7 @@ open class MatrixUserWithNullProvider : PreviewParameterProvider<MatrixUser?> {
override val values: Sequence<MatrixUser?> override val values: Sequence<MatrixUser?>
get() = sequenceOf( get() = sequenceOf(
aMatrixUser(), aMatrixUser(),
aMatrixUser().copy( aMatrixUser().copy(displayName = null),
username = null,
avatarData = anAvatarData().copy(name = null)
),
null, null,
) )
} }
@@ -37,14 +37,15 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.matrix.ui.model.getBestName
@Composable @Composable
fun MatrixUserRow( fun MatrixUserRow(
matrixUser: MatrixUser, matrixUser: MatrixUser,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
avatarSize: AvatarSize = matrixUser.avatarData.size, avatarSize: AvatarSize = AvatarSize.MEDIUM,
) { ) {
Row( Row(
modifier = modifier modifier = modifier
@@ -54,7 +55,7 @@ fun MatrixUserRow(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Avatar( Avatar(
matrixUser.avatarData.copy(size = avatarSize), matrixUser.getAvatarData(size = avatarSize),
) )
Column( Column(
modifier = Modifier modifier = Modifier
@@ -70,9 +71,9 @@ fun MatrixUserRow(
color = MaterialTheme.colorScheme.primary, color = MaterialTheme.colorScheme.primary,
) )
// Id // Id
if (matrixUser.username.isNullOrEmpty().not()) { if (matrixUser.displayName.isNullOrEmpty().not()) {
Text( Text(
text = matrixUser.id.value, text = matrixUser.userId.value,
color = MaterialTheme.colorScheme.secondary, color = MaterialTheme.colorScheme.secondary,
fontSize = 14.sp, fontSize = 14.sp,
maxLines = 1, maxLines = 1,
@@ -16,20 +16,17 @@
package io.element.android.libraries.matrix.ui.model package io.element.android.libraries.matrix.ui.model
import android.os.Parcelable
import androidx.compose.runtime.Immutable
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import kotlinx.parcelize.Parcelize import io.element.android.libraries.matrix.api.user.MatrixUser
@Parcelize fun MatrixUser.getAvatarData(size: AvatarSize = AvatarSize.MEDIUM) = AvatarData(
@Immutable id = userId.value,
data class MatrixUser( name = displayName,
val id: UserId, url = avatarUrl,
val username: String? = null, size = size,
val avatarData: AvatarData = AvatarData(id.value, username), )
) : Parcelable
fun MatrixUser.getBestName(): String { fun MatrixUser.getBestName(): String {
return username?.takeIf { it.isNotEmpty() } ?: id.value return displayName?.takeIf { it.isNotEmpty() } ?: userId.value
} }