Timeline: continue trying to make Read marker/receipts working

This commit is contained in:
ganfra 2021-11-10 19:17:34 +01:00
parent 92a37f15d4
commit 52df50a686
6 changed files with 60 additions and 16 deletions

View File

@ -44,6 +44,10 @@ data class TimelineEvent(
*/
val localId: Long,
val eventId: String,
/**
* This display index is the position in the current chunk.
* It's not unique on the timeline as it's reset on each chunk.
*/
val displayIndex: Int,
val senderInfo: SenderInfo,
val annotations: EventAnnotationsSummary? = null,

View File

@ -191,3 +191,29 @@ internal fun ChunkEntity.nextDisplayIndex(direction: PaginationDirection): Int {
}
}
}
internal fun ChunkEntity.doesNextChunksVerifyCondition(linkCondition: (ChunkEntity) -> Boolean): Boolean {
var nextChunkToCheck = this.nextChunk
while (nextChunkToCheck != null) {
if (linkCondition(nextChunkToCheck)) {
return true
}
nextChunkToCheck = nextChunkToCheck.nextChunk
}
return false
}
internal fun ChunkEntity.isMoreRecentThan(chunkToCheck: ChunkEntity): Boolean {
if (this.isLastForward) return true
if (chunkToCheck.isLastForward) return false
// Check if the chunk to check is linked to this one
if(chunkToCheck.doesNextChunksVerifyCondition { it == this }){
return true
}
// Otherwise check if this chunk is linked to last forward
if(this.doesNextChunksVerifyCondition { it.isLastForward }){
return true
}
// We don't know, so we assume it's false
return false
}

View File

@ -28,3 +28,13 @@ internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long {
currentIdNum.toLong() + 1
}
}
internal fun TimelineEventEntity.isMoreRecentThan(eventToCheck: TimelineEventEntity): Boolean {
val currentChunk = this.chunk?.first() ?: return false
val chunkToCheck = eventToCheck.chunk?.firstOrNull() ?: return false
return if (currentChunk == chunkToCheck) {
this.displayIndex >= eventToCheck.displayIndex
} else {
currentChunk.isMoreRecentThan(chunkToCheck)
}
}

View File

@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.database.query
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matrix.android.sdk.api.session.events.model.LocalEcho
import org.matrix.android.sdk.internal.database.helper.doesNextChunksVerifyCondition
import org.matrix.android.sdk.internal.database.helper.isMoreRecentThan
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.ReadMarkerEntity
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
@ -33,28 +35,26 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration,
if (LocalEcho.isLocalEchoId(eventId)) {
return true
}
// If we don't know if the event has been read, we assume it's not
var isEventRead = false
Realm.getInstance(realmConfiguration).use { realm ->
val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@use
val eventToCheck = liveChunk.timelineEvents.find(eventId)
val latestEvent = TimelineEventEntity.latestEvent(realm, roomId, true)
// If latest event is from you we are sure the event is read
if (latestEvent?.root?.sender == userId) {
return true
}
val eventToCheck = TimelineEventEntity.where(realm, roomId, eventId).findFirst()
isEventRead = when {
eventToCheck == null -> hasReadMissingEvent(
realm = realm,
latestChunkEntity = liveChunk,
roomId = roomId,
userId = userId,
eventId = eventId
)
eventToCheck == null -> false
eventToCheck.root?.sender == userId -> true
else -> {
val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() ?: return@use
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.displayIndex ?: Int.MIN_VALUE
eventToCheck.displayIndex <= readReceiptIndex
val readReceiptEvent = TimelineEventEntity.where(realm, roomId, readReceipt.eventId).findFirst() ?: return@use
readReceiptEvent.isMoreRecentThan(eventToCheck)
}
}
}
return isEventRead
}

View File

@ -39,7 +39,6 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
internal class DefaultReadService @AssistedInject constructor(
@Assisted private val roomId: String,
@SessionDatabase private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor,
private val setReadMarkersTask: SetReadMarkersTask,
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper,
@UserId private val userId: String

View File

@ -794,7 +794,6 @@ class RoomDetailViewModel @AssistedInject constructor(
}
private fun handleNavigateToEvent(action: RoomDetailAction.NavigateToEvent) {
stopTrackingUnreadMessages()
val targetEventId: String = action.eventId
val indexOfEvent = timeline.getIndexOfEvent(targetEventId)
if (indexOfEvent == null) {
@ -868,12 +867,12 @@ class RoomDetailViewModel @AssistedInject constructor(
.buffer(1, TimeUnit.SECONDS)
.filter { it.isNotEmpty() }
.subscribeBy(onNext = { actions ->
val bufferedMostRecentDisplayedEvent = actions.maxByOrNull { it.event.displayIndex }?.event ?: return@subscribeBy
val bufferedMostRecentDisplayedEvent = actions.minByOrNull { it.event.indexOfEvent() }?.event ?: return@subscribeBy
val globalMostRecentDisplayedEvent = mostRecentDisplayedEvent
if (trackUnreadMessages.get()) {
if (globalMostRecentDisplayedEvent == null) {
mostRecentDisplayedEvent = bufferedMostRecentDisplayedEvent
} else if (bufferedMostRecentDisplayedEvent.displayIndex > globalMostRecentDisplayedEvent.displayIndex) {
} else if (bufferedMostRecentDisplayedEvent.indexOfEvent() < globalMostRecentDisplayedEvent.indexOfEvent()) {
mostRecentDisplayedEvent = bufferedMostRecentDisplayedEvent
}
}
@ -886,6 +885,12 @@ class RoomDetailViewModel @AssistedInject constructor(
.disposeOnClear()
}
/**
* Returns the index of event in the timeline.
* Returns Int.MAX_VALUE if not found
*/
private fun TimelineEvent.indexOfEvent(): Int = timeline.getIndexOfEvent(eventId) ?: Int.MAX_VALUE
private fun handleMarkAllAsRead() {
setState { copy(unreadState = UnreadState.HasNoUnread) }
viewModelScope.launch {