Conversation
SDK Size Comparison 📏
|
0314eff to
6642ece
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
WalkthroughThis PR restructures the message composer UI architecture by replacing the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as MessageComposer UI
participant ViewModel as MessageComposerViewModel
participant Controller as MessageComposerController
Note over User,Controller: New Link Preview Cancellation Flow
User->>UI: Taps cancel icon on link preview
UI->>ViewModel: onCancelClick callback triggered
ViewModel->>Controller: cancelLinkPreview()
Controller->>Controller: linkPreviews = emptyList()
Controller-->>ViewModel: Preview state cleared
ViewModel-->>UI: State updated (no link preview)
UI-->>User: Link preview removed from composer
sequenceDiagram
participant User
participant MessageComposer as MessageComposer
participant MessageInput as MessageInput
participant ViewModelLayer as ViewModel/Controller
Note over User,ViewModelLayer: New Composer Composition Flow
User->>MessageComposer: Invoke with leadingContent
MessageComposer->>MessageComposer: Provide leadingContent slot<br/>(attachments, commands)
MessageComposer->>MessageInput: Render with new parameters
MessageInput->>MessageInput: Compose MessageInputHeader<br/>(quoted, attachments, link preview)
MessageInput->>MessageInput: Compose content Row<br/>(leading, text field, trailing)
User->>MessageInput: Enter text & send
MessageInput->>ViewModelLayer: onSendClick(text, attachments)
ViewModelLayer->>ViewModelLayer: buildNewMessage + send
ViewModelLayer-->>MessageComposer: State updated
MessageComposer-->>User: UI reflects sent message
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~60 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
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: 6
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-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/MessagesActivity.kt (1)
185-205: Add an accessible label for the date picker button.
contentDescription = nullleaves the IconButton unlabeled for screen readers. Provide a localized description.✅ Suggested fix
@@ -import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource @@ - contentDescription = null, + contentDescription = stringResource(R.string.stream_ui_date_picker),Add a matching string resource in the guides module (e.g., “Open date picker”).
🤖 Fix all issues with AI agents
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/ScrollToBottomButton.kt`:
- Around line 66-70: The touch target for FilledIconButton in
ScrollToBottomButton is set to 40.dp which violates the 48.dp minimum; update
the Modifier chain on FilledIconButton to preserve a 48.dp interactive area
while keeping the visible button at 40.dp (for example, use
Modifier.size(48.dp).padding(4.dp) or add
Modifier.minimumInteractiveComponentSize() / requiredSizeIn(minWidth = 48.dp,
minHeight = 48.dp) and keep the inner visual size at 40.dp) so the tap target
meets accessibility guidelines; modify the FilledIconButton modifier
accordingly.
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt`:
- Around line 1749-1761: The KDoc for MessageComposerInput has a stray asterisk
in the `@param` trailingContent line causing formatting issues; edit the KDoc
comment for the MessageComposerInput function/class in ChatComponentFactory.kt
and remove the stray `*` at the end of the `@param trailingContent` line so the
parameter doc is properly formatted and rendered.
In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt`:
- Around line 39-87: Rename the standard identifier test functions to use
backticked names per test conventions: change the functions placeholder, filled,
overflow, attachments, link, reply (and the already backticked `slow mode`) to
backticked test names (e.g., fun `placeholder`() ) so each `@Test` method uses a
descriptive backtick string identifier; update the function declarations for
MessageComposerInputPlaceholder, MessageComposerInputFilled,
MessageComposerInputOverflow, MessageComposerInputAttachments,
MessageComposerInputLink, and MessageComposerInputReply test functions
accordingly while keeping the bodies and annotations intact.
- Around line 95-99: The test function `reply, attachments, and link` is
rendering `MessageComposerInputAttachmentsAndLink()` instead of the dedicated
`MessageComposerInputReplyAttachmentsAndLink()` composable; update the import to
include `MessageComposerInputReplyAttachmentsAndLink` and replace the call
inside the snapshot block with `MessageComposerInputReplyAttachmentsAndLink()`
so the test renders the reply+attachments+link state rather than the
attachments-only composable.
In
`@stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/cookbook/ui/CustomComposerAndAttachmentsPicker.kt`:
- Around line 184-187: The custom Send IconButton is always enabled and can
bypass MessageComposerState.canSendMessage(); update the IconButton in
CustomComposerAndAttachmentsPicker (the one invoking onSendClick with
composerState.inputValue and composerState.attachments) to use enabled =
composerState.canSendMessage() and also guard the onClick handler (e.g., no-op
or return early) to ensure clicks cannot trigger onSendClick when
canSendMessage() is false so behavior matches the default composer.
In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt`:
- Around line 721-727: Introduce a boolean flag (e.g., linkPreviewDismissed)
that is set when cancelLinkPreview() is invoked and used to determine enrichment
instead of linkPreviews.value.isEmpty(); update the message send call in
MessageComposerController (the chatClient.sendMessage(...) invocation where
message.copy(..., skipEnrichUrl = ...)) to use skipEnrichUrl =
linkPreviewDismissed, ensure any existing logic that clears or repopulates
linkPreviews does not also reset this flag unless explicitly intended, and
initialize and update linkPreviewDismissed alongside the existing
preview-fetching/debounce flow so quick sends won't incorrectly skip enrichment.
🧹 Nitpick comments (13)
stream-chat-android-previewdata/src/main/kotlin/io/getstream/chat/android/previewdata/PreviewAttachmentData.kt (1)
22-63: Add KDoc for this public preview API.Guidelines require KDoc on public APIs; please document the object’s purpose (preview-only sample attachments) and any intended usage constraints.
As per coding guidelines, document public APIs with KDoc.
stream-chat-android-previewdata/src/main/kotlin/io/getstream/chat/android/previewdata/PreviewLinkData.kt (1)
23-36: Consider adding KDoc documentation for public members.As per coding guidelines, public APIs should be documented with KDoc. While this is marked
@InternalStreamChatApi, adding brief documentation would improve maintainability.📝 Suggested KDoc additions
`@InternalStreamChatApi` +/** + * Provides sample [LinkPreview] data for Compose previews and UI tests. + */ public object PreviewLinkData { + /** + * A sample link preview with placeholder content. + */ public val link1: LinkPreview = LinkPreview(stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/ScrollToBottomButton.kt (1)
106-108: Prefer StreamPreview for Compose previews.Use the Stream preview helper instead of raw
@Previewto keep previews consistent across the module.As per coding guidelines, Compose previews should use
StreamPreviewhelpers.stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/cookbook/ui/CustomComposerAndAttachmentsPicker.kt (1)
157-195: Wire recordingActions to actual UI or drop it here.
recordingActionsis passed, but the customtrailingContentdoesn’t expose any recording UI, so audio recording actions won’t be reachable. Either add a mic/record affordance that triggersrecordingActionsor remove the parameter to avoid implying support.stream-chat-android-compose/api/stream-chat-android-compose.api (1)
4882-4882: cancelLinkPreview is now public—add coverage for state reset.
Please confirm it clears preview state and consider a small ViewModel/UI test to guard regressions.stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/ImageAttachmentPreviewContent.kt (1)
61-66: Use StreamTokens for padding consistency.Hardcoded
12.dpcan drift from tokenized spacing used elsewhere. PreferStreamTokens.spacingSmto keep padding aligned with theme tokens.♻️ Proposed refactor
@@ -import io.getstream.chat.android.compose.ui.theme.ChatTheme +import io.getstream.chat.android.compose.ui.theme.ChatTheme +import io.getstream.chat.android.compose.ui.theme.StreamTokens @@ - contentPadding = PaddingValues(12.dp), + contentPadding = PaddingValues(StreamTokens.spacingSm),stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentPreviewContent.kt (1)
59-66: Use StreamTokens for padding consistency.To keep spacing aligned with the token system, prefer
StreamTokens.spacingSmover hardcoded12.dp.♻️ Proposed refactor
@@ -import io.getstream.chat.android.compose.ui.theme.ChatTheme +import io.getstream.chat.android.compose.ui.theme.ChatTheme +import io.getstream.chat.android.compose.ui.theme.StreamTokens @@ - contentPadding = PaddingValues(12.dp), + contentPadding = PaddingValues(StreamTokens.spacingSm),stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt (1)
421-440: Duplicated send logic betweenonSendClickandComposerTrailingIcon.The send message logic is duplicated in both the
onSendClickhandler (lines 395-398) andComposerTrailingIcon(lines 425-431). Consider extracting a shared function to avoid duplication.♻️ Proposed refactor to eliminate duplication
+ private fun sendMessage() { + val state = composerViewModel.messageComposerState.value + composerViewModel.sendMessage( + composerViewModel.buildNewMessage( + state.inputValue, + state.attachments, + ), + ) + } + `@Composable` fun MyCustomComposer() { MessageComposer( viewModel = composerViewModel, leadingContent = {}, input = { inputState -> MessageInput( // ... onSendClick = { input, attachments -> - val message = composerViewModel.buildNewMessage(input, attachments) - composerViewModel.sendMessage(message) + sendMessage() }, // ... ) }, // ... ) } `@Composable` private fun ComposerTrailingIcon() { IconButton( - onClick = { - val state = composerViewModel.messageComposerState.value - composerViewModel.sendMessage( - composerViewModel.buildNewMessage( - state.inputValue, - state.attachments, - ), - ) - }, + onClick = { sendMessage() }, ) { // ... } }stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt (1)
266-278: Redundant condition check in cursor repositioning logic.The condition
textState.text != valueis checked twice: once on line 268 and again on line 271. The outer check is sufficient sinceLaunchedEffectwill suspend untilvaluechanges.♻️ Simplified cursor repositioning logic
- if (textState.text != value) { - // Workaround to move cursor to the end after selecting a suggestion - LaunchedEffect(value) { - if (textState.text != value) { - textState = textState.copy( - text = value, - selection = TextRange(value.length), - ) - } + // Workaround to move cursor to the end after selecting a suggestion + LaunchedEffect(value) { + if (textState.text != value) { + textState = textState.copy( + text = value, + selection = TextRange(value.length), + ) } }stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerDefaults.kt (1)
335-338: Consider using a theme color instead of hardcodedColor.White.The send button content color is hardcoded to
Color.White. For better theme customization support, consider deriving this fromChatTheme.colorsor the button style.♻️ Proposed change
colors = IconButtonDefaults.filledIconButtonColors( containerColor = ChatTheme.colors.primaryAccent, - contentColor = Color.White, + contentColor = sendButtonStyle.icon.tint, ),stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/MessageComposer.kt (3)
520-526: Preview should use@StreamPreviewannotation instead of@Preview.As per coding guidelines, Compose previews in stream-chat-android-compose should use
@StreamPreviewhelpers instead of the standard@Previewannotation for consistency across the codebase.♻️ Suggested refactor
-@Preview +@StreamPreview `@Composable` private fun MessageComposerDefaultStylePreview() { ChatTheme { MessageComposerDefaultStyle() } }
536-542: Preview should use@StreamPreviewannotation.Same as above - use
@StreamPreviewhelpers for consistency. Based on coding guidelines.♻️ Suggested refactor
-@Preview(showBackground = true) +@StreamPreview `@Composable` private fun MessageComposerFloatingStylePreview() { ChatTheme { MessageComposerFloatingStyle() } }
379-391: Conditional padding logic looks correct but consider extracting to a variable.The padding calculation with conditional
topvalue based on floating style is correct. However, the inline conditional makes it harder to read. Consider extracting this for clarity.♻️ Optional refactor for readability
+ val topPadding = if (ChatTheme.messageComposerFloatingStyleEnabled) { + 0.dp + } else { + StreamTokens.spacingMd + } Row( modifier = Modifier .fillMaxWidth() .padding( start = StreamTokens.spacingMd, end = StreamTokens.spacingMd, - top = if (ChatTheme.messageComposerFloatingStyleEnabled) { - 0.dp - } else { - StreamTokens.spacingMd - }, + top = topPadding, bottom = StreamTokens.spacing2xl, ), verticalAlignment = Bottom, ) {
...c/main/java/io/getstream/chat/android/compose/ui/components/messages/ScrollToBottomButton.kt
Show resolved
Hide resolved
...oid-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt
Outdated
Show resolved
Hide resolved
...se/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt
Show resolved
Hide resolved
...se/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt
Show resolved
Hide resolved
.../main/kotlin/io/getstream/chat/docs/kotlin/cookbook/ui/CustomComposerAndAttachmentsPicker.kt
Show resolved
Hide resolved
...n/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt
Show resolved
Hide resolved
gpunto
left a comment
There was a problem hiding this comment.
Looks good! Left just two minor comments
...mpose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt
Outdated
Show resolved
Hide resolved
...mpose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt
Outdated
Show resolved
Hide resolved
5a5d051 to
9cf2bf7
Compare
…composer send action
…Content` and remove the commands button from the default leading content.
This change makes the following composables `internal`: - `DefaultMessageComposerHeaderContent` - `DefaultMessageComposerFooterInThreadMode` - `DefaultMessageComposerLeadingContent` - `DefaultComposerLabel` - `DefaultMessageComposerInput` - `DefaultMessageComposerInputTrailingContent` - `AttachmentsButton` - `CommandsButton` - `SendButton`
- Introduce shadow in the message input on floating style mode on
72a3e51 to
1a8f020
Compare
…tale reference errors
…t reliable as it sometimes targeted the quoted message. - assert message with a text selector to prevent flakiness
1a8f020 to
184694b
Compare
|
gpunto
left a comment
There was a problem hiding this comment.
Looks good, just one non-blocking question


🎯 Goal
This is the 1st part of a series of PRs to update the Message Composer design of the Compose SDK.
This scope includes supporting the floating style, updating icons, margins/paddings, and the layout structure, without touching much in the composer API, which will be handled in another PR.
https://www.figma.com/design/Us73erK1xFNcB5EH3hyq6Y/Chat-SDK-Design-System?node-id=167-2375&m=dev
🛠 Implementation details
🎨 UI Changes
Screen_recording_20260121_142448.webm
Screen_recording_20260121_142646.webm
🧪 Testing
Run the Compose sample app
Summary by CodeRabbit
New Features
UI/UX Improvements
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.