mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Start branching TimelineEventEntity
This commit is contained in:
parent
b37877746a
commit
cbfd2af74b
24 changed files with 251 additions and 371 deletions
|
@ -18,25 +18,6 @@ package im.vector.matrix.android.session.room.timeline
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.InstrumentedTest
|
import im.vector.matrix.android.InstrumentedTest
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
|
||||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
|
||||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
|
||||||
import im.vector.matrix.android.internal.database.model.SessionRealmModule
|
|
||||||
import im.vector.matrix.android.internal.session.room.EventRelationExtractor
|
|
||||||
import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor
|
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline
|
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory
|
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
|
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
|
||||||
import im.vector.matrix.android.testCoroutineDispatchers
|
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmConfiguration
|
|
||||||
import org.amshove.kluent.shouldEqual
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
|
|
||||||
internal class TimelineTest : InstrumentedTest {
|
internal class TimelineTest : InstrumentedTest {
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,14 @@ package im.vector.matrix.android.internal.database.helper
|
||||||
|
|
||||||
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.events.model.EventType
|
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.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.mapper.toEntity
|
import im.vector.matrix.android.internal.database.mapper.toEntity
|
||||||
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.EventEntity
|
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
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.model.TimelineEventEntityFields
|
||||||
|
import im.vector.matrix.android.internal.database.query.find
|
||||||
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.extensions.assertIsManaged
|
import im.vector.matrix.android.internal.extensions.assertIsManaged
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||||
import io.realm.Sort
|
import io.realm.Sort
|
||||||
|
@ -32,12 +33,12 @@ import io.realm.Sort
|
||||||
// By default if a chunk is empty we consider it unlinked
|
// By default if a chunk is empty we consider it unlinked
|
||||||
internal fun ChunkEntity.isUnlinked(): Boolean {
|
internal fun ChunkEntity.isUnlinked(): Boolean {
|
||||||
assertIsManaged()
|
assertIsManaged()
|
||||||
return events.where().equalTo(EventEntityFields.IS_UNLINKED, false).findAll().isEmpty()
|
return timelineEvents.where().equalTo(TimelineEventEntityFields.ROOT.IS_UNLINKED, false).findAll().isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ChunkEntity.deleteOnCascade() {
|
internal fun ChunkEntity.deleteOnCascade() {
|
||||||
assertIsManaged()
|
assertIsManaged()
|
||||||
this.events.deleteAllFromRealm()
|
this.timelineEvents.deleteAllFromRealm()
|
||||||
this.deleteFromRealm()
|
this.deleteFromRealm()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,20 +51,22 @@ internal fun ChunkEntity.merge(roomId: String,
|
||||||
val isUnlinked = isCurrentChunkUnlinked && isChunkToMergeUnlinked
|
val isUnlinked = isCurrentChunkUnlinked && isChunkToMergeUnlinked
|
||||||
|
|
||||||
if (isCurrentChunkUnlinked && !isChunkToMergeUnlinked) {
|
if (isCurrentChunkUnlinked && !isChunkToMergeUnlinked) {
|
||||||
this.events.forEach { it.isUnlinked = false }
|
this.timelineEvents.forEach { it.root?.isUnlinked = false }
|
||||||
}
|
}
|
||||||
val eventsToMerge: List<EventEntity>
|
val eventsToMerge: List<TimelineEventEntity>
|
||||||
if (direction == PaginationDirection.FORWARDS) {
|
if (direction == PaginationDirection.FORWARDS) {
|
||||||
this.nextToken = chunkToMerge.nextToken
|
this.nextToken = chunkToMerge.nextToken
|
||||||
this.isLastForward = chunkToMerge.isLastForward
|
this.isLastForward = chunkToMerge.isLastForward
|
||||||
eventsToMerge = chunkToMerge.events.sort(EventEntityFields.DISPLAY_INDEX, Sort.ASCENDING)
|
eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.ASCENDING)
|
||||||
} else {
|
} else {
|
||||||
this.prevToken = chunkToMerge.prevToken
|
this.prevToken = chunkToMerge.prevToken
|
||||||
this.isLastBackward = chunkToMerge.isLastBackward
|
this.isLastBackward = chunkToMerge.isLastBackward
|
||||||
eventsToMerge = chunkToMerge.events.sort(EventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
|
eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING)
|
||||||
}
|
}
|
||||||
eventsToMerge.forEach {
|
eventsToMerge.forEach {
|
||||||
add(roomId, it.asDomain(), direction, isUnlinked = isUnlinked)
|
it.root?.let { root ->
|
||||||
|
add(roomId, root.asDomain(), direction, isUnlinked = isUnlinked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +89,7 @@ internal fun ChunkEntity.add(roomId: String,
|
||||||
isUnlinked: Boolean = false) {
|
isUnlinked: Boolean = false) {
|
||||||
|
|
||||||
assertIsManaged()
|
assertIsManaged()
|
||||||
if (event.eventId != null && events.fastContains(event.eventId)) {
|
if (event.eventId != null && timelineEvents.find(event.eventId) != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var currentDisplayIndex = lastDisplayIndex(direction, 0)
|
var currentDisplayIndex = lastDisplayIndex(direction, 0)
|
||||||
|
@ -101,21 +104,22 @@ internal fun ChunkEntity.add(roomId: String,
|
||||||
if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(event.getClearType())) {
|
if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(event.getClearType())) {
|
||||||
currentStateIndex += 1
|
currentStateIndex += 1
|
||||||
forwardsStateIndex = currentStateIndex
|
forwardsStateIndex = currentStateIndex
|
||||||
} else if (direction == PaginationDirection.BACKWARDS && events.isNotEmpty()) {
|
} else if (direction == PaginationDirection.BACKWARDS && timelineEvents.isNotEmpty()) {
|
||||||
val lastEventType = events.last()?.type ?: ""
|
val lastEventType = timelineEvents.last()?.root?.type ?: ""
|
||||||
if (EventType.isStateEvent(lastEventType)) {
|
if (EventType.isStateEvent(lastEventType)) {
|
||||||
currentStateIndex -= 1
|
currentStateIndex -= 1
|
||||||
backwardsStateIndex = currentStateIndex
|
backwardsStateIndex = currentStateIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val eventEntity = event.toEntity(roomId).apply {
|
|
||||||
this.stateIndex = currentStateIndex
|
val eventEntity = TimelineEventEntity().apply {
|
||||||
this.isUnlinked = isUnlinked
|
this.root = event.toEntity(roomId)
|
||||||
this.displayIndex = currentDisplayIndex
|
this.eventId = event.eventId ?: ""
|
||||||
this.sendState = SendState.SYNCED
|
this.roomId = roomId
|
||||||
|
this.annotations = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst()
|
||||||
}
|
}
|
||||||
val position = if (direction == PaginationDirection.FORWARDS) 0 else this.events.size
|
val position = if (direction == PaginationDirection.FORWARDS) 0 else this.timelineEvents.size
|
||||||
events.add(position, eventEntity)
|
timelineEvents.add(position, eventEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
|
internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
|
||||||
|
|
|
@ -21,6 +21,7 @@ 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
|
||||||
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.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
|
||||||
|
|
||||||
|
@ -60,5 +61,10 @@ internal fun RoomEntity.addSendingEvent(event: Event) {
|
||||||
val eventEntity = event.toEntity(roomId).apply {
|
val eventEntity = event.toEntity(roomId).apply {
|
||||||
this.sendState = SendState.UNSENT
|
this.sendState = SendState.UNSENT
|
||||||
}
|
}
|
||||||
sendingTimelineEvents.add(0, eventEntity)
|
val timelineEventEntity = TimelineEventEntity().also {
|
||||||
|
it.root = eventEntity
|
||||||
|
it.eventId = event.eventId ?: ""
|
||||||
|
it.roomId = roomId
|
||||||
|
}
|
||||||
|
sendingTimelineEvents.add(0, timelineEventEntity)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,10 @@ package im.vector.matrix.android.internal.database.mapper
|
||||||
import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.ReactionAggregatedSummary
|
import im.vector.matrix.android.api.session.room.model.ReactionAggregatedSummary
|
||||||
|
import im.vector.matrix.android.internal.database.model.EditAggregatedSummaryEntity
|
||||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntity
|
||||||
|
import io.realm.RealmList
|
||||||
|
|
||||||
internal object EventAnnotationsSummaryMapper {
|
internal object EventAnnotationsSummaryMapper {
|
||||||
fun map(annotationsSummary: EventAnnotationsSummaryEntity): EventAnnotationsSummary {
|
fun map(annotationsSummary: EventAnnotationsSummaryEntity): EventAnnotationsSummary {
|
||||||
|
@ -45,6 +48,35 @@ internal object EventAnnotationsSummaryMapper {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun map(annotationsSummary: EventAnnotationsSummary, roomId: String): EventAnnotationsSummaryEntity {
|
||||||
|
val eventAnnotationsSummaryEntity = EventAnnotationsSummaryEntity()
|
||||||
|
eventAnnotationsSummaryEntity.eventId = annotationsSummary.eventId
|
||||||
|
eventAnnotationsSummaryEntity.roomId = roomId
|
||||||
|
eventAnnotationsSummaryEntity.editSummary = annotationsSummary.editSummary?.let {
|
||||||
|
EditAggregatedSummaryEntity(
|
||||||
|
ContentMapper.map(it.aggregatedContent),
|
||||||
|
RealmList<String>().apply { addAll(it.sourceEvents) },
|
||||||
|
RealmList<String>().apply { addAll(it.localEchos) },
|
||||||
|
it.lastEditTs
|
||||||
|
)
|
||||||
|
}
|
||||||
|
eventAnnotationsSummaryEntity.reactionsSummary = annotationsSummary.reactionsSummary?.let {
|
||||||
|
RealmList<ReactionAggregatedSummaryEntity>().apply {
|
||||||
|
addAll(it.map {
|
||||||
|
ReactionAggregatedSummaryEntity(
|
||||||
|
it.key,
|
||||||
|
it.count,
|
||||||
|
it.addedByMe,
|
||||||
|
it.firstTimestamp,
|
||||||
|
RealmList<String>().apply { addAll(it.sourceEvents) },
|
||||||
|
RealmList<String>().apply { addAll(it.localEchoEvents) }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eventAnnotationsSummaryEntity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun EventAnnotationsSummaryEntity.asDomain(): EventAnnotationsSummary {
|
internal fun EventAnnotationsSummaryEntity.asDomain(): EventAnnotationsSummary {
|
||||||
|
|
|
@ -19,29 +19,21 @@ package im.vector.matrix.android.internal.database.mapper
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RoomSummaryMapper @Inject constructor(private val timelineEventFactory: TimelineEventFactory) {
|
internal class RoomSummaryMapper @Inject constructor() {
|
||||||
|
|
||||||
fun map(roomSummaryEntity: RoomSummaryEntity, getLatestEvent: Boolean = false): RoomSummary {
|
fun map(roomSummaryEntity: RoomSummaryEntity, getLatestEvent: Boolean = false): RoomSummary {
|
||||||
val tags = roomSummaryEntity.tags.map {
|
val tags = roomSummaryEntity.tags.map {
|
||||||
RoomTag(it.tagName, it.tagOrder)
|
RoomTag(it.tagName, it.tagOrder)
|
||||||
}
|
}
|
||||||
val latestEvent = if (getLatestEvent) {
|
|
||||||
roomSummaryEntity.latestEvent?.let {
|
|
||||||
timelineEventFactory.create(it, it.realm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
return RoomSummary(
|
return RoomSummary(
|
||||||
roomId = roomSummaryEntity.roomId,
|
roomId = roomSummaryEntity.roomId,
|
||||||
displayName = roomSummaryEntity.displayName ?: "",
|
displayName = roomSummaryEntity.displayName ?: "",
|
||||||
topic = roomSummaryEntity.topic ?: "",
|
topic = roomSummaryEntity.topic ?: "",
|
||||||
avatarUrl = roomSummaryEntity.avatarUrl ?: "",
|
avatarUrl = roomSummaryEntity.avatarUrl ?: "",
|
||||||
isDirect = roomSummaryEntity.isDirect,
|
isDirect = roomSummaryEntity.isDirect,
|
||||||
latestEvent = latestEvent,
|
latestEvent = roomSummaryEntity.latestEvent?.asDomain(),
|
||||||
otherMemberIds = roomSummaryEntity.otherMemberIds.toList(),
|
otherMemberIds = roomSummaryEntity.otherMemberIds.toList(),
|
||||||
highlightCount = roomSummaryEntity.highlightCount,
|
highlightCount = roomSummaryEntity.highlightCount,
|
||||||
notificationCount = roomSummaryEntity.notificationCount,
|
notificationCount = roomSummaryEntity.notificationCount,
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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.database.mapper
|
||||||
|
|
||||||
|
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.timeline.TimelineEvent
|
||||||
|
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||||
|
|
||||||
|
internal object TimelineEventMapper {
|
||||||
|
|
||||||
|
fun map(timelineEvent: TimelineEvent, roomId: String): TimelineEventEntity {
|
||||||
|
val timelineEventEntity = TimelineEventEntity()
|
||||||
|
timelineEventEntity.root = timelineEvent.root.toEntity(roomId)
|
||||||
|
timelineEventEntity.eventId = timelineEvent.root.eventId ?: ""
|
||||||
|
timelineEventEntity.roomId = roomId
|
||||||
|
timelineEventEntity.annotations = timelineEvent.annotations?.let { EventAnnotationsSummaryMapper.map(it, roomId) }
|
||||||
|
return timelineEventEntity
|
||||||
|
}
|
||||||
|
|
||||||
|
fun map(timelineEventEntity: TimelineEventEntity): TimelineEvent {
|
||||||
|
return TimelineEvent(
|
||||||
|
root = timelineEventEntity.root?.asDomain()
|
||||||
|
?: Event("", timelineEventEntity.eventId),
|
||||||
|
annotations = timelineEventEntity.annotations?.asDomain(),
|
||||||
|
localId = timelineEventEntity.localId,
|
||||||
|
displayIndex = timelineEventEntity.root?.displayIndex ?: 0,
|
||||||
|
senderName = timelineEventEntity.senderName,
|
||||||
|
isUniqueDisplayName = timelineEventEntity.isUniqueDisplayName,
|
||||||
|
senderAvatar = timelineEventEntity.senderAvatar,
|
||||||
|
sendState = timelineEventEntity.root?.sendState ?: SendState.UNKNOWN,
|
||||||
|
hasClearEventFlag = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun TimelineEventEntity.asDomain(): TimelineEvent {
|
||||||
|
return TimelineEventMapper.map(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun TimelineEvent.toEntity(roomId: String): TimelineEventEntity {
|
||||||
|
return TimelineEventMapper.map(this, roomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import io.realm.annotations.LinkingObjects
|
||||||
|
|
||||||
internal open class ChunkEntity(@Index var prevToken: String? = null,
|
internal open class ChunkEntity(@Index var prevToken: String? = null,
|
||||||
@Index var nextToken: String? = null,
|
@Index var nextToken: String? = null,
|
||||||
var events: RealmList<EventEntity> = RealmList(),
|
var timelineEvents: RealmList<TimelineEventEntity> = RealmList(),
|
||||||
@Index var isLastForward: Boolean = false,
|
@Index var isLastForward: Boolean = false,
|
||||||
@Index var isLastBackward: Boolean = false,
|
@Index var isLastBackward: Boolean = false,
|
||||||
var backwardsDisplayIndex: Int? = null,
|
var backwardsDisplayIndex: Int? = null,
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.*
|
||||||
|
|
||||||
internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(),
|
internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(),
|
||||||
@Index var eventId: String = "",
|
@Index var eventId: String = "",
|
||||||
var roomId: String = "",
|
@Index var roomId: String = "",
|
||||||
@Index var type: String = "",
|
@Index var type: String = "",
|
||||||
var content: String? = null,
|
var content: String? = null,
|
||||||
var prevContent: String? = null,
|
var prevContent: String? = null,
|
||||||
|
@ -61,9 +61,6 @@ internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUI
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
|
|
||||||
@LinkingObjects("events")
|
|
||||||
val chunk: RealmResults<ChunkEntity>? = null
|
|
||||||
|
|
||||||
@LinkingObjects("untimelinedStateEvents")
|
@LinkingObjects("untimelinedStateEvents")
|
||||||
val room: RealmResults<RoomEntity>? = null
|
val room: RealmResults<RoomEntity>? = null
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ import kotlin.properties.Delegates
|
||||||
internal open class RoomEntity(@PrimaryKey var roomId: String = "",
|
internal open class RoomEntity(@PrimaryKey var roomId: String = "",
|
||||||
var chunks: RealmList<ChunkEntity> = RealmList(),
|
var chunks: RealmList<ChunkEntity> = RealmList(),
|
||||||
var untimelinedStateEvents: RealmList<EventEntity> = RealmList(),
|
var untimelinedStateEvents: RealmList<EventEntity> = RealmList(),
|
||||||
var sendingTimelineEvents: RealmList<EventEntity> = RealmList(),
|
var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList(),
|
||||||
var areAllMembersLoaded: Boolean = false
|
var areAllMembersLoaded: Boolean = false
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||||
var displayName: String? = "",
|
var displayName: String? = "",
|
||||||
var avatarUrl: String? = "",
|
var avatarUrl: String? = "",
|
||||||
var topic: String? = "",
|
var topic: String? = "",
|
||||||
var latestEvent: EventEntity? = null,
|
var latestEvent: TimelineEventEntity? = null,
|
||||||
var heroes: RealmList<String> = RealmList(),
|
var heroes: RealmList<String> = RealmList(),
|
||||||
var joinedMembersCount: Int? = 0,
|
var joinedMembersCount: Int? = 0,
|
||||||
var invitedMembersCount: Int? = 0,
|
var invitedMembersCount: Int? = 0,
|
||||||
|
|
|
@ -17,13 +17,16 @@
|
||||||
package im.vector.matrix.android.internal.database.model
|
package im.vector.matrix.android.internal.database.model
|
||||||
|
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
|
import io.realm.RealmResults
|
||||||
import io.realm.annotations.Index
|
import io.realm.annotations.Index
|
||||||
|
import io.realm.annotations.LinkingObjects
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.annotations.PrimaryKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
internal open class TimelineEventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(),
|
internal open class TimelineEventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(),
|
||||||
@Index var eventId: String = "",
|
@Index var eventId: String = "",
|
||||||
|
@Index var roomId: String = "",
|
||||||
var root: EventEntity? = null,
|
var root: EventEntity? = null,
|
||||||
var annotations: EventAnnotationsSummaryEntity? = null,
|
var annotations: EventAnnotationsSummaryEntity? = null,
|
||||||
var senderName: String? = null,
|
var senderName: String? = null,
|
||||||
|
@ -31,6 +34,9 @@ internal open class TimelineEventEntity(@PrimaryKey var localId: String = UUID.r
|
||||||
var senderAvatar: String? = null
|
var senderAvatar: String? = null
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
|
@LinkingObjects("timelineEvents")
|
||||||
|
val chunk: RealmResults<ChunkEntity>? = null
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
|
|
||||||
}
|
}
|
|
@ -49,7 +49,7 @@ internal fun ChunkEntity.Companion.findLastLiveChunkFromRoom(realm: Realm, roomI
|
||||||
|
|
||||||
internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
|
internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
|
||||||
return realm.where<ChunkEntity>()
|
return realm.where<ChunkEntity>()
|
||||||
.`in`(ChunkEntityFields.EVENTS.EVENT_ID, eventIds.toTypedArray())
|
.`in`(ChunkEntityFields.TIMELINE_EVENTS.EVENT_ID, eventIds.toTypedArray())
|
||||||
.findAll()
|
.findAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.database.query
|
package im.vector.matrix.android.internal.database.query
|
||||||
|
|
||||||
import im.vector.matrix.android.internal.database.helper.addSendingEvent
|
|
||||||
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.EventEntity
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.*
|
import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.*
|
||||||
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.RoomEntity
|
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.TimelineEventEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmList
|
import io.realm.RealmList
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
|
@ -62,30 +63,6 @@ internal fun EventEntity.Companion.types(realm: Realm,
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun EventEntity.Companion.latestEvent(realm: Realm,
|
|
||||||
roomId: String,
|
|
||||||
includedTypes: List<String> = emptyList(),
|
|
||||||
excludedTypes: List<String> = emptyList()): EventEntity? {
|
|
||||||
|
|
||||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null
|
|
||||||
val eventList = if (roomEntity.sendingTimelineEvents.isNotEmpty()) {
|
|
||||||
roomEntity.sendingTimelineEvents
|
|
||||||
} else {
|
|
||||||
ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.events
|
|
||||||
}
|
|
||||||
val query = eventList?.where()
|
|
||||||
if (includedTypes.isNotEmpty()) {
|
|
||||||
query?.`in`(EventEntityFields.TYPE, includedTypes.toTypedArray())
|
|
||||||
} else if (excludedTypes.isNotEmpty()) {
|
|
||||||
query?.not()?.`in`(EventEntityFields.TYPE, excludedTypes.toTypedArray())
|
|
||||||
}
|
|
||||||
return query
|
|
||||||
?.sort(EventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
|
|
||||||
?.findFirst()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal fun RealmQuery<EventEntity>.next(from: Int? = null, strict: Boolean = true): EventEntity? {
|
internal fun RealmQuery<EventEntity>.next(from: Int? = null, strict: Boolean = true): EventEntity? {
|
||||||
if (from != null) {
|
if (from != null) {
|
||||||
if (strict) {
|
if (strict) {
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.database.query
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.*
|
||||||
|
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.TimelineEventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.TimelineEventEntityFields
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.RealmList
|
||||||
|
import io.realm.RealmQuery
|
||||||
|
import io.realm.Sort
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
|
internal fun TimelineEventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery<TimelineEventEntity> {
|
||||||
|
return realm.where<TimelineEventEntity>().equalTo(TimelineEventEntityFields.EVENT_ID, eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun TimelineEventEntity.Companion.where(realm: Realm, eventIds: List<String>): RealmQuery<TimelineEventEntity> {
|
||||||
|
return realm.where<TimelineEventEntity>().`in`(TimelineEventEntityFields.EVENT_ID, eventIds.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm,
|
||||||
|
roomId: String,
|
||||||
|
includedTypes: List<String> = emptyList(),
|
||||||
|
excludedTypes: List<String> = emptyList()): TimelineEventEntity? {
|
||||||
|
|
||||||
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null
|
||||||
|
val eventList = if (roomEntity.sendingTimelineEvents.isNotEmpty()) {
|
||||||
|
roomEntity.sendingTimelineEvents
|
||||||
|
} else {
|
||||||
|
ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.timelineEvents
|
||||||
|
}
|
||||||
|
val query = eventList?.where()
|
||||||
|
if (includedTypes.isNotEmpty()) {
|
||||||
|
query?.`in`(EventEntityFields.TYPE, includedTypes.toTypedArray())
|
||||||
|
} else if (excludedTypes.isNotEmpty()) {
|
||||||
|
query?.not()?.`in`(EventEntityFields.TYPE, excludedTypes.toTypedArray())
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
?.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING)
|
||||||
|
?.findFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun RealmList<TimelineEventEntity>.find(eventId: String): TimelineEventEntity? {
|
||||||
|
return this.where().equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId).findFirst()
|
||||||
|
}
|
|
@ -1,36 +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
|
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
|
||||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
|
||||||
import im.vector.matrix.android.internal.session.SessionScope
|
|
||||||
import io.realm.Realm
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches annotations (reactions, edits...) associated to a given eventEntity from the data layer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
internal class EventRelationExtractor @Inject constructor() {
|
|
||||||
|
|
||||||
fun extractFrom(event: EventEntity, realm: Realm = event.realm): EventAnnotationsSummary? {
|
|
||||||
return EventAnnotationsSummaryEntity.where(realm, event.eventId).findFirst()?.asDomain()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -39,7 +39,6 @@ import im.vector.matrix.android.internal.session.room.state.DefaultStateService
|
||||||
import im.vector.matrix.android.internal.session.room.state.SendStateTask
|
import im.vector.matrix.android.internal.session.room.state.SendStateTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
|
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.InMemoryTimelineEventFactory
|
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -63,8 +62,7 @@ internal class RoomFactory @Inject constructor(private val context: Context,
|
||||||
private val leaveRoomTask: LeaveRoomTask) {
|
private val leaveRoomTask: LeaveRoomTask) {
|
||||||
|
|
||||||
fun create(roomId: String): Room {
|
fun create(roomId: String): Room {
|
||||||
val timelineEventFactory = InMemoryTimelineEventFactory(SenderRoomMemberExtractor(), EventRelationExtractor(), cryptoService)
|
val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, cryptoService, paginationTask)
|
||||||
val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, timelineEventFactory, contextOfEventTask, cryptoService, paginationTask)
|
|
||||||
val sendService = DefaultSendService(context, credentials, roomId, eventFactory, cryptoService, monarchy)
|
val sendService = DefaultSendService(context, credentials, roomId, eventFactory, cryptoService, monarchy)
|
||||||
val stateService = DefaultStateService(roomId, taskExecutor, sendStateTask)
|
val stateService = DefaultStateService(roomId, taskExecutor, sendStateTask)
|
||||||
val roomMembersService = DefaultMembershipService(roomId, monarchy, taskExecutor, loadRoomMembersTask, inviteTask, joinRoomTask, leaveRoomTask)
|
val roomMembersService = DefaultMembershipService(roomId, monarchy, taskExecutor, loadRoomMembersTask, inviteTask, joinRoomTask, leaveRoomTask)
|
||||||
|
|
|
@ -138,10 +138,4 @@ internal abstract class RoomModule {
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindTimelineService(timelineService: DefaultTimelineService): TimelineService
|
abstract fun bindTimelineService(timelineService: DefaultTimelineService): TimelineService
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract fun bindSimpleTimelineEventFactory(timelineEventFactory: SimpleTimelineEventFactory): TimelineEventFactory
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract fun bindCacheableTimelineEventFactory(inMemoryTimelineEventFactory: InMemoryTimelineEventFactory): CacheableTimelineEventFactory
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ 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.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.query.latestEvent
|
import im.vector.matrix.android.internal.database.query.latestEvent
|
||||||
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
|
||||||
|
@ -77,19 +78,19 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
roomSummaryEntity.highlightCount = unreadNotifications?.highlightCount ?: 0
|
roomSummaryEntity.highlightCount = unreadNotifications?.highlightCount ?: 0
|
||||||
roomSummaryEntity.notificationCount = unreadNotifications?.notificationCount ?:0
|
roomSummaryEntity.notificationCount = unreadNotifications?.notificationCount ?: 0
|
||||||
|
|
||||||
if (membership != null) {
|
if (membership != null) {
|
||||||
roomSummaryEntity.membership = membership
|
roomSummaryEntity.membership = membership
|
||||||
}
|
}
|
||||||
|
|
||||||
val lastEvent = EventEntity.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).getLoaded().filterKeys { it != credentials.userId }
|
||||||
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 = lastEvent
|
roomSummaryEntity.latestEvent = latestEvent
|
||||||
roomSummaryEntity.otherMemberIds.clear()
|
roomSummaryEntity.otherMemberIds.clear()
|
||||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers.keys)
|
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers.keys)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,29 +16,12 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.session.room.membership
|
package im.vector.matrix.android.internal.session.room.membership
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
internal object SenderRoomMemberExtractor {
|
||||||
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.api.session.room.send.SendState
|
|
||||||
import im.vector.matrix.android.internal.database.mapper.ContentMapper
|
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
|
||||||
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.query.findIncludingEvent
|
|
||||||
import im.vector.matrix.android.internal.database.query.next
|
|
||||||
import im.vector.matrix.android.internal.database.query.prev
|
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmQuery
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
internal class SenderRoomMemberExtractor @Inject constructor() {
|
/*
|
||||||
|
fun extractFrom(event: Event, realm: Realm): RoomMember? {
|
||||||
fun extractFrom(event: EventEntity, realm: Realm = event.realm): RoomMember? {
|
|
||||||
val roomId = event.roomId
|
val roomId = event.roomId
|
||||||
val sender = event.sender ?: return null
|
val sender = event.senderId ?: return null
|
||||||
// If the event is unlinked we want to fetch unlinked state events
|
// If the event is unlinked we want to fetch unlinked state events
|
||||||
val unlinked = event.isUnlinked
|
val unlinked = event.isUnlinked
|
||||||
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: return null
|
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: return null
|
||||||
|
@ -69,4 +52,5 @@ internal class SenderRoomMemberExtractor @Inject constructor() {
|
||||||
.equalTo(EventEntityFields.IS_UNLINKED, isUnlinked)
|
.equalTo(EventEntityFields.IS_UNLINKED, isUnlinked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
|
@ -21,8 +21,8 @@ import im.vector.matrix.android.api.MatrixCallback
|
||||||
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.room.read.ReadService
|
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||||
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.EventEntity
|
|
||||||
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||||
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.latestEvent
|
import im.vector.matrix.android.internal.database.query.latestEvent
|
||||||
|
@ -55,21 +55,21 @@ internal class DefaultReadService @Inject constructor(private val roomId: String
|
||||||
setReadMarkersTask.configureWith(params).dispatchTo(callback).executeBy(taskExecutor)
|
setReadMarkersTask.configureWith(params).dispatchTo(callback).executeBy(taskExecutor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLatestEvent(): EventEntity? {
|
private fun getLatestEvent(): TimelineEventEntity? {
|
||||||
return monarchy.fetchCopied { EventEntity.latestEvent(it, roomId) }
|
return monarchy.fetchCopied { TimelineEventEntity.latestEvent(it, roomId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isEventRead(eventId: String): Boolean {
|
override fun isEventRead(eventId: String): Boolean {
|
||||||
var isEventRead = false
|
var isEventRead = false
|
||||||
monarchy.doWithRealm {
|
monarchy.doWithRealm {
|
||||||
val readReceipt = ReadReceiptEntity.where(it, roomId, credentials.userId).findFirst()
|
val readReceipt = ReadReceiptEntity.where(it, roomId, credentials.userId).findFirst()
|
||||||
?: return@doWithRealm
|
?: return@doWithRealm
|
||||||
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId)
|
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId)
|
||||||
?: return@doWithRealm
|
?: return@doWithRealm
|
||||||
val readReceiptIndex = liveChunk.events.find(readReceipt.eventId)?.displayIndex
|
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex
|
||||||
?: Int.MIN_VALUE
|
?: Int.MIN_VALUE
|
||||||
val eventToCheckIndex = liveChunk.events.find(eventId)?.displayIndex
|
val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex
|
||||||
?: Int.MAX_VALUE
|
?: Int.MAX_VALUE
|
||||||
isEventRead = eventToCheckIndex <= readReceiptIndex
|
isEventRead = eventToCheckIndex <= readReceiptIndex
|
||||||
}
|
}
|
||||||
return isEventRead
|
return isEventRead
|
||||||
|
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
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.ReadReceiptEntity
|
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
||||||
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.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.latestEvent
|
import im.vector.matrix.android.internal.database.query.latestEvent
|
||||||
|
@ -82,7 +83,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI
|
||||||
|
|
||||||
private fun updateNotificationCountIfNecessary(roomId: String, eventId: String) {
|
private fun updateNotificationCountIfNecessary(roomId: String, eventId: String) {
|
||||||
monarchy.tryTransactionAsync { realm ->
|
monarchy.tryTransactionAsync { realm ->
|
||||||
val isLatestReceived = EventEntity.latestEvent(realm, roomId)?.eventId == eventId
|
val isLatestReceived = TimelineEventEntity.latestEvent(realm, roomId)?.eventId == eventId
|
||||||
if (isLatestReceived) {
|
if (isLatestReceived) {
|
||||||
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||||
?: return@tryTransactionAsync
|
?: return@tryTransactionAsync
|
||||||
|
@ -99,9 +100,9 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI
|
||||||
?: return@doWithRealm
|
?: return@doWithRealm
|
||||||
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId)
|
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId)
|
||||||
?: return@doWithRealm
|
?: return@doWithRealm
|
||||||
val readReceiptIndex = liveChunk.events.find(readReceipt.eventId)?.displayIndex
|
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex
|
||||||
?: Int.MIN_VALUE
|
?: Int.MIN_VALUE
|
||||||
val eventToCheckIndex = liveChunk.events.find(eventId)?.displayIndex
|
val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex
|
||||||
?: Int.MAX_VALUE
|
?: Int.MAX_VALUE
|
||||||
isEventRead = eventToCheckIndex <= readReceiptIndex
|
isEventRead = eventToCheckIndex <= readReceiptIndex
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,6 @@ internal class DefaultTimeline(
|
||||||
private val realmConfiguration: RealmConfiguration,
|
private val realmConfiguration: RealmConfiguration,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val contextOfEventTask: GetContextOfEventTask,
|
private val contextOfEventTask: GetContextOfEventTask,
|
||||||
private val timelineEventFactory: CacheableTimelineEventFactory,
|
|
||||||
private val paginationTask: PaginationTask,
|
private val paginationTask: PaginationTask,
|
||||||
private val cryptoService: CryptoService,
|
private val cryptoService: CryptoService,
|
||||||
private val allowedTypes: List<String>?
|
private val allowedTypes: List<String>?
|
||||||
|
@ -116,7 +115,6 @@ internal class DefaultTimeline(
|
||||||
nextDisplayIndex = DISPLAY_INDEX_UNKNOWN
|
nextDisplayIndex = DISPLAY_INDEX_UNKNOWN
|
||||||
builtEvents.clear()
|
builtEvents.clear()
|
||||||
builtEventsIdMap.clear()
|
builtEventsIdMap.clear()
|
||||||
timelineEventFactory.clear()
|
|
||||||
}
|
}
|
||||||
changeSet.insertionRanges.forEach { range ->
|
changeSet.insertionRanges.forEach { range ->
|
||||||
val (startDisplayIndex, direction) = if (range.startIndex == 0) {
|
val (startDisplayIndex, direction) = if (range.startIndex == 0) {
|
||||||
|
@ -145,7 +143,7 @@ internal class DefaultTimeline(
|
||||||
builtEventsIdMap[eventId]?.let { builtIndex ->
|
builtEventsIdMap[eventId]?.let { builtIndex ->
|
||||||
//Update the relation of existing event
|
//Update the relation of existing event
|
||||||
builtEvents[builtIndex]?.let { te ->
|
builtEvents[builtIndex]?.let { te ->
|
||||||
builtEvents[builtIndex] = timelineEventFactory.create(eventEntity, eventEntity.realm)
|
//builtEvents[builtIndex] = timelineEventFactory.create(eventEntity, eventEntity.realm)
|
||||||
hasChanged = true
|
hasChanged = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,7 +187,7 @@ internal class DefaultTimeline(
|
||||||
&& (timelineEvent.root.mClearEvent == null || timelineEvent.root.mCryptoError != null)) {
|
&& (timelineEvent.root.mClearEvent == null || timelineEvent.root.mCryptoError != null)) {
|
||||||
//we need to rebuild this event
|
//we need to rebuild this event
|
||||||
EventEntity.where(realm, eventId = timelineEvent.root.eventId!!).findFirst()?.let {
|
EventEntity.where(realm, eventId = timelineEvent.root.eventId!!).findFirst()?.let {
|
||||||
builtEvents[index] = timelineEventFactory.create(it, realm)
|
//builtEvents[index] = timelineEventFactory.create(it, realm)
|
||||||
hasChange = true
|
hasChange = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,10 +324,10 @@ internal class DefaultTimeline(
|
||||||
val sendingEvents = ArrayList<TimelineEvent>()
|
val sendingEvents = ArrayList<TimelineEvent>()
|
||||||
if (hasReachedEnd(Timeline.Direction.FORWARDS)) {
|
if (hasReachedEnd(Timeline.Direction.FORWARDS)) {
|
||||||
roomEntity?.sendingTimelineEvents
|
roomEntity?.sendingTimelineEvents
|
||||||
?.filter { allowedTypes?.contains(it.type) ?: false }
|
?.filter { allowedTypes?.contains(it.root?.type) ?: false }
|
||||||
?.forEach {
|
?.forEach {
|
||||||
val timelineEvent = timelineEventFactory.create(it, it.realm)
|
//val timelineEvent = timelineEventFactory.create(it, it.realm)
|
||||||
sendingEvents.add(timelineEvent)
|
//sendingEvents.add(timelineEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sendingEvents
|
return sendingEvents
|
||||||
|
@ -432,7 +430,7 @@ internal class DefaultTimeline(
|
||||||
* This has to be called on TimelineThread as it access realm live results
|
* This has to be called on TimelineThread as it access realm live results
|
||||||
*/
|
*/
|
||||||
private fun getLiveChunk(): ChunkEntity? {
|
private fun getLiveChunk(): ChunkEntity? {
|
||||||
return liveEvents.firstOrNull()?.chunk?.firstOrNull()
|
return null //return liveEvents.firstOrNull()?.chunk?.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,15 +17,15 @@
|
||||||
package im.vector.matrix.android.internal.session.room.timeline
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MediatorLiveData
|
import androidx.lifecycle.Transformations
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||||
import im.vector.matrix.android.internal.database.RealmLiveData
|
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
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.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.util.fetchCopyMap
|
import im.vector.matrix.android.internal.util.fetchCopyMap
|
||||||
|
@ -34,7 +34,6 @@ import javax.inject.Inject
|
||||||
internal class DefaultTimelineService @Inject constructor(private val roomId: String,
|
internal class DefaultTimelineService @Inject constructor(private val roomId: String,
|
||||||
private val monarchy: Monarchy,
|
private val monarchy: Monarchy,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val timelineEventFactory: CacheableTimelineEventFactory,
|
|
||||||
private val contextOfEventTask: GetContextOfEventTask,
|
private val contextOfEventTask: GetContextOfEventTask,
|
||||||
private val cryptoService: CryptoService,
|
private val cryptoService: CryptoService,
|
||||||
private val paginationTask: PaginationTask
|
private val paginationTask: PaginationTask
|
||||||
|
@ -42,46 +41,31 @@ internal class DefaultTimelineService @Inject constructor(private val roomId: St
|
||||||
|
|
||||||
override fun createTimeline(eventId: String?, allowedTypes: List<String>?): Timeline {
|
override fun createTimeline(eventId: String?, allowedTypes: List<String>?): Timeline {
|
||||||
return DefaultTimeline(roomId,
|
return DefaultTimeline(roomId,
|
||||||
eventId,
|
eventId,
|
||||||
monarchy.realmConfiguration,
|
monarchy.realmConfiguration,
|
||||||
taskExecutor,
|
taskExecutor,
|
||||||
contextOfEventTask,
|
contextOfEventTask,
|
||||||
timelineEventFactory,
|
paginationTask,
|
||||||
paginationTask,
|
cryptoService,
|
||||||
cryptoService,
|
allowedTypes)
|
||||||
allowedTypes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTimeLineEvent(eventId: String): TimelineEvent? {
|
override fun getTimeLineEvent(eventId: String): TimelineEvent? {
|
||||||
return monarchy
|
return monarchy
|
||||||
.fetchCopyMap({
|
.fetchCopyMap({
|
||||||
EventEntity.where(it, eventId = eventId).findFirst()
|
TimelineEventEntity.where(it, eventId = eventId).findFirst()
|
||||||
}, { entity, realm ->
|
}, { entity, realm ->
|
||||||
timelineEventFactory.create(entity, realm)
|
entity.asDomain()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun liveTimeLineEvent(eventId: String): LiveData<TimelineEvent> {
|
override fun liveTimeLineEvent(eventId: String): LiveData<TimelineEvent> {
|
||||||
val liveEventEntity = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
val liveData = RealmLiveData(monarchy.realmConfiguration) {
|
||||||
EventEntity.where(realm, eventId = eventId)
|
TimelineEventEntity.where(it, eventId = eventId)
|
||||||
}
|
}
|
||||||
val liveAnnotationsEntity = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
return Transformations.map(liveData) {
|
||||||
EventAnnotationsSummaryEntity.where(realm, eventId = eventId)
|
it.firstOrNull()?.asDomain()
|
||||||
}
|
}
|
||||||
val result = MediatorLiveData<TimelineEvent>()
|
|
||||||
result.addSource(liveEventEntity) { realmResults ->
|
|
||||||
result.value = realmResults.firstOrNull()?.let { timelineEventFactory.create(it, it.realm) }
|
|
||||||
}
|
|
||||||
|
|
||||||
result.addSource(liveAnnotationsEntity) {
|
|
||||||
liveEventEntity.value?.let {
|
|
||||||
result.value = liveEventEntity.value?.let { realmResults ->
|
|
||||||
//recreate the timeline event
|
|
||||||
realmResults.firstOrNull()?.let { timelineEventFactory.create(it, it.realm) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,164 +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.timeline
|
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
|
||||||
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.room.timeline.TimelineEvent
|
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
|
||||||
import im.vector.matrix.android.internal.crypto.MXDecryptionException
|
|
||||||
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
|
||||||
import im.vector.matrix.android.internal.session.room.EventRelationExtractor
|
|
||||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
|
||||||
import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor
|
|
||||||
import io.realm.Realm
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.*
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
internal interface TimelineEventFactory {
|
|
||||||
fun create(eventEntity: EventEntity, realm: Realm): TimelineEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
internal interface CacheableTimelineEventFactory : TimelineEventFactory {
|
|
||||||
fun clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is responsible for building [TimelineEvent] returned by a [Timeline] through [TimelineService]
|
|
||||||
* It handles decryption, extracting additional data around an event as sender data and relation.
|
|
||||||
*/
|
|
||||||
internal class SimpleTimelineEventFactory @Inject constructor(private val roomMemberExtractor: SenderRoomMemberExtractor,
|
|
||||||
private val relationExtractor: EventRelationExtractor,
|
|
||||||
private val cryptoService: CryptoService
|
|
||||||
) : TimelineEventFactory {
|
|
||||||
|
|
||||||
override fun create(eventEntity: EventEntity, realm: Realm): TimelineEvent {
|
|
||||||
val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity, realm)
|
|
||||||
val relations = relationExtractor.extractFrom(eventEntity, realm)
|
|
||||||
|
|
||||||
val event = eventEntity.asDomain()
|
|
||||||
if (event.getClearType() == EventType.ENCRYPTED) {
|
|
||||||
handleEncryptedEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
val isUniqueDisplayName = RoomMembers(realm, eventEntity.roomId).isUniqueDisplayName(senderRoomMember?.displayName)
|
|
||||||
|
|
||||||
return TimelineEvent(
|
|
||||||
event,
|
|
||||||
eventEntity.localId,
|
|
||||||
eventEntity.displayIndex,
|
|
||||||
senderRoomMember?.displayName,
|
|
||||||
isUniqueDisplayName,
|
|
||||||
senderRoomMember?.avatarUrl,
|
|
||||||
eventEntity.sendState,
|
|
||||||
event.mClearEvent != null,
|
|
||||||
relations
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleEncryptedEvent(event: Event) {
|
|
||||||
Timber.v("Encrypted event: try to decrypt ${event.eventId}")
|
|
||||||
try {
|
|
||||||
val result = cryptoService.decryptEvent(event, UUID.randomUUID().toString())
|
|
||||||
event.setClearData(result)
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
Timber.e("Encrypted event: decryption failed")
|
|
||||||
if (failure is MXDecryptionException) {
|
|
||||||
event.setCryptoError(failure.cryptoError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class InMemoryTimelineEventFactory @Inject constructor(private val roomMemberExtractor: SenderRoomMemberExtractor,
|
|
||||||
private val relationExtractor: EventRelationExtractor,
|
|
||||||
private val cryptoService: CryptoService) : CacheableTimelineEventFactory {
|
|
||||||
|
|
||||||
private val timelineId = UUID.randomUUID().toString()
|
|
||||||
private val senderCache = mutableMapOf<String, SenderData>()
|
|
||||||
private val decryptionCache = mutableMapOf<String, MXEventDecryptionResult>()
|
|
||||||
|
|
||||||
override fun create(eventEntity: EventEntity, realm: Realm): TimelineEvent {
|
|
||||||
val sender = eventEntity.sender
|
|
||||||
val cacheKey = sender + eventEntity.localId
|
|
||||||
val senderData = senderCache.getOrPut(cacheKey) {
|
|
||||||
val senderRoomMember = roomMemberExtractor.extractFrom(eventEntity, realm)
|
|
||||||
val isUniqueDisplayName = RoomMembers(realm, eventEntity.roomId).isUniqueDisplayName(senderRoomMember?.displayName)
|
|
||||||
|
|
||||||
SenderData(senderRoomMember?.displayName,
|
|
||||||
isUniqueDisplayName,
|
|
||||||
senderRoomMember?.avatarUrl)
|
|
||||||
}
|
|
||||||
val event = eventEntity.asDomain()
|
|
||||||
if (event.getClearType() == EventType.ENCRYPTED && !event.isRedacted()) {
|
|
||||||
handleEncryptedEvent(event, eventEntity.localId)
|
|
||||||
}
|
|
||||||
|
|
||||||
val relations = relationExtractor.extractFrom(eventEntity, realm)
|
|
||||||
return TimelineEvent(
|
|
||||||
event,
|
|
||||||
eventEntity.localId,
|
|
||||||
eventEntity.displayIndex,
|
|
||||||
senderData.senderName,
|
|
||||||
senderData.isUniqueDisplayName,
|
|
||||||
senderData.senderAvatar,
|
|
||||||
eventEntity.sendState,
|
|
||||||
event.mClearEvent != null,
|
|
||||||
relations
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleEncryptedEvent(event: Event, cacheKey: String) {
|
|
||||||
Timber.v("Encrypted event: try to decrypt ${event.eventId}")
|
|
||||||
val cachedDecryption = decryptionCache[cacheKey]
|
|
||||||
if (cachedDecryption != null) {
|
|
||||||
Timber.v("Encrypted event ${event.eventId} cached")
|
|
||||||
event.setClearData(cachedDecryption)
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val result = cryptoService.decryptEvent(event, timelineId)
|
|
||||||
if (result != null) {
|
|
||||||
decryptionCache[cacheKey] = result
|
|
||||||
}
|
|
||||||
event.setClearData(result)
|
|
||||||
} catch (failure: Throwable) {
|
|
||||||
Timber.e("Encrypted event: decryption failed ${failure.localizedMessage}")
|
|
||||||
if (failure is MXDecryptionException) {
|
|
||||||
event.setCryptoError(failure.cryptoError)
|
|
||||||
} else {
|
|
||||||
// Other error
|
|
||||||
Timber.e("Other error, should be handled")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clear() {
|
|
||||||
senderCache.clear()
|
|
||||||
decryptionCache.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class SenderData(
|
|
||||||
val senderName: String?,
|
|
||||||
val isUniqueDisplayName: Boolean,
|
|
||||||
val senderAvatar: String?
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in a new issue