mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Try to insert users directly to see if perfs are better [WIP]
This commit is contained in:
parent
b77310fe92
commit
10e4d0190f
17 changed files with 343 additions and 202 deletions
|
@ -33,7 +33,7 @@ data class TimelineEvent(
|
|||
val localId: Long,
|
||||
val displayIndex: Int,
|
||||
val senderName: String?,
|
||||
val isUniqueDisplayName: Boolean,
|
||||
val isUniqueDisplayName: Boolean = false,
|
||||
val senderAvatar: String?,
|
||||
val sendState: SendState,
|
||||
val annotations: EventAnnotationsSummary? = null
|
||||
|
|
|
@ -103,7 +103,6 @@ internal fun ChunkEntity.updateSenderDataFor(eventIds: List<String>) {
|
|||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun ChunkEntity.add(roomId: String,
|
||||
event: Event,
|
||||
direction: PaginationDirection,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.matrix.android.internal.database.helper
|
||||
|
||||
import com.squareup.moshi.JsonReader
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
import im.vector.matrix.android.internal.database.mapper.toEntity
|
||||
|
@ -24,7 +25,10 @@ import im.vector.matrix.android.internal.database.model.RoomEntity
|
|||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||
import im.vector.matrix.android.internal.database.query.fastContains
|
||||
import im.vector.matrix.android.internal.extensions.assertIsManaged
|
||||
import im.vector.matrix.android.internal.network.parsing.GetRoomMembersResponseHandler
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||
import okhttp3.ResponseBody
|
||||
import okio.Okio
|
||||
|
||||
internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) {
|
||||
chunks.remove(chunkEntity)
|
||||
|
@ -37,25 +41,42 @@ internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) {
|
|||
}
|
||||
}
|
||||
|
||||
internal fun RoomEntity.addStateEvents(stateEvents: List<Event>,
|
||||
stateIndex: Int = Int.MIN_VALUE,
|
||||
filterDuplicates: Boolean = false,
|
||||
isUnlinked: Boolean = false) {
|
||||
internal fun RoomEntity.addStateEvent(stateEvent: Event,
|
||||
stateIndex: Int = Int.MIN_VALUE,
|
||||
filterDuplicates: Boolean = false,
|
||||
isUnlinked: Boolean = false) {
|
||||
assertIsManaged()
|
||||
|
||||
stateEvents.forEach { event ->
|
||||
if (event.eventId == null || (filterDuplicates && fastContains(event.eventId))) {
|
||||
return@forEach
|
||||
}
|
||||
val eventEntity = event.toEntity(roomId).apply {
|
||||
if (stateEvent.eventId == null || (filterDuplicates && fastContains(stateEvent.eventId))) {
|
||||
return
|
||||
} else {
|
||||
val entity = stateEvent.toEntity(roomId).apply {
|
||||
this.stateIndex = stateIndex
|
||||
this.isUnlinked = isUnlinked
|
||||
this.sendState = SendState.SYNCED
|
||||
}
|
||||
untimelinedStateEvents.add(0, eventEntity)
|
||||
untimelinedStateEvents.add(entity)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RoomEntity.addStateEvents(stateEvents: List<Event>,
|
||||
stateIndex: Int = Int.MIN_VALUE,
|
||||
filterDuplicates: Boolean = false,
|
||||
isUnlinked: Boolean = false) {
|
||||
stateEvents.forEach { event ->
|
||||
addStateEvent(event, stateIndex, filterDuplicates, isUnlinked)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RoomEntity.addStateEvents(response: ResponseBody,
|
||||
stateIndex: Int = Int.MIN_VALUE,
|
||||
isUnlinked: Boolean = false) {
|
||||
val manualParser = GetRoomMembersResponseHandler()
|
||||
val bufferedSource = Okio.buffer(Okio.source(response.byteStream()))
|
||||
val inputReader = JsonReader.of(bufferedSource)
|
||||
manualParser.handle(inputReader, this, stateIndex, isUnlinked)
|
||||
}
|
||||
|
||||
|
||||
internal fun RoomEntity.addSendingEvent(event: Event) {
|
||||
assertIsManaged()
|
||||
val senderId = event.senderId ?: return
|
||||
|
@ -64,7 +85,7 @@ internal fun RoomEntity.addSendingEvent(event: Event) {
|
|||
}
|
||||
val roomMembers = RoomMembers(realm, roomId)
|
||||
val myUser = roomMembers.get(senderId)
|
||||
val localId = TimelineEventEntity.nextId(realm)
|
||||
val localId = TimelineEventEntity.nextId(realm)
|
||||
val timelineEventEntity = TimelineEventEntity(localId).also {
|
||||
it.root = eventEntity
|
||||
it.eventId = event.eventId ?: ""
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2019 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 im.vector.matrix.android.internal.network.parsing
|
||||
|
||||
import com.squareup.moshi.JsonReader
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
|
||||
internal class GetRoomMembersResponseHandler {
|
||||
|
||||
companion object {
|
||||
private val NAMES = JsonReader.Options.of("event_id", "content", "prev_content", "origin_server_ts", "sender", "state_key")
|
||||
}
|
||||
|
||||
internal fun handle(reader: JsonReader, roomEntity: RoomEntity, stateIndex: Int = Int.MIN_VALUE, isUnlinked: Boolean = false) {
|
||||
reader.readObject {
|
||||
reader.nextName()
|
||||
val eventEntity = EventEntity().apply {
|
||||
this.roomId = roomEntity.roomId
|
||||
this.stateIndex = stateIndex
|
||||
this.isUnlinked = isUnlinked
|
||||
this.sendState = SendState.SYNCED
|
||||
this.type = EventType.STATE_ROOM_MEMBER
|
||||
}
|
||||
reader.readArray {
|
||||
reader.readObject {
|
||||
when
|
||||
(reader.selectName(NAMES)) {
|
||||
0 -> eventEntity.eventId = reader.nextString()
|
||||
1 -> eventEntity.content = reader.readJsonValue()?.toString()
|
||||
2 -> eventEntity.prevContent = reader.readJsonValue()?.toString()
|
||||
3 -> eventEntity.originServerTs = reader.nextLong()
|
||||
4 -> eventEntity.sender = reader.nextString()
|
||||
5 -> eventEntity.stateKey = reader.nextString()
|
||||
else -> reader.skipNameAndValue()
|
||||
}
|
||||
}
|
||||
roomEntity.untimelinedStateEvents.add(eventEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2019 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 im.vector.matrix.android.internal.network.parsing
|
||||
|
||||
import com.squareup.moshi.JsonReader
|
||||
|
||||
fun JsonReader.skipNameAndValue() {
|
||||
skipName()
|
||||
skipValue()
|
||||
}
|
||||
|
||||
inline fun JsonReader.readObject(body: () -> Unit) {
|
||||
beginObject()
|
||||
while (hasNext()) {
|
||||
body()
|
||||
}
|
||||
endObject()
|
||||
}
|
||||
|
||||
inline fun JsonReader.readArray(body: () -> Unit) {
|
||||
beginArray()
|
||||
while (hasNext()) {
|
||||
body()
|
||||
}
|
||||
endArray()
|
||||
}
|
|
@ -38,7 +38,6 @@ import im.vector.matrix.android.internal.network.RetrofitFactory
|
|||
import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater
|
||||
import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater
|
||||
import im.vector.matrix.android.internal.session.room.prune.EventsPruner
|
||||
import im.vector.matrix.android.internal.session.user.UserEntityUpdater
|
||||
import im.vector.matrix.android.internal.util.md5
|
||||
import io.realm.RealmConfiguration
|
||||
import okhttp3.OkHttpClient
|
||||
|
@ -129,10 +128,6 @@ internal abstract class SessionModule {
|
|||
@IntoSet
|
||||
abstract fun bindEventRelationsAggregationUpdater(groupSummaryUpdater: EventRelationsAggregationUpdater): LiveEntityObserver
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun bindUserEntityUpdater(groupSummaryUpdater: UserEntityUpdater): LiveEntityObserver
|
||||
|
||||
@Binds
|
||||
abstract fun bindInitialSyncProgressService(initialSyncProgressService: DefaultInitialSyncProgressService): InitialSyncProgressService
|
||||
|
||||
|
|
|
@ -20,14 +20,13 @@ import com.zhuinden.monarchy.Monarchy
|
|||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomAvatarContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.prev
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -42,32 +41,25 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona
|
|||
fun resolve(roomId: String): String? {
|
||||
var res: String? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()?.asDomain()
|
||||
res = roomName?.content.toModel<RoomAvatarContent>()?.avatarUrl
|
||||
if (!res.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
val roomMembers = RoomMembers(realm, roomId)
|
||||
val members = roomMembers.getLoaded()
|
||||
if (roomEntity?.membership == Membership.INVITE) {
|
||||
if (members.size == 1) {
|
||||
res = members.entries.first().value.avatarUrl
|
||||
} else if (members.size > 1) {
|
||||
val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull()
|
||||
res = firstOtherMember?.avatarUrl
|
||||
}
|
||||
} else {
|
||||
// detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat)
|
||||
if (members.size == 1) {
|
||||
res = members.entries.first().value.avatarUrl
|
||||
} else if (members.size == 2) {
|
||||
val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull()
|
||||
res = firstOtherMember?.avatarUrl
|
||||
}
|
||||
val members = roomMembers.queryRoomMembersEvent().findAll()
|
||||
// detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat)
|
||||
if (members.size == 1) {
|
||||
res = members.firstOrNull()?.toRoomMember()?.avatarUrl
|
||||
} else if (members.size == 2) {
|
||||
val firstOtherMember = members.where().notEqualTo(EventEntityFields.STATE_KEY, credentials.userId).findFirst()
|
||||
res = firstOtherMember?.toRoomMember()?.avatarUrl
|
||||
}
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
private fun EventEntity?.toRoomMember(): RoomMember? {
|
||||
return this?.asDomain()?.content?.toModel<RoomMember>()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.room.model.Membership
|
|||
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||
import im.vector.matrix.android.internal.database.query.latestEvent
|
||||
|
@ -86,12 +87,20 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
|||
|
||||
val latestEvent = TimelineEventEntity.latestEvent(realm, roomId, includedTypes = PREVIEWABLE_TYPES)
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
|
||||
val otherRoomMembers = RoomMembers(realm, roomId).getLoaded().filterKeys { it != credentials.userId }
|
||||
|
||||
val otherRoomMembers = RoomMembers(realm, roomId)
|
||||
.queryRoomMembersEvent()
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, credentials.userId)
|
||||
.findAll()
|
||||
.asSequence()
|
||||
.map { it.stateKey }
|
||||
|
||||
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
|
||||
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
|
||||
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
|
||||
roomSummaryEntity.latestEvent = latestEvent
|
||||
roomSummaryEntity.otherMemberIds.clear()
|
||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers.keys)
|
||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
|
||||
|
||||
}
|
||||
}
|
|
@ -18,19 +18,25 @@ package im.vector.matrix.android.internal.session.room.membership
|
|||
|
||||
import arrow.core.Try
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvent
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
||||
import im.vector.matrix.android.internal.database.helper.updateSenderData
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||
import im.vector.matrix.android.internal.session.user.UserEntityFactory
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import okhttp3.ResponseBody
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface LoadRoomMembersTask : Task<LoadRoomMembersTask.Params, Boolean> {
|
||||
|
@ -60,23 +66,27 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP
|
|||
}
|
||||
}
|
||||
|
||||
private fun insertInDb(response: RoomMembersResponse, roomId: String): Try<RoomMembersResponse> {
|
||||
private fun insertInDb(response: RoomMembersResponse, roomId: String): Try<Unit> {
|
||||
return monarchy
|
||||
.tryTransactionSync { realm ->
|
||||
// We ignore all the already known members
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: realm.createObject(roomId)
|
||||
|
||||
val roomMembers = RoomMembers(realm, roomId).getLoaded()
|
||||
val eventsToInsert = response.roomMemberEvents.filter { !roomMembers.containsKey(it.stateKey) }
|
||||
roomEntity.addStateEvents(eventsToInsert)
|
||||
val userEntities = ArrayList<UserEntity>(response.roomMemberEvents.size)
|
||||
for (roomMemberEvent in response.roomMemberEvents) {
|
||||
roomEntity.addStateEvent(roomMemberEvent)
|
||||
UserEntityFactory.create(roomMemberEvent)?.also {
|
||||
userEntities.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(userEntities)
|
||||
roomEntity.chunks.flatMap { it.timelineEvents }.forEach {
|
||||
it.updateSenderData()
|
||||
}
|
||||
roomEntity.areAllMembersLoaded = true
|
||||
roomSummaryUpdater.update(realm, roomId)
|
||||
}
|
||||
.map { response }
|
||||
}
|
||||
|
||||
private fun areAllMembersAlreadyLoaded(roomId: String): Boolean {
|
||||
|
@ -85,4 +95,4 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,16 @@ import im.vector.matrix.android.api.session.events.model.toModel
|
|||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomAliasesContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomCanonicalAliasContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.api.session.room.model.RoomNameContent
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.prev
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.RealmResults
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -39,7 +42,6 @@ import javax.inject.Inject
|
|||
*/
|
||||
internal class RoomDisplayNameResolver @Inject constructor(private val context: Context,
|
||||
private val monarchy: Monarchy,
|
||||
private val roomMemberDisplayNameResolver: RoomMemberDisplayNameResolver,
|
||||
private val credentials: Credentials
|
||||
) {
|
||||
|
||||
|
@ -78,48 +80,59 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
|||
}
|
||||
|
||||
val roomMembers = RoomMembers(realm, roomId)
|
||||
val loadedMembers = roomMembers.getLoaded()
|
||||
val otherRoomMembers = loadedMembers.filterKeys { it != credentials.userId }
|
||||
val loadedMembers = roomMembers.queryRoomMembersEvent().findAll()
|
||||
val otherMembersSubset = loadedMembers.where()
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, credentials.userId)
|
||||
.limit(3)
|
||||
.findAll()
|
||||
|
||||
if (roomEntity?.membership == Membership.INVITE) {
|
||||
val inviteMeEvent = roomMembers.queryRoomMemberEvent(credentials.userId).findFirst()
|
||||
val inviterId = inviteMeEvent?.sender
|
||||
name = if (inviterId != null && otherRoomMembers.containsKey(inviterId)) {
|
||||
roomMemberDisplayNameResolver.resolve(inviterId, otherRoomMembers)
|
||||
name = if (inviterId != null) {
|
||||
val inviterMemberEvent = loadedMembers.where().equalTo(EventEntityFields.STATE_KEY, inviterId).findFirst()
|
||||
inviterMemberEvent?.toRoomMember()?.displayName
|
||||
} else {
|
||||
context.getString(R.string.room_displayname_room_invite)
|
||||
}
|
||||
} else {
|
||||
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
val memberIds = if (roomSummary?.heroes?.isNotEmpty() == true) {
|
||||
val memberIds: List<String> = if (roomSummary?.heroes?.isNotEmpty() == true) {
|
||||
roomSummary.heroes
|
||||
} else {
|
||||
otherRoomMembers.keys.toList()
|
||||
otherMembersSubset.mapNotNull { it.stateKey }
|
||||
}
|
||||
|
||||
val nbOfOtherMembers = memberIds.size
|
||||
|
||||
when (nbOfOtherMembers) {
|
||||
0 -> name = context.getString(R.string.room_displayname_empty_room)
|
||||
1 -> name = roomMemberDisplayNameResolver.resolve(memberIds[0], otherRoomMembers)
|
||||
2 -> {
|
||||
val member1 = memberIds[0]
|
||||
val member2 = memberIds[1]
|
||||
name = context.getString(R.string.room_displayname_two_members,
|
||||
roomMemberDisplayNameResolver.resolve(member1, otherRoomMembers),
|
||||
roomMemberDisplayNameResolver.resolve(member2, otherRoomMembers)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val member = memberIds[0]
|
||||
name = context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
||||
roomMembers.getNumberOfJoinedMembers() - 1,
|
||||
roomMemberDisplayNameResolver.resolve(member, otherRoomMembers),
|
||||
roomMembers.getNumberOfJoinedMembers() - 1)
|
||||
}
|
||||
name = when (memberIds.size) {
|
||||
0 -> context.getString(R.string.room_displayname_empty_room)
|
||||
1 -> resolveRoomMember(otherMembersSubset[0], roomMembers)
|
||||
2 -> context.getString(R.string.room_displayname_two_members,
|
||||
resolveRoomMember(otherMembersSubset[0], roomMembers),
|
||||
resolveRoomMember(otherMembersSubset[1], roomMembers)
|
||||
)
|
||||
else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
||||
roomMembers.getNumberOfJoinedMembers() - 1,
|
||||
resolveRoomMember(otherMembersSubset[0], roomMembers),
|
||||
roomMembers.getNumberOfJoinedMembers() - 1)
|
||||
}
|
||||
}
|
||||
return@doWithRealm
|
||||
}
|
||||
return name ?: roomId
|
||||
}
|
||||
|
||||
private fun resolveRoomMember(eventEntity: EventEntity?,
|
||||
roomMembers: RoomMembers): String? {
|
||||
if (eventEntity == null) return null
|
||||
val roomMember = eventEntity.toRoomMember() ?: return null
|
||||
val isUnique = roomMembers.isUniqueDisplayName(roomMember.displayName)
|
||||
return if (isUnique) {
|
||||
roomMember.displayName
|
||||
} else {
|
||||
"${roomMember.displayName} ( ${eventEntity.stateKey} )"
|
||||
}
|
||||
}
|
||||
|
||||
private fun EventEntity?.toRoomMember(): RoomMember? {
|
||||
return this?.asDomain()?.content?.toModel<RoomMember>()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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 im.vector.matrix.android.internal.session.room.membership
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RoomMemberDisplayNameResolver @Inject constructor() {
|
||||
|
||||
fun resolve(userId: String, members: Map<String, RoomMember>): String? {
|
||||
val currentMember = members[userId]
|
||||
var displayName = currentMember?.displayName
|
||||
// Get the user display name from the member list of the room
|
||||
// Do not consider null display name
|
||||
|
||||
if (currentMember != null && !currentMember.displayName.isNullOrEmpty()) {
|
||||
val hasNameCollision = members
|
||||
.filterValues { it != currentMember && it.displayName == currentMember.displayName }
|
||||
.isNotEmpty()
|
||||
if (hasNameCollision) {
|
||||
displayName = "${currentMember.displayName} ( $userId )"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO handle invited users
|
||||
/*else if (null != member && TextUtils.equals(member!!.membership, RoomMember.MEMBERSHIP_INVITE)) {
|
||||
val user = (mDataHandler as MXDataHandler).getUser(userId)
|
||||
if (null != user) {
|
||||
displayName = user!!.displayname
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (displayName == null) {
|
||||
// By default, use the user ID
|
||||
displayName = userId
|
||||
}
|
||||
return displayName
|
||||
}
|
||||
|
||||
}
|
|
@ -33,6 +33,7 @@ import io.realm.Sort
|
|||
* This class is an helper around STATE_ROOM_MEMBER events.
|
||||
* It allows to get the live membership of a user.
|
||||
*/
|
||||
|
||||
internal class RoomMembers(private val realm: Realm,
|
||||
private val roomId: String
|
||||
) {
|
||||
|
@ -72,27 +73,27 @@ internal class RoomMembers(private val realm: Realm,
|
|||
.isNotNull(EventEntityFields.CONTENT)
|
||||
}
|
||||
|
||||
fun queryJoinedRoomMembersEvent(): RealmQuery<EventEntity> {
|
||||
return queryRoomMembersEvent().contains(EventEntityFields.CONTENT, "\"membership\":\"join\"")
|
||||
}
|
||||
|
||||
fun queryInvitedRoomMembersEvent(): RealmQuery<EventEntity> {
|
||||
return queryRoomMembersEvent().contains(EventEntityFields.CONTENT, "\"membership\":\"invite\"")
|
||||
}
|
||||
|
||||
fun queryRoomMemberEvent(userId: String): RealmQuery<EventEntity> {
|
||||
return queryRoomMembersEvent()
|
||||
.equalTo(EventEntityFields.STATE_KEY, userId)
|
||||
}
|
||||
|
||||
fun getLoaded(): Map<String, RoomMember> {
|
||||
return queryRoomMembersEvent()
|
||||
.findAll()
|
||||
.map { it.asDomain() }
|
||||
.associateBy { it.stateKey!! }
|
||||
.mapValues { it.value.content.toModel<RoomMember>()!! }
|
||||
}
|
||||
|
||||
fun getNumberOfJoinedMembers(): Int {
|
||||
return roomSummary?.joinedMembersCount
|
||||
?: getLoaded().filterValues { it.membership == Membership.JOIN }.size
|
||||
?: queryJoinedRoomMembersEvent().findAll().size
|
||||
}
|
||||
|
||||
fun getNumberOfInvitedMembers(): Int {
|
||||
return roomSummary?.invitedMembersCount
|
||||
?: getLoaded().filterValues { it.membership == Membership.INVITE }.size
|
||||
?: queryInvitedRoomMembersEvent().findAll().size
|
||||
}
|
||||
|
||||
fun getNumberOfMembers(): Int {
|
||||
|
@ -133,4 +134,4 @@ internal class RoomMembers(private val realm: Realm,
|
|||
.toList()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,16 +20,19 @@ import arrow.core.Try
|
|||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvent
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
||||
import im.vector.matrix.android.internal.database.helper.deleteOnCascade
|
||||
import im.vector.matrix.android.internal.database.helper.isUnlinked
|
||||
import im.vector.matrix.android.internal.database.helper.merge
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
import im.vector.matrix.android.internal.database.query.create
|
||||
import im.vector.matrix.android.internal.database.query.find
|
||||
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.user.UserEntityFactory
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
import io.realm.kotlin.createObject
|
||||
import timber.log.Timber
|
||||
|
@ -153,8 +156,13 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
|||
currentChunk.isLastBackward = true
|
||||
} else {
|
||||
Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}")
|
||||
currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())
|
||||
|
||||
val userEntities = ArrayList<UserEntity>(receivedChunk.events.size + receivedChunk.stateEvents.size)
|
||||
for (event in receivedChunk.events) {
|
||||
currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())
|
||||
UserEntityFactory.create(event)?.also {
|
||||
userEntities.add(it)
|
||||
}
|
||||
}
|
||||
// Then we merge chunks if needed
|
||||
if (currentChunk != prevChunk && prevChunk != null) {
|
||||
currentChunk = handleMerge(roomEntity, direction, currentChunk, prevChunk)
|
||||
|
@ -170,7 +178,13 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
|||
}
|
||||
}
|
||||
roomEntity.addOrUpdate(currentChunk)
|
||||
roomEntity.addStateEvents(receivedChunk.stateEvents, isUnlinked = currentChunk.isUnlinked())
|
||||
for (stateEvent in receivedChunk.stateEvents) {
|
||||
roomEntity.addStateEvent(stateEvent, isUnlinked = currentChunk.isUnlinked())
|
||||
UserEntityFactory.create(stateEvent)?.also {
|
||||
userEntities.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(userEntities)
|
||||
}
|
||||
}
|
||||
.map {
|
||||
|
|
|
@ -22,14 +22,18 @@ import im.vector.matrix.android.api.session.events.model.Event
|
|||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent
|
||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||
import im.vector.matrix.android.internal.database.helper.add
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvent
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
||||
import im.vector.matrix.android.internal.database.helper.lastStateIndex
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
import im.vector.matrix.android.internal.database.query.find
|
||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
|
@ -40,6 +44,7 @@ import im.vector.matrix.android.internal.session.notification.ProcessEventForPus
|
|||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
import im.vector.matrix.android.internal.session.sync.model.*
|
||||
import im.vector.matrix.android.internal.session.user.UserEntityFactory
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import io.realm.Realm
|
||||
|
@ -118,7 +123,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
Timber.v("Handle join sync for room $roomId")
|
||||
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: realm.createObject(roomId)
|
||||
?: realm.createObject(roomId)
|
||||
|
||||
if (roomEntity.membership == Membership.INVITE) {
|
||||
roomEntity.chunks.deleteAllFromRealm()
|
||||
|
@ -133,43 +138,30 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
|
||||
// State event
|
||||
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
||||
val userEntities = ArrayList<UserEntity>(roomSync.state.events.size)
|
||||
val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset
|
||||
roomEntity.addStateEvents(roomSync.state.events, filterDuplicates = true, stateIndex = untimelinedStateIndex)
|
||||
|
||||
// Give info to crypto module
|
||||
roomSync.state.events.forEach {
|
||||
cryptoManager.onStateEvent(roomId, it)
|
||||
roomSync.state.events.forEach { event ->
|
||||
roomEntity.addStateEvent(event, filterDuplicates = true, stateIndex = untimelinedStateIndex)
|
||||
// Give info to crypto module
|
||||
cryptoManager.onStateEvent(roomId, event)
|
||||
UserEntityFactory.create(event)?.also {
|
||||
userEntities.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(userEntities)
|
||||
}
|
||||
|
||||
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
|
||||
val timelineStateOffset = if (isInitialSync || roomSync.timeline.limited.not()) 0 else stateIndexOffset
|
||||
val chunkEntity = handleTimelineEvents(
|
||||
realm,
|
||||
roomId,
|
||||
roomEntity,
|
||||
roomSync.timeline.events,
|
||||
roomSync.timeline.prevToken,
|
||||
roomSync.timeline.limited,
|
||||
timelineStateOffset
|
||||
)
|
||||
roomEntity.addOrUpdate(chunkEntity)
|
||||
|
||||
// Give info to crypto module
|
||||
roomSync.timeline.events.forEach {
|
||||
cryptoManager.onLiveEvent(roomId, it)
|
||||
}
|
||||
|
||||
// Try to remove local echo
|
||||
val transactionIds = roomSync.timeline.events.mapNotNull { it.unsignedData?.transactionId }
|
||||
transactionIds.forEach {
|
||||
val sendingEventEntity = roomEntity.sendingTimelineEvents.find(it)
|
||||
if (sendingEventEntity != null) {
|
||||
Timber.v("Remove local echo for tx:$it")
|
||||
roomEntity.sendingTimelineEvents.remove(sendingEventEntity)
|
||||
} else {
|
||||
Timber.v("Can't find corresponding local echo for tx:$it")
|
||||
}
|
||||
}
|
||||
}
|
||||
roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications)
|
||||
|
||||
|
@ -189,10 +181,10 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
InvitedRoomSync): RoomEntity {
|
||||
Timber.v("Handle invited sync for room $roomId")
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: realm.createObject(roomId)
|
||||
?: realm.createObject(roomId)
|
||||
roomEntity.membership = Membership.INVITE
|
||||
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
||||
val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.inviteState.events)
|
||||
val chunkEntity = handleTimelineEvents(realm, roomEntity, roomSync.inviteState.events)
|
||||
roomEntity.addOrUpdate(chunkEntity)
|
||||
}
|
||||
roomSummaryUpdater.update(realm, roomId, Membership.INVITE)
|
||||
|
@ -203,7 +195,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
roomId: String,
|
||||
roomSync: RoomSync): RoomEntity {
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: realm.createObject(roomId)
|
||||
?: realm.createObject(roomId)
|
||||
|
||||
roomEntity.membership = Membership.LEAVE
|
||||
roomEntity.chunks.deleteAllFromRealm()
|
||||
|
@ -212,13 +204,13 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
}
|
||||
|
||||
private fun handleTimelineEvents(realm: Realm,
|
||||
roomId: String,
|
||||
roomEntity: RoomEntity,
|
||||
eventList: List<Event>,
|
||||
prevToken: String? = null,
|
||||
isLimited: Boolean = true,
|
||||
stateIndexOffset: Int = 0): ChunkEntity {
|
||||
|
||||
val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||
val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomEntity.roomId)
|
||||
val chunkEntity = if (!isLimited && lastChunk != null) {
|
||||
lastChunk
|
||||
} else {
|
||||
|
@ -226,13 +218,31 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
}
|
||||
lastChunk?.isLastForward = false
|
||||
chunkEntity.isLastForward = true
|
||||
chunkEntity.addAll(roomId, eventList, PaginationDirection.FORWARDS, stateIndexOffset)
|
||||
|
||||
//update eventAnnotationSummary here?
|
||||
|
||||
val userEntities = ArrayList<UserEntity>(eventList.size)
|
||||
for (event in eventList) {
|
||||
chunkEntity.add(roomEntity.roomId, event, PaginationDirection.FORWARDS, stateIndexOffset)
|
||||
// Give info to crypto module
|
||||
cryptoManager.onLiveEvent(roomEntity.roomId, event)
|
||||
// Try to remove local echo
|
||||
event.unsignedData?.transactionId?.also {
|
||||
val sendingEventEntity = roomEntity.sendingTimelineEvents.find(it)
|
||||
if (sendingEventEntity != null) {
|
||||
Timber.v("Remove local echo for tx:$it")
|
||||
roomEntity.sendingTimelineEvents.remove(sendingEventEntity)
|
||||
} else {
|
||||
Timber.v("Can't find corresponding local echo for tx:$it")
|
||||
}
|
||||
}
|
||||
UserEntityFactory.create(event)?.also {
|
||||
userEntities.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(userEntities)
|
||||
return chunkEntity
|
||||
}
|
||||
|
||||
|
||||
private fun handleEphemeral(realm: Realm,
|
||||
roomId: String,
|
||||
ephemeral: RoomSyncEphemeral) {
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.zhuinden.monarchy.Monarchy
|
|||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
|
@ -38,21 +39,6 @@ internal interface UpdateUserTask : Task<UpdateUserTask.Params, Unit> {
|
|||
internal class DefaultUpdateUserTask @Inject constructor(private val monarchy: Monarchy) : UpdateUserTask {
|
||||
|
||||
override suspend fun execute(params: UpdateUserTask.Params): Try<Unit> {
|
||||
return monarchy.tryTransactionSync { realm ->
|
||||
params.eventIds.forEach { eventId ->
|
||||
val event = EventEntity.where(realm, eventId).findFirst()?.asDomain()
|
||||
?: return@forEach
|
||||
val roomId = event.roomId ?: return@forEach
|
||||
val userId = event.stateKey ?: return@forEach
|
||||
val roomMember = RoomMembers(realm, roomId).get(userId) ?: return@forEach
|
||||
if (roomMember.membership != Membership.JOIN) return@forEach
|
||||
|
||||
val userEntity = UserEntity.where(realm, userId).findFirst()
|
||||
?: realm.createObject(UserEntity::class.java, userId)
|
||||
userEntity.displayName = roomMember.displayName ?: ""
|
||||
userEntity.avatarUrl = roomMember.avatarUrl ?: ""
|
||||
}
|
||||
}
|
||||
return Try.just(Unit)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019 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 im.vector.matrix.android.internal.session.user
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
|
||||
internal object UserEntityFactory {
|
||||
|
||||
fun create(event: Event): UserEntity? {
|
||||
if (event.type != EventType.STATE_ROOM_MEMBER) {
|
||||
return null
|
||||
}
|
||||
val roomMember = event.content.toModel<RoomMember>() ?: return null
|
||||
return UserEntity(event.stateKey ?: "",
|
||||
roomMember.displayName ?: "",
|
||||
roomMember.avatarUrl ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -21,11 +21,14 @@ import im.vector.matrix.android.api.session.events.model.EventType
|
|||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
import im.vector.matrix.android.internal.database.query.types
|
||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.TaskThread
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.tryTransactionAsync
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
import io.realm.OrderedCollectionChangeSet
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmResults
|
||||
|
@ -33,6 +36,7 @@ import io.realm.Sort
|
|||
import javax.inject.Inject
|
||||
|
||||
internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
|
||||
private val monarchy: Monarchy,
|
||||
private val updateUserTask: UpdateUserTask,
|
||||
private val taskExecutor: TaskExecutor)
|
||||
: RealmLiveEntityObserver<EventEntity>(realmConfiguration) {
|
||||
|
@ -45,16 +49,19 @@ internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfi
|
|||
}
|
||||
|
||||
override fun onChange(results: RealmResults<EventEntity>, changeSet: OrderedCollectionChangeSet) {
|
||||
val roomMembersEvents = changeSet.insertions
|
||||
.asSequence()
|
||||
.mapNotNull { results[it]?.eventId }
|
||||
.toList()
|
||||
|
||||
val taskParams = UpdateUserTask.Params(roomMembersEvents)
|
||||
updateUserTask
|
||||
.configureWith(taskParams)
|
||||
.executeOn(TaskThread.IO)
|
||||
.executeBy(taskExecutor)
|
||||
monarchy.tryTransactionSync { realm ->
|
||||
val userEntities = ArrayList<UserEntity>(changeSet.insertions.size)
|
||||
for (insertion in changeSet.insertions) {
|
||||
val roomMemberEvent = results[insertion] ?: continue
|
||||
val roomMemberTimelineEvent = roomMemberEvent.timelineEventEntity?.firstOrNull()
|
||||
?: continue
|
||||
val userEntity = UserEntity(roomMemberEvent.stateKey
|
||||
?: "", roomMemberTimelineEvent.senderName ?: "",
|
||||
roomMemberTimelineEvent.senderAvatar ?: "")
|
||||
userEntities.add(userEntity)
|
||||
}
|
||||
realm.insertOrUpdate(userEntities)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue