Skip to content

Commit 9b7e94e

Browse files
authored
Fixes myroomnick changing Display Name (#5618)
1 parent e109319 commit 9b7e94e

File tree

11 files changed

+167
-62
lines changed

11 files changed

+167
-62
lines changed

changelog.d/5618.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes display name being changed when using /myroomnick

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/model/User.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.matrix.android.sdk.api.session.user.model
1818

19+
import org.matrix.android.sdk.api.session.profile.ProfileService
20+
import org.matrix.android.sdk.api.util.JsonDict
21+
1922
/**
2023
* Data class which holds information about a user.
2124
* It can be retrieved with [org.matrix.android.sdk.api.session.user.UserService]
@@ -27,4 +30,14 @@ data class User(
2730
*/
2831
val displayName: String? = null,
2932
val avatarUrl: String? = null
30-
)
33+
) {
34+
35+
companion object {
36+
37+
fun fromJson(userId: String, json: JsonDict) = User(
38+
userId = userId,
39+
displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String,
40+
avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String
41+
)
42+
}
43+
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ sealed class MatrixItem(
3737
override val displayName: String? = null,
3838
override val avatarUrl: String? = null) :
3939
MatrixItem(id, displayName?.removeSuffix(IRC_PATTERN), avatarUrl) {
40+
4041
init {
4142
if (BuildConfig.DEBUG) checkId()
4243
}
@@ -200,7 +201,7 @@ fun RoomMemberSummary.toMatrixItem() = MatrixItem.UserItem(userId, displayName,
200201

201202
fun SenderInfo.toMatrixItem() = MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl)
202203

203-
fun SenderInfo.toMatrixItemOrNull() = tryOrNull { MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl) }
204+
fun SenderInfo.toMatrixItemOrNull() = tryOrNull { MatrixItem.UserItem(userId, disambiguatedDisplayName, avatarUrl) }
204205

205206
fun SpaceChildInfo.toMatrixItem() = if (roomType == RoomType.SPACE) {
206207
MatrixItem.SpaceItem(childRoomId, name ?: canonicalAlias, avatarUrl)

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
123123
eventId = roomMemberEvent.eventId
124124
root = eventEntity
125125
}
126-
roomMemberEventHandler.handle(realm, roomId, roomMemberEvent)
126+
roomMemberEventHandler.handle(realm, roomId, roomMemberEvent, false)
127127
}
128128
roomEntity.membersLoadStatus = RoomMembersLoadStatusType.LOADED
129129
roomSummaryUpdater.update(realm, roomId, updateMembers = true)

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.matrix.android.sdk.internal.session.room.membership
1818

1919
import io.realm.Realm
20+
import org.matrix.android.sdk.api.session.events.model.Content
2021
import org.matrix.android.sdk.api.session.events.model.Event
2122
import org.matrix.android.sdk.api.session.events.model.EventType
2223
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
@@ -33,23 +34,49 @@ internal class RoomMemberEventHandler @Inject constructor(
3334
@UserId private val myUserId: String
3435
) {
3536

36-
fun handle(realm: Realm, roomId: String, event: Event, aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
37+
fun handle(realm: Realm,
38+
roomId: String,
39+
event: Event,
40+
isInitialSync: Boolean,
41+
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
3742
if (event.type != EventType.STATE_ROOM_MEMBER) {
3843
return false
3944
}
40-
val userId = event.stateKey ?: return false
41-
val roomMember = event.getFixedRoomMemberContent()
42-
return handle(realm, roomId, userId, roomMember, aggregator)
45+
val eventUserId = event.stateKey ?: return false
46+
val roomMember = event.getFixedRoomMemberContent() ?: return false
47+
48+
return if (isInitialSync) {
49+
handleInitialSync(realm, roomId, myUserId, eventUserId, roomMember, aggregator)
50+
} else {
51+
handleIncrementalSync(
52+
realm,
53+
roomId,
54+
eventUserId,
55+
roomMember,
56+
event.resolvedPrevContent(),
57+
aggregator
58+
)
59+
}
4360
}
4461

45-
fun handle(realm: Realm,
46-
roomId: String,
47-
userId: String,
48-
roomMember: RoomMemberContent?,
49-
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
50-
if (roomMember == null) {
51-
return false
62+
private fun handleInitialSync(realm: Realm,
63+
roomId: String,
64+
currentUserId: String,
65+
eventUserId: String,
66+
roomMember: RoomMemberContent,
67+
aggregator: SyncResponsePostTreatmentAggregator?): Boolean {
68+
if (currentUserId != eventUserId) {
69+
saveUserEntityLocallyIfNecessary(realm, eventUserId, roomMember)
5270
}
71+
saveRoomMemberEntityLocally(realm, roomId, eventUserId, roomMember)
72+
updateDirectChatsIfNecessary(roomId, roomMember, aggregator)
73+
return true
74+
}
75+
76+
private fun saveRoomMemberEntityLocally(realm: Realm,
77+
roomId: String,
78+
userId: String,
79+
roomMember: RoomMemberContent) {
5380
val roomMemberEntity = RoomMemberEntityFactory.create(
5481
roomId,
5582
userId,
@@ -58,26 +85,58 @@ internal class RoomMemberEventHandler @Inject constructor(
5885
// but we want to preserve presence record value and not replace it with null
5986
getExistingPresenceState(realm, roomId, userId))
6087
realm.insertOrUpdate(roomMemberEntity)
88+
}
89+
90+
/**
91+
* Get the already existing presence state for a specific user & room in order NOT to be replaced in RoomMemberSummaryEntity
92+
* by NULL value.
93+
*/
94+
private fun getExistingPresenceState(realm: Realm, roomId: String, userId: String): UserPresenceEntity? {
95+
return RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()?.userPresenceEntity
96+
}
97+
98+
private fun saveUserEntityLocallyIfNecessary(realm: Realm,
99+
userId: String,
100+
roomMember: RoomMemberContent) {
61101
if (roomMember.membership.isActive()) {
62-
val userEntity = UserEntityFactory.create(userId, roomMember)
63-
realm.insertOrUpdate(userEntity)
102+
saveUserLocally(realm, userId, roomMember)
64103
}
104+
}
65105

106+
private fun saveUserLocally(realm: Realm, userId: String, roomMember: RoomMemberContent) {
107+
val userEntity = UserEntityFactory.create(userId, roomMember)
108+
realm.insertOrUpdate(userEntity)
109+
}
110+
111+
private fun updateDirectChatsIfNecessary(roomId: String,
112+
roomMember: RoomMemberContent,
113+
aggregator: SyncResponsePostTreatmentAggregator?) {
66114
// check whether this new room member event may be used to update the directs dictionary in account data
67115
// this is required to handle correctly invite by email in DM
68116
val mxId = roomMember.thirdPartyInvite?.signed?.mxid
69117
if (mxId != null && mxId != myUserId) {
70118
aggregator?.directChatsToCheck?.put(roomId, mxId)
71119
}
72-
return true
73120
}
74121

75-
/**
76-
* Get the already existing presence state for a specific user & room in order NOT to be replaced in RoomMemberSummaryEntity
77-
* by NULL value.
78-
*/
122+
private fun handleIncrementalSync(realm: Realm,
123+
roomId: String,
124+
eventUserId: String,
125+
roomMember: RoomMemberContent,
126+
prevContent: Content?,
127+
aggregator: SyncResponsePostTreatmentAggregator?): Boolean {
128+
if (aggregator != null) {
129+
val previousDisplayName = prevContent?.get("displayname") as? String
130+
val previousAvatar = prevContent?.get("avatar_url") as? String
79131

80-
private fun getExistingPresenceState(realm: Realm, roomId: String, userId: String): UserPresenceEntity? {
81-
return RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()?.userPresenceEntity
132+
if (previousDisplayName != roomMember.displayName || previousAvatar != roomMember.avatarUrl) {
133+
aggregator.userIdsToFetch.add(eventUserId)
134+
}
135+
}
136+
137+
saveRoomMemberEntityLocally(realm, roomId, eventUserId, roomMember)
138+
// At the end of the sync, fetch all the profiles from the aggregator
139+
updateDirectChatsIfNecessary(roomId, roomMember, aggregator)
140+
return true
82141
}
83142
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,7 @@ internal class SyncResponsePostTreatmentAggregator {
2222

2323
// Map of roomId to directUserId
2424
val directChatsToCheck = mutableMapOf<String, String>()
25+
26+
// List of userIds to fetch and update at the end of incremental syncs
27+
val userIdsToFetch = mutableListOf<String>()
2528
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,31 @@
1616

1717
package org.matrix.android.sdk.internal.session.sync.handler
1818

19+
import com.zhuinden.monarchy.Monarchy
1920
import org.matrix.android.sdk.api.MatrixPatterns
21+
import org.matrix.android.sdk.api.extensions.tryOrNull
22+
import org.matrix.android.sdk.api.session.user.model.User
23+
import org.matrix.android.sdk.internal.di.SessionDatabase
24+
import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
2025
import org.matrix.android.sdk.internal.session.sync.RoomSyncEphemeralTemporaryStore
2126
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
2227
import org.matrix.android.sdk.internal.session.sync.model.accountdata.toMutable
28+
import org.matrix.android.sdk.internal.session.user.UserEntityFactory
2329
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
2430
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
2531
import javax.inject.Inject
2632

2733
internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
2834
private val directChatsHelper: DirectChatsHelper,
2935
private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore,
30-
private val updateUserAccountDataTask: UpdateUserAccountDataTask
36+
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
37+
private val getProfileInfoTask: GetProfileInfoTask,
38+
@SessionDatabase private val monarchy: Monarchy,
3139
) {
32-
suspend fun handle(synResHaResponsePostTreatmentAggregator: SyncResponsePostTreatmentAggregator) {
33-
cleanupEphemeralFiles(synResHaResponsePostTreatmentAggregator.ephemeralFilesToDelete)
34-
updateDirectUserIds(synResHaResponsePostTreatmentAggregator.directChatsToCheck)
40+
suspend fun handle(aggregator: SyncResponsePostTreatmentAggregator) {
41+
cleanupEphemeralFiles(aggregator.ephemeralFilesToDelete)
42+
updateDirectUserIds(aggregator.directChatsToCheck)
43+
fetchAndUpdateUsers(aggregator.userIdsToFetch)
3544
}
3645

3746
private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List<String>) {
@@ -59,13 +68,33 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
5968
}
6069

6170
// remove roomId from currentDirectUserId entry
62-
hasUpdate = hasUpdate or(directChats[currentDirectUserId]?.remove(roomId) == true)
71+
hasUpdate = hasUpdate or (directChats[currentDirectUserId]?.remove(roomId) == true)
6372
// remove currentDirectUserId entry if there is no attached room anymore
64-
hasUpdate = hasUpdate or(directChats.takeIf { it[currentDirectUserId].isNullOrEmpty() }?.remove(currentDirectUserId) != null)
73+
hasUpdate = hasUpdate or (directChats.takeIf { it[currentDirectUserId].isNullOrEmpty() }?.remove(currentDirectUserId) != null)
6574
}
6675
}
6776
if (hasUpdate) {
6877
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
6978
}
7079
}
80+
81+
private suspend fun fetchAndUpdateUsers(userIdsToFetch: List<String>) {
82+
fetchUsers(userIdsToFetch)
83+
.takeIf { it.isNotEmpty() }
84+
?.saveLocally()
85+
}
86+
87+
private suspend fun fetchUsers(userIdsToFetch: List<String>) = userIdsToFetch.mapNotNull {
88+
tryOrNull {
89+
val profileJson = getProfileInfoTask.execute(GetProfileInfoTask.Params(it))
90+
User.fromJson(it, profileJson)
91+
}
92+
}
93+
94+
private fun List<User>.saveLocally() {
95+
val userEntities = map { user -> UserEntityFactory.create(user) }
96+
monarchy.doWithRealm {
97+
it.insertOrUpdate(userEntities)
98+
}
99+
}
71100
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
206206
syncLocalTimestampMillis: Long,
207207
aggregator: SyncResponsePostTreatmentAggregator): RoomEntity {
208208
Timber.v("Handle join sync for room $roomId")
209+
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
209210

210211
val ephemeralResult = (roomSync.ephemeral as? LazyRoomSyncEphemeral.Parsed)
211212
?._roomSyncEphemeral
@@ -240,7 +241,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
240241
}
241242
// Give info to crypto module
242243
cryptoService.onStateEvent(roomId, event)
243-
roomMemberEventHandler.handle(realm, roomId, event, aggregator)
244+
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync, aggregator)
244245
}
245246
}
246247
if (roomSync.timeline?.events?.isNotEmpty() == true) {
@@ -282,6 +283,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
282283
insertType: EventInsertType,
283284
syncLocalTimestampMillis: Long): RoomEntity {
284285
Timber.v("Handle invited sync for room $roomId")
286+
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
285287
val roomEntity = RoomEntity.getOrCreate(realm, roomId)
286288
roomEntity.membership = Membership.INVITE
287289
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
@@ -295,7 +297,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
295297
eventId = eventEntity.eventId
296298
root = eventEntity
297299
}
298-
roomMemberEventHandler.handle(realm, roomId, event)
300+
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync)
299301
}
300302
}
301303
val inviterEvent = roomSync.inviteState?.events?.lastOrNull {
@@ -311,6 +313,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
311313
roomSync: RoomSync,
312314
insertType: EventInsertType,
313315
syncLocalTimestampMillis: Long): RoomEntity {
316+
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
314317
val roomEntity = RoomEntity.getOrCreate(realm, roomId)
315318
for (event in roomSync.state?.events.orEmpty()) {
316319
if (event.eventId == null || event.stateKey == null || event.type == null) {
@@ -322,7 +325,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
322325
eventId = event.eventId
323326
root = eventEntity
324327
}
325-
roomMemberEventHandler.handle(realm, roomId, event)
328+
roomMemberEventHandler.handle(realm, roomId, event, isInitialSync)
326329
}
327330
for (event in roomSync.timeline?.events.orEmpty()) {
328331
if (event.eventId == null || event.senderId == null || event.type == null) {
@@ -336,7 +339,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
336339
root = eventEntity
337340
}
338341
if (event.type == EventType.STATE_ROOM_MEMBER) {
339-
roomMemberEventHandler.handle(realm, roomEntity.roomId, event)
342+
roomMemberEventHandler.handle(realm, roomEntity.roomId, event, isInitialSync)
340343
}
341344
}
342345
}
@@ -380,11 +383,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
380383
continue
381384
}
382385

383-
eventIds.add(event.eventId)
384-
liveEventService.get().dispatchLiveEventReceived(event, roomId, insertType == EventInsertType.INITIAL_SYNC)
385-
386386
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
387387

388+
eventIds.add(event.eventId)
389+
liveEventService.get().dispatchLiveEventReceived(event, roomId, isInitialSync)
390+
388391
if (event.isEncrypted() && !isInitialSync) {
389392
runBlocking {
390393
decryptIfNeeded(event, roomId)
@@ -403,9 +406,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
403406
root = eventEntity
404407
}
405408
if (event.type == EventType.STATE_ROOM_MEMBER) {
406-
val fixedContent = event.getFixedRoomMemberContent()
407-
roomMemberContentsByUser[event.stateKey] = fixedContent
408-
roomMemberEventHandler.handle(realm, roomEntity.roomId, event.stateKey, fixedContent, aggregator)
409+
roomMemberContentsByUser[event.stateKey] = event.getFixedRoomMemberContent()
410+
roomMemberEventHandler.handle(realm, roomEntity.roomId, event, isInitialSync, aggregator)
409411
}
410412
}
411413

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.user
1818

1919
import androidx.lifecycle.LiveData
2020
import androidx.paging.PagedList
21-
import org.matrix.android.sdk.api.session.profile.ProfileService
2221
import org.matrix.android.sdk.api.session.user.UserService
2322
import org.matrix.android.sdk.api.session.user.model.User
2423
import org.matrix.android.sdk.api.util.Optional
@@ -37,16 +36,10 @@ internal class DefaultUserService @Inject constructor(private val userDataSource
3736
}
3837

3938
override suspend fun resolveUser(userId: String): User {
40-
val known = getUser(userId)
41-
if (known != null) {
42-
return known
43-
} else {
39+
return getUser(userId) ?: run {
4440
val params = GetProfileInfoTask.Params(userId)
45-
val data = getProfileInfoTask.execute(params)
46-
return User(
47-
userId,
48-
data[ProfileService.DISPLAY_NAME_KEY] as? String,
49-
data[ProfileService.AVATAR_URL_KEY] as? String)
41+
val json = getProfileInfoTask.execute(params)
42+
User.fromJson(userId, json)
5043
}
5144
}
5245

0 commit comments

Comments
 (0)