class CustomChatComponentFactory : ChatComponentFactory {
// Override the specific composable methods which you like to customize
}
Component Factory
The ChatComponentFactory
is a factory which defines most of the stateless
low-level composable components, which are used as building blocks for the
high-level screen components and the bound components
(see Component Architecture).
The screen components, the bound components, and even the low-level components
which depend on different low-level components, use the ChatComponentFactory
to render specific components of the UI in a stateless manner.
By overriding the ChatComponentFactory
, developers can easily customize or
override specific parts of the Chat UI, without the need to build their own
implementations from scratch. This enables a high degree of customization and
flexibility, allowing the Chat UI to be tailored to specific design requirements.
The ChatComponentFactory is available on the Compose SDK since version 6.11.0
Usage
To apply a custom component factory to your Chat UI, all you need to do is to
implement the ChatComponentFactory
interface:
And pass the custom ChatComponentFactory
to the ChatTheme
wrapping your
Chat UI:
ChatTheme(
componentFactory = CustomChatComponentFactory(),
) {
MessagesScreen(
viewModelFactory = viewModelFactory,
)
}
The custom components provided by the custom ChatComponentFactory
will now
override all the default components used by the wrapped MessagesScreen
.
Customization options
The ChatComponentFactory
allows customization of most low-level components
used in different Chat screens. It provides the ability to customize common components globally,
as well as specific components in particular locations.
Available Components
Component | Description |
---|---|
Avatars | Customize user, group, and channel avatars. |
Channel List Header | Modify the header of the channel list. |
Channel Items | Customize how individual channels and their elements appear. |
Messages List Header | Customize the header of the message list. |
Messages Items | Customize message bubbles, timestamps, and other elements. |
Message Composer | Customize the message input field, send button, and attachments. |
Menus & Actions | Customize context menus for messages and channels. |
Reactions | Modify the reaction picker and displayed reactions. |
Thread List | Customize the thread list components. |
Pinned Message List | Customize the pinned message list components. |
Avatars
The ChatComponentFactory
provides a way to customize the avatars which are
used in the Chat screens. You can customize several types of avatars:
ChannelAvatar
Avatar shown in the leading part of the channel items, or in the heading of a message list:
ChannelItem | MessageListHeader |
---|---|
![]() | ![]() |
To customize the default ChannelAvatar
,
you need to override the ChatComponentFactory#ChannelAvatar
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelAvatar(
modifier: Modifier,
channel: Channel,
currentUser: User?,
onClick: (() -> Unit)?
) {
// Your implementation of the channel avatar
}
}
UserAvatar
Avatar shown for a single user, showing his image (if available), or the user initials. It also shows an online indicator if the user is online. It is used in several places such as:
- Search results
- Channel members
- Mention suggestions
ChannelAvatar
- if theChannel
is a channel consisting of two members, one of which is the current user, or if theChannel
has only one user.
Search results | Channel members | Mention suggestions |
---|---|---|
![]() | ![]() | ![]() |
To customize the default UserAvatar
, you need to override the
ChatComponentFactory#UserAvatar
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun UserAvatar(
modifier: Modifier,
user: User,
textStyle: TextStyle,
showOnlineIndicator: Boolean,
onlineIndicator: @Composable (BoxScope.() -> Unit),
onClick: (() -> Unit)?
) {
// Your implementation of the user avatar
}
}
GroupAvatar
Avatar which is internally used by the ChannelAvatar
, to render an avatar for
2 or more users. You can override it if you want to utilize the default
ChannelAvatar
for channel consisting of 1 or 2 members, but want to customize
the case when the Channel
has more than 2 members.
To customize the default GroupAvatar
, you need to override the
ChatComponentFactory#GroupAvatar
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun GroupAvatar(
modifier: Modifier,
users: List<User>,
shape: Shape,
textStyle: TextStyle,
onClick: (() -> Unit)?
) {
// Your implementation of the group avatar
}
}
Avatar
Default, low-level component which is independent from Channel
or User
. It
is internally used by the ChannelAvatar
and the GroupAvatar
to render a
single avatar in the grid, and also by the UserAvatar
to render the avatar
content. It is also used in other places where we show an avatar for a single
user, where the online indicator is not shown, such as:
- Channel list header - avatar of the currently logged in user
- Quoted messages - avatar of the user who sent the quoted message
- Thread participants in the message footer
- Polls - avatar of users which casted a vote
- User reactions
- Leading content of a message - avatar of the user who sent the message
Channel list header | Quoted message | Thread participants | Polls | User reactions | Message sender |
---|---|---|---|---|---|
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
To customize the default Avatar
, you need to override the
ChatComponentFactory#Avatar
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun Avatar(
modifier: Modifier,
imageUrl: String,
initials: String,
shape: Shape,
textStyle: TextStyle,
placeholderPainter: Painter?,
contentDescription: String?,
initialsAvatarOffset: DpOffset,
onClick: (() -> Unit)?
) {
// Your implementation of the avatar
}
}
Channel List Header
The ChannelListHeader
is the default component displayed in the
ChannelsScreen
header if the isShowingHeader
flag is set to true
(See: Channels Screen
and Channel List Header).
Channel List Header |
---|
![]() |
If you would like to customize the default ChannelListHeader
while using the
high-level screen component ChannelsScreen
you can override the corresponding
ChatComponentFactory
method: ChannelListHeader
. The method provides some
default data such as the title, the connection state, and the default user
actions, which you can use to build your own channel list header:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelListHeader(
modifier: Modifier,
title: String,
currentUser: User?,
connectionState: ConnectionState,
onAvatarClick: (User?) -> Unit,
onHeaderActionClick: () -> Unit
) {
// Your custom implementation of the channel list header
}
}
The factory also allows for a more granular customization of the channel list header, by providing different factory methods for the leading, the center and the trailing content of the header. The default leading content is an avatar of the currently logged in user, the default center content consists of a title showing the connection state, while the trailing content displays an additional custom action button.
You can customize the different parts of the header by providing your own implementation of the corresponding methods:
ChannelListHeaderLeadingContent
ChannelListHeaderCenterContent
ChannelListHeaderTrailingContent
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.ChannelListHeaderLeadingContent(
currentUser: User?,
onAvatarClick: (User?) -> Unit
) {
// Your implementation of the leading content
}
@Composable
override fun RowScope.ChannelListHeaderCenterContent(
connectionState: ConnectionState,
title: String
) {
// Your implementation of the center content
}
@Composable
override fun RowScope.ChannelListHeaderTrailingContent(
onHeaderActionClick: () -> Unit
) {
// Your implementation of the trailing content
}
}
By overriding any of these ChatComponentFactory
methods, you can easily swap
in and out the ChannelListHeader
(or specific parts from it), while using the
high-level ChannelsScreen
component.
If you are not using the high-level screen component ChannelsScreen
, you can
still use the ChannelListHeader
component independently from the
ChatComponentFactory
, and customize its leading/center/trailing content
directly by passing your own content for the
leadingContent
/centerContent
/trailingContent
slots as described in
Channel List Header.
Channel Items
Similar to the ChannelListHeader
, the ChatComponentFactory
provides a way
to customize the channel items which are shown in the list of channels
(in the high-level screen component ChannelsScreen
, or the bound
ChannelList
component).
Channel list item |
---|
![]() |
To provide your own implementation for the channel item, you can override the
ChatComponentFactory#ChannelListItemContent
. The method provides the channel
item which needs to be rendered, the default click and long-click actions, and
the current user which you can use to build your own implementation of the
channel item:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun LazyItemScope.ChannelListItemContent(
channelItem: ItemState.ChannelItemState,
currentUser: User?,
onChannelClick: (Channel) -> Unit,
onChannelLongClick: (Channel) -> Unit,
) {
// Your implementation of the channel item
}
}
The factory also allows for a more granular customization of the channel items, by providing different factory methods for the leading, the center and the trailing content of the item. The default leading content is an avatar of channel, the default center content consists of the channel name and the last message in the channel, while the trailing content displays the timestamp of the last message in the channel.
You can customize the leading/center/trailing content of the channel item separately, but overriding one or more of the dedicated methods:
ChannelItemLeadingContent
ChannelItemCenterContent
ChannelItemTrailingContent
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.ChannelItemLeadingContent(
channelItem: ItemState.ChannelItemState,
currentUser: User?,
) {
// Your channel item leading content implementation
}
@Composable
override fun RowScope.ChannelItemCenterContent(
channelItem: ItemState.ChannelItemState,
currentUser: User?,
) {
// Your channel item center content implementation
}
@Composable
override fun RowScope.ChannelItemTrailingContent(
channelItem: ItemState.ChannelItemState,
currentUser: User?,
) {
// Your channel item trailing content implementation
}
}
By utilizing these methods, you can easily customize the appearance of the
channel items (or parts of them), while still utilizng the features that the
high-level ChannelsScreen
component provides.
If you are using the bound ChannelList
component instead of the high-level
ChannelsScreen
, you can also directly customize the channel items by
providing a custom implementation for the channelContent
(more details in the
Channel List
documentation).
Message List Header
The MessageListHeader
is the default component displayed in the
MessagesScreen
header if the showHeader
flag is set to true
(See: Messages Screen
and Message List Header).
Message List Header |
---|
![]() |
If you would like to customize the default MessageListHeader
while using the
high-level screen component MessagesScreen
you can override the corresponding
ChatComponentFactory
method: MessageListHeader
. The method provides some
default data such as the Channel
, the connection state, the typing users, and
the default user actions which you can use to build your own message list
header:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageListHeader(
modifier: Modifier,
channel: Channel,
currentUser: User?,
connectionState: ConnectionState,
typingUsers: List<User>,
messageMode: MessageMode,
onBackPressed: () -> Unit,
onHeaderTitleClick: (Channel) -> Unit,
onChannelAvatarClick: () -> Unit,
) {
// Your implementation of the message list header
}
}
The factory also allows for a more granular customization of the message list header, by providing different factory methods for the leading, the center and the trailing content of the header. The default leading content is a back button, while the center content consists of a title holding the channel name, and a subtitle showing info about the user count. The trailing content shows the channel avatar.
You can customize the different parts of the header by providing your own implementation of the corresponding methods:
MessageListHeaderLeadingContent
MessageListHeaderCenterContent
MessageListHeaderTrailingContent
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.MessageListHeaderLeadingContent(
onBackPressed: () -> Unit,
) {
// Your implementation for the message list header leading content
}
@Composable
override fun RowScope.MessageListHeaderCenterContent(
modifier: Modifier,
channel: Channel,
currentUser: User?,
typingUsers: List<User>,
messageMode: MessageMode,
onHeaderTitleClick: (Channel) -> Unit,
connectionState: ConnectionState,
) {
// Your implementation for the message list header center content
}
@Composable
override fun RowScope.MessageListHeaderTrailingContent(
channel: Channel,
currentUser: User?,
onClick: () -> Unit,
) {
// Your implementation for the message list header trailing content
}
}
By overriding any of these ChatComponentFactory
methods, you can easily swap
in and out the MessageListHeader
(or specific parts from it), while using the
high-level MessagesScreen
component.
You can also customize the MessageListHeader
from the MessagesScreen
by
passing your implemenation in the topBarContent
slot.
If you are not using the high-level screen component MessagesScreen
, you can
still use the MessageListHeader
component independently from the
ChatComponentFactory
, and customize its leading/center/trailing content
directly by passing your own content for the
leadingContent
/centerContent
/trailingContent
slots as described in
Message List Header.
Message Items
MessageListItemContent
The message list item content represents the entire content of a regular chat message.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
public fun LazyItemScope.MessageListItemContent(
messageItem: MessageItemState,
reactionSorting: ReactionSorting,
onPollUpdated: (Message, Poll) -> Unit,
onCastVote: (Message, Poll, Option) -> Unit,
onRemoveVote: (Message, Poll, Vote) -> Unit,
selectPoll: (Message, Poll, PollSelectionType) -> Unit,
onClosePoll: (String) -> Unit,
onAddPollOption: (Poll, String) -> Unit,
onLongItemClick: (Message) -> Unit,
onThreadClick: (Message) -> Unit,
onReactionsClick: (Message) -> Unit,
onGiphyActionClick: (GiphyAction) -> Unit,
onMediaGalleryPreviewResult: (MediaGalleryPreviewResult?) -> Unit,
onQuotedMessageClick: (Message) -> Unit,
onUserAvatarClick: ((User) -> Unit)?,
onMessageLinkClick: ((Message, String) -> Unit)?,
onUserMentionClick: (User) -> Unit,
onAddAnswer: (Message, Poll, String) -> Unit,
) {
// Custom message list item content implementation
}
}
MessageTextContent
This allows customization of the text content inside a message bubble.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageTextContent(
message: Message,
currentUser: User?,
onLongItemClick: (Message) -> Unit,
onLinkClick: ((Message, String) -> Unit)?,
onUserMentionClick: (User) -> Unit
) {
// Custom message text content implementation
}
}
MessageItemFooterContent
This allows customization of the entire footer of a message, which includes timestamps and message status.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ColumnScope.MessageItemFooterContent(
messageItem: MessageItemState
) {
// Custom message item footer implementation
}
}
MessageFooterStatusIndicator
This allows customization of the status indicator of a message, which includes the read status and read count.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageFooterStatusIndicator(
modifier: Modifier,
message: Message,
isMessageRead: Boolean,
readCount: Int
) {
// Custom status indicator implementation
}
}
Message Composer
The ChatComponentFactory
provides a way to customize different parts of the
MessageComposer
when it is used as part of the high-level screen component
MessagesScreen
, by simply overriding the corresponding factory method,
without the need to re-implement big parts of the UI.
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can use the ChatComponentFactory
, but
you can also customize most of the components by passing custom implementation
in the specific slots. More details can be found in the
Message Composer
docs.
The default composer consists of several basic components:
- Attachments button
- Commands button
- Input field
- Send button
Message composer |
---|
![]() |
Let’s see how you can customize each one of the base composer components:
Composer label
By default, when there is no message entered in the composer, it shows a simple
“Send a message” label. To override the default text with a new one, or to
completely replace the component with a different one, you can override the
ChatComponentFactory#MessageComposerLabel
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerLabel(state: MessageComposerState) {
// Your implementation of the composer label
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the label
slot.
Composer input
If you need to modify the whole input field, you can override the method:
ChatComponentFactory#MessageComposerInput
, which provides the current
MessageComposerState
, and the callbacks required to update the state backing
the composer input field: onInputChanged
and onAttachmentRemoved
. It also
provides the aforementioned label
component, so that you can re-use the
default composer label in your custom input field:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.MessageComposerInput(
state: MessageComposerState,
onInputChanged: (String) -> Unit,
onAttachmentRemoved: (Attachment) -> Unit,
label: @Composable (MessageComposerState) -> Unit,
) {
// Your custom implementation of the composer input field
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the input
slot.
Attachments button
The first button in the default message composer - the “Attachments” button can
be customized by overriding the
ChatComponentFactory#MessageComposerAttachmentsButton
method. It provides two
arguments:
enabled
- flag instructing whether the button should be enabled/disabledonClick
- the action to be taken when the button is clicked. By default, calling this method will result in the opening of the attachments picker.
If you want to update the appearance of the button, but at the same time to
also preserve the existing behaviour, we strongly recommend to respect the
enabled
flag, and to call the provided onClick
lambda in your custom button
implementation.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.MessageComposerAttachmentsButton(
enabled: Boolean,
onClick: () -> Unit,
) {
// Your custom implementation of the 'Attachments' button
}
}
Commands button
Similar to the “Attachments” button, you can easily customize the second button
shown in the default message composer - the “Commands” button.
You can do that by overriding the
ChatComponentFactory#MessageComposerCommandsButton
method. It provides
several arguments:
hasCommandSuggestions
- indicator if the commands suggestion menu is activeenabled
- flag instructing whether the button should be enabled/disabledonClick
- the action to be taken when the button is clicked. By default, calling this method will result in the opening/closing of the commands suggestion menu.
If you want to update the appearance of the button, but at the same time to
also preserve the existing behaviour, we strongly recommend to respect the
enabled
flag, and to call the provided onClick
lambda in your custom button
implementation.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.MessageComposerCommandsButton(
hasCommandSuggestions: Boolean,
enabled: Boolean,
onClick: () -> Unit,
) {
// Your implementation of the commands button
}
}
Integrations
The previously mentioned “Attachments” and “Commands” buttons can also be
customized as a group via ChatComponentFactory#MessageComposerIntegrations
.
The integrations represent the ‘leading’ content of the message composer, and
it contains both the “Attachments” and “Commands” buttons. So if you want to
customize, or maybe even remove the whole content before the input field, you
can do that by overriding the following:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.MessageComposerIntegrations(
state: MessageComposerState,
onAttachmentsClick: () -> Unit,
onCommandsClick: () -> Unit,
) {
// Your implementation of the composer integrations
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the integrations
slot.
Send button
The “Send” button shown after the input field in the default message composer
can be customized via the
ChatComponentFactory#MessageComposerSendButton
. The method provides couple of
arguments:
enabled
- flag instructing whether the button should be enabled/disabledisInputValid
- flag indicating if the currently entered input passed the validation checks and can be submittedonClick
- the action to be taken when the button is clicked. By default, calling this method will result in attempting to send the currently entered message to the channel.
If you want to update the appearance of the button, but at the same time to
also preserve the existing behaviour, we strongly recommend to respect the
enabled
and isInputValid
flags, and to call the provided onClick
lambda
in your custom button implementation.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerSendButton(
enabled: Boolean,
isInputValid: Boolean,
onClick: () -> Unit,
) {
// Your implementation of the send button
}
}
Audio record button
The “Audio record” button and voice messages are disabled by default.
To enable it, you need to set the AudioRecordingTheme.enabled
flag to true
,
which is defined in the MessageComposerTheme
.
The “Audio record” button in the message composer is used to record and send audio messages to the channel. You can start the recording process by pressing and holding the “Audio record” button.
Audio Record Button |
---|
![]() |
You can customize this button by overriding the
ChatComponentFactory#MessageComposerAudioRecordButton
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerAudioRecordButton(
state: RecordingState,
recordingActions: AudioRecordingActions,
) {
// Your implementation of the audio record button
}
}
Composer trailing content
Similar to how the “Attachments” and “Commands” buttons are grouped in a single
“Integrations” component, the “Send” and “Audio record” buttons are grouped in
the “Trailing content” component. You can customize the trailing content by
overriding the ChatComponentFactory#MessageComposerTrailingContent
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerTrailingContent(
state: MessageComposerState,
onSendClick: (String, List<Attachment>) -> Unit,
recordingActions: AudioRecordingActions,
) {
// Your implementation of the composer trailing content
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the trailingContent
slot.
Mentions popup content
When the user enters the @
character in the message composer, it is detected
as a mention action, and a popup showing all suggested users that can be
mentioned is shown:
Mentions popup |
---|
![]() |
You can customize this popup dialog by overriding the
ChatComponentFactory#MessageComposerMentionsPopupContent
method, which
provides:
mentionSuggestions
- the list of users which match the mention stringonMentionSelected
- the action to be taken when a suggestion is clicked. By default, calling this method results in appending the full user name to the@
character in the current message.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerMentionsPopupContent(
mentionSuggestions: List<User>,
onMentionSelected: (User) -> Unit,
) {
// Your implementation of the the mentions popup content
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the mentionPopupContent
slot.
If you want to keep the default layout of the popup content, and only change
the content of the mention items, you can do that by overriding the specific
ChatComponentFactory#MessageComposerMentionSuggestionItem
method. This method
provides the User
for which the item will be rendered, and the lambda to be
invoked when the item is clicked. You can use these arguments to build your own
custom mention suggestion item:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerMentionSuggestionItem(
user: User,
onMentionSelected: (User) -> Unit,
) {
// Your implementation for the mention suggestion item
}
}
As with other similar items, the ChatComponentFactory
provides a way for
granular customization of the mention suggestion items, by overriding the
corresponding methods for the leading/center/trailing content of the items.
The default leading content displays the user avatar, while the center content
displays the user name and ID. The trailing content displays a decorative @
icon. You can customize or even remove any of these parts of the items by
overriding the corresponding methods:
MessageComposerMentionSuggestionItemLeadingContent
MessageComposerMentionSuggestionItemCenterContent
MessageComposerMentionSuggestionItemTrailingContent
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.MessageComposerMentionSuggestionItemLeadingContent(
user: User,
) {
// Your implementation of the leading content
}
@Composable
override fun RowScope.MessageComposerMentionSuggestionItemCenterContent(
user: User,
) {
// Your implementation of the center content
}
@Composable
override fun RowScope.MessageComposerMentionSuggestionItemTrailingContent(
user: User,
) {
// Your implementation of the trailing content
}
}
Commands popup content
Clicking on the “Commands” button from the message composer, or starting your
message with the /
character results in showing a popup which displays all
the possible commands that can be performed in the channel (ex. /mute
,
/unmute
).
Commands popup |
---|
![]() |
You can customize this popup dialog by overriding the
ChatComponentFactory#MessageComposerCommandsPopupContent
method, which
provides:
commandSuggestions
- the list of commands which match the command stringonCommandSelected
- the action to be taken when a suggestion is clicked. By default, calling this method results in appending the full command to the/
character in the current message.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerCommandsPopupContent(
commandSuggestions: List<Command>,
onCommandSelected: (Command) -> Unit,
) {
// Your implementation of the command suggestions popup
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the commandPopupContent
slot.
If you want to keep the default layout of the popup content, and only change
the content of the command items, you can do that by overriding the specific
ChatComponentFactory#MessageComposerCommandSuggestionItem
method. This method
provides the Command
for which the item will be rendered, and the lambda to be
invoked when the item is clicked. You can use these arguments to build your own
custom command suggestion item:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerCommandSuggestionItem(
command: Command,
onCommandSelected: (Command) -> Unit,
) {
// Your implementation of the command suggestion item
}
}
As with other similar items, the ChatComponentFactory
provides a way for
granular customization of the command suggestion items, by overriding the
corresponding methods for the leading/center content of the items. The default
leading content displays the command icon, while the center content displays
the full name of the command, and an example of how the whole command string
should look like. You can customize or even remove any of these parts of the
items by overriding the corresponding methods:
MessageComposerCommandSuggestionItemLeadingContent
MessageComposerCommandSuggestionItemCenterContent
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.MessageComposerCommandSuggestionItemLeadingContent(
command: Command,
) {
// Your implementation of the leading content
}
@Composable
override fun RowScope.MessageComposerCommandSuggestionItemCenterContent(
modifier: Modifier,
command: Command,
) {
// Your implementation of the center content
}
}
Composer header
The message composer header is a component which appears only in specific scenarios, such as:
- Editing a message
- Replying to a message
- Adding a URL in the message
Edit message | Reply to message | Add URL |
---|---|---|
![]() | ![]() | ![]() |
If you want to fully replace the default composer header implementations, you
can do to that by overriding the ChatComponentFactory#MessageComposerHeader
.
The method provides the current state
of the composer, which you can use to
build your own implementation of the header. It also provides the onCancel
and onLinkPreviewClick
lambdas, which you can call if you want to dismiss
the header, or to open the currently visible link preview:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ColumnScope.MessageComposerHeaderContent(
state: MessageComposerState,
onCancel: () -> Unit,
onLinkPreviewClick: ((LinkPreview) -> Unit)?,
) {
// Your implementation of the composer header
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the headerContent
slot.
You can also customize the the different states of the composer header
separately: Overriding the
ChatComponentFactory#MessageComposerMessageInputOptions
will result in
changing the Edit/Reply message header content, while overriding the
ChatComponentFactory#MessageComposerLinkPreview
will result in changing the
URL preview content:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerMessageInputOptions(
modifier: Modifier,
activeAction: MessageAction,
onCancel: () -> Unit,
) {
// Your implementation of the Edit/Reply header
}
@Composable
override fun MessageComposerLinkPreview(
modifier: Modifier,
linkPreview: LinkPreview,
onClick: ((LinkPreview) -> Unit)?,
) {
// Your implementation of the link preview
}
}
Composer footer
The message composer footer is a component which only appears when the user replies in a thread, and it shows a checkbox that the user can toggle on, to send the message as a direct message as well.
Thread reply |
---|
![]() |
To customize this component, you can override the
ChatComponentFactory#MessageComposerFooterContent
method. The method provides
the current state
of the composer, which you can use to build your own
implementation of the footer. It also provides a onAlsoSendToChannelSelected
lambda, which is invoked when the checkmark is updated:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ColumnScope.MessageComposerFooterContent(
state: MessageComposerState,
onAlsoSendToChannelSelected: (Boolean) -> Unit,
) {
// Your implementation of the footer content
}
}
If you are using the bound/stateless component MessageComposer
directly
instead of the MessagesScreen
, you can also customize this component by
providing your implementation in the footerContent
slot.
Quoted message
Another component that can be customized via the ChatComponentFactory
is the
quoted message which is shown in the composer when the user replies to a
message:
Quoted message |
---|
![]() |
You can customize the appearance of the quoted message in the message composer
by overriding the ChatComponentFactory#MessageComposerQuotedMessage
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageComposerQuotedMessage(
modifier: Modifier,
state: MessageComposerState,
quotedMessage: Message,
) {
// Your implementation of the quoted message
}
}
Attachments Picker
The AttachmentsPicker
is a component that allows the user to browse and
select media files to be sent in a message. The type of attachments that it
supports and its appearance can be customized via the
ChatTheme#attachmentsPickerTabFactories
property, with which you can provide
a list of custom AttachmentsPickerTabFactory
instances (see:
Attachments Picker).
The ChatComponentFactory
provides some additional customizations that you can
apply to the default attachments picker, such as modifying the Add (>)
button
in the picker header:
Attachments picker |
---|
![]() |
You can customize the appearance of the “Add” button in the attachments picker
by overriding the ChatComponentFactory#AttachmentsPickerAddButton
method.
The method provides two arguments:
hasPickedAttachments
- flag indicating if the user has selected any attachmentsonClick
- the action to be taken when the button is clicked. By default, calling this method will result in closing the attachments picker and sending the selected attachments to the message composer.
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun AttachmentsPickerSendButton(
hasPickedAttachments: Boolean,
onClick: () -> Unit,
) {
// Your implementation for the "Add" button in the attachments picker
}
}
Menus
The ChatComponentFactory
provides a way to customize different menus used in
the Chat screens:
- Channel options menu
- Message options menu
- Reactions menu
Channel menu
The channel menu provides actions that the user can perform over a given channel.
Channel menu |
---|
![]() |
To provide a custom implementation of the channel menu, you need to override
the ChatComponentFactory#ChannelMenu
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelMenu(
modifier: Modifier,
selectedChannel: Channel,
isMuted: Boolean,
currentUser: User?,
onChannelOptionClick: (ChannelAction) -> Unit,
onDismiss: () -> Unit
) {
// Your implementation of the channel menu
}
}
The ChatComponentFactory
also provides a way for more granular customization
of this menu. You can separately override/customize the header of the menu:
Channel menu header |
---|
![]() |
by overriding the ChatComponentFactory#ChannelMenuHeaderContent
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelMenuHeaderContent(modifier: Modifier, selectedChannel: Channel, currentUser: User?) {
// Your implementation for the channel menu header
}
}
Similarly, you can customize the main content of the menu - the actual channel options:
Channel menu options |
---|
![]() |
by overriding the ChatComponentFactory#ChannelMenuOptions
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelMenuOptions(
modifier: Modifier,
onChannelOptionClick: (ChannelAction) -> Unit,
channelOptions: List<ChannelOptionState>
) {
// Your implementation for the channel menu options
}
}
Additionally, if you want to keep the default channel menu layout and content,
but want to only modify the appearance of the option items, you can do that by
overriding the ChatComponentFactory#ChannelOptionsItem
method. This method
provides the ChannelOptionState
, which you can use to retrieve the information
about the item to be rendered, like the title, the icon, or the action:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelOptionsItem(modifier: Modifier, option: ChannelOptionState, onClick: () -> Unit) {
// Your implementation of the channel option item
}
}
For an even more fine-grained customisation, there is also a method which
allows customizing of the icons shown in the channel menu option items:
ChatComponentFactory#ChannelOptionsItemLeadingIcon
. By overriding this
method you can provide custom icons for the items, change the icon for a
different content, or even completely remove the icons from the items:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ChannelOptionsItemLeadingIcon(modifier: Modifier, option: ChannelOptionState) {
// Your implementation for the leading icon
}
}
Message menu
The message menu provides actions that the user can perform over a given message.
Message menu |
---|
![]() |
To provide a custom implementation of the message menu, you need to override
the ChatComponentFactory#MessageMenu
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageMenu(
modifier: Modifier,
message: Message,
messageOptions: List<MessageOptionItemState>,
ownCapabilities: Set<String>,
onMessageAction: (MessageAction) -> Unit,
onShowMore: () -> Unit,
onDismiss: () -> Unit
) {
// Your implementation of the message menu
}
}
Similar to the channel menu, you can separately customize the header content of the message menu, which holds the available reactions:
Message menu header |
---|
![]() |
by overriding the ChatComponentFactory#MessageMenuHeaderContent
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageMenuHeaderContent(
modifier: Modifier,
message: Message,
messageOptions: List<MessageOptionItemState>,
onMessageAction: (MessageAction) -> Unit,
ownCapabilities: Set<String>,
onShowMore: () -> Unit,
reactionTypes: Map<String, ReactionIcon>,
showMoreReactionsIcon: Int
) {
// Your implementation of the message menu header (reactions)
}
}
Similarly, you can customize the main content of the menu - the actual message options:
Message menu options |
---|
![]() |
by overriding the ChatComponentFactory#MessageMenuOptions
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageMenuOptions(
modifier: Modifier,
message: Message,
options: List<MessageOptionItemState>,
onMessageOptionSelected: (MessageOptionItemState) -> Unit
) {
// Your implementation of the message menu options
}
}
Additionally, if you want to keep the default message menu layout and content,
but want to only modify the appearance of the option items, you can do that by
overriding the ChatComponentFactory#MessageMenuOptionsItem
method. This method
provides the MessageOptionItemState
, which you can use to retrieve the
information about the item to be rendered, like the title, the icon, or the
action:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageMenuOptionsItem(
modifier: Modifier,
option: MessageOptionItemState,
onMessageOptionSelected: (MessageOptionItemState) -> Unit
) {
// Your implementation of the message option item
}
}
For an even more fine-grained customisation, there is also a method which
allows customizing of the icons shown in the message menu option items:
ChatComponentFactory#MessageMenuOptionsItemLeadingContent
. By overriding this
method you can provide custom icons for the items, change the icon for a
different content, or even completely remove the icons from the items:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageMenuOptionsItemLeadingContent(modifier: Modifier, option: MessageOptionItemState) {
// Your implementation for the leading icon
}
}
Channel and Message menu
In the previous sections, we demonstrated how to customize the channel and the
message menus separately, using the ChatComponentFactory
.
The component factory also provides a simpler way, to customize the option
items for both the channel and message menu, by overriding the
ChatComponentFactory#MessageMenuItem
. For example, if you would like
to remove the leading icons from the options items in both channel and
message menus, you can do something like:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MenuOptionItem(
modifier: Modifier,
onClick: () -> Unit,
leadingIcon: @Composable (RowScope.() -> Unit),
title: String,
titleColor: Color,
style: TextStyle,
itemHeight: Dp,
verticalAlignment: Alignment.Vertical,
horizontalArrangement: Arrangement.Horizontal
) {
// Call super.MenuOptionItem, but override the leading icon composable
super.MenuOptionItem(
modifier = modifier,
onClick = onClick,
leadingIcon = {
// Remove leading icon
Spacer(modifier = Modifier.width(16.dp))
},
title = title,
titleColor = titleColor,
style = style,
itemHeight = itemHeight,
verticalAlignment = verticalAlignment,
horizontalArrangement = horizontalArrangement,
)
}
}
This would result in menus like:
Channel menu | Message menu |
---|---|
![]() | ![]() |
Reactions menu
The reactions menu appears when the user taps on the reaction icon in a message header. It shows an overview of all the reactions for a given message and provides the option for adding/changing/removing the current user’s reaction.
Reactions menu |
---|
![]() |
To customize the reactions menu, you need to override the ChatComponentFactory#ReactionsMenu
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ReactionsMenu(
modifier: Modifier,
currentUser: User?,
message: Message,
onMessageAction: (MessageAction) -> Unit,
onShowMoreReactionsSelected: () -> Unit,
ownCapabilities: Set<String>,
onDismiss: () -> Unit,
) {
// Your implementation of the reactions menu
}
}
Similar to the other menus, you can separately customize the header content of the reactions menu, which holds the available reactions:
Reactions menu header |
---|
![]() |
by overriding the ChatComponentFactory#ReactionsMenuHeaderContent
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ReactionsMenuHeaderContent(
modifier: Modifier,
message: Message,
reactionTypes: Map<String, ReactionIcon>,
onMessageAction: (MessageAction) -> Unit,
onShowMoreReactionsSelected: () -> Unit,
showMoreReactionsIcon: Int,
) {
// Your implementation of the reactions menu header content
}
}
Similarly, you can customize the main content of the menu - the overview of all reactions:
Reactions menu overview |
---|
![]() |
by overriding the ChatComponentFactory#ReactionsMenuCenterContent
:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ReactionsMenuCenterContent(
modifier: Modifier,
userReactions: List<UserReactionItemState>,
) {
// Your implementation of the reactions menu center content
}
}
Reaction options
The previously described “Message menu” and “Reactions menu” reuse the same
reactions header component, and the ChatComponentFactory
provides a way to
customize this component generally, without the need to customize both menus
separately. You can achieve this by overriding the
ChatComponentFactory#ReactionMenuOptions
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ReactionMenuOptions(
modifier: Modifier,
message: Message,
reactionTypes: Map<String, ReactionIcon>,
onMessageAction: (MessageAction) -> Unit,
onShowMoreReactionsSelected: () -> Unit,
showMoreReactionsIcon: Int,
) {
// Your implementation for the reactions menu options
}
}
If you want to only customize the appearance of the individual reaction items
you can override the ChatComponentFactory#ReactionMenuOptionItem
method. This
method provides the ReactionOptionItemState
, which you can use to retrieve the
information about the item to be rendered, and the onReactionSelected
lambda,
which you can call when the item is clicked:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ReactionMenuOptionItem(
modifier: Modifier,
option: ReactionOptionItemState,
onReactionOptionSelected: (ReactionOptionItemState) -> Unit,
) {
// Your implementation for the reaction menu item
}
}
Extended reactions menu
The reactions picker menu by default shows up to 5 items. If there are more possible reactions to show, the “Show more” item is displayed:
Reactions menu show more |
---|
![]() |
To customize the appearance of the “Show more” item in the reactions menu, you
can override the ChatComponentFactory#ReactionsMenuShowMore
method. The
method provides the onShowMoreReactionsSelected
lambda, which you can call to
open the “Extended reactions menu”:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ReactionMenuShowMore(
modifier: Modifier,
onShowMoreReactionsSelected: () -> Unit,
showMoreReactionsIcon: Int,
) {
// Your implementation of the "Show more reactions" item
}
}
Clicking on the “Show more” item will open the “Extended reactions menu”:
Extended reactions menu |
---|
![]() |
To customize the appearance of the “Extended reactions menu”, you can override
the ChatComponentFactory#MessageReactionPicker
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageReactionPicker(
modifier: Modifier,
message: Message,
onMessageAction: (MessageAction) -> Unit,
onDismiss: () -> Unit,
) {
// Your implementation for the 'extended' reactions picker
}
}
This extended reactions picker is built from 2 separate components which can be customized separately:
- The header content, which is empty by default.
- The center content, which displays the list of all reactions.
To customize (add) a header to the extended reactions picker, you can override
the ChatComponentFactory#MessageReactionPickerHeaderContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageReactionPickerHeaderContent(
modifier: Modifier,
message: Message,
onMessageAction: (MessageAction) -> Unit,
onDismiss: () -> Unit,
) {
// Your implementation of the extended reactions picker header
}
}
And to customize the content which displays the list of all reactions, you can
override the ChatComponentFactory#MessageReactionPickerCenterContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun MessageReactionPickerCenterContent(
modifier: Modifier,
message: Message,
onMessageAction: (MessageAction) -> Unit,
reactionTypes: Map<String, ReactionIcon>,
onDismiss: () -> Unit,
) {
// Your implementation of the extended reactions picker content
}
}
If you want to only customize the appearance of the individual reaction items
you can override the ChatComponentFactory#ExtendedReactionMenuOptionItem
method. This method provides the ReactionOptionItemState
, which you can use
to retrieve the information about the item to be rendered, and the
onReactionOptionSelected
lambda, which you can call when the item is clicked:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ExtendedReactionMenuOptionItem(
modifier: Modifier,
option: ReactionOptionItemState,
onReactionOptionSelected: (ReactionOptionItemState) -> Unit,
) {
// Your implementation of the reaction menu item
}
}
The ExtendedReactionMenuOptionItem
internally uses the
ReactionMenuOptionItem
, so overriding the ReactionMenuOptionItem
will also
result in overriding the ExtendedReactionMenuOptionItem
.
Thread List
The ThreadList
component is used to display a list of all threads for a given
user (See Thread List).
Thread list |
---|
![]() |
As an alternative to using the composable slot parameters provided by the
ThreadList
component, you can also customize the appearance of the threads
via the ChatComponentFactory
.
To customize the “New threads” banner which displays the number of new unseen
threads, you can override the
ChatComponentFactory#ThreadListUnreadThreadsBanner
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ThreadListUnreadThreadsBanner(
unreadThreads: Int,
onClick: () -> Unit,
) {
// Your implementation of the unread threads banner
}
}
Overriding the ThreadListUnreadThreadsBanner
is the same as passing a custom
implementation for the ThreadList#unreadThreadsBanner
slot.
To customize the items in the thread list, you can override the
ChatComponentFactory#ThreadListItem
method. This method provides the Thread
data which you can use to build your own implementation of the thread item, and
the onThreadClick
lambda which you can call when the item is clicked:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ThreadListItem(
thread: Thread,
currentUser: User?,
onThreadClick: (Thread) -> Unit
) {
// Your implementation of the thread item
}
}
Overriding the ThreadListItem
is the same as passing a custom
implementation for the ThreadList#itemContent
slot.
Similar to other list items, the ChatComponentFactory
provides a way for a
more granular customization of the thread list items. It provides methods for
customization of the:
- Thread title - Shows the thread icon and the channel name in which the thread exists.
- Reply to - Shows a preview of the thread root message.
- Unread count indicator - Shows the number of unread messages in the thread.
- Latest reply - Shows the latest message in the thread.
To customize one or more of these parts of the thread list items, you can override any of the corresponding methods:
ThreadListItemTitle
ThreadListItemReplyToContent
ThreadListItemUnreadCountContent
ThreadListItemLatestReplyContent
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ThreadListItemTitle(thread: Thread, channel: Channel, currentUser: User?) {
// Your implementation of the thread title
}
@Composable
override fun RowScope.ThreadListItemReplyToContent(thread: Thread) {
// Your implementation of the thread root message content
}
@Composable
override fun RowScope.ThreadListItemUnreadCountContent(unreadCount: Int) {
// Your implementation of the unread count content
}
@Composable
override fun ThreadListItemLatestReplyContent(thread: Thread, currentUser: User?) {
// Your implementation of the latest reply content
}
}
The ChatComponentFactory
also provides a way for customizing the loading
content of the thread list. You can customize the default loading indicator by
overriding the ChatComponentFactory#ThreadListLoadingContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ThreadListLoadingContent(modifier: Modifier) {
// Your implementation of the loading content
}
}
Overriding the ThreadListLoadingContent
is the same as passing a custom
implementation for the ThreadList#loadingContent
slot.
You can also customize the empty content of the thread list. You can do that by
overriding the ChatComponentFactory#ThreadListEmptyContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ThreadListEmptyContent(modifier: Modifier) {
// Your implementation for the empty state
}
}
Overriding the ThreadListEmptyContent
is the same as passing a custom
implementation for the ThreadList#emptyContent
slot.
Finally, using the ChatComponentFactory
you can also customize the loading
more indicator of the list, which is a loading indicator shown when a new page
of threads is being loaded. You can do that by overriding the
ChatComponentFactory#ThreadListLoadingMoreContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun ThreadListLoadingMoreContent() {
// Your implementation of the loading more indicator
}
}
Overriding the ThreadListLoadingMoreContent
is the same as passing a custom
implementation for the ThreadList#loadingMoreContent
slot.
Pinned Message List
The PinnedMessageList
component is used to display a list of all pinned
messages in a given channel (See
Pinned Message List).
Pinned messages list |
---|
![]() |
As an alternative to using the composable slot parameters provided by the
PinnedMessageList
component, you can also customize the appearance of the threads
via the ChatComponentFactory
.
To customize the items in the pinned message list, you can override the
ChatComponentFactory#PinnedMessageListItem
method. This method provides the
Message
data which you can use to build your own implementation of the pinned
message item, and the onClick
lambda which you can call when the item is
clicked:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun PinnedMessageListItem(
message: Message,
currentUser: User?,
onClick: (Message) -> Unit,
) {
// Your implementation of the pinned message list item
}
}
Overriding the PinnedMessageListItem
is the same as passing a custom
implementation for the PinnedMessageList#itemContent
slot.
Similar to other list items, the ChatComponentFactory
provides a way for a
more granular customization of the pinned message list items. It provides
methods for customization of the:
- Loading content - Shows an avatar of the user who sent the pinned message.
- Center content - Shows the name of the sender, and a preview of the pinned message.
- Trailing content - Shows the timestamp when the message was sent.
To customize one or more of these parts of the pinned message list items, you can override any of the corresponding methods:
PinnedMessageListItemLeadingContent
PinnedMessageListItemCenterContent
PinnedMessageListItemTrailingContent
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun RowScope.PinnedMessageListItemLeadingContent(
message: Message,
currentUser: User?,
) {
// Your implementation of the pinned message leading content
}
@Composable
override fun RowScope.PinnedMessageListItemCenterContent(
message: Message,
currentUser: User?,
) {
// Your implementation of the pinned message center content
}
@Composable
override fun RowScope.PinnedMessageListItemTrailingContent(
message: Message,
) {
// Your implementation of the pinned message trailing content
}
}
The ChatComponentFactory
also provides a way for customizing the loading
content of the pinned message list. You can customize the default loading
indicator by overriding the
ChatComponentFactory#PinnedMessageListLoadingContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun PinnedMessageListLoadingContent(modifier: Modifier) {
// Your implementation of the loading content
}
}
Overriding the PinnedMessageListLoadingContent
is the same as passing a
custom implementation for the PinnedMessageList#loadingContent
slot.
You can also customize the empty content of the pinned message list. You can do
that by overriding the ChatComponentFactory#PinnedMessageListEmptyContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun PinnedMessageListEmptyContent(modifier: Modifier) {
// Your implementation for the empty state
}
}
Overriding the PinnedMessageListEmptyContent
is the same as passing a custom
implementation for the PinnedMessageList#emptyContent
slot.
Finally, using the ChatComponentFactory
you can also customize the loading
more indicator of the list, which is a loading indicator shown when a new page
of pinned messages is being loaded. You can do that by overriding the
ChatComponentFactory#PinnedMessageListLoadingMoreContent
method:
class CustomChatComponentFactory : ChatComponentFactory {
@Composable
override fun PinnedMessageListLoadingMoreContent() {
// Your implementation of the loading more indicator
}
}
Overriding the PinnedMessageListLoadingMoreContent
is the same as passing a
custom implementation for the PinnedMessageList#loadingMoreContent
slot.
Summary
The ChatComponentFactory
interface provides a powerful way to customize the
UI components of the Chat screens. By implementing this interface and
overriding the desired methods, developers can precisely customize specific
components, without the need to re-implement big parts of the composable UI.