1616
1717package io.getstream.chat.android.client.receipts
1818
19+ import io.getstream.chat.android.client.api.ChatApi
20+ import io.getstream.chat.android.client.api.models.QueryChannelRequest
21+ import io.getstream.chat.android.client.extensions.cidToTypeAndId
1922import io.getstream.chat.android.client.extensions.getCreatedAtOrThrow
2023import io.getstream.chat.android.client.extensions.internal.NEVER
2124import io.getstream.chat.android.client.extensions.internal.lastMessage
2225import io.getstream.chat.android.client.extensions.userRead
26+ import io.getstream.chat.android.client.persistance.repository.ChannelRepository
2327import io.getstream.chat.android.client.persistence.repository.MessageReceiptRepository
2428import io.getstream.chat.android.client.utils.message.isDeleted
2529import io.getstream.chat.android.models.Channel
2630import io.getstream.chat.android.models.Message
2731import io.getstream.chat.android.models.MessageType
2832import io.getstream.chat.android.models.User
29- import io.getstream.chat.android.models.UserId
3033import io.getstream.log.taggedLogger
3134import kotlinx.coroutines.CoroutineScope
3235import kotlinx.coroutines.launch
@@ -40,111 +43,143 @@ internal class MessageReceiptManager(
4043 private val scope : CoroutineScope ,
4144 private val now : () -> Date ,
4245 private val getCurrentUser : () -> User ? ,
46+ private val channelRepository : ChannelRepository ,
4347 private val messageReceiptRepository : MessageReceiptRepository ,
48+ private val api : ChatApi ,
4449) {
4550
4651 private val logger by taggedLogger(" Chat:MessageReceiptManager" )
4752
4853 /* *
49- * Request to mark the last undelivered messages in the given channels as delivered.
54+ * Request to mark the given channels as delivered
55+ * if delivery receipts are enabled for the current user.
5056 *
51- * A delivery message candidate is the last non-deleted message in the channel that:
57+ * A channel can have a message marked as delivered only if:
58+ * - Delivery events are enabled in the channel config
5259 *
60+ * A delivery message candidate is the last non-deleted message in the channel that:
61+ * - It was not sent by the current user
62+ * - It is not a system message
63+ * - It is not deleted
5364 * - Is not yet marked as read by the current user
5465 * - Is not yet marked as delivered by the current user
5566 */
5667 fun markChannelsAsDelivered (channels : List <Channel >) {
57- val deliveredMessageCandidates = channels.mapNotNull(::getUndeliveredMessage)
68+ val currentUser = getCurrentUser() ? : run {
69+ logger.w { " [markChannelsAsDelivered] Current user is null" }
70+ return
71+ }
72+
73+ if (! currentUser.isDeliveryReceiptsEnabled) return
74+
75+ val deliveredMessageCandidates = channels.mapNotNull { channel ->
76+ channel.lastMessage?.takeIf { lastNonDeletedMessage ->
77+ canMarkMessageAsDelivered(currentUser, channel, lastNonDeletedMessage)
78+ }
79+ }
5880 markMessagesAsDelivered(messages = deliveredMessageCandidates)
5981 }
6082
6183 /* *
62- * Request to mark the given messages as delivered if delivery receipts are enabled
63- * in the current user privacy settings.
64- *
65- * A message can be marked as delivered only if:
84+ * Request to mark the given message as delivered
85+ * if delivery receipts are enabled for the current user.
6686 *
67- * - It was not sent by the current user
68- * - It is not a system message
69- * - It is not deleted
87+ * @see [markChannelsAsDelivered] for the conditions to mark a message as delivered.
7088 */
71- fun markMessagesAsDelivered ( messages : List < Message > ) {
72- if (messages.isEmpty()) {
73- logger.w { " [markMessagesAsDelivered] No receipts to send " }
89+ fun markMessageAsDelivered ( message : Message ) {
90+ val currentUser = getCurrentUser() ? : run {
91+ logger.w { " [markMessageAsDelivered] Current user is null " }
7492 return
7593 }
7694
77- logger.d { " [markMessagesAsDelivered] Processing delivery receipts for ${messages.size} messages… " }
95+ if ( ! currentUser.isDeliveryReceiptsEnabled) return
7896
79- val currentUser = getCurrentUser() ? : run {
80- logger.w { " [markMessagesAsDelivered] Cannot send delivery receipts: current user is null" }
81- return
82- }
97+ scope.launch {
98+ val channel = getChannel(message.cid) ? : run {
99+ logger.w { " [markMessageAsDelivered] Channel ${message.cid} not found" }
100+ return @launch
101+ }
83102
84- // Check if delivery receipts are enabled for the current user
85- if (! currentUser.isDeliveryReceiptsEnabled) {
86- logger.w { " [markMessagesAsDelivered] Delivery receipts disabled for user ${currentUser.id} " }
87- return
103+ if (canMarkMessageAsDelivered(currentUser, channel, message)) {
104+ markMessagesAsDelivered(messages = listOf (message))
105+ }
88106 }
107+ }
89108
90- // Filter out messages that shouldn't have delivery receipts sent
91- val filteredMessages = messages.filter { message ->
92- shouldSendDeliveryReceipt(currentUserId = currentUser.id, message = message)
93- }
94- if (filteredMessages.size != messages.size) {
95- logger.d {
96- " [markMessagesAsDelivered] " +
97- " Skipping delivery receipts for ${messages.size - filteredMessages.size} messages"
109+ private suspend fun getChannel (cid : String ): Channel ? =
110+ channelRepository.selectChannel(cid)
111+ ? : run {
112+ val (channelType, channelId) = cid.cidToTypeAndId()
113+ val request = QueryChannelRequest ()
114+ api.queryChannel(channelType, channelId, request)
115+ .await().getOrNull()
98116 }
99- }
100117
101- if (filteredMessages.isEmpty()) {
118+ private fun markMessagesAsDelivered (messages : List <Message >) {
119+ if (messages.isEmpty()) {
102120 logger.w { " [markMessagesAsDelivered] No receipts to send" }
103121 return
104122 }
105123
124+ logger.d { " [markMessagesAsDelivered] Processing delivery receipts for ${messages.size} messages…" }
125+
106126 scope.launch {
107- val receipts = filteredMessages .map { message -> message.toDeliveryReceipt() }
127+ val receipts = messages .map { message -> message.toDeliveryReceipt() }
108128 messageReceiptRepository.upsertMessageReceipts(receipts)
109129
110- logger.d { " [markMessagesAsDelivered] ${filteredMessages .size} delivery receipts upserted" }
130+ logger.d { " [markMessagesAsDelivered] ${messages .size} delivery receipts upserted" }
111131 }
112132 }
113133
114- private fun getUndeliveredMessage (channel : Channel ): Message ? {
134+ private fun canMarkMessageAsDelivered (
135+ currentUser : User ,
136+ channel : Channel ,
137+ message : Message ,
138+ ): Boolean {
139+ // Check if delivery events are enabled for the channel
115140 if (! channel.config.deliveryEventsEnabled) {
116- logger.w { " [getUndeliveredMessage] Delivery events disabled for channel ${channel.cid} " }
117- return null
118- }
119- val currentUser = getCurrentUser() ? : run {
120- logger.w { " [getUndeliveredMessage] Cannot get undelivered message: current user is null" }
121- return null
141+ logger.w { " [canMarkMessageAsDelivered] Delivery events disabled for channel ${channel.cid} " }
142+ return false
122143 }
123- val userRead = channel.userRead(currentUser.id) ? : return null
124- // Get the last non-deleted message in the channel
125- val lastMessage = channel.lastMessage ? : return null
126- val createdAt = lastMessage.getCreatedAtOrThrow()
127- // Check if the last message is already marked as read
128- if (createdAt <= userRead.lastRead) return null
129- // Check if the last message is already marked as delivered
130- if (createdAt <= (userRead.lastDeliveredAt ? : NEVER )) return null
131144
132- return lastMessage
133- }
134-
135- private fun shouldSendDeliveryReceipt (currentUserId : UserId , message : Message ): Boolean {
136- // Don't send delivery receipts for messages sent by the current user
137- if (message.user.id == currentUserId) {
145+ // Do not send delivery receipts for messages sent by the current user
146+ if (message.user.id == currentUser.id) {
147+ logger.w {
148+ " [canMarkMessageAsDelivered] Message ${message.id} was sent by the current user ${currentUser.id} "
149+ }
138150 return false
139151 }
140152
141- // Don't send delivery receipts for system messages
153+ // Do not send delivery receipts for system messages
142154 if (message.type == MessageType .SYSTEM ) {
155+ logger.w { " [canMarkMessageAsDelivered] Message ${message.id} is a system message" }
143156 return false
144157 }
145158
146- // Don't send delivery receipts for deleted messages
159+ // Do not send delivery receipts for deleted messages
147160 if (message.isDeleted()) {
161+ logger.w { " [canMarkMessageAsDelivered] Message ${message.id} is deleted" }
162+ return false
163+ }
164+
165+ val userRead = channel.userRead(currentUser.id) ? : run {
166+ logger.w {
167+ " [canMarkMessageAsDelivered] No read state for user ${currentUser.id} in channel ${channel.cid} "
168+ }
169+ return false
170+ }
171+
172+ val createdAt = message.getCreatedAtOrThrow()
173+
174+ // Check if the last message is already marked as read
175+ if (createdAt <= userRead.lastRead) {
176+ logger.w { " [canMarkMessageAsDelivered] Message ${message.id} is already marked as read" }
177+ return false
178+ }
179+
180+ // Check if the last message is already marked as delivered
181+ if (createdAt <= (userRead.lastDeliveredAt ? : NEVER )) {
182+ logger.w { " [canMarkMessageAsDelivered] Message ${message.id} is already marked as delivered" }
148183 return false
149184 }
150185
0 commit comments