Skip to content

Message composer thread state redesign#6200

Merged
andremion merged 18 commits intov7from
redesign/AND-1098-composer-thread-state-redesign
Mar 4, 2026
Merged

Message composer thread state redesign#6200
andremion merged 18 commits intov7from
redesign/AND-1098-composer-thread-state-redesign

Conversation

@andremion
Copy link
Contributor

@andremion andremion commented Mar 2, 2026

Goal

Simplify the Compose message composer API and align it with the component-factory model: move header, footer, leading, and trailing slots into ChatComponentFactory and consolidate the input area so "also send to channel" and related thread state live inside the input component instead of separate footer/header slots.

Implementation

  • MessageComposer: Removed headerContent, footerContent, leadingContent, and trailingContent parameters; composition is driven by ChatComponentFactory (e.g. MessageComposerLeadingContent, MessageComposerInput). Renamed onAlsoSendToChannelSelected to onAlsoSendToChannelChange and pass it into the input.
  • MessageComposerInput: Now takes a Modifier and no longer uses RowScope. Replaced leadingContent / centerContent / trailingContent with a single MessageComposerInput factory that owns leading (e.g. attachments), center (text field + link preview), and trailing (send/recording). Added MessageComposerInputCenterBottomContent in the factory for "also send to channel" in thread mode, so thread UI is inside the input block.
  • ChatComponentFactory: Removed MessageComposerHeaderContent and MessageComposerFooterContent. Added MessageComposerInputCenterBottomContent. MessageComposerLeadingContent and MessageComposerInput now use an explicit Modifier instead of RowScope.
  • Thread state: alsoSendToChannel is preserved when clearing composer data in thread mode.
  • Samples & docs: Removed duplicate MessagesActivity from compose sample; updated custom-attachment sample and "Adding custom attachments" guide to the new factory-based API. Adjusted composer string resource names/placeholders.
  • Tests: Updated MessageComposerControllerTest (including alsoSendToChannel propagation); added/updated MessageComposerInputTest and Paparazzi snapshots for the new layout.

🎨 UI Changes

Unselected Selected

Testing

Open a channel → open a thread → reply; confirm "Also send to channel" appears and toggles correctly; clear/compose again and confirm the checkbox state is preserved when applicable.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added improved "Also send in channel" option for thread mode messaging with dedicated UI component.
    • Introduced component factory pattern for cleaner message composer customization.
  • Bug Fixes

    • Fixed message composer behavior in thread mode to preserve "send to channel" state.
  • Documentation

    • Updated string resources with clearer naming for message composer elements.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled.

🎉 Great job! This PR is ready for review.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.25 MB 5.69 MB 0.44 MB 🟡
stream-chat-android-ui-components 10.60 MB 10.97 MB 0.37 MB 🟡
stream-chat-android-compose 12.81 MB 11.96 MB -0.86 MB 🚀

@andremion andremion added pr:breaking-change Breaking change pr:new-feature New feature labels Mar 2, 2026
@andremion andremion marked this pull request as ready for review March 2, 2026 16:44
@andremion andremion requested a review from a team as a code owner March 2, 2026 16:44
@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

Walkthrough

This PR refactors the message composer architecture by consolidating customizable content slots from individual MessageComposer parameters into a ChatComponentFactory-based composition system. It introduces a dedicated MessageComposerInputCenterBottomContent component for rendering the thread-mode "also send to channel" toggle, updates API signatures to reflect the new structure, and renames string resources for consistency.

Changes

Cohort / File(s) Summary
MessageComposer Core Architecture
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/MessageComposer.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt
Removed public customization slots (headerContent, footerContent, leadingContent, trailingContent) from MessageComposer and MessageInput. Refactored composition to use ChatComponentFactory for leading/trailing content. Renamed onAlsoSendToChannelSelected to onAlsoSendToChannelChange. Added new thread-mode preview composables in MessageInput.
ChatComponentFactory Updates
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt, stream-chat-android-compose/api/stream-chat-android-compose.api
Converted MessageComposerLeadingContent and MessageComposerInput from RowScope extensions to top-level public functions with explicit Modifier parameters. Introduced new MessageComposerInputCenterBottomContent method for center-bottom content rendering. Updated method signatures and lambda arities throughout the component factory interface.
New Center Bottom Content Component
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputCenterBottomContent.kt
Introduced new internal composable for rendering the "also send to channel" checkbox and label in thread mode. Includes custom Checkbox implementation with ripple interactions and animated appearance. Replaced removed DefaultMessageComposerFooterInThreadMode logic.
Input Content Refinements
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputCenterContent.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputTrailingContent.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt
Added top padding to input field container. Updated placeholder text resource references (stream_compose_message_label → stream_compose_message_composer_empty_placeholder). Updated icon content descriptions (stream_compose_send_message → stream_compose_message_composer_send_button).
String Resources
stream-chat-android-compose/src/main/res/values*/strings.xml
Renamed and consolidated message composer string resources across all locales (es, hi, default). Added stream_compose_message_composer_empty_placeholder, stream_compose_message_composer_cannot_send_placeholder, stream_compose_message_composer_send_button, stream_compose_message_composer_save_button. Updated stream_compose_message_composer_show_in_channel value to "Also send in Channel".
UI Common & Control Logic
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt, stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerControllerTest.kt
Made alsoSendToChannel reset conditional in clearData: only reset in non-thread mode. Added class-level OptIn for ExperimentalCoroutinesApi and new test cases for thread mode behavior.
Sample & Documentation Updates
stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/add/AddChannelActivity.kt, stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/add/AddChannelScreen.kt, stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt, stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/AddingCustomAttachments.kt, stream-chat-android-docs/...
Updated sample code to use CustomChatComponentFactory pattern for customization. Removed inline composer customizations in favor of ComponentFactory overrides. Updated handler callbacks from onAlsoSendToChannelSelected to onAlsoSendToChannelChange.
Test Updates
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt, stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/composer/MessageComposerScreenTest.kt
Added snapshot tests for thread-mode and thread-mode-also-send-to-channel composables. Updated screen test expectations for updated "Also send in Channel" label text.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • gpunto
  • VelikovPetar
  • aleksandar-apostolov

Poem

🐰 Slots are simplified, the factory takes the stage,
Leading content dances in a cleaner age!
Thread-mode checkboxes hop with care,
String resources now pair with flair.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.33% 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
Title check ✅ Passed The title 'Message composer thread state redesign' is fully related to the main change: a comprehensive redesign of the message composer API and thread state handling in the Compose implementation.
Description check ✅ Passed The pull request description includes most required sections: Goal, Implementation, UI Changes with before/after images, and Testing instructions. However, the Contributor and Reviewer checklists are missing, and some sections like documentation updates are mentioned but lack detail.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch redesign/AND-1098-composer-thread-state-redesign

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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: 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/messages/composer/MessageComposer.kt (1)

117-121: ⚠️ Potential issue | 🔴 Critical

FocusRequester call will crash—requester is never attached to any composable.

On lines 117-121, inputFocusRequester.requestFocus() is called when inputFocusEvents emits, but this requester is never passed to any component or attached via Modifier.focusRequester(). The MessageComposerInput factory and its underlying MessageInput and BasicTextField components receive no focusRequester parameter. Calling requestFocus() on an unattached requester throws at runtime.

Either wire the requester to the text input via Modifier.focusRequester() or remove the collector and focus logic until the wiring is restored.

🤖 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/messages/composer/MessageComposer.kt`
around lines 117 - 121, The code calls inputFocusRequester.requestFocus() from
the LaunchedEffect collecting viewModel.inputFocusEvents but the FocusRequester
(inputFocusRequester) is never attached to any composable, so requestFocus()
will crash; fix by wiring the requester into the text input chain (pass
inputFocusRequester into MessageComposerInput/MessageInput and attach it with
Modifier.focusRequester(inputFocusRequester) on the BasicTextField) or remove
the LaunchedEffect/collector until focus wiring is implemented so
inputFocusRequester.requestFocus() is not invoked on an unattached requester.
🧹 Nitpick comments (8)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputCenterBottomContent.kt (1)

118-126: Parameter shadowing in AnimatedContent lambda.

The lambda parameter checked shadows the outer function parameter of the same name. While this works correctly, it can reduce code clarity. Consider renaming the lambda parameter.

♻️ Proposed fix to avoid shadowing
-        AnimatedContent(checked) { checked ->
-            if (checked) {
+        AnimatedContent(checked) { isChecked ->
+            if (isChecked) {
                 Icon(
                     painter = painterResource(id = R.drawable.stream_compose_ic_checkmark),
                     contentDescription = null,
                     tint = ChatTheme.colors.controlRadioCheckIconSelected,
                 )
             }
         }
🤖 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/messages/composer/internal/MessageComposerInputCenterBottomContent.kt`
around lines 118 - 126, The inner lambda parameter of AnimatedContent currently
named "checked" shadows the outer "checked" parameter; rename the
AnimatedContent lambda parameter (e.g., to "isChecked" or "innerChecked") and
update its usages inside the lambda (the Icon block and any conditional) so the
outer "checked" remains distinct; locate the AnimatedContent call in
MessageComposerInputCenterBottomContent (symbol: AnimatedContent(checked) { ...
}) and only change the lambda parameter name and its references.
stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/CustomChatComponentFactory.kt (1)

58-78: The modifier parameter is not applied to the composable.

The modifier parameter is defined but not used. Per Compose best practices, the modifier should be applied to the outermost composable to allow callers to customize layout behavior.

♻️ Proposed fix to apply the modifier
     `@Composable`
     override fun MessageComposerLeadingContent(
         modifier: Modifier,
         state: MessageComposerState,
         isAttachmentPickerVisible: Boolean,
         onAttachmentsClick: () -> Unit,
     ) {
         IconButton(
-            modifier = Modifier
+            modifier = modifier
                 .size(48.dp)
                 .padding(12.dp),
             content = {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/CustomChatComponentFactory.kt`
around lines 58 - 78, The MessageComposerLeadingContent composable ignores its
modifier parameter; update the IconButton call to use the incoming modifier as
the outermost modifier (e.g., combine the passed-in modifier with the local
size/padding using modifier.size(48.dp).padding(12.dp) or modifier.then(...)) so
callers can customize layout; change the IconButton's modifier argument
(currently Modifier.size(...).padding(...)) to use the provided modifier
combined with the size/padding while keeping the rest of the implementation
(Icon and onClick) intact.
stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/cookbook/ui/CustomComposerAndAttachmentsPicker.kt (1)

185-198: Consider wiring onAlsoSendToChannelChange for thread mode support.

The MessageInput component now accepts an onAlsoSendToChannelChange parameter (see MessageInput.kt lines 72-151 in the relevant snippets), but it's not passed here. If this cookbook example should support thread mode with the "Also send in Channel" checkbox, you may need to add this callback.

If thread mode is intentionally not supported in this example, this is fine as-is.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/cookbook/ui/CustomComposerAndAttachmentsPicker.kt`
around lines 185 - 198, The MessageInput call is missing the new
onAlsoSendToChannelChange callback; wire it to the composer view model by adding
onAlsoSendToChannelChange = { composerViewModel.setAlsoSendToChannel(it) } (or
the appropriate setter in composerViewModel if named differently) so the "Also
send in Channel" checkbox updates the composer state and enables thread-mode
support (referencing MessageInput, onAlsoSendToChannelChange, and
composerViewModel).
stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/AddingCustomAttachments.kt (1)

173-176: Use the incoming modifier in the custom leading slot.

On Line [174], Modifier is hardcoded, so any modifier passed into MessageComposerLeadingContent is dropped.

♻️ Proposed fix
         IconButton(
-            modifier = Modifier
+            modifier = modifier
                 .size(48.dp)
                 .padding(12.dp),

Based on learnings, in Compose UI components modifiers should be applied on the outermost composable so caller-provided modifiers are preserved.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/AddingCustomAttachments.kt`
around lines 173 - 176, The custom leading slot drops the caller-provided
modifier because IconButton uses the hardcoded Modifier instead of the incoming
modifier parameter; in MessageComposerLeadingContent (the composable containing
the IconButton), replace the hardcoded Modifier with the function's modifier and
chain the existing size(48.dp) and padding(12.dp) onto it (e.g.,
modifier.size(...).padding(...)) so caller modifiers are preserved and still
apply the size/padding.
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt (3)

1425-1443: Factory API still exposes the old callback name.

Line [1425] keeps onAlsoSendToChannelSelected while the rest of the redesigned composer API uses onAlsoSendToChannelChange. Consider renaming here too (or deprecating old name with a forwarder) to avoid mixed migration surface.

🤖 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 1425 - 1443, The factory currently exposes the old callback name
onAlsoSendToChannelSelected while the composer API expects
onAlsoSendToChannelChange; update the ChatComponentFactory signature to use
onAlsoSendToChannelChange and pass it into
io.getstream.chat.android.compose.ui.messages.composer.MessageComposer (replace
onAlsoSendToChannelSelected with onAlsoSendToChannelChange), and if you need
backward compatibility add a deprecated onAlsoSendToChannelSelected parameter
that simply forwards to the new onAlsoSendToChannelChange to avoid breaking
callers.

1613-1623: Apply the modifier parameter in MessageComposerLeadingContent.

The new modifier argument is currently ignored, so caller-provided layout/semantics cannot flow through.

♻️ Proposed fix
     public fun MessageComposerLeadingContent(
         modifier: Modifier,
         state: MessageComposerState,
         isAttachmentPickerVisible: Boolean,
         onAttachmentsClick: () -> Unit,
     ) {
-        io.getstream.chat.android.compose.ui.messages.composer.internal.MessageComposerLeadingContent(
-            messageInputState = state,
-            isAttachmentPickerVisible = isAttachmentPickerVisible,
-            onAttachmentsClick = onAttachmentsClick,
-        )
+        Box(modifier = modifier) {
+            io.getstream.chat.android.compose.ui.messages.composer.internal.MessageComposerLeadingContent(
+                messageInputState = state,
+                isAttachmentPickerVisible = isAttachmentPickerVisible,
+                onAttachmentsClick = onAttachmentsClick,
+            )
+        }
     }

Based on learnings, in Compose UI components modifiers should be applied on the outermost composable so caller-provided modifiers are preserved.

🤖 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 1613 - 1623, The public MessageComposerLeadingContent is ignoring
the incoming modifier; forward and apply it to the outermost internal composable
call so caller modifiers flow through. Update the public
MessageComposerLeadingContent to pass the modifier argument into
io.getstream.chat.android.compose.ui.messages.composer.internal.MessageComposerLeadingContent
(alongside messageInputState = state, isAttachmentPickerVisible,
onAttachmentsClick) so the modifier is applied to the outermost composable.

1766-1779: MessageComposerInputCenterBottomContent drops its modifier.

Line [1769] accepts a modifier but it is never used. This prevents external layout/styling control.

♻️ Proposed fix
-        AnimatedContent(targetState = inThreadMode) { visible ->
+        AnimatedContent(
+            modifier = modifier,
+            targetState = inThreadMode,
+        ) { visible ->
             if (visible) {
                 io.getstream.chat.android.compose.ui.messages.composer.internal.MessageComposerInputCenterBottomContent(
                     alsoSendToChannel = state.alsoSendToChannel,
                     onAlsoSendToChannelChange = onAlsoSendToChannelChange,
                 )
             }
         }

Based on learnings, in Compose UI components modifiers should be applied on the outermost composable so caller-provided modifiers are preserved.

🤖 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 1766 - 1779, The supplied modifier parameter is never applied in
MessageComposerInputCenterBottomContent; apply it to the outer composable (use
the modifier on AnimatedContent) so caller styling/layout is respected, and also
forward it to the inner component call
io.getstream.chat.android.compose.ui.messages.composer.internal.MessageComposerInputCenterBottomContent
(or wrap that call in a container using the modifier) so the modifier affects
the rendered content.
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt (1)

73-73: Please avoid an undocumented suppression in this path.

Line [73] introduces @Suppress("LongMethod") without rationale. Prefer extracting helpers or documenting why suppression is required.

As per coding guidelines, "**/*.kt: Use @OptIn annotations explicitly; avoid suppressions unless documented."

🤖 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/components/composer/MessageInput.kt`
at line 73, Remove the undocumented suppression `@Suppress`("LongMethod") in
MessageInput.kt: either refactor the long function(s) inside the MessageInput
component into smaller helper functions (e.g., extract UI sections or
input-handling logic into private functions) to eliminate the need for the
suppression, or if suppression is absolutely necessary, replace it with a
documented justification using a KDoc comment above the suppression explaining
why refactoring is impractical and referencing the specific function/class
(MessageInput) it applies to; prefer using `@OptIn` where appropriate per
guidelines instead of an undocumented `@Suppress`.
🤖 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/main/res/values-hi/strings.xml`:
- Around line 76-77: Add the missing Hindi localization for the string resource
stream_compose_message_composer_cannot_send_placeholder by adding an entry in
the Hindi strings.xml (same key as other locales) with an appropriate Hindi
translation, ensuring you follow the existing XML string format (no extra
surrounding quotes and proper escaping for special characters) so the app shows
Hindi text when message sending is disabled.

---

Outside diff comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/MessageComposer.kt`:
- Around line 117-121: The code calls inputFocusRequester.requestFocus() from
the LaunchedEffect collecting viewModel.inputFocusEvents but the FocusRequester
(inputFocusRequester) is never attached to any composable, so requestFocus()
will crash; fix by wiring the requester into the text input chain (pass
inputFocusRequester into MessageComposerInput/MessageInput and attach it with
Modifier.focusRequester(inputFocusRequester) on the BasicTextField) or remove
the LaunchedEffect/collector until focus wiring is implemented so
inputFocusRequester.requestFocus() is not invoked on an unattached requester.

---

Nitpick comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt`:
- Line 73: Remove the undocumented suppression `@Suppress`("LongMethod") in
MessageInput.kt: either refactor the long function(s) inside the MessageInput
component into smaller helper functions (e.g., extract UI sections or
input-handling logic into private functions) to eliminate the need for the
suppression, or if suppression is absolutely necessary, replace it with a
documented justification using a KDoc comment above the suppression explaining
why refactoring is impractical and referencing the specific function/class
(MessageInput) it applies to; prefer using `@OptIn` where appropriate per
guidelines instead of an undocumented `@Suppress`.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputCenterBottomContent.kt`:
- Around line 118-126: The inner lambda parameter of AnimatedContent currently
named "checked" shadows the outer "checked" parameter; rename the
AnimatedContent lambda parameter (e.g., to "isChecked" or "innerChecked") and
update its usages inside the lambda (the Icon block and any conditional) so the
outer "checked" remains distinct; locate the AnimatedContent call in
MessageComposerInputCenterBottomContent (symbol: AnimatedContent(checked) { ...
}) and only change the lambda parameter name and its references.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt`:
- Around line 1425-1443: The factory currently exposes the old callback name
onAlsoSendToChannelSelected while the composer API expects
onAlsoSendToChannelChange; update the ChatComponentFactory signature to use
onAlsoSendToChannelChange and pass it into
io.getstream.chat.android.compose.ui.messages.composer.MessageComposer (replace
onAlsoSendToChannelSelected with onAlsoSendToChannelChange), and if you need
backward compatibility add a deprecated onAlsoSendToChannelSelected parameter
that simply forwards to the new onAlsoSendToChannelChange to avoid breaking
callers.
- Around line 1613-1623: The public MessageComposerLeadingContent is ignoring
the incoming modifier; forward and apply it to the outermost internal composable
call so caller modifiers flow through. Update the public
MessageComposerLeadingContent to pass the modifier argument into
io.getstream.chat.android.compose.ui.messages.composer.internal.MessageComposerLeadingContent
(alongside messageInputState = state, isAttachmentPickerVisible,
onAttachmentsClick) so the modifier is applied to the outermost composable.
- Around line 1766-1779: The supplied modifier parameter is never applied in
MessageComposerInputCenterBottomContent; apply it to the outer composable (use
the modifier on AnimatedContent) so caller styling/layout is respected, and also
forward it to the inner component call
io.getstream.chat.android.compose.ui.messages.composer.internal.MessageComposerInputCenterBottomContent
(or wrap that call in a container using the modifier) so the modifier affects
the rendered content.

In
`@stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/AddingCustomAttachments.kt`:
- Around line 173-176: The custom leading slot drops the caller-provided
modifier because IconButton uses the hardcoded Modifier instead of the incoming
modifier parameter; in MessageComposerLeadingContent (the composable containing
the IconButton), replace the hardcoded Modifier with the function's modifier and
chain the existing size(48.dp) and padding(12.dp) onto it (e.g.,
modifier.size(...).padding(...)) so caller modifiers are preserved and still
apply the size/padding.

In
`@stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/cookbook/ui/CustomComposerAndAttachmentsPicker.kt`:
- Around line 185-198: The MessageInput call is missing the new
onAlsoSendToChannelChange callback; wire it to the composer view model by adding
onAlsoSendToChannelChange = { composerViewModel.setAlsoSendToChannel(it) } (or
the appropriate setter in composerViewModel if named differently) so the "Also
send in Channel" checkbox updates the composer state and enables thread-mode
support (referencing MessageInput, onAlsoSendToChannelChange, and
composerViewModel).

In
`@stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/CustomChatComponentFactory.kt`:
- Around line 58-78: The MessageComposerLeadingContent composable ignores its
modifier parameter; update the IconButton call to use the incoming modifier as
the outermost modifier (e.g., combine the passed-in modifier with the local
size/padding using modifier.size(48.dp).padding(12.dp) or modifier.then(...)) so
callers can customize layout; change the IconButton's modifier argument
(currently Modifier.size(...).padding(...)) to use the provided modifier
combined with the size/padding while keeping the rest of the implementation
(Icon and onClick) intact.

ℹ️ 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 3e696eb and 6d65bdf.

⛔ Files ignored due to path filters (18)
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_attachments.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_attachments_and_link.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_edit,_attachments,_and_link.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_edit.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_edit_empty.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_filled.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_link.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_overflow.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_placeholder.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_reply,_attachments,_and_link.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_reply.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_slow_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_thread_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerInputTest_thread_mode_also_send_to_channel.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerTest_default_style.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerTest_default_style_with_visible_attachment_picker.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerTest_floating_style.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerTest_floating_style_with_visible_attachment_picker.png is excluded by !**/*.png
📒 Files selected for processing (24)
  • stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/add/AddChannelActivity.kt
  • stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/add/AddChannelScreen.kt
  • stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/composer/MessageInput.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/MessageComposer.kt
  • 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/messages/composer/internal/MessageComposerInputCenterBottomContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputCenterContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerInputTrailingContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt
  • stream-chat-android-compose/src/main/res/values-es/strings.xml
  • stream-chat-android-compose/src/main/res/values-hi/strings.xml
  • stream-chat-android-compose/src/main/res/values/strings.xml
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/MessageComposerInputTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/composer/MessageComposerScreenTest.kt
  • stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/guides/AddingCustomAttachments.kt
  • stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/messages/MessageComposer.kt
  • stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/cookbook/ui/CustomComposerAndAttachmentsPicker.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt
  • stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerControllerTest.kt
  • stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/CustomChatComponentFactory.kt
  • stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/MessagesActivity.kt
💤 Files with no reviewable changes (3)
  • stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/add/AddChannelScreen.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/MessageComposerDefaults.kt
  • stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt

@andremion andremion enabled auto-merge (squash) March 3, 2026 15:36
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 3, 2026

@andremion andremion merged commit 796037d into v7 Mar 4, 2026
19 of 20 checks passed
@andremion andremion deleted the redesign/AND-1098-composer-thread-state-redesign branch March 4, 2026 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:breaking-change Breaking change pr:new-feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants