From 0e2213a199a3981811712dc90b24ad7fedb23118 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 26 May 2026 10:10:42 +0200 Subject: [PATCH] Fix public read receipts being sent by mistake (#6838) When returning to the chat screen from the room details one or a member's profile, `TimelineEvent.OnScrollFinished` will be called immediately, and this would read the default value for `isSendPublicReadReceiptsEnabled`, which is `true`. If you had public read receipts disabled, this is a mistake, and would send a public read receipt. Instead, what we want to do is wait until the updated value is emitted and use it to decide whether we want to send a public or private read receipt. --- .../impl/timeline/TimelinePresenter.kt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index 0b99c45e06..0681a0ff38 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -66,6 +66,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -137,9 +138,6 @@ class TimelinePresenter( val messageShieldDialogData: MutableState = remember { mutableStateOf(null) } val resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailurePresenter.present() - val isSendPublicReadReceiptsEnabled by remember { - sessionPreferencesStore.isSendPublicReadReceiptsEnabled() - }.collectAsState(initial = true) val renderReadReceipts by remember { sessionPreferencesStore.isRenderReadReceiptsEnabled() }.collectAsState(initial = true) @@ -171,12 +169,15 @@ class TimelinePresenter( newEventState.value = NewEventState.None } Timber.tag(tag).d("## sendReadReceiptIfNeeded firstVisibleIndex: ${event.firstIndex}") - sessionCoroutineScope.sendReadReceiptIfNeeded( - firstVisibleIndex = event.firstIndex, - timelineItems = timelineItems, - lastReadReceiptId = lastReadReceiptId, - readReceiptType = if (isSendPublicReadReceiptsEnabled) ReceiptType.READ else ReceiptType.READ_PRIVATE, - ) + sessionCoroutineScope.launch { + val sendPublicReadReceipts = sessionPreferencesStore.isSendPublicReadReceiptsEnabled().first() + sendReadReceiptIfNeeded( + firstVisibleIndex = event.firstIndex, + timelineItems = timelineItems, + lastReadReceiptId = lastReadReceiptId, + readReceiptType = if (sendPublicReadReceipts) ReceiptType.READ else ReceiptType.READ_PRIVATE, + ) + } } else { newEventState.value = NewEventState.None }