Skip to content

Fixing notifications not being dismissed when read from other devices #4129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/3347.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes notifications not dismissing when reading messages on other devices
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
*/
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.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.ReadMarkerEntity
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import io.realm.Realm
import io.realm.RealmConfiguration

internal fun isEventRead(realmConfiguration: RealmConfiguration,
userId: String?,
Expand All @@ -39,26 +39,43 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration,
val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@use
val eventToCheck = liveChunk.timelineEvents.find(eventId)
isEventRead = when {
eventToCheck == null -> {
// This can happen in case of fast lane Event
false
}
eventToCheck == null -> hasReadMissingEvent(
realm = realm,
latestChunkEntity = liveChunk,
roomId = roomId,
userId = userId,
eventId = eventId
)
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
val eventToCheckIndex = eventToCheck.displayIndex

eventToCheckIndex <= readReceiptIndex
val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() ?: return@use
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.displayIndex ?: Int.MIN_VALUE
eventToCheck.displayIndex <= readReceiptIndex
}
}
}

return isEventRead
}

/**
* Missing events can be caused by the latest timeline chunk no longer contain an older event or
* by fast lane eagerly displaying events before the database has finished updating
*/
private fun hasReadMissingEvent(realm: Realm, latestChunkEntity: ChunkEntity, roomId: String, userId: String, eventId: String): Boolean {
return realm.doesEventExistInChunkHistory(eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId)
}

private fun Realm.doesEventExistInChunkHistory(eventId: String): Boolean {
return ChunkEntity.findIncludingEvent(this, eventId) != null
}

private fun Realm.hasReadReceiptInLatestChunk(latestChunkEntity: ChunkEntity, roomId: String, userId: String): Boolean {
return ReadReceiptEntity.where(this, roomId = roomId, userId = userId).findFirst()?.let {
latestChunkEntity.timelineEvents.find(it.eventId)
} != null
}

internal fun isReadMarkerMoreRecent(realmConfiguration: RealmConfiguration,
roomId: String?,
eventId: String?): Boolean {
Expand Down