forked from GitHub-Mirror/riotX-android
Merge branch 'develop' into feature/Perf
This commit is contained in:
@ -81,13 +81,11 @@ interface Session :
|
||||
/**
|
||||
* This method start the sync thread.
|
||||
*/
|
||||
@MainThread
|
||||
fun startSync()
|
||||
|
||||
/**
|
||||
* This method stop the sync thread.
|
||||
*/
|
||||
@MainThread
|
||||
fun stopSync()
|
||||
|
||||
/**
|
||||
@ -99,7 +97,6 @@ interface Session :
|
||||
/**
|
||||
* This method allow to close a session. It does stop some services.
|
||||
*/
|
||||
@MainThread
|
||||
fun close()
|
||||
|
||||
/**
|
||||
|
@ -177,11 +177,7 @@ data class Event(
|
||||
* @return The curve25519 key that sent this event.
|
||||
*/
|
||||
fun getSenderKey(): String? {
|
||||
return if (null != mClearEvent) {
|
||||
mClearEvent!!.mSenderCurve25519Key
|
||||
} else {
|
||||
mSenderCurve25519Key
|
||||
}
|
||||
return mClearEvent?.mSenderCurve25519Key ?: mSenderCurve25519Key
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,7 +47,7 @@ interface MembershipService {
|
||||
*/
|
||||
fun getRoomMemberIdsLive(): LiveData<List<String>>
|
||||
|
||||
fun getNumberOfJoinedMembers() : Int
|
||||
fun getNumberOfJoinedMembers(): Int
|
||||
|
||||
/**
|
||||
* Invite a user in the room
|
||||
@ -55,13 +55,12 @@ interface MembershipService {
|
||||
fun invite(userId: String, callback: MatrixCallback<Unit>)
|
||||
|
||||
/**
|
||||
* Join the room
|
||||
* Join the room, or accept an invitation.
|
||||
*/
|
||||
fun join(callback: MatrixCallback<Unit>)
|
||||
|
||||
/**
|
||||
* Leave the room.
|
||||
*
|
||||
* Leave the room, or reject an invitation.
|
||||
*/
|
||||
fun leave(callback: MatrixCallback<Unit>)
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package im.vector.matrix.android.api.session.room.model
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
|
||||
/**
|
||||
* This class holds some data of a room.
|
||||
@ -29,7 +29,7 @@ data class RoomSummary(
|
||||
val topic: String = "",
|
||||
val avatarUrl: String = "",
|
||||
val isDirect: Boolean = false,
|
||||
val lastMessage: Event? = null,
|
||||
val latestEvent: TimelineEvent? = null,
|
||||
val otherMemberIds: List<String> = emptyList(),
|
||||
val notificationCount: Int = 0,
|
||||
val highlightCount: Int = 0,
|
||||
|
@ -16,24 +16,37 @@
|
||||
|
||||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
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.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
internal object RoomSummaryMapper {
|
||||
internal class RoomSummaryMapper @Inject constructor(
|
||||
private val timelineEventFactory: TimelineEventFactory,
|
||||
private val monarchy: Monarchy) {
|
||||
|
||||
fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
|
||||
val tags = roomSummaryEntity.tags.map {
|
||||
RoomTag(it.tagName, it.tagOrder)
|
||||
}
|
||||
val latestEvent = roomSummaryEntity.latestEvent?.let {
|
||||
var ev: TimelineEvent? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
ev = timelineEventFactory.create(it, realm)
|
||||
}
|
||||
ev
|
||||
}
|
||||
return RoomSummary(
|
||||
roomId = roomSummaryEntity.roomId,
|
||||
displayName = roomSummaryEntity.displayName ?: "",
|
||||
topic = roomSummaryEntity.topic ?: "",
|
||||
avatarUrl = roomSummaryEntity.avatarUrl ?: "",
|
||||
isDirect = roomSummaryEntity.isDirect,
|
||||
lastMessage = roomSummaryEntity.lastMessage?.asDomain(),
|
||||
latestEvent = latestEvent,
|
||||
otherMemberIds = roomSummaryEntity.otherMemberIds.toList(),
|
||||
highlightCount = roomSummaryEntity.highlightCount,
|
||||
notificationCount = roomSummaryEntity.notificationCount,
|
||||
@ -42,7 +55,3 @@ internal object RoomSummaryMapper {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RoomSummaryEntity.asDomain(): RoomSummary {
|
||||
return RoomSummaryMapper.map(this)
|
||||
}
|
@ -27,7 +27,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||
var displayName: String? = "",
|
||||
var avatarUrl: String? = "",
|
||||
var topic: String? = "",
|
||||
var lastMessage: EventEntity? = null,
|
||||
var latestEvent: EventEntity? = null,
|
||||
var heroes: RealmList<String> = RealmList(),
|
||||
var joinedMembersCount: Int? = 0,
|
||||
var invitedMembersCount: Int? = 0,
|
||||
|
@ -16,10 +16,12 @@
|
||||
|
||||
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.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 io.realm.Realm
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmQuery
|
||||
@ -65,7 +67,14 @@ internal fun EventEntity.Companion.latestEvent(realm: Realm,
|
||||
roomId: String,
|
||||
includedTypes: List<String> = emptyList(),
|
||||
excludedTypes: List<String> = emptyList()): EventEntity? {
|
||||
val query = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.events?.where()
|
||||
|
||||
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()) {
|
||||
|
@ -20,6 +20,7 @@ import android.content.Context
|
||||
import android.os.Looper
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.work.WorkManager
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
@ -102,7 +103,6 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||
SyncWorker.stopAnyBackgroundSync(context)
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun startSync() {
|
||||
assert(isOpen)
|
||||
if (!syncThread.isAlive) {
|
||||
@ -113,16 +113,14 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun stopSync() {
|
||||
assert(isOpen)
|
||||
syncThread.kill()
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun close() {
|
||||
assertMainThread()
|
||||
assert(isOpen)
|
||||
stopSync()
|
||||
liveEntityObservers.forEach { it.dispose() }
|
||||
cryptoService.close()
|
||||
if (monarchy.isMonarchyThreadOpen) {
|
||||
@ -153,6 +151,11 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||
override fun onSuccess(data: Unit) {
|
||||
Timber.w("SIGN_OUT: clear cache -> SUCCESS: clear crypto cache")
|
||||
cryptoService.clearCryptoCache(MatrixCallbackDelegate(callback))
|
||||
|
||||
WorkManager.getInstance(context).also {
|
||||
it.cancelAllWork()
|
||||
it.pruneWork()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
@ -29,7 +29,7 @@ import im.vector.matrix.android.api.session.room.send.SendService
|
||||
import im.vector.matrix.android.api.session.room.state.StateService
|
||||
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.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
@ -38,6 +38,7 @@ import javax.inject.Inject
|
||||
|
||||
internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
private val monarchy: Monarchy,
|
||||
private val roomSummaryMapper: RoomSummaryMapper,
|
||||
private val timelineService: TimelineService,
|
||||
private val sendService: SendService,
|
||||
private val stateService: StateService,
|
||||
@ -58,7 +59,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME)
|
||||
}
|
||||
Transformations.map(liveRealmData) { results ->
|
||||
val roomSummaries = results.map { it.asDomain() }
|
||||
val roomSummaries = results.map { roomSummaryMapper.map(it) }
|
||||
|
||||
if (roomSummaries.isEmpty()) {
|
||||
// Create a dummy RoomSummary to avoid Crash during Sign Out or clear cache
|
||||
@ -72,7 +73,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
override val roomSummary: RoomSummary?
|
||||
get() {
|
||||
var sum: RoomSummaryEntity? = monarchy.fetchCopied { RoomSummaryEntity.where(it, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME).findFirst() }
|
||||
return sum?.asDomain()
|
||||
return sum?.let { roomSummaryMapper.map(it) }
|
||||
}
|
||||
|
||||
override fun isEncrypted(): Boolean {
|
||||
|
@ -23,12 +23,11 @@ import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
|
||||
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.RoomSummaryEntityFields
|
||||
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.create.CreateRoomTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
@ -36,6 +35,7 @@ import im.vector.matrix.android.internal.util.fetchManaged
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultRoomService @Inject constructor(private val monarchy: Monarchy,
|
||||
private val roomSummaryMapper: RoomSummaryMapper,
|
||||
private val createRoomTask: CreateRoomTask,
|
||||
private val roomFactory: RoomFactory,
|
||||
private val taskExecutor: TaskExecutor) : RoomService {
|
||||
@ -55,7 +55,7 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
||||
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ realm -> RoomSummaryEntity.where(realm).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
|
||||
{ it.asDomain() }
|
||||
{ roomSummaryMapper.map(it) }
|
||||
)
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
|
||||
import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService
|
||||
import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask
|
||||
import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor
|
||||
@ -38,8 +39,8 @@ 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.timeline.DefaultTimelineService
|
||||
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.TimelineEventFactory
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -47,6 +48,7 @@ internal class RoomFactory @Inject constructor(private val context: Context,
|
||||
private val credentials: Credentials,
|
||||
private val monarchy: Monarchy,
|
||||
private val eventFactory: LocalEchoEventFactory,
|
||||
private val roomSummaryMapper: RoomSummaryMapper,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val loadRoomMembersTask: LoadRoomMembersTask,
|
||||
private val inviteTask: InviteTask,
|
||||
@ -61,9 +63,7 @@ internal class RoomFactory @Inject constructor(private val context: Context,
|
||||
private val leaveRoomTask: LeaveRoomTask) {
|
||||
|
||||
fun create(roomId: String): Room {
|
||||
val roomMemberExtractor = SenderRoomMemberExtractor(roomId)
|
||||
val relationExtractor = EventRelationExtractor()
|
||||
val timelineEventFactory = TimelineEventFactory(roomMemberExtractor, relationExtractor, cryptoService)
|
||||
val timelineEventFactory = InMemoryTimelineEventFactory(SenderRoomMemberExtractor(), EventRelationExtractor(), cryptoService)
|
||||
val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, timelineEventFactory, contextOfEventTask, paginationTask)
|
||||
val sendService = DefaultSendService(context, credentials, roomId, eventFactory, cryptoService, monarchy)
|
||||
val stateService = DefaultStateService(roomId, taskExecutor, sendStateTask)
|
||||
@ -74,6 +74,7 @@ internal class RoomFactory @Inject constructor(private val context: Context,
|
||||
return DefaultRoom(
|
||||
roomId,
|
||||
monarchy,
|
||||
roomSummaryMapper,
|
||||
timelineService,
|
||||
sendService,
|
||||
stateService,
|
||||
|
@ -138,4 +138,10 @@ internal abstract class RoomModule {
|
||||
@Binds
|
||||
abstract fun bindTimelineService(timelineService: DefaultTimelineService): TimelineService
|
||||
|
||||
@Binds
|
||||
abstract fun bindSimpleTimelineEventFactory(timelineEventFactory: SimpleTimelineEventFactory): TimelineEventFactory
|
||||
|
||||
@Binds
|
||||
abstract fun bindCacheableTimelineEventFactory(inMemoryTimelineEventFactory: InMemoryTimelineEventFactory): CacheableTimelineEventFactory
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
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.where
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
||||
@ -40,6 +39,23 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
||||
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||
private val roomAvatarResolver: RoomAvatarResolver) {
|
||||
|
||||
// TODO: maybe allow user of SDK to give that list
|
||||
private val PREVIEWABLE_TYPES = listOf(
|
||||
EventType.MESSAGE,
|
||||
EventType.STATE_ROOM_NAME,
|
||||
EventType.STATE_ROOM_TOPIC,
|
||||
EventType.STATE_ROOM_MEMBER,
|
||||
EventType.STATE_HISTORY_VISIBILITY,
|
||||
EventType.CALL_INVITE,
|
||||
EventType.CALL_HANGUP,
|
||||
EventType.CALL_ANSWER,
|
||||
EventType.ENCRYPTED,
|
||||
EventType.ENCRYPTION,
|
||||
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
||||
EventType.STICKER,
|
||||
EventType.STATE_ROOM_CREATE
|
||||
)
|
||||
|
||||
fun update(realm: Realm,
|
||||
roomId: String,
|
||||
membership: Membership? = null,
|
||||
@ -47,7 +63,7 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
||||
unreadNotifications: RoomSyncUnreadNotifications? = null) {
|
||||
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
?: realm.createObject(roomId)
|
||||
?: realm.createObject(roomId)
|
||||
|
||||
if (roomSummary != null) {
|
||||
if (roomSummary.heroes.isNotEmpty()) {
|
||||
@ -71,13 +87,13 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
||||
roomSummaryEntity.membership = membership
|
||||
}
|
||||
|
||||
val lastEvent = EventEntity.latestEvent(realm, roomId)
|
||||
val lastEvent = EventEntity.latestEvent(realm, roomId, includedTypes = PREVIEWABLE_TYPES)
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
|
||||
val otherRoomMembers = RoomMembers(realm, roomId).getLoaded().filterKeys { it != credentials.userId }
|
||||
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
|
||||
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
|
||||
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
|
||||
roomSummaryEntity.lastMessage = lastEvent
|
||||
roomSummaryEntity.latestEvent = lastEvent
|
||||
roomSummaryEntity.otherMemberIds.clear()
|
||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers.keys)
|
||||
}
|
||||
|
@ -34,9 +34,10 @@ import io.realm.RealmList
|
||||
import io.realm.RealmQuery
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class SenderRoomMemberExtractor @Inject constructor(private val roomId: String) {
|
||||
internal class SenderRoomMemberExtractor @Inject constructor() {
|
||||
|
||||
fun extractFrom(event: EventEntity, realm: Realm = event.realm): RoomMember? {
|
||||
val roomId = event.roomId
|
||||
val sender = event.sender ?: return null
|
||||
// If the event is unlinked we want to fetch unlinked state events
|
||||
val unlinked = event.isUnlinked
|
||||
|
@ -34,6 +34,7 @@ import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.content.ThumbnailExtractor
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||
import im.vector.matrix.android.internal.util.StringProvider
|
||||
import im.vector.matrix.android.internal.util.tryTransactionAsync
|
||||
import org.commonmark.parser.Parser
|
||||
@ -50,8 +51,9 @@ import javax.inject.Inject
|
||||
*
|
||||
* The transactionID is used as loc
|
||||
*/
|
||||
|
||||
internal class LocalEchoEventFactory @Inject constructor(private val credentials: Credentials, private val stringProvider: StringProvider) {
|
||||
internal class LocalEchoEventFactory @Inject constructor(private val credentials: Credentials,
|
||||
private val stringProvider: StringProvider,
|
||||
private val roomSummaryUpdater: RoomSummaryUpdater) {
|
||||
|
||||
fun createTextEvent(roomId: String, msgType: String, text: String, autoMarkdown: Boolean): Event {
|
||||
if (autoMarkdown && msgType == MessageType.MSGTYPE_TEXT) {
|
||||
@ -342,10 +344,12 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
|
||||
}
|
||||
|
||||
fun saveLocalEcho(monarchy: Monarchy, event: Event) {
|
||||
if (event.roomId == null) throw IllegalStateException("Your event should have a roomId")
|
||||
monarchy.tryTransactionAsync { realm ->
|
||||
val roomEntity = RoomEntity.where(realm, roomId = event.roomId!!).findFirst()
|
||||
val roomEntity = RoomEntity.where(realm, roomId = event.roomId).findFirst()
|
||||
?: return@tryTransactionAsync
|
||||
roomEntity.addSendingEvent(event)
|
||||
roomSummaryUpdater.update(realm, event.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ internal class DefaultTimeline(
|
||||
private val realmConfiguration: RealmConfiguration,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val contextOfEventTask: GetContextOfEventTask,
|
||||
private val timelineEventFactory: TimelineEventFactory,
|
||||
private val timelineEventFactory: CacheableTimelineEventFactory,
|
||||
private val paginationTask: PaginationTask,
|
||||
private val allowedTypes: List<String>?
|
||||
) : Timeline {
|
||||
@ -129,7 +129,7 @@ internal class DefaultTimeline(
|
||||
builtEventsIdMap[eventId]?.let { builtIndex ->
|
||||
//Update the relation of existing event
|
||||
builtEvents[builtIndex]?.let { te ->
|
||||
builtEvents[builtIndex] = timelineEventFactory.create(eventEntity)
|
||||
builtEvents[builtIndex] = timelineEventFactory.create(eventEntity, eventEntity.realm)
|
||||
hasChanged = true
|
||||
}
|
||||
}
|
||||
@ -290,7 +290,7 @@ internal class DefaultTimeline(
|
||||
roomEntity?.sendingTimelineEvents
|
||||
?.filter { allowedTypes?.contains(it.type) ?: false }
|
||||
?.forEach {
|
||||
val timelineEvent = timelineEventFactory.create(it)
|
||||
val timelineEvent = timelineEventFactory.create(it, it.realm)
|
||||
sendingEvents.add(timelineEvent)
|
||||
}
|
||||
}
|
||||
@ -418,7 +418,7 @@ internal class DefaultTimeline(
|
||||
nextDisplayIndex = offsetIndex + 1
|
||||
}
|
||||
offsetResults.forEach { eventEntity ->
|
||||
val timelineEvent = timelineEventFactory.create(eventEntity)
|
||||
val timelineEvent = timelineEventFactory.create(eventEntity, eventEntity.realm)
|
||||
val position = if (direction == Timeline.Direction.FORWARDS) 0 else builtEvents.size
|
||||
builtEvents.add(position, timelineEvent)
|
||||
//Need to shift :/
|
||||
|
@ -33,7 +33,7 @@ import javax.inject.Inject
|
||||
internal class DefaultTimelineService @Inject constructor(private val roomId: String,
|
||||
private val monarchy: Monarchy,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val timelineEventFactory: TimelineEventFactory,
|
||||
private val timelineEventFactory: CacheableTimelineEventFactory,
|
||||
private val contextOfEventTask: GetContextOfEventTask,
|
||||
private val paginationTask: PaginationTask
|
||||
) : TimelineService {
|
||||
@ -60,14 +60,14 @@ internal class DefaultTimelineService @Inject constructor(private val roomId: St
|
||||
}
|
||||
val result = MediatorLiveData<TimelineEvent>()
|
||||
result.addSource(liveEventEntity) { realmResults ->
|
||||
result.value = realmResults.firstOrNull()?.let { timelineEventFactory.create(it) }
|
||||
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) }
|
||||
realmResults.firstOrNull()?.let { timelineEventFactory.create(it, it.realm) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,20 +33,69 @@ 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 TimelineEventFactory @Inject constructor(
|
||||
private val roomMemberExtractor: SenderRoomMemberExtractor,
|
||||
private val relationExtractor: EventRelationExtractor,
|
||||
private val cryptoService: CryptoService) {
|
||||
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,
|
||||
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(failure, "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>()
|
||||
|
||||
fun create(eventEntity: EventEntity, realm: Realm = eventEntity.realm): TimelineEvent {
|
||||
override fun create(eventEntity: EventEntity, realm: Realm): TimelineEvent {
|
||||
val sender = eventEntity.sender
|
||||
val cacheKey = sender + eventEntity.localId
|
||||
val senderData = senderCache.getOrPut(cacheKey) {
|
||||
@ -97,8 +146,9 @@ internal class TimelineEventFactory @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
override fun clear() {
|
||||
senderCache.clear()
|
||||
decryptionCache.clear()
|
||||
}
|
||||
|
||||
private data class SenderData(
|
||||
|
Reference in New Issue
Block a user