-
public final class MessageComposerControllerController responsible for handling the composing and sending of messages.
It acts as a central place for both the core business logic and state required to create and send messages, handle attachments, message actions and more.
If you require more state and business logic, compose this Controller with your code and apply the necessary changes.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description public final classMessageComposerController.ConfigConfiguration for the message composer controller.
-
Field Summary
Fields Modifier and Type Field Description private TypingUpdatesBuffertypingUpdatesBufferprivate final SharedFlow<Unit>inputFocusEventsprivate final SharedFlow<MessageComposerViewEvent>eventsprivate final StateFlow<MessageComposerState>stateprivate final StateFlow<MessageInput>messageInputprivate final StateFlow<Set<MessageAction>>messageActionsprivate final StateFlow<ChannelState>channelState
-
Constructor Summary
Constructors Constructor Description MessageComposerController(String channelCid, ChatClient chatClient, StateFlow<ChannelState> channelState, StreamMediaRecorder mediaRecorder, UserLookupHandler userLookupHandler, Function1<File, String> fileToUri, MessageComposerController.Config config, Flow<GlobalState> globalState, SavedStateHandle savedStateHandle, String initialParentMessageId)
-
Method Summary
Modifier and Type Method Description final TypingUpdatesBuffergetTypingUpdatesBuffer()Buffers typing updates. final UnitsetTypingUpdatesBuffer(TypingUpdatesBuffer typingUpdatesBuffer)Buffers typing updates. final SharedFlow<Unit>getInputFocusEvents()Emits each time the message input field should request focus (e.g. final SharedFlow<MessageComposerViewEvent>getEvents()One-shot events emitted by the composer, such as feedback for unavailable commands. final StateFlow<MessageComposerState>getState()Full message composer state holding all the required information. final StateFlow<MessageInput>getMessageInput()UI state of the current composer input. final StateFlow<Set<MessageAction>>getMessageActions()Set of currently active message actions. final StateFlow<ChannelState>getChannelState()final UnitsetMessageInput(String value)Called when the input changes and the internal state needs to be updated. final UnitsetMessageMode(MessageMode messageMode)Called when the message mode changes and the internal state needs to be updated. final UnitsetAlsoSendToChannel(Boolean alsoSendToChannel)Called when the "Also send as a direct message" checkbox is checked or unchecked. final UnitperformMessageAction(MessageAction messageAction)Handles selected messageAction. final UnitdismissMessageActions()Dismisses all message actions from the UI and clears the input if isInEditMode is true. final UnitaddAttachments(List<Attachment> attachments)Adds attachments to the staged list, preserving insertion order. final UnitremoveAttachment(Attachment attachment)Removes attachment from the staged list. final UnitremoveAttachmentsByUris(Set<String> uris)Removes all staged attachments whose URI string key is contained in uris. final UnitclearAttachments()Removes all staged attachments and updates the composer state. final UnitcreatePoll(CreatePollParams createPollParams, Function1<Result<Message>, Unit> onResult)Creates a poll with the given createPollParams. final UnitclearData()Clears all the data from the input — text, attachments, validation errors, actions, and active command. final UnitsendMessage(Message message, Call.Callback<Message> callback, SuspendFunction1<List<Attachment>, List<Attachment>> resolveAttachments)Sends a given message using our Stream API. final MessagebuildNewMessage(String message, List<Attachment> attachments)Builds a new Message to send to our API. final UnitleaveThread()Updates the UI state when leaving the thread, to switch back to the MessageMode.Normal, by calling setMessageMode. final UnitonCleared()Cancels any pending work when the parent ViewModel is about to be destroyed. final UnitselectMention(User user)Autocompletes the current text input with the mention from the selected user. final UnitselectMention(Mention mention)Autocompletes the current text input with the mention from the selected mention. final UnitselectCommand(Command command)Switches the message composer to the command input mode. final UnitclearActiveCommand()Dismisses the active command, clearing MessageComposerState.activeCommand. final UnittoggleCommandsVisibility()Toggles the visibility of the command suggestion list popup. final UnitdismissSuggestionsPopup()Dismisses the suggestions popup above the message composer. final UnitstartRecording()Starts audio recording and moves MessageComposerState.recording state from RecordingState.Idle to RecordingState.Hold. final UnitholdRecording(Pair<Float, Float> offset)Sends coordinates of the touch event to the AudioRecordingController. final UnitlockRecording()Moves MessageComposerState.recording state to RecordingState.Locked. final UnitcancelRecording()Cancels audio recording and moves MessageComposerState.recording state to RecordingState.Idle. final UnittoggleRecordingPlayback()Toggles audio recording playback if MessageComposerState.recording is instance of RecordingState.Overview. final UnitstopRecording()Stops audio recording and moves MessageComposerState.recording state to RecordingState.Overview. final UnitcompleteRecording(Function1<Result<Attachment>, Unit> onComplete)Completes audio recording and updates the MessageComposerState.attachments list. final UnitpauseRecording()Pauses audio recording and sets RecordingState.Overview.isPlaying to false. final UnitseekRecordingTo(Float progress)Pauses audio recording and seeks to the given progress. final UnitsendRecording()Completes the active audio recording and sends the recorded audio as an attachment. final UnitcancelLinkPreview()Dismisses the current link preview and marks enrichment as skipped. -
-
Constructor Detail
-
MessageComposerController
MessageComposerController(String channelCid, ChatClient chatClient, StateFlow<ChannelState> channelState, StreamMediaRecorder mediaRecorder, UserLookupHandler userLookupHandler, Function1<File, String> fileToUri, MessageComposerController.Config config, Flow<GlobalState> globalState, SavedStateHandle savedStateHandle, String initialParentMessageId)
- Parameters:
channelCid- The CID of the channel we're chatting in.chatClient- The client used to communicate to the API.channelState- The current state of the channel.mediaRecorder- The media recorder used to record audio messages.userLookupHandler- The handler used to lookup users for mentions.fileToUri- The function used to convert a file to a URI.config- The configuration for the message composer.globalState- A flow emitting the current GlobalState.savedStateHandle- Handle used to persist and restore picker selections and edit-mode state across process death (e.g.initialParentMessageId- The ID of the parent Message to open the composer directly in a thread, starting it in thread mode.
-
-
Method Detail
-
getTypingUpdatesBuffer
final TypingUpdatesBuffer getTypingUpdatesBuffer()
Buffers typing updates.
-
setTypingUpdatesBuffer
final Unit setTypingUpdatesBuffer(TypingUpdatesBuffer typingUpdatesBuffer)
Buffers typing updates.
-
getInputFocusEvents
final SharedFlow<Unit> getInputFocusEvents()
Emits each time the message input field should request focus (e.g. after a command is selected).
-
getEvents
final SharedFlow<MessageComposerViewEvent> getEvents()
One-shot events emitted by the composer, such as feedback for unavailable commands. UI layers collect this flow and react with transient UI (e.g. a snackbar).
-
getState
final StateFlow<MessageComposerState> getState()
Full message composer state holding all the required information.
-
getMessageInput
final StateFlow<MessageInput> getMessageInput()
UI state of the current composer input.
-
getMessageActions
final StateFlow<Set<MessageAction>> getMessageActions()
Set of currently active message actions. These are used to display different UI in the composer, as well as help us decorate the message with information, such as the quoted message id.
-
getChannelState
final StateFlow<ChannelState> getChannelState()
-
setMessageInput
final Unit setMessageInput(String value)
Called when the input changes and the internal state needs to be updated.
- Parameters:
value- Current state value.
-
setMessageMode
final Unit setMessageMode(MessageMode messageMode)
Called when the message mode changes and the internal state needs to be updated.
This affects the business logic.
- Parameters:
messageMode- The current message mode.
-
setAlsoSendToChannel
final Unit setAlsoSendToChannel(Boolean alsoSendToChannel)
Called when the "Also send as a direct message" checkbox is checked or unchecked.
- Parameters:
alsoSendToChannel- If the message will be shown in the channel after it is sent.
-
performMessageAction
final Unit performMessageAction(MessageAction messageAction)
Handles selected messageAction. We only have three actions we can react to in the composer:
ThreadReply - We change the message mode so we can send the message to a thread.
Reply - We need to reply to a message and set up the reply UI.
Edit - We need to change the messageInput to the message we want to edit and change the UI to match the editing action.
- Parameters:
messageAction- The newly selected action.
-
dismissMessageActions
final Unit dismissMessageActions()
Dismisses all message actions from the UI and clears the input if isInEditMode is true.
-
addAttachments
final Unit addAttachments(List<Attachment> attachments)
Adds attachments to the staged list, preserving insertion order.
Each attachment is keyed by its EXTRA_SOURCE_URI if present, or by a deterministic fallback derived from Attachment.name and Attachment.mimeType. If a key is already present, its value is updated in place without changing its position.
- Parameters:
attachments- The attachments to stage.
-
removeAttachment
final Unit removeAttachment(Attachment attachment)
Removes attachment from the staged list.
Searches picker selections first (by key), then edit-mode attachments, then the recording attachment. Removes from the first list that contains it.
- Parameters:
attachment- The attachment to remove.
-
removeAttachmentsByUris
final Unit removeAttachmentsByUris(Set<String> uris)
Removes all staged attachments whose URI string key is contained in uris.
- Parameters:
uris- The URI string keys to remove.
-
clearAttachments
final Unit clearAttachments()
Removes all staged attachments and updates the composer state. Clears picker selections, edit-mode base attachments, and any completed recording attachment.
-
createPoll
final Unit createPoll(CreatePollParams createPollParams, Function1<Result<Message>, Unit> onResult)
Creates a poll with the given createPollParams.
- Parameters:
createPollParams- Configuration for creating a poll.
-
clearData
final Unit clearData()
Clears all the data from the input — text, attachments, validation errors, actions, and active command. In thread mode, MessageComposerState.alsoSendToChannel is preserved until the user toggles it; otherwise it is reset.
-
sendMessage
final Unit sendMessage(Message message, Call.Callback<Message> callback, SuspendFunction1<List<Attachment>, List<Attachment>> resolveAttachments)
Sends a given message using our Stream API. Based on isInEditMode, we either edit an existing message, or we send a new message, using ChatClient. In case the message is a moderated message the old one is deleted before the replacing one is sent.
It also dismisses any current message actions.
- Parameters:
message- The message to send.
-
buildNewMessage
final Message buildNewMessage(String message, List<Attachment> attachments)
Builds a new Message to send to our API. If isInEditMode is true, we use the current action's message and apply the given changes.
If we're not editing a message, we fill in the required data for the message.
- Parameters:
message- Message text.attachments- Message attachments.
-
leaveThread
final Unit leaveThread()
Updates the UI state when leaving the thread, to switch back to the MessageMode.Normal, by calling setMessageMode.
It also dismisses any currently active message actions, such as Edit and Reply, as the user left the relevant thread.
-
onCleared
final Unit onCleared()
Cancels any pending work when the parent ViewModel is about to be destroyed.
-
selectMention
final Unit selectMention(User user)
Autocompletes the current text input with the mention from the selected user.
- Parameters:
user- The user that is used to autocomplete the mention.
-
selectMention
final Unit selectMention(Mention mention)
Autocompletes the current text input with the mention from the selected mention.
Built-in Mention subclasses are submitted to the server on send via the corresponding fields on io.getstream.chat.android.models.Message.
- Parameters:
mention- The mention that is used for the autocomplete.
-
selectCommand
final Unit selectCommand(Command command)
Switches the message composer to the command input mode.
Sets MessageComposerState.activeCommand and clears the text input so the user can type the command arguments. The full
/command argsstring is assembled in buildNewMessage.When Config.activeCommandEnabled is
true, any pre-command input value, picker-selected attachments, and mention selections are stashed so clearActiveCommand can restore them if the user dismisses the command. Re-selecting a command while one is already active does not overwrite an existing stash (in-command input is command-specific and not preserved across command switches).When Config.activeCommandEnabled is
trueand the command is not available for the current composer action (edit mode or a moderation command during reply), emits a MessageComposerViewEvent.CommandUnavailable on events and returns without changing the active command. Legacy mode skips this check and sets the command unconditionally.- Parameters:
command- The command that was selected.
-
clearActiveCommand
final Unit clearActiveCommand()
Dismisses the active command, clearing MessageComposerState.activeCommand.
When a pre-command stash exists (populated by selectCommand under Config.activeCommandEnabled), the stashed input, attachments, and mentions are restored and any text typed inside command mode is discarded. When no stash exists, the input is reset to empty.
-
toggleCommandsVisibility
final Unit toggleCommandsVisibility()
Toggles the visibility of the command suggestion list popup.
-
dismissSuggestionsPopup
final Unit dismissSuggestionsPopup()
Dismisses the suggestions popup above the message composer.
-
startRecording
final Unit startRecording()
Starts audio recording and moves MessageComposerState.recording state from RecordingState.Idle to RecordingState.Hold.
-
holdRecording
final Unit holdRecording(Pair<Float, Float> offset)
Sends coordinates of the touch event to the AudioRecordingController.
-
lockRecording
final Unit lockRecording()
Moves MessageComposerState.recording state to RecordingState.Locked.
-
cancelRecording
final Unit cancelRecording()
Cancels audio recording and moves MessageComposerState.recording state to RecordingState.Idle.
-
toggleRecordingPlayback
final Unit toggleRecordingPlayback()
Toggles audio recording playback if MessageComposerState.recording is instance of RecordingState.Overview.
-
stopRecording
final Unit stopRecording()
Stops audio recording and moves MessageComposerState.recording state to RecordingState.Overview.
-
completeRecording
final Unit completeRecording(Function1<Result<Attachment>, Unit> onComplete)
Completes audio recording and updates the MessageComposerState.attachments list.
- Parameters:
onComplete- Optional callback invoked with the result of the recording once the recording has been finalized.
-
pauseRecording
final Unit pauseRecording()
Pauses audio recording and sets RecordingState.Overview.isPlaying to false.
-
seekRecordingTo
final Unit seekRecordingTo(Float progress)
Pauses audio recording and seeks to the given progress. Sets RecordingState.Overview.isPlaying to false. Sets RecordingState.Overview.playingProgress to the given progress.
-
sendRecording
final Unit sendRecording()
Completes the active audio recording and sends the recorded audio as an attachment.
-
cancelLinkPreview
final Unit cancelLinkPreview()
Dismisses the current link preview and marks enrichment as skipped. When a message is sent after dismissal, the backend will not enrich its URLs unless the detected URL in the input changes (e.g. the user replaces the link).
-
-
-
-