From fb2ed9a7ac7b9d65f081fb0b50787ac2858559e8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 23 Feb 2022 18:00:31 +0100 Subject: [PATCH 1/6] Rename getTimeLine to getTimeline to align naming. Also create TimelineEventDataSource. --- .../org/matrix/android/sdk/flow/FlowRoom.kt | 4 +- .../sdk/internal/crypto/PreShareKeysTest.kt | 2 +- .../crypto/gossiping/KeyShareTests.kt | 4 +- .../crypto/gossiping/WithHeldTests.kt | 14 ++-- .../session/room/timeline/TimelineService.kt | 4 +- .../EventRelationsAggregationProcessor.kt | 2 +- .../room/relation/DefaultRelationService.kt | 15 ++--- .../room/timeline/DefaultTimelineService.kt | 38 ++--------- .../room/timeline/TimelineEventDataSource.kt | 64 +++++++++++++++++++ .../fcm/VectorFirebaseMessagingService.kt | 2 +- .../home/room/detail/TimelineViewModel.kt | 16 ++--- .../composer/MessageComposerViewModel.kt | 14 ++-- .../factory/VerificationItemFactory.kt | 2 +- .../reactions/ViewReactionsViewModel.kt | 2 +- .../media/DataAttachmentRoomProvider.kt | 2 +- .../notifications/NotifiableEventResolver.kt | 2 +- .../features/permalink/PermalinkHandler.kt | 2 +- .../poll/create/CreatePollViewModel.kt | 4 +- 18 files changed, 113 insertions(+), 80 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt index 826f584f6a..c5d1d19fec 100644 --- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt @@ -58,9 +58,9 @@ class FlowRoom(private val room: Room) { } fun liveTimelineEvent(eventId: String): Flow> { - return room.getTimeLineEventLive(eventId).asFlow() + return room.getTimelineEventLive(eventId).asFlow() .startWith(room.coroutineDispatchers.io) { - room.getTimeLineEvent(eventId).toOptional() + room.getTimelineEvent(eventId).toOptional() } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt index c95cc6b4ca..a7a81bacf5 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt @@ -95,7 +95,7 @@ class PreShareKeysTest : InstrumentedTest { assertEquals(megolmSessionId, sentEvent.root.content.toModel()?.sessionId, "Unexpected megolm session") testHelper.waitWithLatch { latch -> testHelper.retryPeriodicallyWithLatch(latch) { - bobSession.getRoom(e2eRoomID)?.getTimeLineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE + bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt index e0605db0b8..82aee454eb 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt @@ -92,7 +92,7 @@ class KeyShareTests : InstrumentedTest { val roomSecondSessionPOV = aliceSession2.getRoom(roomId) - val receivedEvent = roomSecondSessionPOV?.getTimeLineEvent(sentEventId) + val receivedEvent = roomSecondSessionPOV?.getTimelineEvent(sentEventId) assertNotNull(receivedEvent) assert(receivedEvent!!.isEncrypted()) @@ -382,7 +382,7 @@ class KeyShareTests : InstrumentedTest { commonTestHelper.sendTextMessage(roomAlicePov, "After", 1) val roomRoomBobPov = aliceSession.getRoom(roomId) - val beforeJoin = roomRoomBobPov!!.getTimeLineEvent(secondEventId) + val beforeJoin = roomRoomBobPov!!.getTimelineEvent(secondEventId) var dRes = tryOrNull { bobSession.cryptoService().decryptEvent(beforeJoin!!.root, "") } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt index 586d96b007..9fda21763a 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt @@ -80,11 +80,11 @@ class WithHeldTests : InstrumentedTest { // await for bob unverified session to get the message testHelper.waitWithLatch { latch -> testHelper.retryPeriodicallyWithLatch(latch) { - bobUnverifiedSession.getRoom(roomId)?.getTimeLineEvent(timelineEvent.eventId) != null + bobUnverifiedSession.getRoom(roomId)?.getTimelineEvent(timelineEvent.eventId) != null } } - val eventBobPOV = bobUnverifiedSession.getRoom(roomId)?.getTimeLineEvent(timelineEvent.eventId)!! + val eventBobPOV = bobUnverifiedSession.getRoom(roomId)?.getTimelineEvent(timelineEvent.eventId)!! // ============================= // ASSERT @@ -109,7 +109,7 @@ class WithHeldTests : InstrumentedTest { testHelper.waitWithLatch { latch -> testHelper.retryPeriodicallyWithLatch(latch) { - val ev = bobUnverifiedSession.getRoom(roomId)?.getTimeLineEvent(secondEvent.eventId) + val ev = bobUnverifiedSession.getRoom(roomId)?.getTimelineEvent(secondEvent.eventId) // wait until it's decrypted ev?.root?.getClearType() == EventType.MESSAGE } @@ -157,12 +157,12 @@ class WithHeldTests : InstrumentedTest { // await for bob session to get the message testHelper.waitWithLatch { latch -> testHelper.retryPeriodicallyWithLatch(latch) { - bobSession.getRoom(testData.roomId)?.getTimeLineEvent(eventId) != null + bobSession.getRoom(testData.roomId)?.getTimelineEvent(eventId) != null } } // Previous message should still be undecryptable (partially withheld session) - val eventBobPOV = bobSession.getRoom(testData.roomId)?.getTimeLineEvent(eventId) + val eventBobPOV = bobSession.getRoom(testData.roomId)?.getTimelineEvent(eventId) try { // .. might need to wait a bit for stability? bobSession.cryptoService().decryptEvent(eventBobPOV!!.root, "") @@ -190,7 +190,7 @@ class WithHeldTests : InstrumentedTest { // await for bob SecondSession session to get the message testHelper.waitWithLatch { latch -> testHelper.retryPeriodicallyWithLatch(latch) { - bobSecondSession.getRoom(testData.roomId)?.getTimeLineEvent(secondMessageId) != null + bobSecondSession.getRoom(testData.roomId)?.getTimelineEvent(secondMessageId) != null } } @@ -231,7 +231,7 @@ class WithHeldTests : InstrumentedTest { // await for bob SecondSession session to get the message testHelper.waitWithLatch { latch -> testHelper.retryPeriodicallyWithLatch(latch) { - val timeLineEvent = bobSecondSession.getRoom(testData.roomId)?.getTimeLineEvent(eventId)?.also { + val timeLineEvent = bobSecondSession.getRoom(testData.roomId)?.getTimelineEvent(eventId)?.also { // try to decrypt and force key request tryOrNull { bobSecondSession.cryptoService().decryptEvent(it.root, "") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineService.kt index 3c021384e1..6152069644 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineService.kt @@ -41,7 +41,7 @@ interface TimelineService { * At the opposite of getTimeLineEventLive which will be updated when local echo event is synced, it will return null in this case. * @param eventId the eventId to get the TimelineEvent */ - fun getTimeLineEvent(eventId: String): TimelineEvent? + fun getTimelineEvent(eventId: String): TimelineEvent? /** * Creates a LiveData of Optional TimelineEvent event with eventId. @@ -49,7 +49,7 @@ interface TimelineService { * In this case, makes sure to use the new synced eventId from the TimelineEvent class if you want to interact, as the local echo is removed from the SDK. * @param eventId the eventId to listen for TimelineEvent */ - fun getTimeLineEventLive(eventId: String): LiveData> + fun getTimelineEventLive(eventId: String): LiveData> /** * Returns a snapshot list of TimelineEvent with EventType.MESSAGE and MessageType.MSGTYPE_IMAGE or MessageType.MSGTYPE_VIDEO. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index acceaf6e24..1e0eb8b497 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -513,7 +513,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( private fun getPollEvent(roomId: String, eventId: String): TimelineEvent? { val session = sessionManager.getSessionComponent(sessionId)?.session() - return session?.getRoom(roomId)?.getTimeLineEvent(eventId) ?: return null.also { + return session?.getRoom(roomId)?.getTimelineEvent(eventId) ?: return null.also { Timber.v("## POLL target poll event $eventId not found in room $roomId") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt index 848e14ff57..d5019aea7b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt @@ -30,15 +30,14 @@ import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.NoOpCancellable import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional -import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.room.relation.threads.FetchThreadTimelineTask import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor +import org.matrix.android.sdk.internal.session.room.timeline.TimelineEventDataSource import org.matrix.android.sdk.internal.util.fetchCopyMap import timber.log.Timber @@ -50,7 +49,7 @@ internal class DefaultRelationService @AssistedInject constructor( private val findReactionEventForUndoTask: FindReactionEventForUndoTask, private val fetchEditHistoryTask: FetchEditHistoryTask, private val fetchThreadTimelineTask: FetchThreadTimelineTask, - private val timelineEventMapper: TimelineEventMapper, + private val timelineEventDataSource: TimelineEventDataSource, @SessionDatabase private val monarchy: Monarchy ) : RelationService { @@ -60,14 +59,8 @@ internal class DefaultRelationService @AssistedInject constructor( } override fun sendReaction(targetEventId: String, reaction: String): Cancelable { - return if (monarchy - .fetchCopyMap( - { realm -> - TimelineEventEntity.where(realm, roomId, targetEventId).findFirst() - }, - { entity, _ -> - timelineEventMapper.map(entity) - }) + val targetTimelineEvent = timelineEventDataSource.getTimelineEvent(roomId, targetEventId) + return if (targetTimelineEvent ?.annotations ?.reactionsSummary .orEmpty() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt index d7d61f0b47..8094fee504 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt @@ -21,36 +21,23 @@ import com.zhuinden.monarchy.Monarchy import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import io.realm.Sort -import io.realm.kotlin.where import org.matrix.android.sdk.api.MatrixCoroutineDispatchers -import org.matrix.android.sdk.api.session.events.model.isImageMessage -import org.matrix.android.sdk.api.session.events.model.isVideoMessage import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.util.Optional -import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.lightweight.LightweightSettingsStorage import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper -import org.matrix.android.sdk.internal.database.model.TimelineEventEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields -import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase -import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask import org.matrix.android.sdk.internal.session.sync.handler.room.ReadReceiptHandler import org.matrix.android.sdk.internal.session.sync.handler.room.ThreadsAwarenessHandler -import org.matrix.android.sdk.internal.task.TaskExecutor internal class DefaultTimelineService @AssistedInject constructor( @Assisted private val roomId: String, - @UserId private val userId: String, @SessionDatabase private val monarchy: Monarchy, - private val realmSessionProvider: RealmSessionProvider, private val timelineInput: TimelineInput, - private val taskExecutor: TaskExecutor, private val contextOfEventTask: GetContextOfEventTask, private val eventDecryptor: TimelineEventDecryptor, private val paginationTask: PaginationTask, @@ -60,7 +47,8 @@ internal class DefaultTimelineService @AssistedInject constructor( private val threadsAwarenessHandler: ThreadsAwarenessHandler, private val lightweightSettingsStorage: LightweightSettingsStorage, private val readReceiptHandler: ReadReceiptHandler, - private val coroutineDispatchers: MatrixCoroutineDispatchers + private val coroutineDispatchers: MatrixCoroutineDispatchers, + private val timelineEventDataSource: TimelineEventDataSource ) : TimelineService { @AssistedFactory @@ -88,27 +76,15 @@ internal class DefaultTimelineService @AssistedInject constructor( ) } - override fun getTimeLineEvent(eventId: String): TimelineEvent? { - return realmSessionProvider.withRealm { realm -> - TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId).findFirst()?.let { - timelineEventMapper.map(it) - } - } + override fun getTimelineEvent(eventId: String): TimelineEvent? { + return timelineEventDataSource.getTimelineEvent(roomId, eventId) } - override fun getTimeLineEventLive(eventId: String): LiveData> { - return LiveTimelineEvent(monarchy, taskExecutor.executorScope, timelineEventMapper, roomId, eventId) + override fun getTimelineEventLive(eventId: String): LiveData> { + return timelineEventDataSource.getTimelineEventLive(roomId, eventId) } override fun getAttachmentMessages(): List { - // TODO pretty bad query.. maybe we should denormalize clear type in base? - return realmSessionProvider.withRealm { realm -> - realm.where() - .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) - .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING) - .findAll() - ?.mapNotNull { timelineEventMapper.map(it).takeIf { it.root.isImageMessage() || it.root.isVideoMessage() } } - .orEmpty() - } + return timelineEventDataSource.getAttachmentMessages(roomId) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt new file mode 100644 index 0000000000..7ce752e85c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 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 org.matrix.android.sdk.internal.session.room.timeline + +import androidx.lifecycle.LiveData +import com.zhuinden.monarchy.Monarchy +import io.realm.Sort +import io.realm.kotlin.where +import org.matrix.android.sdk.api.session.events.model.isImageMessage +import org.matrix.android.sdk.api.session.events.model.isVideoMessage +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.internal.database.RealmSessionProvider +import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper +import org.matrix.android.sdk.internal.database.model.TimelineEventEntity +import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields +import org.matrix.android.sdk.internal.database.query.where +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.task.TaskExecutor +import javax.inject.Inject + +internal class TimelineEventDataSource @Inject constructor(private val realmSessionProvider: RealmSessionProvider, + private val timelineEventMapper: TimelineEventMapper, + private val taskExecutor: TaskExecutor, + @SessionDatabase private val monarchy: Monarchy) { + + fun getTimelineEvent(roomId: String, eventId: String): TimelineEvent? { + return realmSessionProvider.withRealm { realm -> + TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId).findFirst()?.let { + timelineEventMapper.map(it) + } + } + } + + fun getTimelineEventLive(roomId: String, eventId: String): LiveData> { + return LiveTimelineEvent(monarchy, taskExecutor.executorScope, timelineEventMapper, roomId, eventId) + } + + fun getAttachmentMessages(roomId: String): List { + // TODO pretty bad query.. maybe we should denormalize clear type in base? + return realmSessionProvider.withRealm { realm -> + realm.where() + .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) + .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING) + .findAll() + ?.mapNotNull { timelineEventMapper.map(it).takeIf { it.root.isImageMessage() || it.root.isVideoMessage() } } + .orEmpty() + } + } +} diff --git a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt index e323506e9f..93a82f24f9 100755 --- a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -213,7 +213,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { try { val session = activeSessionHolder.getSafeActiveSession() ?: return false val room = session.getRoom(roomId) ?: return false - return room.getTimeLineEvent(eventId) != null + return room.getTimelineEvent(eventId) != null } catch (e: Exception) { Timber.tag(loggerTag.value).e(e, "## isEventAlreadyKnown() : failed to check if the event was already defined") } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index 0198c77280..4d2f280c72 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -742,7 +742,7 @@ class TimelineViewModel @AssistedInject constructor( } private fun handleRedactEvent(action: RoomDetailAction.RedactAction) { - val event = room.getTimeLineEvent(action.targetEventId) ?: return + val event = room.getTimelineEvent(action.targetEventId) ?: return room.redactEvent(event.root, action.reason) } @@ -782,7 +782,7 @@ class TimelineViewModel @AssistedInject constructor( } // We need to update this with the related m.replace also (to move read receipt) action.event.annotations?.editSummary?.sourceEvents?.forEach { - room.getTimeLineEvent(it)?.let { event -> + room.getTimelineEvent(it)?.let { event -> visibleEventsSource.post(RoomDetailAction.TimelineEventTurnsVisible(event)) } } @@ -886,7 +886,7 @@ class TimelineViewModel @AssistedInject constructor( private fun handleResendEvent(action: RoomDetailAction.ResendMessage) { val targetEventId = action.eventId - room.getTimeLineEvent(targetEventId)?.let { + room.getTimelineEvent(targetEventId)?.let { // State must be UNDELIVERED or Failed if (!it.root.sendState.hasFailed()) { Timber.e("Cannot resend message, it is not failed, Cancel first") @@ -904,7 +904,7 @@ class TimelineViewModel @AssistedInject constructor( private fun handleRemove(action: RoomDetailAction.RemoveFailedEcho) { val targetEventId = action.eventId - room.getTimeLineEvent(targetEventId)?.let { + room.getTimelineEvent(targetEventId)?.let { // State must be UNDELIVERED or Failed if (!it.root.sendState.hasFailed()) { Timber.e("Cannot resend message, it is not failed, Cancel first") @@ -920,7 +920,7 @@ class TimelineViewModel @AssistedInject constructor( return } val targetEventId = action.eventId - room.getTimeLineEvent(targetEventId)?.let { + room.getTimelineEvent(targetEventId)?.let { // State must be in one of the sending states if (!it.root.sendState.isSending()) { Timber.e("Cannot cancel message, it is not sending") @@ -1046,14 +1046,14 @@ class TimelineViewModel @AssistedInject constructor( private fun handleReRequestKeys(action: RoomDetailAction.ReRequestKeys) { // Check if this request is still active and handled by me - room.getTimeLineEvent(action.eventId)?.let { + room.getTimelineEvent(action.eventId)?.let { session.cryptoService().reRequestRoomKeyForEvent(it.root) _viewEvents.post(RoomDetailViewEvents.ShowMessage(stringProvider.getString(R.string.e2e_re_request_encryption_key_dialog_content))) } } private fun handleTapOnFailedToDecrypt(action: RoomDetailAction.TapOnFailedToDecrypt) { - room.getTimeLineEvent(action.eventId)?.let { + room.getTimelineEvent(action.eventId)?.let { val code = when (it.root.mCryptoError) { MXCryptoError.ErrorType.KEYS_WITHHELD -> { WithHeldCode.fromCode(it.root.mCryptoErrorReason) @@ -1069,7 +1069,7 @@ class TimelineViewModel @AssistedInject constructor( // Do not allow to vote unsent local echo of the poll event if (LocalEcho.isLocalEchoId(action.eventId)) return // Do not allow to vote the same option twice - room.getTimeLineEvent(action.eventId)?.let { pollTimelineEvent -> + room.getTimelineEvent(action.eventId)?.let { pollTimelineEvent -> val currentVote = pollTimelineEvent.annotations?.pollResponseSummary?.aggregatedContent?.myVote if (currentVote != action.optionKey) { room.voteToPoll(action.eventId, action.optionKey) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt index 6adf248af9..325e9b9330 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt @@ -143,7 +143,7 @@ class MessageComposerViewModel @AssistedInject constructor( } private fun handleEnterEditMode(action: MessageComposerAction.EnterEditMode) { - room.getTimeLineEvent(action.eventId)?.let { timelineEvent -> + room.getTimelineEvent(action.eventId)?.let { timelineEvent -> setState { copy(sendMode = SendMode.Edit(timelineEvent, timelineEvent.getTextEditableContent())) } } } @@ -175,13 +175,13 @@ class MessageComposerViewModel @AssistedInject constructor( } private fun handleEnterQuoteMode(action: MessageComposerAction.EnterQuoteMode) { - room.getTimeLineEvent(action.eventId)?.let { timelineEvent -> + room.getTimelineEvent(action.eventId)?.let { timelineEvent -> setState { copy(sendMode = SendMode.Quote(timelineEvent, action.text)) } } } private fun handleEnterReplyMode(action: MessageComposerAction.EnterReplyMode) { - room.getTimeLineEvent(action.eventId)?.let { timelineEvent -> + room.getTimelineEvent(action.eventId)?.let { timelineEvent -> setState { copy(sendMode = SendMode.Reply(timelineEvent, action.text)) } } } @@ -479,7 +479,7 @@ class MessageComposerViewModel @AssistedInject constructor( if (inReplyTo != null) { // TODO check if same content? - room.getTimeLineEvent(inReplyTo)?.let { + room.getTimelineEvent(inReplyTo)?.let { room.editReply(state.sendMode.timelineEvent, it, action.text.toString()) } } else { @@ -555,17 +555,17 @@ class MessageComposerViewModel @AssistedInject constructor( sendMode = when (currentDraft) { is UserDraft.Regular -> SendMode.Regular(currentDraft.content, false) is UserDraft.Quote -> { - room.getTimeLineEvent(currentDraft.linkedEventId)?.let { timelineEvent -> + room.getTimelineEvent(currentDraft.linkedEventId)?.let { timelineEvent -> SendMode.Quote(timelineEvent, currentDraft.content) } } is UserDraft.Reply -> { - room.getTimeLineEvent(currentDraft.linkedEventId)?.let { timelineEvent -> + room.getTimelineEvent(currentDraft.linkedEventId)?.let { timelineEvent -> SendMode.Reply(timelineEvent, currentDraft.content) } } is UserDraft.Edit -> { - room.getTimeLineEvent(currentDraft.linkedEventId)?.let { timelineEvent -> + room.getTimelineEvent(currentDraft.linkedEventId)?.let { timelineEvent -> SendMode.Edit(timelineEvent, currentDraft.content) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt index e972ddcab5..bdc6906593 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt @@ -65,7 +65,7 @@ class VerificationItemFactory @Inject constructor( ?: return ignoredConclusion(params) // If we cannot find the referenced request we do not display the done event - val refEvent = session.getRoom(event.root.roomId ?: "")?.getTimeLineEvent(refEventId) + val refEvent = session.getRoom(event.root.roomId ?: "")?.getTimelineEvent(refEventId) ?: return ignoredConclusion(params) // If it's not a request ignore this event diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt index 686d767850..25d6f907b5 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt @@ -86,7 +86,7 @@ class ViewReactionsViewModel @AssistedInject constructor(@Assisted annotationsSummary.reactionsSummary .flatMap { reactionsSummary -> reactionsSummary.sourceEvents.map { - val event = room.getTimeLineEvent(it) + val event = room.getTimelineEvent(it) ?: throw RuntimeException("Your eventId is not valid") ReactionInfo( event.root.eventId!!, diff --git a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt index 31162f309f..b9d98429a7 100644 --- a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt +++ b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt @@ -81,7 +81,7 @@ class DataAttachmentRoomProvider( override fun getTimelineEventAtPosition(position: Int): TimelineEvent? { val item = getItem(position) - return room?.getTimeLineEvent(item.eventId) + return room?.getTimelineEvent(item.eventId) } override suspend fun getFileForSharing(position: Int): File? { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt index f73e2ab0c3..ec034173fc 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt @@ -65,7 +65,7 @@ class NotifiableEventResolver @Inject constructor( if (event.getClearType() == EventType.STATE_ROOM_MEMBER) { return resolveStateRoomEvent(event, session, canBeReplaced = false, isNoisy = isNoisy) } - val timelineEvent = session.getRoom(roomID)?.getTimeLineEvent(eventId) ?: return null + val timelineEvent = session.getRoom(roomID)?.getTimelineEvent(eventId) ?: return null return when (event.getClearType()) { EventType.MESSAGE, EventType.ENCRYPTED -> { diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt index b67e779a33..fa7b5aa7bc 100644 --- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt +++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt @@ -89,7 +89,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti val rootThreadEventId = permalinkData.eventId?.let { eventId -> val room = roomId?.let { session?.getRoom(it) } - room?.getTimeLineEvent(eventId)?.root?.getRootThreadEventId() + room?.getTimelineEvent(eventId)?.root?.getRootThreadEventId() } openRoom( navigationInterceptor, diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewModel.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewModel.kt index 7750e6d909..5c7ef72297 100644 --- a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewModel.kt @@ -68,7 +68,7 @@ class CreatePollViewModel @AssistedInject constructor( } private fun initializeEditedPoll(eventId: String) { - val event = room.getTimeLineEvent(eventId) ?: return + val event = room.getTimelineEvent(eventId) ?: return val content = event.getLastMessageContent() as? MessagePollContent ?: return val pollType = content.pollCreationInfo?.kind ?: PollType.DISCLOSED @@ -115,7 +115,7 @@ class CreatePollViewModel @AssistedInject constructor( } private fun sendEditedPoll(editedEventId: String, pollType: PollType, question: String, options: List) { - val editedEvent = room.getTimeLineEvent(editedEventId) ?: return + val editedEvent = room.getTimelineEvent(editedEventId) ?: return room.editPoll(editedEvent, pollType, question, options) } From beeee7c84bde4352908af7a9ab87da01f352f625 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 23 Feb 2022 18:01:19 +0100 Subject: [PATCH 2/6] Realm: avoid opening realm if not necessary in ReadReceiptsSummaryMapper --- .../mapper/ReadReceiptsSummaryMapper.kt | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt index f3770e4afe..2be4510b6f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt @@ -16,8 +16,11 @@ package org.matrix.android.sdk.internal.database.mapper +import io.realm.Realm +import io.realm.RealmList import org.matrix.android.sdk.api.session.room.model.ReadReceipt import org.matrix.android.sdk.internal.database.RealmSessionProvider +import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity import org.matrix.android.sdk.internal.database.query.where @@ -32,14 +35,22 @@ internal class ReadReceiptsSummaryMapper @Inject constructor( return emptyList() } val readReceipts = readReceiptsSummaryEntity.readReceipts - - return realmSessionProvider.withRealm { realm -> - readReceipts - .mapNotNull { - val roomMember = RoomMemberSummaryEntity.where(realm, roomId = it.roomId, userId = it.userId).findFirst() - ?: return@mapNotNull null - ReadReceipt(roomMember.asDomain(), it.originServerTs.toLong()) - } + // Avoid opening a new realm if we already have one opened + return if (readReceiptsSummaryEntity.isManaged) { + map(readReceipts, readReceiptsSummaryEntity.realm) + } else { + realmSessionProvider.withRealm { realm -> + map(readReceipts, realm) + } } } + + private fun map(readReceipts: RealmList, realm: Realm): List { + return readReceipts + .mapNotNull { + val roomMember = RoomMemberSummaryEntity.where(realm, roomId = it.roomId, userId = it.userId).findFirst() + ?: return@mapNotNull null + ReadReceipt(roomMember.asDomain(), it.originServerTs.toLong()) + } + } } From f7c79a6de2313329efaf69e82df9634e60c770e3 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 23 Feb 2022 18:02:02 +0100 Subject: [PATCH 3/6] Realm: fix remaining frozen result --- .../session/room/timeline/SendingEventsDataSource.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt index a98de1c595..b7a2cf2fce 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt @@ -46,7 +46,7 @@ internal class RealmSendingEventsDataSource( private val sendingTimelineEventsListener = RealmChangeListener> { events -> uiEchoManager.onSentEventsInDatabase(events.map { it.eventId }) - frozenSendingTimelineEvents = sendingTimelineEvents?.freeze() + updateFrozenResults(events) onEventsUpdated(false) } @@ -59,10 +59,17 @@ internal class RealmSendingEventsDataSource( override fun stop() { sendingTimelineEvents?.removeChangeListener(sendingTimelineEventsListener) + updateFrozenResults(null) sendingTimelineEvents = null roomEntity = null } + private fun updateFrozenResults(sendingEvents: RealmList?) { + // Makes sure to close the previous frozen realm + frozenSendingTimelineEvents?.realm?.close() + frozenSendingTimelineEvents = sendingEvents?.freeze() + } + override fun buildSendingEvents(): List { val builtSendingEvents = mutableListOf() uiEchoManager.getInMemorySendingEvents() From fd48fc910320f5935be0348851e0345a2b2d2470 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 23 Feb 2022 19:30:34 +0100 Subject: [PATCH 4/6] Add changelog --- changelog.d/5330.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5330.misc diff --git a/changelog.d/5330.misc b/changelog.d/5330.misc new file mode 100644 index 0000000000..6315ad536c --- /dev/null +++ b/changelog.d/5330.misc @@ -0,0 +1 @@ +Continue improving realm usage. \ No newline at end of file From ca8b69e3778f34b89326ce534955347fd57d2d7e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 24 Feb 2022 14:20:48 +0100 Subject: [PATCH 5/6] Use correct copyright --- .../internal/session/room/timeline/TimelineEventDataSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt index 7ce752e85c..638866a46e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From e32e006b8582382c9f60b687fa321352dc5f10db Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 28 Feb 2022 15:12:15 +0100 Subject: [PATCH 6/6] Add SDK changelog. --- changelog.d/5330.sdk | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5330.sdk diff --git a/changelog.d/5330.sdk b/changelog.d/5330.sdk new file mode 100644 index 0000000000..3f6d46401c --- /dev/null +++ b/changelog.d/5330.sdk @@ -0,0 +1 @@ +Change name of getTimeLineEvent and getTimeLineEventLive methods to getTimelineEvent and getTimelineEventLive. \ No newline at end of file