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 908bdcf6cd
commit 5c935818c6
51 changed files with 125 additions and 215 deletions

View file

@ -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
} }

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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>,

View file

@ -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

View file

@ -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)
} }
} }

View file

@ -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,

View file

@ -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)
} }

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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(

View file

@ -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

View file

@ -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

View file

@ -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(

View file

@ -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

View file

@ -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(

View file

@ -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
)
)
}
} }

View file

@ -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,
) )
} }

View file

@ -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

View file

@ -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(),

View file

@ -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()),
) )
} }

View file

@ -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)
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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(

View file

@ -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(

View file

@ -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(

View file

@ -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)

View file

@ -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,

View file

@ -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

View file

@ -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(

View file

@ -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)

View file

@ -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

View file

@ -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 {

View file

@ -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 ->

View file

@ -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

View file

@ -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
} }

View file

@ -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,
) )

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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()
}
}

View file

@ -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,
) { ) {

View file

@ -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,

View file

@ -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,
) )
} }

View file

@ -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,

View file

@ -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
} }