class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelItemReadStatusIndicator(
channel: Channel,
message: Message,
currentUser: User?,
modifier: Modifier
) {
// Do not show any status indicator
}
@Composable
override fun MessageFooterStatusIndicator(
params: MessageFooterStatusIndicatorParams,
) {
// Do not show any status indicator
}
}Message Status Indicators
For messages sent by the current user, the status indicators represent the state of the message. It is shown below the message bubble, by default.
Status indicators states
The possible states of the status indicators are:
- pending: The message is pending to be sent to the server.
- sent: The message has been sent to the server successfully. It is shown as a gray checkmark.
- delivered: The message has been delivered to at least one of the channel members devices. It is shown as double gray checkmark.
- read: The message has been read by at least one of the channel members. It is shown as double blue checkmark.
The delivered state is only available since version 6.28.0 and it needs to be enabled in the Dashboard for each channel type.
| Pending | Sent | Delivered | Read | Read by many |
|---|---|---|---|---|
![]() | ![]() | ![]() | ![]() | ![]() |
If read_events are turned OFF for the channel, read indicators are hidden.
If delivery_events are turned OFF for the channel, delivery indicators are hidden.
Basic Customization
Hide status indicators
In case your app does not need to show the status indicators,
you can hide them by overriding the MessageFooterStatusIndicator component factory method.
| Before | After |
|---|---|
![]() | ![]() |
Advanced Customization
Show all read and delivered members
To show all the read and delivered members, you can create a custom screen that shows the members that have read the message and the ones that were delivered but not read yet.
For this, we can extend the message menu to add a message info option to show a screen with the read and delivered members.
class CustomChatComponentFactory : ChatComponentFactory {
/**
* Creates a message menu with option for message info.
*/
@Composable
override fun MessageMenu(
modifier: Modifier,
message: Message,
messageOptions: List<MessageOptionItemState>,
ownCapabilities: Set<String>,
onMessageAction: (MessageAction) -> Unit,
onShowMore: () -> Unit,
onDismiss: () -> Unit,
) {
var showMessageInfoDialog by remember { mutableStateOf(false) }
val allOptions = listOf(
MessageOptionItemState(
title = R.string.message_option_message_info,
titleColor = ChatTheme.colors.textHighEmphasis,
iconPainter = rememberVectorPainter(Icons.Outlined.Info),
iconColor = ChatTheme.colors.textLowEmphasis,
action = CustomAction(message, mapOf("message_info" to true)),
),
) + messageOptions
val extendedOnMessageAction: (MessageAction) -> Unit = { action ->
when {
action is CustomAction && action.extraProperties.contains("message_info") ->
showMessageInfoDialog = true
else -> onMessageAction(action)
}
}
var dismissed by remember { mutableStateOf(false) }
if (showMessageInfoDialog) {
ModalBottomSheet(
onDismissRequest = {
showMessageInfoDialog = false
onDismiss()
dismissed = true // Mark as dismissed to avoid animating the menu again
},
containerColor = ChatTheme.colors.appBackground,
) {
val coroutineScope = rememberCoroutineScope()
val state by readsOf(message, coroutineScope).collectAsState(null)
state?.let {
val (reads, deliveredReads) = it
MessageInfoContent(
reads = reads,
deliveredReads = deliveredReads,
)
}
}
} else if (!dismissed) {
super.MessageMenu(
modifier = modifier,
message = message,
messageOptions = allOptions,
ownCapabilities = ownCapabilities,
onMessageAction = extendedOnMessageAction,
onShowMore = onShowMore,
onDismiss = onDismiss,
)
}
}
}You can check the full sample implementation here, which renders a bottom sheet showing the members who read the message, and the members who had the message delivered.

At the moment, showing the timestamps of the read and delivered members is not recommended since the timestamp is always related to the latest message in the channel, and not for each message individually.






