Skip to content

Message Composer structural redesign#6088

Merged
andremion merged 38 commits intov7from
uplift-message-composer
Jan 23, 2026
Merged

Message Composer structural redesign#6088
andremion merged 38 commits intov7from
uplift-message-composer

Conversation

@andremion
Copy link
Contributor

@andremion andremion commented Jan 16, 2026

🎯 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

  • Refactor composer internals (new defaults, updated input layout, attachment/link preview handling).
  • Update theming/tokens and supporting UI components (icons, scroll-to-bottom, avatar, cooldown indicator).
  • Update/generate new screenshot golden files.
  • Update e2e tests.

🎨 UI Changes

Default style Floating style
Screen_recording_20260121_142448.webm
Screen_recording_20260121_142646.webm

🧪 Testing

Run the Compose sample app

Summary by CodeRabbit

  • New Features

    • Added ability to cancel link previews in the message composer.
    • Introduced floating style option for message composer.
    • Added audio recording actions support.
  • UI/UX Improvements

    • Redesigned message composer layout with improved content organization.
    • Updated composer button styling and sizing.
    • Enhanced spacing and padding throughout attachments and preview components.
    • Modernized icon designs with stroked outlines.
    • Refined placeholder text from "Send a message" to "Message".
  • Bug Fixes

    • Improved test reliability for message assertions and animated content.

✏️ Tip: You can customize this high-level summary in your review settings.

@andremion andremion changed the base branch from develop to v7 January 16, 2026 14:47
@github-actions
Copy link
Contributor

github-actions bot commented Jan 16, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.25 MB 5.25 MB 0.00 MB 🟢
stream-chat-android-offline 5.48 MB 5.48 MB 0.00 MB 🟢
stream-chat-android-ui-components 10.62 MB 10.61 MB -0.01 MB 🚀
stream-chat-android-compose 12.84 MB 11.64 MB -1.20 MB 🚀

@andremion andremion force-pushed the uplift-message-composer branch 3 times, most recently from 0314eff to 6642ece Compare January 21, 2026 13:53
@andremion andremion marked this pull request as ready for review January 21, 2026 14:32
@andremion andremion requested a review from a team as a code owner January 21, 2026 14:32
@andremion
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

Walkthrough

This PR restructures the message composer UI architecture by replacing the integrations parameter with leadingContent, adding link preview cancellation support, introducing new content composition slots, adding audio recording capabilities, and updating UI styling with new design tokens and modified icon drawables.

Changes

Cohort / File(s) Summary
E2E Test Pages & Locators
stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/pages/MessageListPage.kt
Removed quotedMessageAvatar test locators from Composer and Message companions; added linkPreviewCancelButton locator
E2E Test Robots
stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/robots/UserRobot.kt
Replaced tapOnAttachmentCancelIcon() method with tapOnLinkPreviewCancelButton(); updated tapOnSendButton() to wait for button before clicking
E2E Test Assertions
stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/robots/UserRobotMessageListAsserts.kt
Added waitToAppear() on text locator; removed quotedMessageAvatar visibility assertion
E2E Tests
stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/GiphyTests.kt, HyperLinksTests.kt
Added @Ignore to Giphy test; enabled HyperLink tests by removing @Ignore annotations; updated method calls and assertion text
Message Composer Core
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt
Major refactoring: introduced leadingContent and trailingContent parameters; added onCancelLinkPreviewClick, onSendClick, recordingActions; created MessageInputHeader for quoted/link preview rendering; added extensive preview composables
Link Preview Component
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/ComposerLinkPreview.kt
Renamed onClick to onContentClick; added onCancelClick parameter; removed internal previewClosed state logic
Composer Main
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/MessageComposer.kt
Replaced integrations parameter with leadingContent; added onCancelLinkPreviewClick; introduced MessageComposerSurface wrapper; removed legacy default composer components; added preview composables for default and floating styles
Composer Defaults
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerDefaults.kt
New file: added comprehensive internal composer components (header, footer, leading/trailing content, input row, send/commands buttons, label) with permission and state handling
Composer Input Trailing Content
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/DefaultMessageComposerRecordingContent.kt
Removed tint parameter from Icon in DefaultAudioRecordButton
Theme – Local Composition
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt
Introduced public LocalMessageComposerFloatingStyleEnabled; made LocalComposerLinkPreviewEnabled public; added messageComposerFloatingStyleEnabled parameter and accessor
Component Factory
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt
Renamed MessageComposerIntegrations to MessageComposerLeadingContent; added new content hooks (MessageComposerInputLeadingContent, MessageComposerInputTrailingContent); updated MessageComposer/MessageComposerInput signatures to use new content slots
Message Composer Theme
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageComposerTheme.kt
Increased attachments button from 32×32 to 48×48; increased send button size and adjusted padding/icon sizing; changed icon tints
Design Tokens & Dimensions
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/StreamTokens.kt, StreamDimens.kt
Added spacing3xs = 2.dp token; increased messageComposerShadowElevation from 4.dp to 24.dp
Audio Recording Theme
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/messages/composer/AudioRecordingTheme.kt
Changed mic icon resource from stream_compose_ic_mic_active to stream_compose_ic_mic
ViewModels
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModel.kt
Added public cancelLinkPreview() method
Controller
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt
Added public cancelLinkPreview() method; added skipEnrichUrl parameter to send path
Message List Composition
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageList.kt, Messages.kt
Changed default contentPadding from PaddingValues(vertical = 16.dp) to PaddingValues(); propagated contentPadding through helper content; applied graphicsLayer { clip = false } to LazyColumn
Scroll to Bottom Button
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/ScrollToBottomButton.kt
Replaced Surface-based implementation with FilledIconButton; updated badge styling with Border, private BadgeShape, and StreamTokens; adjusted alignment and padding
Messages Screen & Input Field
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/MessagesScreen.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/InputField.kt
MessagesScreen: replaced padding with contentPadding parameter; InputField: removed accessibility semantics and testTag; added onValueChange invocation
Composer Cool Down & Icon
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/CoolDownIndicator.kt
Reduced inner padding from 12.dp to 8.dp
Avatar Component
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/avatar/Avatar.kt
Removed testTag("Stream_QuotedMessageAuthorAvatar") usage
Attachment Preview Content
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentPreviewContent.kt, ImageAttachmentPreviewContent.kt, MediaAttachmentPreviewContent.kt
Added contentPadding = PaddingValues(12.dp) to LazyRow in file/image previews; updated spacing in media preview to use StreamTokens.spacing2xs and StreamTokens.spacingSm
Public API Surface
stream-chat-android-compose/api/stream-chat-android-compose.api
Extensive signature updates across MessageInput, MessageComposer, ComposerLinkPreview, ChatTheme, ChatComponentFactory; added new composition locals, content hooks, and lambda fields; reorganized function/parameter types
Icon Drawables
stream-chat-android-compose/src/main/res/drawable/stream_compose_ic_add.xml, stream_compose_ic_arrow_down.xml, stream_compose_ic_mic.xml, stream_compose_ic_send.xml
Converted filled icons to stroked outlines; reduced sizes (20×20 or 24→20); added android:autoMirrored="true"; updated stroke properties (width 1.5, colors, caps/joins)
Resources
stream-chat-android-compose/src/main/res/values/strings.xml
Changed stream_compose_message_label from "Send a message" to "Message"
Sample App
stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/add/AddChannelScreen.kt, MessagesActivity.kt
Updated MessageComposer invocations: replaced integrations with leadingContent; MessagesActivity: added leadingContent, recordingActions, onSendClick; replaced innerTrailingContent with trailingContent; removed integrations
Test Infrastructure
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/PaparazziComposeTest.kt
Added optional contentAlignment parameter (default Alignment.TopStart) to snapshotWithDarkMode() and snapshotWithDarkModeRow()
Snapshot Tests
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt, MessageComposerTest.kt
New MessageComposerInputTest with 9 snapshot tests for input states; updated MessageComposerTest to use MessageComposerDefaultStyle/MessageComposerFloatingStyle instead of direct MessageComposer
Documentation & Guides
stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/AddingCustomAttachments.kt, messages/MessageComposer.kt, cookbook/ui/CustomComposerAndAttachmentsPicker.kt
Updated MessageComposer invocations: replaced integrations with leadingContent; added onSendClick handler; added recordingActions; replaced innerTrailingContent with trailingContent
Preview Data
stream-chat-android-previewdata/src/main/kotlin/io/getstream/chat/android/previewdata/PreviewAttachmentData.kt, PreviewLinkData.kt
New files: introduced PreviewAttachmentData and PreviewLinkData objects with sample attachment and link preview instances for UI previews
E2E Guides
stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/MessagesActivity.kt
Updated MessageComposer parameter from integrations to leadingContent

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
Loading
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
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

Suggested Labels

compose, ui-components

Suggested Reviewers

  • VelikovPetar

Poem

🐰 A composer reborn, with slots so clean,
Leading content flows where integrations had been,
Link previews now cancel with style,
Icons stroke instead of fill—such a smile!
From attachments to tokens, the redesign's grand,
A refactor done right, oh how perfectly planned!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed PR description follows the template with all main sections (Goal, Implementation details, UI Changes, Testing) completed and appropriately filled out.
Title check ✅ Passed The PR title 'Message Composer structural redesign' accurately captures the main change, which is a comprehensive refactor of the message composer with updated layouts, styling, and internal structure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 = null leaves 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 @Preview to keep previews consistent across the module.

As per coding guidelines, Compose previews should use StreamPreview helpers.

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.

recordingActions is passed, but the custom trailingContent doesn’t expose any recording UI, so audio recording actions won’t be reachable. Either add a mic/record affordance that triggers recordingActions or 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.dp can drift from tokenized spacing used elsewhere. Prefer StreamTokens.spacingSm to 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.spacingSm over hardcoded 12.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 between onSendClick and ComposerTrailingIcon.

The send message logic is duplicated in both the onSendClick handler (lines 395-398) and ComposerTrailingIcon (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 != value is checked twice: once on line 268 and again on line 271. The outer check is sufficient since LaunchedEffect will suspend until value changes.

♻️ 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 hardcoded Color.White.

The send button content color is hardcoded to Color.White. For better theme customization support, consider deriving this from ChatTheme.colors or 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 @StreamPreview annotation instead of @Preview.

As per coding guidelines, Compose previews in stream-chat-android-compose should use @StreamPreview helpers instead of the standard @Preview annotation for consistency across the codebase.

♻️ Suggested refactor
-@Preview
+@StreamPreview
 `@Composable`
 private fun MessageComposerDefaultStylePreview() {
     ChatTheme {
         MessageComposerDefaultStyle()
     }
 }

536-542: Preview should use @StreamPreview annotation.

Same as above - use @StreamPreview helpers 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 top value 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,
             ) {

@andremion andremion added the compose Jetpack Compose label Jan 21, 2026
Copy link
Contributor

@gpunto gpunto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Left just two minor comments

@andremion andremion force-pushed the uplift-message-composer branch 3 times, most recently from 5a5d051 to 9cf2bf7 Compare January 22, 2026 15:32
…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
@andremion andremion force-pushed the uplift-message-composer branch from 72a3e51 to 1a8f020 Compare January 23, 2026 13:42
@andremion andremion changed the title Initial UI update of message composer Message Composer structural redesign Jan 23, 2026
@andremion andremion force-pushed the uplift-message-composer branch from 1a8f020 to 184694b Compare January 23, 2026 14:10
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
75.7% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Copy link
Contributor

@gpunto gpunto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just one non-blocking question

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compose Jetpack Compose

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants