From 7105a20f4fb96bf34300e1977907fb2d440cb0df Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 30 Sep 2021 17:14:31 +0100 Subject: [PATCH 1/5] fixes notifications not being marked as read when the last chunk containing the event is no longer the latest - use explict returns constants to attempt to add more documentation - queries for the existence of the event in all of the chunk history and if a read receipt exists in the latest chunk (which it should if a user has just read on another client) which allows us to mark old notifications events as read --- .../internal/database/query/ReadQueries.kt | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt index 5423025823d..eb98faec347 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt @@ -23,6 +23,9 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import io.realm.Realm import io.realm.RealmConfiguration +private const val MARK_OLD_EVENT_AS_READ = true +private const val MARK_UNREAD_DUE_TO_FASTLANE = false + internal fun isEventRead(realmConfiguration: RealmConfiguration, userId: String?, roomId: String?, @@ -39,10 +42,7 @@ 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 -> handleMissingEvent(realm, liveChunk, roomId, userId, eventId) eventToCheck.root?.sender == userId -> true else -> { val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() @@ -59,6 +59,26 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration, return isEventRead } +private fun handleMissingEvent(realm: Realm, latestChunkEntity: ChunkEntity, roomId: String, userId: String, eventId: String): Boolean { + return if (realm.doesEventExistInChunkHistory(eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId)) { + MARK_OLD_EVENT_AS_READ + } else { + // This can happen when fast lane events are displayed before the database finishes updating + MARK_UNREAD_DUE_TO_FASTLANE + } +} + +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, userId).findFirst()?.let { + latestChunkEntity.timelineEvents.find(it.eventId) + } != null +} + + internal fun isReadMarkerMoreRecent(realmConfiguration: RealmConfiguration, roomId: String?, eventId: String?): Boolean { From 49e332cb1cbeb937e99f06c09a47ee6de48b0519 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 30 Sep 2021 17:30:23 +0100 Subject: [PATCH 2/5] formatting --- .../matrix/android/sdk/internal/database/query/ReadQueries.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt index eb98faec347..47969270f4c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt @@ -78,7 +78,6 @@ private fun Realm.hasReadReceiptInLatestChunk(latestChunkEntity: ChunkEntity, ro } != null } - internal fun isReadMarkerMoreRecent(realmConfiguration: RealmConfiguration, roomId: String?, eventId: String?): Boolean { From a3c4f5677484b8bf31f0fcc6af977bb69496c00f Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 30 Sep 2021 17:31:23 +0100 Subject: [PATCH 3/5] adding changelog entry --- changelog.d/3347.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/3347.bugfix diff --git a/changelog.d/3347.bugfix b/changelog.d/3347.bugfix new file mode 100644 index 00000000000..8ba1d7af882 --- /dev/null +++ b/changelog.d/3347.bugfix @@ -0,0 +1 @@ +Fixes notifications not dismissing when reading messages on other devices \ No newline at end of file From f9d2f236a491f50176692c30647201f5b819a3b9 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 1 Oct 2021 14:43:39 +0100 Subject: [PATCH 4/5] using named parameters when the same types are used in close proximity --- .../internal/database/query/ReadQueries.kt | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt index 47969270f4c..f0470605e9c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt @@ -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 private const val MARK_OLD_EVENT_AS_READ = true private const val MARK_UNREAD_DUE_TO_FASTLANE = false @@ -42,16 +42,18 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration, val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@use val eventToCheck = liveChunk.timelineEvents.find(eventId) isEventRead = when { - eventToCheck == null -> handleMissingEvent(realm, liveChunk, roomId, userId, eventId) + eventToCheck == null -> handleMissingEvent( + 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 + 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 } } } @@ -72,8 +74,8 @@ 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, userId).findFirst()?.let { +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 } From c72f66871fc9f1a442cbe0dab66ee15347ec77d5 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 1 Oct 2021 16:20:42 +0100 Subject: [PATCH 5/5] replacing boolean constants with an improved function name + doc around why the events can be missing --- .../internal/database/query/ReadQueries.kt | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt index f0470605e9c..60096777d9f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt @@ -23,9 +23,6 @@ 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 -private const val MARK_OLD_EVENT_AS_READ = true -private const val MARK_UNREAD_DUE_TO_FASTLANE = false - internal fun isEventRead(realmConfiguration: RealmConfiguration, userId: String?, roomId: String?, @@ -42,7 +39,7 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration, val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@use val eventToCheck = liveChunk.timelineEvents.find(eventId) isEventRead = when { - eventToCheck == null -> handleMissingEvent( + eventToCheck == null -> hasReadMissingEvent( realm = realm, latestChunkEntity = liveChunk, roomId = roomId, @@ -50,7 +47,7 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration, eventId = eventId ) eventToCheck.root?.sender == userId -> true - else -> { + 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 @@ -61,13 +58,12 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration, return isEventRead } -private fun handleMissingEvent(realm: Realm, latestChunkEntity: ChunkEntity, roomId: String, userId: String, eventId: String): Boolean { - return if (realm.doesEventExistInChunkHistory(eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId)) { - MARK_OLD_EVENT_AS_READ - } else { - // This can happen when fast lane events are displayed before the database finishes updating - MARK_UNREAD_DUE_TO_FASTLANE - } +/** + * 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 {