Handle latest thread message & root thread edition to update thread summary and thread list appropriately
This commit is contained in:
parent
92d082c26a
commit
358a7d0ec4
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue