mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Fixes myroomnick changing Display Name (#5618)
This commit is contained in:
parent
e109319b1e
commit
9b7e94ebab
1
changelog.d/5618.bugfix
Normal file
1
changelog.d/5618.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fixes display name being changed when using /myroomnick
|
@ -16,6 +16,9 @@
|
||||
|
||||
package org.matrix.android.sdk.api.session.user.model
|
||||
|
||||
import org.matrix.android.sdk.api.session.profile.ProfileService
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
|
||||
/**
|
||||
* Data class which holds information about a user.
|
||||
* It can be retrieved with [org.matrix.android.sdk.api.session.user.UserService]
|
||||
@ -27,4 +30,14 @@ data class User(
|
||||
*/
|
||||
val displayName: String? = null,
|
||||
val avatarUrl: String? = null
|
||||
)
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
fun fromJson(userId: String, json: JsonDict) = User(
|
||||
userId = userId,
|
||||
displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String,
|
||||
avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ sealed class MatrixItem(
|
||||
override val displayName: String? = null,
|
||||
override val avatarUrl: String? = null) :
|
||||
MatrixItem(id, displayName?.removeSuffix(IRC_PATTERN), avatarUrl) {
|
||||
|
||||
init {
|
||||
if (BuildConfig.DEBUG) checkId()
|
||||
}
|
||||
@ -200,7 +201,7 @@ fun RoomMemberSummary.toMatrixItem() = MatrixItem.UserItem(userId, displayName,
|
||||
|
||||
fun SenderInfo.toMatrixItem() = MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl)
|
||||
|
||||
fun SenderInfo.toMatrixItemOrNull() = tryOrNull { MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl) }
|
||||
fun SenderInfo.toMatrixItemOrNull() = tryOrNull { MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl) }
|
||||
|
||||
fun SpaceChildInfo.toMatrixItem() = if (roomType == RoomType.SPACE) {
|
||||
MatrixItem.SpaceItem(childRoomId, name ?: canonicalAlias, avatarUrl)
|
||||
|
@ -123,7 +123,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
|
||||
eventId = roomMemberEvent.eventId
|
||||
root = eventEntity
|
||||
}
|
||||
roomMemberEventHandler.handle(realm, roomId, roomMemberEvent)
|
||||
roomMemberEventHandler.handle(realm, roomId, roomMemberEvent, false)
|
||||
}
|
||||
roomEntity.membersLoadStatus = RoomMembersLoadStatusType.LOADED
|
||||
roomSummaryUpdater.update(realm, roomId, updateMembers = true)
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.matrix.android.sdk.internal.session.room.membership
|
||||
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||
@ -33,23 +34,49 @@ internal class RoomMemberEventHandler @Inject constructor(
|
||||
@UserId private val myUserId: String
|
||||
) {
|
||||
|
||||
fun handle(realm: Realm, roomId: String, event: Event, aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
|
||||
fun handle(realm: Realm,
|
||||
roomId: String,
|
||||
event: Event,
|
||||
isInitialSync: Boolean,
|
||||
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
|
||||
if (event.type != EventType.STATE_ROOM_MEMBER) {
|
||||
return false
|
||||
}
|
||||
val userId = event.stateKey ?: return false
|
||||
val roomMember = event.getFixedRoomMemberContent()
|
||||
return handle(realm, roomId, userId, roomMember, aggregator)
|
||||
val eventUserId = event.stateKey ?: return false
|
||||
val roomMember = event.getFixedRoomMemberContent() ?: return false
|
||||
|
||||
return if (isInitialSync) {
|
||||
handleInitialSync(realm, roomId, myUserId, eventUserId, roomMember, aggregator)
|
||||
} else {
|
||||
handleIncrementalSync(
|
||||
realm,
|
||||
roomId,
|
||||
eventUserId,
|
||||
roomMember,
|
||||
event.resolvedPrevContent(),
|
||||
aggregator
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun handle(realm: Realm,
|
||||
roomId: String,
|
||||
userId: String,
|
||||
roomMember: RoomMemberContent?,
|
||||
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
|
||||
if (roomMember == null) {
|
||||
return false
|
||||
private fun handleInitialSync(realm: Realm,
|
||||
roomId: String,
|
||||
currentUserId: String,
|
||||
eventUserId: String,
|
||||
roomMember: RoomMemberContent,
|
||||
aggregator: SyncResponsePostTreatmentAggregator?): Boolean {
|
||||
if (currentUserId != eventUserId) {
|
||||
saveUserEntityLocallyIfNecessary(realm, eventUserId, roomMember)
|
||||
}
|
||||
saveRoomMemberEntityLocally(realm, roomId, eventUserId, roomMember)
|
||||
updateDirectChatsIfNecessary(roomId, roomMember, aggregator)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun saveRoomMemberEntityLocally(realm: Realm,
|
||||
roomId: String,
|
||||
userId: String,
|
||||
roomMember: RoomMemberContent) {
|
||||
val roomMemberEntity = RoomMemberEntityFactory.create(
|
||||
roomId,
|
||||
userId,
|
||||
@ -58,26 +85,58 @@ internal class RoomMemberEventHandler @Inject constructor(
|
||||
// but we want to preserve presence record value and not replace it with null
|
||||
getExistingPresenceState(realm, roomId, userId))
|
||||
realm.insertOrUpdate(roomMemberEntity)
|
||||
if (roomMember.membership.isActive()) {
|
||||
val userEntity = UserEntityFactory.create(userId, roomMember)
|
||||
realm.insertOrUpdate(userEntity)
|
||||
}
|
||||
|
||||
// check whether this new room member event may be used to update the directs dictionary in account data
|
||||
// this is required to handle correctly invite by email in DM
|
||||
val mxId = roomMember.thirdPartyInvite?.signed?.mxid
|
||||
if (mxId != null && mxId != myUserId) {
|
||||
aggregator?.directChatsToCheck?.put(roomId, mxId)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the already existing presence state for a specific user & room in order NOT to be replaced in RoomMemberSummaryEntity
|
||||
* by NULL value.
|
||||
*/
|
||||
|
||||
private fun getExistingPresenceState(realm: Realm, roomId: String, userId: String): UserPresenceEntity? {
|
||||
return RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()?.userPresenceEntity
|
||||
}
|
||||
|
||||
private fun saveUserEntityLocallyIfNecessary(realm: Realm,
|
||||
userId: String,
|
||||
roomMember: RoomMemberContent) {
|
||||
if (roomMember.membership.isActive()) {
|
||||
saveUserLocally(realm, userId, roomMember)
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveUserLocally(realm: Realm, userId: String, roomMember: RoomMemberContent) {
|
||||
val userEntity = UserEntityFactory.create(userId, roomMember)
|
||||
realm.insertOrUpdate(userEntity)
|
||||
}
|
||||
|
||||
private fun updateDirectChatsIfNecessary(roomId: String,
|
||||
roomMember: RoomMemberContent,
|
||||
aggregator: SyncResponsePostTreatmentAggregator?) {
|
||||
// check whether this new room member event may be used to update the directs dictionary in account data
|
||||
// this is required to handle correctly invite by email in DM
|
||||
val mxId = roomMember.thirdPartyInvite?.signed?.mxid
|
||||
if (mxId != null && mxId != myUserId) {
|
||||
aggregator?.directChatsToCheck?.put(roomId, mxId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIncrementalSync(realm: Realm,
|
||||
roomId: String,
|
||||
eventUserId: String,
|
||||
roomMember: RoomMemberContent,
|
||||
prevContent: Content?,
|
||||
aggregator: SyncResponsePostTreatmentAggregator?): Boolean {
|
||||
if (aggregator != null) {
|
||||
val previousDisplayName = prevContent?.get("displayname") as? String
|
||||
val previousAvatar = prevContent?.get("avatar_url") as? String
|
||||
|
||||
if (previousDisplayName != roomMember.displayName || previousAvatar != roomMember.avatarUrl) {
|
||||
aggregator.userIdsToFetch.add(eventUserId)
|
||||
}
|
||||
}
|
||||
|
||||
saveRoomMemberEntityLocally(realm, roomId, eventUserId, roomMember)
|
||||
// At the end of the sync, fetch all the profiles from the aggregator
|
||||
updateDirectChatsIfNecessary(roomId, roomMember, aggregator)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -22,4 +22,7 @@ internal class SyncResponsePostTreatmentAggregator {
|
||||
|
||||
// Map of roomId to directUserId
|
||||
val directChatsToCheck = mutableMapOf<String, String>()
|
||||
|
||||
// List of userIds to fetch and update at the end of incremental syncs
|
||||
val userIdsToFetch = mutableListOf<String>()
|
||||
}
|
||||
|
@ -16,10 +16,16 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.sync.handler
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.api.MatrixPatterns
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
|
||||
import org.matrix.android.sdk.internal.session.sync.RoomSyncEphemeralTemporaryStore
|
||||
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
|
||||
import org.matrix.android.sdk.internal.session.sync.model.accountdata.toMutable
|
||||
import org.matrix.android.sdk.internal.session.user.UserEntityFactory
|
||||
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
|
||||
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
|
||||
import javax.inject.Inject
|
||||
@ -27,11 +33,14 @@ import javax.inject.Inject
|
||||
internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
|
||||
private val directChatsHelper: DirectChatsHelper,
|
||||
private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore,
|
||||
private val updateUserAccountDataTask: UpdateUserAccountDataTask
|
||||
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
||||
private val getProfileInfoTask: GetProfileInfoTask,
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
) {
|
||||
suspend fun handle(synResHaResponsePostTreatmentAggregator: SyncResponsePostTreatmentAggregator) {
|
||||
cleanupEphemeralFiles(synResHaResponsePostTreatmentAggregator.ephemeralFilesToDelete)
|
||||
updateDirectUserIds(synResHaResponsePostTreatmentAggregator.directChatsToCheck)
|
||||
suspend fun handle(aggregator: SyncResponsePostTreatmentAggregator) {
|
||||
cleanupEphemeralFiles(aggregator.ephemeralFilesToDelete)
|
||||
updateDirectUserIds(aggregator.directChatsToCheck)
|
||||
fetchAndUpdateUsers(aggregator.userIdsToFetch)
|
||||
}
|
||||
|
||||
private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List<String>) {
|
||||
@ -59,13 +68,33 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
|
||||
}
|
||||
|
||||
// remove roomId from currentDirectUserId entry
|
||||
hasUpdate = hasUpdate or(directChats[currentDirectUserId]?.remove(roomId) == true)
|
||||
hasUpdate = hasUpdate or (directChats[currentDirectUserId]?.remove(roomId) == true)
|
||||
// remove currentDirectUserId entry if there is no attached room anymore
|
||||
hasUpdate = hasUpdate or(directChats.takeIf { it[currentDirectUserId].isNullOrEmpty() }?.remove(currentDirectUserId) != null)
|
||||
hasUpdate = hasUpdate or (directChats.takeIf { it[currentDirectUserId].isNullOrEmpty() }?.remove(currentDirectUserId) != null)
|
||||
}
|
||||
}
|
||||
if (hasUpdate) {
|
||||
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchAndUpdateUsers(userIdsToFetch: List<String>) {
|
||||
fetchUsers(userIdsToFetch)
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.saveLocally()
|
||||
}
|
||||
|
||||
private suspend fun fetchUsers(userIdsToFetch: List<String>) = userIdsToFetch.mapNotNull {
|
||||
tryOrNull {
|
||||
val profileJson = getProfileInfoTask.execute(GetProfileInfoTask.Params(it))
|
||||
User.fromJson(it, profileJson)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<User>.saveLocally() {
|
||||
val userEntities = map { user -> UserEntityFactory.create(user) }
|
||||
monarchy.doWithRealm {
|
||||
it.insertOrUpdate(userEntities)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,6 +206,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
syncLocalTimestampMillis: Long,
|
||||
aggregator: SyncResponsePostTreatmentAggregator): RoomEntity {
|
||||
Timber.v("Handle join sync for room $roomId")
|
||||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
|
||||
|
||||
val ephemeralResult = (roomSync.ephemeral as? LazyRoomSyncEphemeral.Parsed)
|
||||
?._roomSyncEphemeral
|
||||
@ -240,7 +241,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
}
|
||||
// Give info to crypto module
|
||||
cryptoService.onStateEvent(roomId, event)
|
||||
roomMemberEventHandler.handle(realm, roomId, event, aggregator)
|
||||
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync, aggregator)
|
||||
}
|
||||
}
|
||||
if (roomSync.timeline?.events?.isNotEmpty() == true) {
|
||||
@ -282,6 +283,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
insertType: EventInsertType,
|
||||
syncLocalTimestampMillis: Long): RoomEntity {
|
||||
Timber.v("Handle invited sync for room $roomId")
|
||||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
|
||||
val roomEntity = RoomEntity.getOrCreate(realm, roomId)
|
||||
roomEntity.membership = Membership.INVITE
|
||||
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
||||
@ -295,7 +297,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
eventId = eventEntity.eventId
|
||||
root = eventEntity
|
||||
}
|
||||
roomMemberEventHandler.handle(realm, roomId, event)
|
||||
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync)
|
||||
}
|
||||
}
|
||||
val inviterEvent = roomSync.inviteState?.events?.lastOrNull {
|
||||
@ -311,6 +313,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
roomSync: RoomSync,
|
||||
insertType: EventInsertType,
|
||||
syncLocalTimestampMillis: Long): RoomEntity {
|
||||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
|
||||
val roomEntity = RoomEntity.getOrCreate(realm, roomId)
|
||||
for (event in roomSync.state?.events.orEmpty()) {
|
||||
if (event.eventId == null || event.stateKey == null || event.type == null) {
|
||||
@ -322,7 +325,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
eventId = event.eventId
|
||||
root = eventEntity
|
||||
}
|
||||
roomMemberEventHandler.handle(realm, roomId, event)
|
||||
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync)
|
||||
}
|
||||
for (event in roomSync.timeline?.events.orEmpty()) {
|
||||
if (event.eventId == null || event.senderId == null || event.type == null) {
|
||||
@ -336,7 +339,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
root = eventEntity
|
||||
}
|
||||
if (event.type == EventType.STATE_ROOM_MEMBER) {
|
||||
roomMemberEventHandler.handle(realm, roomEntity.roomId, event)
|
||||
roomMemberEventHandler.handle(realm, roomEntity.roomId, event, isInitialSync)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -380,11 +383,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
continue
|
||||
}
|
||||
|
||||
eventIds.add(event.eventId)
|
||||
liveEventService.get().dispatchLiveEventReceived(event, roomId, insertType == EventInsertType.INITIAL_SYNC)
|
||||
|
||||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
|
||||
|
||||
eventIds.add(event.eventId)
|
||||
liveEventService.get().dispatchLiveEventReceived(event, roomId, isInitialSync)
|
||||
|
||||
if (event.isEncrypted() && !isInitialSync) {
|
||||
runBlocking {
|
||||
decryptIfNeeded(event, roomId)
|
||||
@ -403,9 +406,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
root = eventEntity
|
||||
}
|
||||
if (event.type == EventType.STATE_ROOM_MEMBER) {
|
||||
val fixedContent = event.getFixedRoomMemberContent()
|
||||
roomMemberContentsByUser[event.stateKey] = fixedContent
|
||||
roomMemberEventHandler.handle(realm, roomEntity.roomId, event.stateKey, fixedContent, aggregator)
|
||||
roomMemberContentsByUser[event.stateKey] = event.getFixedRoomMemberContent()
|
||||
roomMemberEventHandler.handle(realm, roomEntity.roomId, event, isInitialSync, aggregator)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.user
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.paging.PagedList
|
||||
import org.matrix.android.sdk.api.session.profile.ProfileService
|
||||
import org.matrix.android.sdk.api.session.user.UserService
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
@ -37,16 +36,10 @@ internal class DefaultUserService @Inject constructor(private val userDataSource
|
||||
}
|
||||
|
||||
override suspend fun resolveUser(userId: String): User {
|
||||
val known = getUser(userId)
|
||||
if (known != null) {
|
||||
return known
|
||||
} else {
|
||||
return getUser(userId) ?: run {
|
||||
val params = GetProfileInfoTask.Params(userId)
|
||||
val data = getProfileInfoTask.execute(params)
|
||||
return User(
|
||||
userId,
|
||||
data[ProfileService.DISPLAY_NAME_KEY] as? String,
|
||||
data[ProfileService.AVATAR_URL_KEY] as? String)
|
||||
val json = getProfileInfoTask.execute(params)
|
||||
User.fromJson(userId, json)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.matrix.android.sdk.internal.session.user
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.internal.database.model.UserEntity
|
||||
|
||||
internal object UserEntityFactory {
|
||||
@ -24,8 +25,16 @@ internal object UserEntityFactory {
|
||||
fun create(userId: String, roomMember: RoomMemberContent): UserEntity {
|
||||
return UserEntity(
|
||||
userId = userId,
|
||||
displayName = roomMember.displayName ?: "",
|
||||
avatarUrl = roomMember.avatarUrl ?: ""
|
||||
displayName = roomMember.displayName.orEmpty(),
|
||||
avatarUrl = roomMember.avatarUrl.orEmpty()
|
||||
)
|
||||
}
|
||||
|
||||
fun create(user: User): UserEntity {
|
||||
return UserEntity(
|
||||
userId = user.userId,
|
||||
displayName = user.displayName.orEmpty(),
|
||||
avatarUrl = user.avatarUrl.orEmpty()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.api.util.toOptional
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
@ -112,8 +112,8 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
|
||||
session.flow().liveUserCryptoDevices(initialState.userId)
|
||||
.map {
|
||||
Pair(
|
||||
it.fold(true, { prev, dev -> prev && dev.isVerified }),
|
||||
it.fold(true, { prev, dev -> prev && (dev.trustLevel?.crossSigningVerified == true) })
|
||||
it.fold(true) { prev, dev -> prev && dev.isVerified },
|
||||
it.fold(true) { prev, dev -> prev && (dev.trustLevel?.crossSigningVerified == true) }
|
||||
)
|
||||
}
|
||||
.execute { it ->
|
||||
@ -327,14 +327,9 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
|
||||
|
||||
private suspend fun fetchProfileInfo() {
|
||||
val result = runCatchingToAsync {
|
||||
session.getProfileAsUser(initialState.userId)
|
||||
.let {
|
||||
MatrixItem.UserItem(
|
||||
id = initialState.userId,
|
||||
displayName = it.displayName,
|
||||
avatarUrl = it.avatarUrl
|
||||
)
|
||||
}
|
||||
session.getProfile(initialState.userId)
|
||||
.let { User.fromJson(initialState.userId, it) }
|
||||
.toMatrixItem()
|
||||
}
|
||||
|
||||
setState {
|
||||
|
Loading…
Reference in New Issue
Block a user