forked from GitHub-Mirror/riotX-android
Try to insert users directly to see if perfs are better [WIP]
This commit is contained in:
parent
b77310fe92
commit
10e4d0190f
@ -33,7 +33,7 @@ data class TimelineEvent(
|
|||||||
val localId: Long,
|
val localId: Long,
|
||||||
val displayIndex: Int,
|
val displayIndex: Int,
|
||||||
val senderName: String?,
|
val senderName: String?,
|
||||||
val isUniqueDisplayName: Boolean,
|
val isUniqueDisplayName: Boolean = false,
|
||||||
val senderAvatar: String?,
|
val senderAvatar: String?,
|
||||||
val sendState: SendState,
|
val sendState: SendState,
|
||||||
val annotations: EventAnnotationsSummary? = null
|
val annotations: EventAnnotationsSummary? = null
|
||||||
|
@ -103,7 +103,6 @@ internal fun ChunkEntity.updateSenderDataFor(eventIds: List<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
internal fun ChunkEntity.add(roomId: String,
|
internal fun ChunkEntity.add(roomId: String,
|
||||||
event: Event,
|
event: Event,
|
||||||
direction: PaginationDirection,
|
direction: PaginationDirection,
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.database.helper
|
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.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.send.SendState
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.internal.database.mapper.toEntity
|
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.model.TimelineEventEntity
|
||||||
import im.vector.matrix.android.internal.database.query.fastContains
|
import im.vector.matrix.android.internal.database.query.fastContains
|
||||||
import im.vector.matrix.android.internal.extensions.assertIsManaged
|
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 im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import okio.Okio
|
||||||
|
|
||||||
internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) {
|
internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) {
|
||||||
chunks.remove(chunkEntity)
|
chunks.remove(chunkEntity)
|
||||||
@ -37,25 +41,42 @@ internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun RoomEntity.addStateEvents(stateEvents: List<Event>,
|
internal fun RoomEntity.addStateEvent(stateEvent: Event,
|
||||||
stateIndex: Int = Int.MIN_VALUE,
|
stateIndex: Int = Int.MIN_VALUE,
|
||||||
filterDuplicates: Boolean = false,
|
filterDuplicates: Boolean = false,
|
||||||
isUnlinked: Boolean = false) {
|
isUnlinked: Boolean = false) {
|
||||||
assertIsManaged()
|
assertIsManaged()
|
||||||
|
if (stateEvent.eventId == null || (filterDuplicates && fastContains(stateEvent.eventId))) {
|
||||||
stateEvents.forEach { event ->
|
return
|
||||||
if (event.eventId == null || (filterDuplicates && fastContains(event.eventId))) {
|
} else {
|
||||||
return@forEach
|
val entity = stateEvent.toEntity(roomId).apply {
|
||||||
}
|
|
||||||
val eventEntity = event.toEntity(roomId).apply {
|
|
||||||
this.stateIndex = stateIndex
|
this.stateIndex = stateIndex
|
||||||
this.isUnlinked = isUnlinked
|
this.isUnlinked = isUnlinked
|
||||||
this.sendState = SendState.SYNCED
|
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) {
|
internal fun RoomEntity.addSendingEvent(event: Event) {
|
||||||
assertIsManaged()
|
assertIsManaged()
|
||||||
val senderId = event.senderId ?: return
|
val senderId = event.senderId ?: return
|
||||||
|
@ -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.group.GroupSummaryUpdater
|
||||||
import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater
|
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.room.prune.EventsPruner
|
||||||
import im.vector.matrix.android.internal.session.user.UserEntityUpdater
|
|
||||||
import im.vector.matrix.android.internal.util.md5
|
import im.vector.matrix.android.internal.util.md5
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -129,10 +128,6 @@ internal abstract class SessionModule {
|
|||||||
@IntoSet
|
@IntoSet
|
||||||
abstract fun bindEventRelationsAggregationUpdater(groupSummaryUpdater: EventRelationsAggregationUpdater): LiveEntityObserver
|
abstract fun bindEventRelationsAggregationUpdater(groupSummaryUpdater: EventRelationsAggregationUpdater): LiveEntityObserver
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoSet
|
|
||||||
abstract fun bindUserEntityUpdater(groupSummaryUpdater: UserEntityUpdater): LiveEntityObserver
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindInitialSyncProgressService(initialSyncProgressService: DefaultInitialSyncProgressService): InitialSyncProgressService
|
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.auth.data.Credentials
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
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.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.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.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
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.prev
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
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 im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -42,32 +41,25 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona
|
|||||||
fun resolve(roomId: String): String? {
|
fun resolve(roomId: String): String? {
|
||||||
var res: String? = null
|
var res: String? = null
|
||||||
monarchy.doWithRealm { realm ->
|
monarchy.doWithRealm { realm ->
|
||||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
|
||||||
val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()?.asDomain()
|
val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()?.asDomain()
|
||||||
res = roomName?.content.toModel<RoomAvatarContent>()?.avatarUrl
|
res = roomName?.content.toModel<RoomAvatarContent>()?.avatarUrl
|
||||||
if (!res.isNullOrEmpty()) {
|
if (!res.isNullOrEmpty()) {
|
||||||
return@doWithRealm
|
return@doWithRealm
|
||||||
}
|
}
|
||||||
val roomMembers = RoomMembers(realm, roomId)
|
val roomMembers = RoomMembers(realm, roomId)
|
||||||
val members = roomMembers.getLoaded()
|
val members = roomMembers.queryRoomMembersEvent().findAll()
|
||||||
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)
|
// 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) {
|
if (members.size == 1) {
|
||||||
res = members.entries.first().value.avatarUrl
|
res = members.firstOrNull()?.toRoomMember()?.avatarUrl
|
||||||
} else if (members.size == 2) {
|
} else if (members.size == 2) {
|
||||||
val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull()
|
val firstOtherMember = members.where().notEqualTo(EventEntityFields.STATE_KEY, credentials.userId).findFirst()
|
||||||
res = firstOtherMember?.avatarUrl
|
res = firstOtherMember?.toRoomMember()?.avatarUrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
return res
|
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.api.session.room.model.RoomTopicContent
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
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.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.RoomSummaryEntity
|
||||||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||||
import im.vector.matrix.android.internal.database.query.latestEvent
|
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 latestEvent = TimelineEventEntity.latestEvent(realm, roomId, includedTypes = PREVIEWABLE_TYPES)
|
||||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
|
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.displayName = roomDisplayNameResolver.resolve(roomId).toString()
|
||||||
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
|
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
|
||||||
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
|
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
|
||||||
roomSummaryEntity.latestEvent = latestEvent
|
roomSummaryEntity.latestEvent = latestEvent
|
||||||
roomSummaryEntity.otherMemberIds.clear()
|
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 arrow.core.Try
|
||||||
import com.zhuinden.monarchy.Monarchy
|
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.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.addStateEvents
|
||||||
import im.vector.matrix.android.internal.database.helper.updateSenderData
|
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.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.database.query.where
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
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.RoomAPI
|
||||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
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.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.task.Task
|
||||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.kotlin.createObject
|
import io.realm.kotlin.createObject
|
||||||
|
import okhttp3.ResponseBody
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal interface LoadRoomMembersTask : Task<LoadRoomMembersTask.Params, Boolean> {
|
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
|
return monarchy
|
||||||
.tryTransactionSync { realm ->
|
.tryTransactionSync { realm ->
|
||||||
// We ignore all the already known members
|
// We ignore all the already known members
|
||||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||||
?: realm.createObject(roomId)
|
?: realm.createObject(roomId)
|
||||||
|
|
||||||
val roomMembers = RoomMembers(realm, roomId).getLoaded()
|
val userEntities = ArrayList<UserEntity>(response.roomMemberEvents.size)
|
||||||
val eventsToInsert = response.roomMemberEvents.filter { !roomMembers.containsKey(it.stateKey) }
|
for (roomMemberEvent in response.roomMemberEvents) {
|
||||||
roomEntity.addStateEvents(eventsToInsert)
|
roomEntity.addStateEvent(roomMemberEvent)
|
||||||
|
UserEntityFactory.create(roomMemberEvent)?.also {
|
||||||
|
userEntities.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
realm.insertOrUpdate(userEntities)
|
||||||
roomEntity.chunks.flatMap { it.timelineEvents }.forEach {
|
roomEntity.chunks.flatMap { it.timelineEvents }.forEach {
|
||||||
it.updateSenderData()
|
it.updateSenderData()
|
||||||
}
|
}
|
||||||
roomEntity.areAllMembersLoaded = true
|
roomEntity.areAllMembersLoaded = true
|
||||||
roomSummaryUpdater.update(realm, roomId)
|
roomSummaryUpdater.update(realm, roomId)
|
||||||
}
|
}
|
||||||
.map { response }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun areAllMembersAlreadyLoaded(roomId: String): Boolean {
|
private fun areAllMembersAlreadyLoaded(roomId: String): Boolean {
|
||||||
|
@ -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.Membership
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomAliasesContent
|
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.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.api.session.room.model.RoomNameContent
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
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.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.RoomEntity
|
||||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
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.prev
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
import io.realm.RealmResults
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,7 +42,6 @@ import javax.inject.Inject
|
|||||||
*/
|
*/
|
||||||
internal class RoomDisplayNameResolver @Inject constructor(private val context: Context,
|
internal class RoomDisplayNameResolver @Inject constructor(private val context: Context,
|
||||||
private val monarchy: Monarchy,
|
private val monarchy: Monarchy,
|
||||||
private val roomMemberDisplayNameResolver: RoomMemberDisplayNameResolver,
|
|
||||||
private val credentials: Credentials
|
private val credentials: Credentials
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -78,48 +80,59 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
|||||||
}
|
}
|
||||||
|
|
||||||
val roomMembers = RoomMembers(realm, roomId)
|
val roomMembers = RoomMembers(realm, roomId)
|
||||||
val loadedMembers = roomMembers.getLoaded()
|
val loadedMembers = roomMembers.queryRoomMembersEvent().findAll()
|
||||||
val otherRoomMembers = loadedMembers.filterKeys { it != credentials.userId }
|
val otherMembersSubset = loadedMembers.where()
|
||||||
|
.notEqualTo(EventEntityFields.STATE_KEY, credentials.userId)
|
||||||
|
.limit(3)
|
||||||
|
.findAll()
|
||||||
|
|
||||||
if (roomEntity?.membership == Membership.INVITE) {
|
if (roomEntity?.membership == Membership.INVITE) {
|
||||||
val inviteMeEvent = roomMembers.queryRoomMemberEvent(credentials.userId).findFirst()
|
val inviteMeEvent = roomMembers.queryRoomMemberEvent(credentials.userId).findFirst()
|
||||||
val inviterId = inviteMeEvent?.sender
|
val inviterId = inviteMeEvent?.sender
|
||||||
name = if (inviterId != null && otherRoomMembers.containsKey(inviterId)) {
|
name = if (inviterId != null) {
|
||||||
roomMemberDisplayNameResolver.resolve(inviterId, otherRoomMembers)
|
val inviterMemberEvent = loadedMembers.where().equalTo(EventEntityFields.STATE_KEY, inviterId).findFirst()
|
||||||
|
inviterMemberEvent?.toRoomMember()?.displayName
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.room_displayname_room_invite)
|
context.getString(R.string.room_displayname_room_invite)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
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
|
roomSummary.heroes
|
||||||
} else {
|
} else {
|
||||||
otherRoomMembers.keys.toList()
|
otherMembersSubset.mapNotNull { it.stateKey }
|
||||||
}
|
}
|
||||||
|
name = when (memberIds.size) {
|
||||||
val nbOfOtherMembers = memberIds.size
|
0 -> context.getString(R.string.room_displayname_empty_room)
|
||||||
|
1 -> resolveRoomMember(otherMembersSubset[0], roomMembers)
|
||||||
when (nbOfOtherMembers) {
|
2 -> context.getString(R.string.room_displayname_two_members,
|
||||||
0 -> name = context.getString(R.string.room_displayname_empty_room)
|
resolveRoomMember(otherMembersSubset[0], roomMembers),
|
||||||
1 -> name = roomMemberDisplayNameResolver.resolve(memberIds[0], otherRoomMembers)
|
resolveRoomMember(otherMembersSubset[1], roomMembers)
|
||||||
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 -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
||||||
else -> {
|
|
||||||
val member = memberIds[0]
|
|
||||||
name = context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
|
||||||
roomMembers.getNumberOfJoinedMembers() - 1,
|
roomMembers.getNumberOfJoinedMembers() - 1,
|
||||||
roomMemberDisplayNameResolver.resolve(member, otherRoomMembers),
|
resolveRoomMember(otherMembersSubset[0], roomMembers),
|
||||||
roomMembers.getNumberOfJoinedMembers() - 1)
|
roomMembers.getNumberOfJoinedMembers() - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return@doWithRealm
|
return@doWithRealm
|
||||||
}
|
}
|
||||||
return name ?: roomId
|
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.
|
* This class is an helper around STATE_ROOM_MEMBER events.
|
||||||
* It allows to get the live membership of a user.
|
* It allows to get the live membership of a user.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
internal class RoomMembers(private val realm: Realm,
|
internal class RoomMembers(private val realm: Realm,
|
||||||
private val roomId: String
|
private val roomId: String
|
||||||
) {
|
) {
|
||||||
@ -72,27 +73,27 @@ internal class RoomMembers(private val realm: Realm,
|
|||||||
.isNotNull(EventEntityFields.CONTENT)
|
.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> {
|
fun queryRoomMemberEvent(userId: String): RealmQuery<EventEntity> {
|
||||||
return queryRoomMembersEvent()
|
return queryRoomMembersEvent()
|
||||||
.equalTo(EventEntityFields.STATE_KEY, userId)
|
.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 {
|
fun getNumberOfJoinedMembers(): Int {
|
||||||
return roomSummary?.joinedMembersCount
|
return roomSummary?.joinedMembersCount
|
||||||
?: getLoaded().filterValues { it.membership == Membership.JOIN }.size
|
?: queryJoinedRoomMembersEvent().findAll().size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNumberOfInvitedMembers(): Int {
|
fun getNumberOfInvitedMembers(): Int {
|
||||||
return roomSummary?.invitedMembersCount
|
return roomSummary?.invitedMembersCount
|
||||||
?: getLoaded().filterValues { it.membership == Membership.INVITE }.size
|
?: queryInvitedRoomMembersEvent().findAll().size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNumberOfMembers(): Int {
|
fun getNumberOfMembers(): Int {
|
||||||
|
@ -20,16 +20,19 @@ import arrow.core.Try
|
|||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.internal.database.helper.addAll
|
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.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.addStateEvents
|
||||||
import im.vector.matrix.android.internal.database.helper.deleteOnCascade
|
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.isUnlinked
|
||||||
import im.vector.matrix.android.internal.database.helper.merge
|
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.ChunkEntity
|
||||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
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.create
|
||||||
import im.vector.matrix.android.internal.database.query.find
|
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.findAllIncludingEvents
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
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 im.vector.matrix.android.internal.util.tryTransactionSync
|
||||||
import io.realm.kotlin.createObject
|
import io.realm.kotlin.createObject
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -153,8 +156,13 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
|||||||
currentChunk.isLastBackward = true
|
currentChunk.isLastBackward = true
|
||||||
} else {
|
} else {
|
||||||
Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}")
|
Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}")
|
||||||
|
val userEntities = ArrayList<UserEntity>(receivedChunk.events.size + receivedChunk.stateEvents.size)
|
||||||
|
for (event in receivedChunk.events) {
|
||||||
currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())
|
currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())
|
||||||
|
UserEntityFactory.create(event)?.also {
|
||||||
|
userEntities.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
// Then we merge chunks if needed
|
// Then we merge chunks if needed
|
||||||
if (currentChunk != prevChunk && prevChunk != null) {
|
if (currentChunk != prevChunk && prevChunk != null) {
|
||||||
currentChunk = handleMerge(roomEntity, direction, currentChunk, prevChunk)
|
currentChunk = handleMerge(roomEntity, direction, currentChunk, prevChunk)
|
||||||
@ -170,7 +178,13 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
roomEntity.addOrUpdate(currentChunk)
|
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 {
|
.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.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
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.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.api.session.room.model.tag.RoomTagContent
|
||||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
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.addAll
|
||||||
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
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.addStateEvents
|
||||||
import im.vector.matrix.android.internal.database.helper.lastStateIndex
|
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.ChunkEntity
|
||||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
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.find
|
||||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
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.RoomSummaryUpdater
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
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.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.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import im.vector.matrix.android.internal.task.configureWith
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
@ -133,43 +138,30 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||||||
|
|
||||||
// State event
|
// State event
|
||||||
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
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
|
val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset
|
||||||
roomEntity.addStateEvents(roomSync.state.events, filterDuplicates = true, stateIndex = untimelinedStateIndex)
|
roomSync.state.events.forEach { event ->
|
||||||
|
roomEntity.addStateEvent(event, filterDuplicates = true, stateIndex = untimelinedStateIndex)
|
||||||
// Give info to crypto module
|
// Give info to crypto module
|
||||||
roomSync.state.events.forEach {
|
cryptoManager.onStateEvent(roomId, event)
|
||||||
cryptoManager.onStateEvent(roomId, it)
|
UserEntityFactory.create(event)?.also {
|
||||||
|
userEntities.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
realm.insertOrUpdate(userEntities)
|
||||||
|
}
|
||||||
|
|
||||||
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
|
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
|
||||||
val timelineStateOffset = if (isInitialSync || roomSync.timeline.limited.not()) 0 else stateIndexOffset
|
val timelineStateOffset = if (isInitialSync || roomSync.timeline.limited.not()) 0 else stateIndexOffset
|
||||||
val chunkEntity = handleTimelineEvents(
|
val chunkEntity = handleTimelineEvents(
|
||||||
realm,
|
realm,
|
||||||
roomId,
|
roomEntity,
|
||||||
roomSync.timeline.events,
|
roomSync.timeline.events,
|
||||||
roomSync.timeline.prevToken,
|
roomSync.timeline.prevToken,
|
||||||
roomSync.timeline.limited,
|
roomSync.timeline.limited,
|
||||||
timelineStateOffset
|
timelineStateOffset
|
||||||
)
|
)
|
||||||
roomEntity.addOrUpdate(chunkEntity)
|
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)
|
roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications)
|
||||||
|
|
||||||
@ -192,7 +184,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||||||
?: realm.createObject(roomId)
|
?: realm.createObject(roomId)
|
||||||
roomEntity.membership = Membership.INVITE
|
roomEntity.membership = Membership.INVITE
|
||||||
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
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)
|
roomEntity.addOrUpdate(chunkEntity)
|
||||||
}
|
}
|
||||||
roomSummaryUpdater.update(realm, roomId, Membership.INVITE)
|
roomSummaryUpdater.update(realm, roomId, Membership.INVITE)
|
||||||
@ -212,13 +204,13 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleTimelineEvents(realm: Realm,
|
private fun handleTimelineEvents(realm: Realm,
|
||||||
roomId: String,
|
roomEntity: RoomEntity,
|
||||||
eventList: List<Event>,
|
eventList: List<Event>,
|
||||||
prevToken: String? = null,
|
prevToken: String? = null,
|
||||||
isLimited: Boolean = true,
|
isLimited: Boolean = true,
|
||||||
stateIndexOffset: Int = 0): ChunkEntity {
|
stateIndexOffset: Int = 0): ChunkEntity {
|
||||||
|
|
||||||
val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomEntity.roomId)
|
||||||
val chunkEntity = if (!isLimited && lastChunk != null) {
|
val chunkEntity = if (!isLimited && lastChunk != null) {
|
||||||
lastChunk
|
lastChunk
|
||||||
} else {
|
} else {
|
||||||
@ -226,13 +218,31 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||||||
}
|
}
|
||||||
lastChunk?.isLastForward = false
|
lastChunk?.isLastForward = false
|
||||||
chunkEntity.isLastForward = true
|
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
|
return chunkEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun handleEphemeral(realm: Realm,
|
private fun handleEphemeral(realm: Realm,
|
||||||
roomId: String,
|
roomId: String,
|
||||||
ephemeral: RoomSyncEphemeral) {
|
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.api.session.room.model.Membership
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
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.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.model.UserEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.session.SessionScope
|
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 {
|
internal class DefaultUpdateUserTask @Inject constructor(private val monarchy: Monarchy) : UpdateUserTask {
|
||||||
|
|
||||||
override suspend fun execute(params: UpdateUserTask.Params): Try<Unit> {
|
override suspend fun execute(params: UpdateUserTask.Params): Try<Unit> {
|
||||||
return monarchy.tryTransactionSync { realm ->
|
return Try.just(Unit)
|
||||||
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 ?: ""
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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.RealmLiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
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.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.database.query.types
|
||||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.TaskThread
|
import im.vector.matrix.android.internal.task.TaskThread
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
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.OrderedCollectionChangeSet
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
@ -33,6 +36,7 @@ import io.realm.Sort
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
|
internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
|
||||||
|
private val monarchy: Monarchy,
|
||||||
private val updateUserTask: UpdateUserTask,
|
private val updateUserTask: UpdateUserTask,
|
||||||
private val taskExecutor: TaskExecutor)
|
private val taskExecutor: TaskExecutor)
|
||||||
: RealmLiveEntityObserver<EventEntity>(realmConfiguration) {
|
: RealmLiveEntityObserver<EventEntity>(realmConfiguration) {
|
||||||
@ -45,16 +49,19 @@ internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onChange(results: RealmResults<EventEntity>, changeSet: OrderedCollectionChangeSet) {
|
override fun onChange(results: RealmResults<EventEntity>, changeSet: OrderedCollectionChangeSet) {
|
||||||
val roomMembersEvents = changeSet.insertions
|
monarchy.tryTransactionSync { realm ->
|
||||||
.asSequence()
|
val userEntities = ArrayList<UserEntity>(changeSet.insertions.size)
|
||||||
.mapNotNull { results[it]?.eventId }
|
for (insertion in changeSet.insertions) {
|
||||||
.toList()
|
val roomMemberEvent = results[insertion] ?: continue
|
||||||
|
val roomMemberTimelineEvent = roomMemberEvent.timelineEventEntity?.firstOrNull()
|
||||||
val taskParams = UpdateUserTask.Params(roomMembersEvents)
|
?: continue
|
||||||
updateUserTask
|
val userEntity = UserEntity(roomMemberEvent.stateKey
|
||||||
.configureWith(taskParams)
|
?: "", roomMemberTimelineEvent.senderName ?: "",
|
||||||
.executeOn(TaskThread.IO)
|
roomMemberTimelineEvent.senderAvatar ?: "")
|
||||||
.executeBy(taskExecutor)
|
userEntities.add(userEntity)
|
||||||
|
}
|
||||||
|
realm.insertOrUpdate(userEntities)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user