Handle latest thread message & root thread edition to update thread summary and thread list appropriately

This commit is contained in:
ariskotsomitopoulos 2022-01-27 13:22:04 +02:00
parent 92d082c26a
commit 358a7d0ec4
7 changed files with 66 additions and 16 deletions

View file

@ -86,6 +86,13 @@ interface TimelineService {
*/
fun isUserParticipatingInThread(rootThreadEventId: String): Boolean
/**
* Enhance the thread list with the edited events if needed
* @return the [LiveData] of [TimelineEvent]
*/
fun mapEventsWithEdition(threads: List<TimelineEvent>): List<TimelineEvent>
/**
* Marks the current thread as read. This is a local implementation
* @param rootThreadEventId the eventId of the current thread

View file

@ -29,5 +29,6 @@ data class ThreadDetails(
val threadSummaryLatestTextMessage: String? = null,
val lastMessageTimestamp: Long? = null,
var threadNotificationState: ThreadNotificationState = ThreadNotificationState.NO_NEW_MESSAGE,
val isThread: Boolean = false
val isThread: Boolean = false,
val lastRootThreadEdition: String? = null
)

View file

@ -19,9 +19,11 @@ package org.matrix.android.sdk.internal.database.helper
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.Sort
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
@ -88,17 +90,6 @@ internal fun EventEntity.markEventAsRoot(
threadSummaryLatestMessage = latestMessageTimelineEventEntity
}
///**
// * Find all TimelineEventEntity that are threads bind to the Event with rootThreadEventId
// * @param rootThreadEventId The root eventId that will try to find bind threads
// */
//internal fun EventEntity.findAllThreadsForRootEventId(realm: Realm, rootThreadEventId: String): RealmResults<TimelineEventEntity> =
// TimelineEventEntity
// .whereRoomId(realm, roomId = roomId)
// .equalTo(TimelineEventEntityFields.ROOT.ROOT_THREAD_EVENT_ID, rootThreadEventId)
// .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
// .findAll()
/**
* Count the number of threads for the provided root thread eventId, and finds the latest event message
* @param rootThreadEventId The root eventId that will find the number of threads
@ -124,7 +115,7 @@ internal fun EventEntity.threadSummaryInThread(realm: Realm, rootThreadEventId:
result = chunk.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)?.firstOrNull {
it.root?.rootThreadEventId == rootThreadEventId
}
chunk = ChunkEntity.find(realm, roomId, nextToken = chunk.prevToken) ?: break
chunk = ChunkEntity.find(realm, roomId, nextToken = chunk.prevToken) ?: break
}
result ?: return null
@ -139,7 +130,25 @@ internal fun TimelineEventEntity.Companion.findAllThreadsForRoomId(realm: Realm,
TimelineEventEntity
.whereRoomId(realm, roomId = roomId)
.equalTo(TimelineEventEntityFields.ROOT.IS_ROOT_THREAD, true)
.sort("${TimelineEventEntityFields.ROOT.THREAD_SUMMARY_LATEST_MESSAGE}.${TimelineEventEntityFields.DISPLAY_INDEX}", Sort.DESCENDING)
.sort("${TimelineEventEntityFields.ROOT.THREAD_SUMMARY_LATEST_MESSAGE}.${TimelineEventEntityFields.ROOT.ORIGIN_SERVER_TS}", Sort.DESCENDING)
internal fun List<TimelineEvent>.mapEventsWithEdition(realm: Realm, roomId: String): List<TimelineEvent> =
this.map {
EventAnnotationsSummaryEntity
.where(realm, roomId, eventId = it.eventId)
.findFirst()
?.editSummary
?.editions
?.lastOrNull()
?.eventId
?.let { editedEventId ->
TimelineEventEntity.where(realm, roomId, eventId = editedEventId).findFirst()?.let { editedEvent ->
it.root.threadDetails = it.root.threadDetails?.copy(lastRootThreadEdition = editedEvent.root?.asDomain()?.getDecryptedTextSummary()
?: "(edited)")
it
} ?: it
} ?: it
}
/**
* Find the number of all the local notifications for the specified room

View file

@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.crypto.verification.toState
import org.matrix.android.sdk.internal.database.helper.findRootThreadEvent
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.mapper.EventMapper
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntity
@ -64,7 +65,7 @@ import javax.inject.Inject
internal class EventRelationsAggregationProcessor @Inject constructor(
@UserId private val userId: String,
private val stateEventDataSource: StateEventDataSource
) : EventInsertLiveProcessor {
) : EventInsertLiveProcessor {
private val allowedTypes = listOf(
EventType.MESSAGE,
@ -302,6 +303,29 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
)
}
}
if(!isLocalEcho) {
val replaceEvent = TimelineEventEntity.where(realm, roomId, eventId).findFirst()
handleThreadSummaryEdition(editedEvent, replaceEvent, existingSummary?.editions)
}
}
/**
* Check if the edition is on the latest thread event, and update it accordingly
*/
private fun handleThreadSummaryEdition(editedEvent: EventEntity?,
replaceEvent: TimelineEventEntity?,
editions: List<EditionOfEvent>?) {
replaceEvent ?: return
editedEvent ?: return
editedEvent.findRootThreadEvent()?.apply {
val threadSummaryEventId = threadSummaryLatestMessage?.eventId
if (editedEvent.eventId == threadSummaryEventId || editions?.any { it.eventId == threadSummaryEventId } == true) {
// The edition is for the latest event or for any event replaced, this is to handle multiple
// edits of the same latest event
threadSummaryLatestMessage = replaceEvent
}
}
}
private fun handleResponse(realm: Realm,

View file

@ -37,6 +37,7 @@ import org.matrix.android.sdk.internal.database.RealmSessionProvider
import org.matrix.android.sdk.internal.database.helper.findAllLocalThreadNotificationsForRoomId
import org.matrix.android.sdk.internal.database.helper.findAllThreadsForRoomId
import org.matrix.android.sdk.internal.database.helper.isUserParticipatingInThread
import org.matrix.android.sdk.internal.database.helper.mapEventsWithEdition
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.EventEntity
@ -157,6 +158,12 @@ internal class DefaultTimelineService @AssistedInject constructor(
}
}
override fun mapEventsWithEdition(threads: List<TimelineEvent>): List<TimelineEvent> {
return Realm.getInstance(monarchy.realmConfiguration).use {
threads.mapEventsWithEdition(it, roomId)
}
}
override suspend fun markThreadAsRead(rootThreadEventId: String) {
monarchy.awaitTransaction {
EventEntity.where(

View file

@ -60,6 +60,7 @@ class ThreadListController @Inject constructor(
?.forEach { timelineEvent ->
val date = dateFormatter.format(timelineEvent.root.threadDetails?.lastMessageTimestamp, DateFormatKind.ROOM_LIST)
val decryptionErrorMessage = stringProvider.getString(R.string.encrypted_message)
val lastRootThreadEdition = timelineEvent.root.threadDetails?.lastRootThreadEdition
threadListItem {
id(timelineEvent.eventId)
avatarRenderer(host.avatarRenderer)
@ -68,7 +69,7 @@ class ThreadListController @Inject constructor(
date(date)
rootMessageDeleted(timelineEvent.root.isRedacted())
threadNotificationState(timelineEvent.root.threadDetails?.threadNotificationState ?: ThreadNotificationState.NO_NEW_MESSAGE)
rootMessage(timelineEvent.root.getDecryptedTextSummary() ?: decryptionErrorMessage)
rootMessage(lastRootThreadEdition ?: timelineEvent.root.getDecryptedTextSummary() ?: decryptionErrorMessage)
lastMessage(timelineEvent.root.threadDetails?.threadSummaryLatestTextMessage ?: decryptionErrorMessage)
lastMessageCounter(timelineEvent.root.threadDetails?.numberOfThreads.toString())
lastMessageMatrixItem(timelineEvent.root.threadDetails?.threadSummarySenderInfo?.toMatrixItem())

View file

@ -61,6 +61,7 @@ class ThreadListViewModel @AssistedInject constructor(@Assisted val initialState
private fun observeThreadsList() {
room?.flow()
?.liveThreadList()
?.map { room.mapEventsWithEdition(it) }
?.map {
it.map { threadRootEvent ->
val isParticipating = room.isUserParticipatingInThread(threadRootEvent.eventId)