Redesign message edit experience with inline indicator and save button#6195
Redesign message edit experience with inline indicator and save button#6195
Conversation
PR checklist ✅All required conditions are satisfied:
🎉 Great job! This PR is ready for review. |
WalkthroughThis PR introduces edit message functionality to the Android Compose message composer. It adds a new Changes
Sequence DiagramsequenceDiagram
actor User
participant MessageComposer
participant MessageInput
participant MessageComposerEditIndicator
participant MessageComposerInputTrailingContent
participant SaveButton
User->>MessageComposer: Initiates edit on message
MessageComposer->>MessageInput: Sets edit state active
MessageInput->>MessageComposerEditIndicator: Renders with edited message
MessageComposerEditIndicator-->>User: Shows edit banner with message preview
User->>MessageComposerEditIndicator: Clicks cancel button
MessageComposerEditIndicator->>MessageComposer: Calls onCancelClick
MessageComposer->>MessageInput: Clears edit state
MessageInput->>MessageComposerInputTrailingContent: Checks edit state
MessageComposerInputTrailingContent->>SaveButton: Renders save button (edit active)
User->>SaveButton: Clicks save button
SaveButton->>MessageComposer: Calls onClick handler
MessageComposer-->>User: Confirms message updated
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt (1)
1853-1870:⚠️ Potential issue | 🔴 CriticalUpdate the API definition file to reflect the method rename.
The implementation has been renamed to
MessageComposerAudioRecordingButton, but the API definition file (stream-chat-android-compose/api/stream-chat-android-compose.api) still contains the old method nameMessageComposerAudioRecordButtonat lines 2807 and 2999. The .api file must be regenerated or manually updated to reference the new method name to maintain API compatibility checking.Additionally, the CHANGELOG.md does not document this breaking change for v7. Consider adding a migration note for consumers upgrading from v6 to document the renamed method.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt` around lines 1853 - 1870, The API surface still references the old method name MessageComposerAudioRecordButton while the implementation was renamed to MessageComposerAudioRecordingButton; update the API definition (stream-chat-android-compose.api) to replace occurrences of MessageComposerAudioRecordButton with MessageComposerAudioRecordingButton (check the entries that previously lived at the reported locations) or regenerate the .api file so it matches the new symbol, and add a short migration note to CHANGELOG.md describing the breaking rename from MessageComposerAudioRecordButton -> MessageComposerAudioRecordingButton for v7 consumers.
🧹 Nitpick comments (2)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt (1)
1701-1724: Consider documenting the unusedstateparameter or using it.The
state: MessageComposerStateparameter is accepted but not used in the current implementation. While this is likely intentional for API consistency with other composer methods (likeMessageComposerQuotedMessage) and for consumer extensibility when overriding, consider either:
- Adding a brief note in the KDoc explaining it's provided for override flexibility, or
- Using it if there's valuable state (e.g.,
currentUser) that could enhance the indicatorThis isn't blocking since the pattern matches other methods in this factory.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt` around lines 1701 - 1724, The MessageComposerEditIndicator function currently accepts a state: MessageComposerState parameter that isn't used; update the KDoc for MessageComposerEditIndicator to explicitly state that the state parameter is intentionally provided for API consistency and override/extensibility (similar to MessageComposerQuotedMessage) and may be used by consumers when overriding (e.g., to access currentUser or other composer state), or alternatively, if you prefer behaviour change, wire a relevant value from state into the composable (e.g., use state.currentUser) — reference the MessageComposerEditIndicator, MessageComposerState, MessageComposerQuotedMessage and MessageComposerInput symbols so reviewers can locate and verify the change.stream-chat-android-compose/api/stream-chat-android-compose.api (1)
2819-2834: Document the newChatComponentFactoryhooks in upgrade notes.Line 2819 and Line 2834 add new public customization points, with defaults at Line 3011 and Line 3026. Please ensure migration notes explicitly call these out for teams maintaining custom component factories.
Also applies to: 3011-3026
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/api/stream-chat-android-compose.api` around lines 2819 - 2834, Add explicit upgrade/migration notes documenting the new ChatComponentFactory hooks by naming each new public function signature added (MessageComposerEditIndicator, MessageComposerFooterContent, MessageComposerHeaderContent, MessageComposerInput, MessageComposerInputCenterContent, MessageComposerInputLeadingContent, MessageComposerInputTrailingContent, MessageComposerLeadingContent, MessageComposerLinkPreview, MessageComposerMentionSuggestionItem, MessageComposerMentionSuggestionItemCenterContent, MessageComposerMentionSuggestionItemLeadingContent, MessageComposerMentionSuggestionItemTrailingContent, MessageComposerMentionsPopupContent, MessageComposerQuotedMessage, MessageComposerSaveButton) and indicate that defaults are provided (referencing the default implementations at MessageComposer... defaults around the spots you noted). In the upgrade notes describe that teams with custom ChatComponentFactory implementations must implement or forward these new hooks, show a simple migration action (add pass-through stubs for each new method in custom factory), and call out the exact method names to update so maintainers can locate them quickly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt`:
- Line 93: Rename the test function edit() to use a backtick-delimited,
sentence-style name per test conventions; locate the function named edit in
MessageComposerInputTest (fun edit()) and change its declaration to a backtick
name that describes the test intent (for example: fun `edit message shows ...`()
), keeping the body unchanged so the test still runs but follows the readable
test naming rule.
---
Outside diff comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt`:
- Around line 1853-1870: The API surface still references the old method name
MessageComposerAudioRecordButton while the implementation was renamed to
MessageComposerAudioRecordingButton; update the API definition
(stream-chat-android-compose.api) to replace occurrences of
MessageComposerAudioRecordButton with MessageComposerAudioRecordingButton (check
the entries that previously lived at the reported locations) or regenerate the
.api file so it matches the new symbol, and add a short migration note to
CHANGELOG.md describing the breaking rename from
MessageComposerAudioRecordButton -> MessageComposerAudioRecordingButton for v7
consumers.
---
Nitpick comments:
In `@stream-chat-android-compose/api/stream-chat-android-compose.api`:
- Around line 2819-2834: Add explicit upgrade/migration notes documenting the
new ChatComponentFactory hooks by naming each new public function signature
added (MessageComposerEditIndicator, MessageComposerFooterContent,
MessageComposerHeaderContent, MessageComposerInput,
MessageComposerInputCenterContent, MessageComposerInputLeadingContent,
MessageComposerInputTrailingContent, MessageComposerLeadingContent,
MessageComposerLinkPreview, MessageComposerMentionSuggestionItem,
MessageComposerMentionSuggestionItemCenterContent,
MessageComposerMentionSuggestionItemLeadingContent,
MessageComposerMentionSuggestionItemTrailingContent,
MessageComposerMentionsPopupContent, MessageComposerQuotedMessage,
MessageComposerSaveButton) and indicate that defaults are provided (referencing
the default implementations at MessageComposer... defaults around the spots you
noted). In the upgrade notes describe that teams with custom
ChatComponentFactory implementations must implement or forward these new hooks,
show a simple migration action (add pass-through stubs for each new method in
custom factory), and call out the exact method names to update so maintainers
can locate them quickly.
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt`:
- Around line 1701-1724: The MessageComposerEditIndicator function currently
accepts a state: MessageComposerState parameter that isn't used; update the KDoc
for MessageComposerEditIndicator to explicitly state that the state parameter is
intentionally provided for API consistency and override/extensibility (similar
to MessageComposerQuotedMessage) and may be used by consumers when overriding
(e.g., to access currentUser or other composer state), or alternatively, if you
prefer behaviour change, wire a relevant value from state into the composable
(e.g., use state.currentUser) — reference the MessageComposerEditIndicator,
MessageComposerState, MessageComposerQuotedMessage and MessageComposerInput
symbols so reviewers can locate and verify the change.
ℹ️ Review info
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (11)
stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_Default_reaction_picker.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_Reaction_picker_with_header.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_attachments_and_link.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_edit,_attachments,_and_link.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_edit.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_edit_empty.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_link.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_reply,_attachments,_and_link.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_reply.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageListTest_scroll_to_bottom_button.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageListTest_scroll_to_bottom_button_in_dark_mode.pngis excluded by!**/*.png
📒 Files selected for processing (13)
stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/pages/MessageListPage.ktstream-chat-android-compose/api/stream-chat-android-compose.apistream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageComposerEditIndicator.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInputOptions.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/QuotedMessage.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/MessageComposer.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerDefaults.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputTrailingContent.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerLeadingContent.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.ktstream-chat-android-compose/src/main/res/values/strings.xmlstream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt
💤 Files with no reviewable changes (2)
- stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerDefaults.kt
- stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInputOptions.kt
...se/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt
Show resolved
Hide resolved
SDK Size Comparison 📏
|
0f31873 to
357a5fc
Compare
There was a problem hiding this comment.
We have an issue when editing a message, now that support for adding attachments during edit is allowed. In the MessageCompsoerController#sendMessage we have the following logic:
if (isInEditMode && !activeMessage.isModerationError(currentUserId)) {
// The following line will prevent sending the call, if we didn't edit the message - and just changed the attachments
if (activeMessage.text == message.text) {
logger.i { "[sendMessage] No changes in the message text, skipping edit." }
clearData()
return
}
val editCall = getEditMessageCall(message)
clearData()
editCall.enqueue(callback)
return
}We should either remove this check, or extend to also verify for no changes in the attachments field as well
Good catch, @VelikovPetar |
- Remove `MessageInputOptions` in favor of a new `MessageComposerEditIndicator` within the component factory. - Introduce `MessageComposerSaveButton` with a checkmark icon, replacing the send button when in edit mode. - Consolidate input top content (replies, edits, attachments, and link previews) into a unified `MessageInputTop` layout with improved spacing. - Update `QuotedMessage` to use theme typography and better alignment. - Refactor trailing content logic to explicitly handle "save", "send", and "record" states. - Ensure leading content (like the attachment picker button) remains visible while editing a message. - Add `stream_compose_save_message` string resource and corresponding test previews for edit states.
…ageComposerInputTrailingContent
…s an `ActionButton` case
357a5fc to
136b742
Compare
@VelikovPetar , Let me know what you think 5067089 |
|



Goal
Redesign the message editing UI in the Compose SDK to match the new Figma specifications. The edit experience moves from a header banner above the composer to a card-style indicator inside the composer's input area, consistent with the quoted-message pattern.
Implementation
MessageInputOptionsheader banner with a newMessageComposerEditIndicatorcard insideMessageInput's header area, using the outgoing bubble style andQuotedMessageBodyBuilderfor attachment-type icons.SaveButton(checkmark) shown during edit mode, disabled when content is empty. Unify save/send/record resolution inMessageComposerInputTrailingContentvia a sealedActionButtoninterface.MessageComposerAudioRecordButton→MessageComposerAudioRecordingButtonfor naming consistency.MessageComposerLeadingContentinto its own file; updateQuotedMessageto useChatTheme.typographytokens.🎨 UI Changes
Check the
MessageComposerInputTestsnapshotsTesting
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Refactor