Skip to content

Conversation

@andremion
Copy link
Contributor

@andremion andremion commented Oct 23, 2025

🎯 Goal

  • Send message delivery receipts, supporting local data buffering, batched reporting, event handling, and UI indicators.
  • Marks messages as delivered on:
    • Single channel query result (first page only)
    • Channel list query result
    • Push notification received
    • WS message.new event

https://linear.app/stream/issue/AND-769

🛠 Implementation details

Client module

  • New persistence and repository for delivery receipts (MessageReceiptDao/Entity/Repository, ChatClientDatabase, DateConverter).
  • New delivery reporting pipeline (MessageReceiptManager, MessageReceiptReporter) with 1s buffer and max 100 confirmations per call.
  • message.delivered WS event support.
  • Introduced new Channel extensions: readsOf, deliveredReadsOf.
  • Introduced ChatClient.markMessageAsDelivered to mark a message as delivered for the current user.
  • PrivacySettings.delivery_receipts support.
  • Channel read state extended with last_delivered_at and last_delivered_message_id.

Delivery receipts are:

  • Buffered and sent every 1s, max 100 per request.
  • Not sent for own messages, not sent if already read or already delivered.
  • Reconciled against reads (reads supersede delivered).

Privacy:

  • Suppressed if ownUser.privacySettings.deliveryReceipts.enabled == false.

UI:

  • Compose and XML indicators updated to support the new grey double tick (delivered)
  • Unified logic to hide the message status indicator when a message is deleted / ephemeral / sync status failed permanently.

🎨 UI Changes

1-to-1 chat

Screen.Recording.2025-11-04.at.08.43.56.mov

Group chat

Screen.Recording.2025-11-04.at.10.06.56.mov

🧪 Testing

  • Open the channel list from two devices connected with different users.
  • Send a message from user A to user B.
  • Long-press on the new message from user A.
  • Click on Message Info.
  • The message should be delivered.
  • Enter the chat from user B.
  • From user A, notice that the message should now be read.

@andremion andremion added the core label Oct 23, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 23, 2025

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.18 MB 5.22 MB 0.04 MB 🟢
stream-chat-android-offline 5.45 MB 5.46 MB 0.02 MB 🟢
stream-chat-android-ui-components 10.55 MB 10.57 MB 0.02 MB 🟢
stream-chat-android-compose 12.77 MB 12.80 MB 0.03 MB 🟢

@andremion andremion force-pushed the AND-769-message-delivery-status branch 3 times, most recently from cbf13fa to 0b052a3 Compare October 27, 2025 15:21
@github-actions
Copy link
Contributor

github-actions bot commented Oct 27, 2025

DB Entities have been updated. Do we need to upgrade DB Version?
Modified Entities :

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/persistence/db/entity/MessageReceiptEntity.kt
stream-chat-android-offline/src/main/java/io/getstream/chat/android/offline/repository/domain/channelconfig/internal/ChannelConfigEntity.kt
stream-chat-android-offline/src/main/java/io/getstream/chat/android/offline/repository/domain/user/internal/UserEntity.kt

@andremion andremion force-pushed the AND-769-message-delivery-status branch 6 times, most recently from d6aebd9 to 89655f6 Compare November 4, 2025 10:23
@andremion andremion requested a review from Copilot November 4, 2025 14:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request adds delivery status indicators for messages in the Stream Chat SDK. It introduces a new "delivered" state between "sent" and "read" states, allowing the UI to display when messages have been delivered to recipients but not yet read.

Key changes:

  • Added isMessageDelivered property to message and channel state classes
  • Introduced new delivery status icon and UI indicators
  • Updated database schema version to support delivery events persistence
  • Added new drawable resource for the delivered state (double checkmark in grey)

Reviewed Changes

Copilot reviewed 116 out of 122 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
stream-chat-android-core/src/main/java/io/getstream/chat/android/models/ChannelUserRead.kt Added lastDeliveredAt and lastDeliveredMessageId properties
stream-chat-android-core/src/main/java/io/getstream/chat/android/models/Config.kt Added deliveryEventsEnabled configuration flag
stream-chat-android-core/src/main/java/io/getstream/chat/android/PrivacySettings.kt Added delivery receipts privacy settings
stream-chat-android-ui-components/src/main/res/drawable/stream_ui_ic_check_double_grey.xml New drawable for delivered status indicator
stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem.kt Added isMessageDelivered property to MessageItem
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/MessageReadStatusIcon.kt Updated to support delivered status icon
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt Added new MessageFooterStatusIndicator overload with params
stream-chat-android-offline/src/main/java/io/getstream/chat/android/offline/repository/database/internal/ChatDatabase.kt Incremented database version to 96
stream-chat-android-state/src/main/java/io/getstream/chat/android/state/event/handler/internal/utils/ChatEventUtils.kt Added MessageDeliveredEvent to ChannelUserRead conversion

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@andremion andremion force-pushed the AND-769-message-delivery-status branch from 19d96be to 7e134c3 Compare November 4, 2025 14:44
@andremion andremion marked this pull request as ready for review November 4, 2025 14:44
@andremion andremion requested a review from a team as a code owner November 4, 2025 14:44
@andremion andremion force-pushed the AND-769-message-delivery-status branch from 7e134c3 to ce8df3f Compare November 7, 2025 12:06
Comment on lines +162 to +164
read.filter { read ->
read.user.id != message.user.id &&
(read.lastDeliveredAt ?: NEVER) >= message.getCreatedAtOrDefault(NEVER)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably want to also check for lastRead and promote it to delivered for supporting old messages where lastDeliveredAt is not present.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Channel.deliveredReadsOf function returns a list of ChannelUserRead objects representing which ones have delivered the given message, regardless of the read state. If lastDeliveredAt is null, as in old messages, it is not returned in the list.
For reads, we can use Channel.readsOf function, which checks specifically read states, regardless of the delivered states.
That's to give customers the flexibility to list who has read messages and who has delivered messages, exclusively.
If they want to list delivered reads that are not read, they can do:
channel.deliveredReadsOf(message) - channel.readsOf(message)

@andremion andremion force-pushed the AND-769-message-delivery-status branch 3 times, most recently from e71c17a to 63b7e99 Compare November 11, 2025 15:30
@andremion andremion requested a review from Copilot November 11, 2025 16:01
Copilot finished reviewing on behalf of andremion November 11, 2025 16:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 131 out of 137 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@andremion andremion force-pushed the AND-769-message-delivery-status branch from 63b7e99 to e235eb4 Compare November 11, 2025 17:22
@andremion andremion force-pushed the AND-769-message-delivery-status branch from 0b179a7 to 716b933 Compare November 12, 2025 10:40
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
77.9% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants