@Composable
private fun CustomMessageComposer(
composerViewModel: MessageComposerViewModel,
attachmentsPickerViewModel: AttachmentsPickerViewModel,
) {
MessageComposer(
viewModel = composerViewModel,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
input = { composerState ->
MessageInput(
messageComposerState = composerState,
onValueChange = { composerViewModel.setMessageInput(it) },
onAttachmentRemoved = { composerViewModel.removeAttachment(it) },
modifier = Modifier
.padding(horizontal = 10.dp)
.align(Alignment.CenterVertically),
)
},
onAttachmentsClick = { attachmentsPickerViewModel.setPickerVisible(true) },
)
}Custom Composer
The MessageComposer component can be customized at two levels:
- Parameters: Adjust the existing UI using
MessageComposerparameters likemodifier,input, andonAttachmentsClick. - Component Factory: Replace the leading/trailing content, input field, or attachment picker UI by overriding methods in
ChatComponentFactory.
For most customizations, the Component Factory approach is recommended. See the Component Factory page for details on overriding MessageComposerLeadingContent(), MessageComposerTrailingContent(), and other composer slots.
Parameter-Level Customization
If you need to customize the composer within a custom screen (without using MessagesScreen), create it directly with MessageComposerViewModel:
The input parameter gives you access to MessageComposerState, which contains the current message text, attachments, and other state. You can use the built-in MessageInput component with custom modifiers, or replace it entirely with your own composable.
Integrating in a Custom Screen
When building a custom messages screen, wire the composer alongside the message list and attachment picker:
@Composable
fun CustomScreen(cid: String, onBackClick: () -> Unit = {}) {
val viewModelFactory = MessagesViewModelFactory(LocalContext.current, channelId = cid)
val listViewModel = viewModel(modelClass = MessageListViewModel::class.java, factory = viewModelFactory)
val composerViewModel = viewModel(modelClass = MessageComposerViewModel::class.java, factory = viewModelFactory)
val attachmentsPickerViewModel = viewModel(modelClass = AttachmentsPickerViewModel::class.java, factory = viewModelFactory)
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
Scaffold(
topBar = { /* MessageListHeader */ },
bottomBar = {
CustomMessageComposer(
composerViewModel = composerViewModel,
attachmentsPickerViewModel = attachmentsPickerViewModel,
)
},
content = { /* MessageList */ },
)
if (attachmentsPickerViewModel.isPickerVisible) {
AttachmentPicker(attachmentsPickerViewModel = attachmentsPickerViewModel)
}
}
}