Skip to content

feat(ui): channel page and floating UI#2748

Open
renefloor wants to merge 44 commits into
masterfrom
feat/channel-page
Open

feat(ui): channel page and floating UI#2748
renefloor wants to merge 44 commits into
masterfrom
feat/channel-page

Conversation

@renefloor

@renefloor renefloor commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Submit a pull request

Linear: FLU-502

CLA

  • I have signed the Stream CLA (required).
  • The code changes follow best practices
  • Code changes are tested (add some information if not applicable)

Description of the pull request

This introduces the floating style on all sample app pages and moves the channel page and thread page to the sdk.
The StreamMessageListViewConfiguration is also added to the global chat config so it's easier to use in the channel and thread page.

Core PR: GetStream/stream-core-flutter#115

Screenshots / Videos

Regular Floating
image image
image image
image image
image image
image image

Summary by CodeRabbit

  • New Features

    • Added ready-to-use StreamChannelPage and StreamThreadPage with reply/edit flows, focus handling, and a themed typing indicator; re-exported from the main package entrypoint.
    • Composer now supports floating vs. docked placement via ComposerLocation/MessageComposerProps.location, plus theme support.
    • StreamMessageListView now accepts nullable per-widget config plus topPadding/bottomPadding, backed by a default configuration in app settings.
    • Added appBarBehavior support for channel/thread headers and back button; floating avatar shadow now follows theme/behavior.
  • Bug Fixes

    • StreamChannelPage now disposes its composer controller; fixed redundant paddings in photo/skeleton galleries and improved attachment picker placeholder.
    • Thread reply action now respects whether channel replies are enabled.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f875f08c-90d4-4769-bcdf-705056795fb2

📥 Commits

Reviewing files that changed from the base of the PR and between 414fd1b and 017e9c4.

📒 Files selected for processing (1)
  • sample_app/lib/widgets/channel_list.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • sample_app/lib/widgets/channel_list.dart

📝 Walkthrough

Walkthrough

This PR introduces ready-to-use StreamChannelPage and StreamThreadPage widgets, adds app-wide messageListViewConfiguration defaults with per-widget topPadding/bottomPadding overrides, introduces a ComposerLocation theme for floating/docked composer layout, propagates isFloating through app bar and avatar components, and migrates the sample app to StreamScaffold, StreamBottomNavBar, and the new page widgets.

Changes

Library UI foundation and public surface

Layer / File(s) Summary
Global message list defaults and StreamMessageListView padding
packages/stream_chat_flutter/lib/src/stream_chat_configuration.dart, packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart
StreamChatConfigurationData gains a default messageListViewConfiguration; StreamMessageListView.config becomes nullable with a fallback to that global default. New topPadding/bottomPadding fields propagate through scroll positioning, floating date divider, unread indicators, and scroll-to-bottom button.
Channel and thread page widgets
packages/stream_chat_flutter/lib/src/channel/channel_page.dart, packages/stream_chat_flutter/lib/src/channel/thread_page.dart, packages/stream_chat_flutter/lib/stream_chat_flutter.dart, packages/stream_chat_flutter/CHANGELOG.md
Adds StreamChannelPage with stateful composer controller lifecycle, reply/edit/focus handlers, typing indicator overlay, and _ChannelPageBody for inset-aware list layout. Adds StreamThreadPage with conditional composer for deleted messages and _ThreadBody list wiring. Both widgets are re-exported from the package barrel.
Floating app bar styling and avatar shadows
packages/stream_chat_flutter/lib/src/channel/channel_header.dart, packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart, packages/stream_chat_flutter/lib/src/misc/back_button.dart, packages/stream_chat_flutter/lib/src/components/avatar/stream_channel_avatar.dart, packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar.dart, packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar_group.dart
Channel/list headers and back button compute an effectiveAppBarBehavior from per-widget override, then StreamAppBarTheme, then theme floating flag. The resulting boolean propagates as isFloating through the avatar component tree to render drop shadows.
Message composer theming infrastructure
packages/stream_chat_flutter/lib/src/theme/message_composer_theme.dart, packages/stream_chat_flutter/lib/src/theme/message_composer_theme.g.theme.dart, packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart, packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.g.theme.dart, packages/stream_chat_flutter/lib/src/theme/themes.dart
New ComposerLocation enum, StreamMessageComposerTheme inherited widget, and StreamMessageComposerThemeData with generated lerp/copyWith/merge/equality support. Integrated into StreamChatThemeData as messageComposerTheme.
Floating and docked composer layout with location parameter
packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart
StreamMessageComposer and MessageComposerProps accept an optional location parameter forwarded through copyWith. Default state derives effective placement from that, the theme, or app style; renders floating (transparent material + backgroundElevation1 band + gradient pill wrapper) vs docked (DecoratedBox). Inline picker is always wrapped in ColoredBox.
Reply gating, padding polish, and dependency bump
packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart, packages/stream_chat_flutter/lib/src/scroll_view/channel_scroll_view/stream_channel_list_skeleton_loading.dart, packages/stream_chat_flutter/lib/src/scroll_view/thread_scroll_view/stream_thread_list_skeleton_loading.dart, packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart, packages/stream_chat_flutter/lib/src/scroll_view/photo_gallery/stream_photo_gallery.dart, docs/docs_screenshots/test/src/mocks.dart, melos.yaml, packages/stream_chat_flutter/pubspec.yaml, docs/docs_screenshots/pubspec.yaml
Thread reply action is gated by channel.config?.replies; skeleton lists set padding: EdgeInsets.zero; gallery picker loading returns SizedBox.expand(); photo gallery defaults to safe-area bottom only. stream_core_flutter ref is rebumped across all pubspec/melos files. Mock updated with replies: true.

Sample app migration to scaffold primitives

Layer / File(s) Summary
Sample style configuration and theme wiring
sample_app/lib/config/sample_app_config.dart, sample_app/lib/app.dart
Adds SampleAppStyle enum (regular/floating) with preference persistence; MaterialApp.router themes are derived from the combined brightness and app style rather than fixed StreamTheme.light()/StreamTheme.dark(). StreamChatConfigurationData gains messageListViewConfiguration with highlightInitialMessage: true and swipeToReply: true.
Channel entry points, navigation shell, and routing
sample_app/lib/pages/channel_list_page.dart, sample_app/lib/widgets/channel_list.dart, sample_app/lib/pages/draft_list_page.dart, sample_app/lib/pages/thread_list_page.dart, sample_app/lib/routes/app_routes.dart
Channel list page switches from Scaffold/BottomNavigationBar to StreamScaffold/StreamBottomNavBar via consolidated _TabDef.navItem. List surfaces read StreamScaffoldInsets for bottom/top padding. Draft and thread pages route through StreamChannelPage/StreamThreadPage. Route builder adds onChannelAvatarPressed navigating to CHAT_INFO_SCREEN or GROUP_INFO_SCREEN.
Screen migration to StreamScaffold
sample_app/lib/config/sample_app_config_screen.dart, sample_app/lib/pages/advanced_options_page.dart, sample_app/lib/pages/channel_file_display_screen.dart, sample_app/lib/pages/channel_media_display_screen.dart, sample_app/lib/pages/chat_info_screen.dart, sample_app/lib/pages/group_chat_details_screen.dart, sample_app/lib/pages/group_info_screen.dart, sample_app/lib/pages/new_chat_screen.dart, sample_app/lib/pages/new_group_chat_screen.dart, sample_app/lib/pages/pinned_messages_screen.dart
All secondary screens replace Scaffold with StreamScaffold and use a Builder reading StreamScaffoldInsets.maybeOf(context)?.topPadding to apply inset-aware scroll view and list padding.

Sequence Diagram(s)

sequenceDiagram
  participant User
  rect rgba(100, 149, 237, 0.5)
  Note over User,StreamChannelPage: Channel Page Entry
  end
  User->>StreamChannelPage: open channel
  StreamChannelPage->>_ChannelPageBody: build(insets)
  _ChannelPageBody->>StreamMessageListView: topPadding/bottomPadding + handlers
  User->>StreamMessageComposer: type/reply/edit
  StreamMessageComposer->>StreamMessageComposerController: setQuotedMessage / editMessage
  StreamMessageComposer-->>_ChannelPageBody: focus requested
  rect rgba(100, 200, 100, 0.5)
  Note over User,StreamThreadPage: Thread Entry via threadBuilder
  end
  User->>StreamMessageListView: tap thread reply
  StreamMessageListView->>StreamThreadPage: threadBuilder(message)
  StreamThreadPage->>StreamMessageComposerController: init with parent
  StreamThreadPage->>_ThreadBody: build(parent, insets)
  _ThreadBody->>StreamMessageListView: thread config + topPadding/bottomPadding
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • GetStream/stream-chat-flutter#2642: Extends StreamMessageComposer in lib/src/message_input/stream_message_composer.dart with floating vs docked composer layout features directly aligned with this PR's ComposerLocation parameter and theme integration.
  • GetStream/stream-chat-flutter#2651: Modifies StreamMessageListView scroll-to-bottom, unread, and pagination logic in the same component where this PR adds topPadding/bottomPadding and _config fallback.
  • GetStream/stream-chat-flutter#2674: Introduced the config/builders consolidation pattern in StreamMessageListView that this PR extends by making config nullable and adding the global configuration fallback.

Suggested reviewers

  • xsahil03x

Poem

🐇 A hop, a skip, and pages brand new,
Floating or docked — composer's your cue!
Scaffold insets line up, padding is right,
Thread and channel pages, what a delight!
The rabbit approves this elegant flight! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(ui): channel page and floating UI' accurately describes the main changes: introducing new ready-to-use channel and thread pages in the SDK and adding floating UI style support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/channel-page

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart (1)

433-470: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing composerLocation in copyWith method.

The new composerLocation field is not included in the copyWith method, breaking the expected API contract. Callers cannot override this field when copying props.

🐛 Proposed fix to add missing parameter
   MessageComposerProps copyWith({
     void Function(Message)? onMessageSent,
     FutureOr<Message> Function(Message)? preMessageSending,
     StreamMessageComposerController? messageComposerController,
     FocusNode? focusNode,
     bool? disableAttachments,
     bool? canAlsoSendToChannelFromThread,
     bool? enableVoiceRecording,
     bool? sendVoiceRecordingAutomatically,
     AudioRecorderFeedback? voiceRecordingFeedback,
     UserMentionTileBuilder? userMentionsTileBuilder,
     ErrorListener? onError,
     int? attachmentLimit,
     List<AttachmentPickerType>? allowedAttachmentPickerTypes,
     Iterable<StreamAutocompleteTrigger>? customAutocompleteTriggers,
     bool? mentionAllAppUsers,
     bool? shouldKeepFocusAfterMessage,
     MessageValidator? validator,
     String? restorationId,
     bool? enableSafeArea,
     bool? enableMentionsOverlay,
     VoidCallback? onQuotedMessageCleared,
     OgPreviewFilter? ogPreviewFilter,
     MessageInputPlaceholderBuilder? placeholderBuilder,
     bool? useSystemAttachmentPicker,
     PollConfig? pollConfig,
     AttachmentPickerOptionsBuilder? attachmentPickerOptionsBuilder,
     OnAttachmentPickerResult? onAttachmentPickerResult,
     KeyEventPredicate? sendMessageKeyPredicate,
     KeyEventPredicate? clearQuotedMessageKeyPredicate,
     TextInputAction? textInputAction,
     TextInputType? keyboardType,
     TextCapitalization? textCapitalization,
     bool? autofocus,
     bool? autoCorrect,
+    ComposerLocation? composerLocation,
   }) {
     return MessageComposerProps(
       onMessageSent: onMessageSent ?? this.onMessageSent,
       preMessageSending: preMessageSending ?? this.preMessageSending,
       messageComposerController: messageComposerController ?? this.messageComposerController,
       focusNode: focusNode ?? this.focusNode,
       disableAttachments: disableAttachments ?? this.disableAttachments,
       canAlsoSendToChannelFromThread: canAlsoSendToChannelFromThread ?? this.canAlsoSendToChannelFromThread,
       enableVoiceRecording: enableVoiceRecording ?? this.enableVoiceRecording,
       sendVoiceRecordingAutomatically: sendVoiceRecordingAutomatically ?? this.sendVoiceRecordingAutomatically,
       voiceRecordingFeedback: voiceRecordingFeedback ?? this.voiceRecordingFeedback,
       userMentionsTileBuilder: userMentionsTileBuilder ?? this.userMentionsTileBuilder,
       onError: onError ?? this.onError,
       attachmentLimit: attachmentLimit ?? this.attachmentLimit,
       allowedAttachmentPickerTypes: allowedAttachmentPickerTypes ?? this.allowedAttachmentPickerTypes,
       customAutocompleteTriggers: customAutocompleteTriggers ?? this.customAutocompleteTriggers,
       mentionAllAppUsers: mentionAllAppUsers ?? this.mentionAllAppUsers,
       shouldKeepFocusAfterMessage: shouldKeepFocusAfterMessage ?? this.shouldKeepFocusAfterMessage,
       validator: validator ?? this.validator,
       restorationId: restorationId ?? this.restorationId,
       enableSafeArea: enableSafeArea ?? this.enableSafeArea,
       enableMentionsOverlay: enableMentionsOverlay ?? this.enableMentionsOverlay,
       onQuotedMessageCleared: onQuotedMessageCleared ?? this.onQuotedMessageCleared,
       ogPreviewFilter: ogPreviewFilter ?? this.ogPreviewFilter,
       placeholderBuilder: placeholderBuilder ?? this.placeholderBuilder,
       useSystemAttachmentPicker: useSystemAttachmentPicker ?? this.useSystemAttachmentPicker,
       pollConfig: pollConfig ?? this.pollConfig,
       attachmentPickerOptionsBuilder: attachmentPickerOptionsBuilder ?? this.attachmentPickerOptionsBuilder,
       onAttachmentPickerResult: onAttachmentPickerResult ?? this.onAttachmentPickerResult,
       sendMessageKeyPredicate: sendMessageKeyPredicate ?? this.sendMessageKeyPredicate,
       clearQuotedMessageKeyPredicate: clearQuotedMessageKeyPredicate ?? this.clearQuotedMessageKeyPredicate,
       textInputAction: textInputAction ?? this.textInputAction,
       keyboardType: keyboardType ?? this.keyboardType,
       textCapitalization: textCapitalization ?? this.textCapitalization,
       autofocus: autofocus ?? this.autofocus,
       autoCorrect: autoCorrect ?? this.autoCorrect,
+      composerLocation: composerLocation ?? this.composerLocation,
     );
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`
around lines 433 - 470, The copyWith method in MessageComposerProps is missing
the new composerLocation field; update the copyWith signature to accept
composerLocation and include it in the returned MessageComposerProps (e.g.,
composerLocation: composerLocation ?? this.composerLocation) alongside the other
fields so callers can override composerLocation when copying props.
sample_app/lib/pages/new_group_chat_screen.dart (1)

10-11: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add public API doc comment.

NewGroupChatScreen is a public widget but lacks documentation. As per coding guidelines, all public APIs must have doc comments.

📝 Suggested doc comment
+/// A screen for selecting users to add to a new group chat.
+///
+/// Users can search for platform members and select multiple participants
+/// before proceeding to group details configuration.
 class NewGroupChatScreen extends StatefulWidget {
   const NewGroupChatScreen({super.key});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sample_app/lib/pages/new_group_chat_screen.dart` around lines 10 - 11, Add a
public Dart doc comment for the NewGroupChatScreen widget: above the class
declaration for NewGroupChatScreen, insert a /// comment that briefly describes
the widget's purpose (e.g., creates a UI for creating a new group chat),
documents its constructor parameters (if any, like key), and any important
behavior or usage notes so it complies with the public API documentation
guideline.

Source: Coding guidelines

🧹 Nitpick comments (3)
packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart (1)

979-984: 💤 Low value

Deprecated axisAlignment parameter usage.

The axisAlignment parameter on SizeTransition is deprecated. The comment acknowledges this, but consider migrating to the replacement API when available to avoid future deprecation warnings during builds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`
around lines 979 - 984, Replace the deprecated axisAlignment usage in the
SizeTransition inside StreamMessageComposer: remove the "axisAlignment: -1"
argument and instead pass an alignment value that preserves the original
behavior (axisAlignment -1 -> top alignment) using the new "alignment" parameter
(e.g., Alignment.topCenter or AlignmentDirectional.topStart) on the
SizeTransition that wraps _buildInlineAttachmentPicker; update the
SizeTransition invocation accordingly so the widget aligns the
collapsing/expanding animation to the top without using the deprecated
axisAlignment.
packages/stream_chat_flutter/lib/src/channel/channel_header.dart (1)

134-136: ⚡ Quick win

Inconsistent documentation pattern for appBarBehavior fields across StreamChannelHeader, StreamChannelListHeader, and StreamBackButton.

All three widgets document their appBarBehavior field with boolean phrasing ("Whether X is floating") when the field is typed as AppBarBehavior?, not a boolean. The documentation should describe the parameter's purpose (controlling visual behavior) and mention the fallback to theme defaults. Consider unifying the wording across channel_header.dart, channel_list_header.dart, and back_button.dart.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart` around
lines 134 - 136, Update the doc comments for the appBarBehavior field in
StreamChannelHeader, StreamChannelListHeader, and StreamBackButton to stop using
boolean phrasing and instead describe that appBarBehavior (type AppBarBehavior?)
controls the header/back button visual/layout behavior (e.g., floating vs
pinned) and that it falls back to the theme's default when null; make the
wording consistent across the three files by using the same concise sentence
describing purpose and null/theme fallback and reference the AppBarBehavior type
in the comment.
packages/stream_chat_flutter/lib/src/channel/channel_page.dart (1)

32-44: ⚡ Quick win

Prefer late final non-nullable FocusNode to avoid force-unwraps.

The _focusNode field is declared nullable but always initialized in initState and force-unwrapped at every usage site (lines 43, 50, 57). This pattern is fragile and could panic if lifecycle order changes. Declaring it as late final FocusNode makes the initialization contract explicit and eliminates the null-check overhead.

♻️ Proposed refactor
-  FocusNode? _focusNode;
+  late final FocusNode _focusNode;
   final _messageComposerController = StreamMessageComposerController();
 
   `@override`
   void initState() {
+    super.initState();
     _focusNode = FocusNode();
-    super.initState();
   }
 
   `@override`
   void dispose() {
-    _focusNode!.dispose();
+    _focusNode.dispose();
     super.dispose();
   }
 
   void _reply(Message message) {
     _messageComposerController.quotedMessage = message;
     WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
-      _focusNode!.requestFocus();
+      _focusNode.requestFocus();
     });
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/src/channel/channel_page.dart` around lines
32 - 44, The _focusNode field is declared nullable but always initialized in
initState and force-unwrapped elsewhere; change its declaration to use
non-nullable late final (late final FocusNode _focusNode) so initialization is
explicit, keep _focusNode = FocusNode() inside initState, call
_focusNode.dispose() in dispose, and remove any force-unwraps (!) where
_focusNode is accessed (e.g., usages in the widget build and handlers).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart`:
- Line 78: The permission-loading branch in stream_gallery_picker.dart returns
const SizedBox.expand() when !snapshot.hasData, but the project's Empty widget
builds const SizedBox.shrink(), so replace the expand with the shrink (or return
Empty()) in the permission/loading branch to avoid introducing an unintended
expanded blank area and layout shift; locate the conditional using
snapshot.hasData in the StreamGalleryPicker build method and update the returned
widget accordingly.

In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`:
- Around line 14-16: The constant _kPickerBodyHeight is unused dead code; either
remove the declaration or apply it as the fixed height for the inline attachment
picker UI—locate the picker implementation in stream_message_composer.dart (look
for the InlineAttachmentPicker or picker body widget inside
StreamMessageComposer/MessageComposer) and replace any hard-coded height values
or SizedBox/Container height with _kPickerBodyHeight, or delete the
_kPickerBodyHeight declaration if you choose not to standardize the height.

In `@sample_app/lib/routes/app_routes.dart`:
- Around line 48-72: The onChannelAvatarPressed handler can crash because
currentUserId may be null and channelMembers.firstWhere(...) will throw if no
match; update the logic in onChannelAvatarPressed to null-guard currentUserId
and safely find the other member (use collection's firstWhereOrNull or
firstWhere with orElse returning null) when computing otherUser from
channel.state?.members, and only navigate to Routes.CHAT_INFO_SCREEN when
otherUser is non-null; fallback to the GROUP_INFO_SCREEN path otherwise. Ensure
you import the collection helper if you use firstWhereOrNull.

---

Outside diff comments:
In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`:
- Around line 433-470: The copyWith method in MessageComposerProps is missing
the new composerLocation field; update the copyWith signature to accept
composerLocation and include it in the returned MessageComposerProps (e.g.,
composerLocation: composerLocation ?? this.composerLocation) alongside the other
fields so callers can override composerLocation when copying props.

In `@sample_app/lib/pages/new_group_chat_screen.dart`:
- Around line 10-11: Add a public Dart doc comment for the NewGroupChatScreen
widget: above the class declaration for NewGroupChatScreen, insert a /// comment
that briefly describes the widget's purpose (e.g., creates a UI for creating a
new group chat), documents its constructor parameters (if any, like key), and
any important behavior or usage notes so it complies with the public API
documentation guideline.

---

Nitpick comments:
In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart`:
- Around line 134-136: Update the doc comments for the appBarBehavior field in
StreamChannelHeader, StreamChannelListHeader, and StreamBackButton to stop using
boolean phrasing and instead describe that appBarBehavior (type AppBarBehavior?)
controls the header/back button visual/layout behavior (e.g., floating vs
pinned) and that it falls back to the theme's default when null; make the
wording consistent across the three files by using the same concise sentence
describing purpose and null/theme fallback and reference the AppBarBehavior type
in the comment.

In `@packages/stream_chat_flutter/lib/src/channel/channel_page.dart`:
- Around line 32-44: The _focusNode field is declared nullable but always
initialized in initState and force-unwrapped elsewhere; change its declaration
to use non-nullable late final (late final FocusNode _focusNode) so
initialization is explicit, keep _focusNode = FocusNode() inside initState, call
_focusNode.dispose() in dispose, and remove any force-unwraps (!) where
_focusNode is accessed (e.g., usages in the widget build and handlers).

In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`:
- Around line 979-984: Replace the deprecated axisAlignment usage in the
SizeTransition inside StreamMessageComposer: remove the "axisAlignment: -1"
argument and instead pass an alignment value that preserves the original
behavior (axisAlignment -1 -> top alignment) using the new "alignment" parameter
(e.g., Alignment.topCenter or AlignmentDirectional.topStart) on the
SizeTransition that wraps _buildInlineAttachmentPicker; update the
SizeTransition invocation accordingly so the widget aligns the
collapsing/expanding animation to the top without using the deprecated
axisAlignment.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9e2a3f42-fca0-422a-96f1-7cd12e8d83ee

📥 Commits

Reviewing files that changed from the base of the PR and between 805e2e0 and 74888d1.

📒 Files selected for processing (40)
  • docs/docs_screenshots/pubspec.yaml
  • melos.yaml
  • packages/stream_chat_flutter/CHANGELOG.md
  • packages/stream_chat_flutter/lib/src/channel/channel_header.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_page.dart
  • packages/stream_chat_flutter/lib/src/channel/thread_page.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_channel_avatar.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar_group.dart
  • packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart
  • packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart
  • packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart
  • packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart
  • packages/stream_chat_flutter/lib/src/misc/back_button.dart
  • packages/stream_chat_flutter/lib/src/scroll_view/channel_scroll_view/stream_channel_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/scroll_view/photo_gallery/stream_photo_gallery.dart
  • packages/stream_chat_flutter/lib/src/scroll_view/thread_scroll_view/stream_thread_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/stream_chat_configuration.dart
  • packages/stream_chat_flutter/lib/stream_chat_flutter.dart
  • packages/stream_chat_flutter/pubspec.yaml
  • sample_app/lib/app.dart
  • sample_app/lib/config/sample_app_config.dart
  • sample_app/lib/config/sample_app_config_screen.dart
  • sample_app/lib/pages/advanced_options_page.dart
  • sample_app/lib/pages/channel_file_display_screen.dart
  • sample_app/lib/pages/channel_list_page.dart
  • sample_app/lib/pages/channel_media_display_screen.dart
  • sample_app/lib/pages/channel_page.dart
  • sample_app/lib/pages/chat_info_screen.dart
  • sample_app/lib/pages/draft_list_page.dart
  • sample_app/lib/pages/group_chat_details_screen.dart
  • sample_app/lib/pages/group_info_screen.dart
  • sample_app/lib/pages/new_chat_screen.dart
  • sample_app/lib/pages/new_group_chat_screen.dart
  • sample_app/lib/pages/pinned_messages_screen.dart
  • sample_app/lib/pages/thread_list_page.dart
  • sample_app/lib/pages/thread_page.dart
  • sample_app/lib/routes/app_routes.dart
  • sample_app/lib/widgets/channel_list.dart
💤 Files with no reviewable changes (2)
  • sample_app/lib/pages/thread_page.dart
  • sample_app/lib/pages/channel_page.dart

Comment thread packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart Outdated
Comment thread sample_app/lib/routes/app_routes.dart

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart (2)

430-467: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Allow copyWith to clear composerLocation.

null means “fall back to the theme” at Lines 799-800 and 918-919, but composerLocation ?? this.composerLocation makes that state unreachable once a copied props object has an explicit override.

Proposed minimal fix
     TextCapitalization? textCapitalization,
     bool? autofocus,
     bool? autoCorrect,
     ComposerLocation? composerLocation,
+    bool clearComposerLocation = false,
   }) {
     return MessageComposerProps(
@@
       textCapitalization: textCapitalization ?? this.textCapitalization,
       autofocus: autofocus ?? this.autofocus,
       autoCorrect: autoCorrect ?? this.autoCorrect,
-      composerLocation: composerLocation ?? this.composerLocation,
+      composerLocation: clearComposerLocation ? null : composerLocation ?? this.composerLocation,
     );
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`
around lines 430 - 467, The copyWith method uses the coalesce operator for
composerLocation parameter, which prevents null values from being passed through
and assigned. This makes it impossible to clear the composerLocation back to
null (which should fall back to the theme) once an explicit override exists.
Change the composerLocation assignment in the return statement of copyWith to
use a pattern that distinguishes between "parameter not provided" and "parameter
explicitly set to null", such as using a sentinel value or optional parameter
pattern. This will allow callers to explicitly set composerLocation to null when
desired.

927-987: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the picker panel inside the desktop drop target.

The DropTarget now wraps only the input pill, while _buildInlineAttachmentPicker is a sibling. When the picker is open, dropping files over the picker panel no longer calls _addAttachments; wrap the whole composer column in the drop target and keep the floating gradient scoped to the pill.

Proposed restructuring
-        final pill = DropTarget(
+        final pill = Focus(
+          skipTraversal: true,
+          onKeyEvent: _handleKeyPressed,
+          child: StreamChatMessageInput(
+            controller: controller,
+            currentUserId: currentUserId,
+            onAttachmentButtonPressed: widget.props.disableAttachments ? null : _onAttachmentButtonPressed,
+            isPickerOpen: _isPickerVisible,
+            placeholder: _buildPlaceholder(context),
+            focusNode: focusNode,
+            onSendPressed: sendMessage,
+            canAlsoSendToChannel: _shouldShowSendToChannelCheckbox(),
+            audioRecorderController: widget.props.enableVoiceRecording ? _audioRecorderController : null,
+            sendVoiceRecordingAutomatically: widget.props.sendVoiceRecordingAutomatically,
+            feedback: widget.props.voiceRecordingFeedback,
+            onQuotedMessageCleared: () {
+              _effectiveController.clearQuotedMessage();
+              widget.props.onQuotedMessageCleared?.call();
+            },
+            textInputAction: widget.props.textInputAction,
+            keyboardType: widget.props.keyboardType,
+            textCapitalization: widget.props.textCapitalization,
+            autofocus: widget.props.autofocus,
+            autocorrect: widget.props.autoCorrect,
+            isFloating: isFloating,
+          ),
+        );
+
+        Widget withDropTarget(Widget child) => DropTarget(
           onDragDone: (details) async {
             final attachments = <Attachment>[];
             for (final file in details.files) {
               attachments.add(await file.toAttachment(type: AttachmentType.file));
             }
             if (attachments.isNotEmpty) _addAttachments(attachments);
           },
           onDragEntered: (_) {},
           onDragExited: (_) {},
-          child: Focus(
-            skipTraversal: true,
-            onKeyEvent: _handleKeyPressed,
-            child: StreamChatMessageInput(
-              controller: controller,
-              currentUserId: currentUserId,
-              onAttachmentButtonPressed: widget.props.disableAttachments ? null : _onAttachmentButtonPressed,
-              isPickerOpen: _isPickerVisible,
-              placeholder: _buildPlaceholder(context),
-              focusNode: focusNode,
-              onSendPressed: sendMessage,
-              canAlsoSendToChannel: _shouldShowSendToChannelCheckbox(),
-              audioRecorderController: widget.props.enableVoiceRecording ? _audioRecorderController : null,
-              sendVoiceRecordingAutomatically: widget.props.sendVoiceRecordingAutomatically,
-              feedback: widget.props.voiceRecordingFeedback,
-              onQuotedMessageCleared: () {
-                _effectiveController.clearQuotedMessage();
-                widget.props.onQuotedMessageCleared?.call();
-              },
-              textInputAction: widget.props.textInputAction,
-              keyboardType: widget.props.keyboardType,
-              textCapitalization: widget.props.textCapitalization,
-              autofocus: widget.props.autofocus,
-              autocorrect: widget.props.autoCorrect,
-              isFloating: isFloating,
-            ),
-          ),
+          child: child,
         );
 
         return PopScope(
           canPop: !_isPickerVisible,
           onPopInvokedWithResult: (didPop, _) {
             if (!didPop) _hidePicker();
           },
-          child: Column(
+          child: withDropTarget(Column(
             mainAxisSize: MainAxisSize.min,
             // Reversed paint order so the pill (and its shadow) paints on top
             // of the picker panel. VerticalDirection.up keeps the pill visually
             // above the picker while making it the last-painted child.
             verticalDirection: VerticalDirection.up,
@@
               if (isFloating) _buildFloatingComposerBand(context, pill) else pill,
             ],
-          ),
+          )),
         );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`
around lines 927 - 987, The DropTarget is currently wrapping only the pill
(StreamChatMessageInput), leaving the picker panel
(_buildInlineAttachmentPicker) outside the drop target as a sibling. This means
dragging files over the open picker won't trigger file attachment handling since
it's not within the drop target's scope. Restructure the code by moving the
DropTarget wrapper to encompass the entire Column that contains both the
SizeTransition (which wraps _buildInlineAttachmentPicker) and the pill. Keep the
gradient wrapping logic scoped to just the pill by preserving the conditional
check for isFloating around _buildFloatingComposerBand so the gradient height
still tracks only the pill and doesn't stretch when the picker opens or closes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart`:
- Around line 430-467: The copyWith method uses the coalesce operator for
composerLocation parameter, which prevents null values from being passed through
and assigned. This makes it impossible to clear the composerLocation back to
null (which should fall back to the theme) once an explicit override exists.
Change the composerLocation assignment in the return statement of copyWith to
use a pattern that distinguishes between "parameter not provided" and "parameter
explicitly set to null", such as using a sentinel value or optional parameter
pattern. This will allow callers to explicitly set composerLocation to null when
desired.
- Around line 927-987: The DropTarget is currently wrapping only the pill
(StreamChatMessageInput), leaving the picker panel
(_buildInlineAttachmentPicker) outside the drop target as a sibling. This means
dragging files over the open picker won't trigger file attachment handling since
it's not within the drop target's scope. Restructure the code by moving the
DropTarget wrapper to encompass the entire Column that contains both the
SizeTransition (which wraps _buildInlineAttachmentPicker) and the pill. Keep the
gradient wrapping logic scoped to just the pill by preserving the conditional
check for isFloating around _buildFloatingComposerBand so the gradient height
still tracks only the pill and doesn't stretch when the picker opens or closes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eca2004c-04c1-4b08-830a-768f69b98373

📥 Commits

Reviewing files that changed from the base of the PR and between 74888d1 and a67a716.

📒 Files selected for processing (7)
  • packages/stream_chat_flutter/lib/src/channel/channel_header.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_page.dart
  • packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart
  • packages/stream_chat_flutter/lib/src/misc/back_button.dart
  • sample_app/lib/pages/new_group_chat_screen.dart
  • sample_app/lib/routes/app_routes.dart
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/stream_chat_flutter/lib/src/misc/back_button.dart
  • sample_app/lib/pages/new_group_chat_screen.dart
  • sample_app/lib/routes/app_routes.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_page.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_header.dart

renefloor and others added 4 commits June 16, 2026 16:06
…ery nit

- Fix StreamChannelPage disposing its StreamMessageComposerController in
  dispose(); aligns it with StreamThreadPage and prevents a resource leak.
  Align init style: late + super.initState() first, matching the thread page.
- Replace inline LinearGradient in _buildFloatingComposerBand with the shared
  streamFloatingFade() helper from stream_core_flutter; re-export the helper
  via stream_chat_flutter.dart.
- Drop redundant top: 0 from StreamPhotoGallery default padding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@renefloor renefloor marked this pull request as ready for review June 17, 2026 10:12
# Conflicts:
#	docs/docs_screenshots/pubspec.yaml
#	melos.yaml
#	packages/stream_chat_flutter/CHANGELOG.md
#	packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart
#	packages/stream_chat_flutter/lib/stream_chat_flutter.dart
#	packages/stream_chat_flutter/pubspec.yaml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/stream_chat_flutter/lib/src/channel/channel_header.dart (1)

151-164: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resolve avatar floating state from the same header theme source used by StreamAppBar.

Line 151 computes effectiveAppBarBehavior from ambient StreamAppBarTheme, but this widget later applies headerTheme via StreamAppBarTheme(data: headerTheme, ...). If channelHeaderTheme.style.behavior is set, avatar shadow state can mismatch the rendered app bar behavior.

Suggested fix
-    final effectiveAppBarBehavior =
-        style?.behavior ??
-        StreamAppBarTheme.of(context).style?.behavior ??
-        (StreamTheme.of(context).appStyle.isFloating ? .floating : .regular);
+    final effectiveAppBarBehavior =
+        style?.behavior ??
+        headerTheme.style?.behavior ??
+        StreamAppBarTheme.of(context).style?.behavior ??
+        (StreamTheme.of(context).appStyle.isFloating ? .floating : .regular);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart` around
lines 151 - 164, The effectiveAppBarBehavior computation uses the ambient
StreamAppBarTheme context, but the headerTheme applied later via
StreamAppBarTheme(data: headerTheme, ...) can override this. If
channelHeaderTheme.style.behavior is set, the showAvatarShadow state for
_DefaultChannelAvatar may mismatch the actual rendered app bar behavior. Modify
the logic that determines showAvatarShadow to resolve the floating state from
the same headerTheme source that will be applied to StreamAppBar, ensuring the
avatar shadow state always matches the app bar behavior that will actually be
rendered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart`:
- Line 213: The const constructor _DefaultChannelAvatar exceeds the
120-character line length limit. Refactor the constructor by wrapping the
parameters across multiple lines, placing each parameter (required this.channel,
this.onPressed, and this.isFloating) on separate lines or grouping them
logically to ensure no single line exceeds 120 characters while maintaining
proper indentation and formatting.

In `@packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart`:
- Line 137: The _DefaultUserAvatar constructor call on line 137 exceeds the 120
character line length limit. Break this constructor invocation across multiple
lines by placing each named parameter (client, onPressed, isFloating) on
separate lines with appropriate indentation. Apply the same line-breaking
approach to the similar constructor call on line 191 to ensure both lines comply
with the 120 character coding guideline.
- Around line 128-137: The effectiveAppBarBehavior derivation in the fallback
chain is missing the channelListHeaderTheme.style?.behavior reference. Update
the null coalescing chain starting at the effectiveAppBarBehavior assignment to
include channelListHeaderTheme.style?.behavior between style?.behavior and
StreamAppBarTheme.of(context).style?.behavior, ensuring the header theme's
behavior is considered before falling back to the context app style's floating
state. This will ensure the avatar floating visuals remain consistent with the
actual app bar behavior since the bar is rendered under StreamAppBarTheme(data:
headerTheme).

In `@packages/stream_chat_flutter/lib/stream_chat_flutter.dart`:
- Around line 4-18: The export statement for stream_core_flutter/chat.dart in
the lib/stream_chat_flutter.dart file currently uses a hide allowlist approach,
which exports everything by default and only hides specific items. This
conflicts with package guidelines that require using a show allowlist instead.
Replace the hide-based export with a show-based export that explicitly lists
only the types that should be exported from stream_core_flutter/chat.dart,
providing better control over the public API surface and ensuring consistency
with the coding guidelines for this file.

---

Outside diff comments:
In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart`:
- Around line 151-164: The effectiveAppBarBehavior computation uses the ambient
StreamAppBarTheme context, but the headerTheme applied later via
StreamAppBarTheme(data: headerTheme, ...) can override this. If
channelHeaderTheme.style.behavior is set, the showAvatarShadow state for
_DefaultChannelAvatar may mismatch the actual rendered app bar behavior. Modify
the logic that determines showAvatarShadow to resolve the floating state from
the same headerTheme source that will be applied to StreamAppBar, ensuring the
avatar shadow state always matches the app bar behavior that will actually be
rendered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d5ef7494-8a39-4941-899f-d8133a3f1e47

📥 Commits

Reviewing files that changed from the base of the PR and between 738d676 and 7bd0db2.

📒 Files selected for processing (23)
  • docs/docs_screenshots/pubspec.yaml
  • melos.yaml
  • packages/stream_chat_flutter/CHANGELOG.md
  • packages/stream_chat_flutter/lib/src/channel/channel_header.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_channel_avatar.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar_group.dart
  • packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart
  • packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart
  • packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart
  • packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart
  • packages/stream_chat_flutter/lib/src/misc/back_button.dart
  • packages/stream_chat_flutter/lib/src/scroll_view/channel_scroll_view/stream_channel_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/scroll_view/thread_scroll_view/stream_thread_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/theme/message_composer_theme.dart
  • packages/stream_chat_flutter/lib/src/theme/message_composer_theme.g.theme.dart
  • packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart
  • packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.g.theme.dart
  • packages/stream_chat_flutter/lib/src/theme/themes.dart
  • packages/stream_chat_flutter/lib/stream_chat_flutter.dart
  • packages/stream_chat_flutter/pubspec.yaml
  • sample_app/lib/app.dart
✅ Files skipped from review due to trivial changes (4)
  • packages/stream_chat_flutter/lib/src/scroll_view/thread_scroll_view/stream_thread_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/theme/themes.dart
  • packages/stream_chat_flutter/lib/src/theme/message_composer_theme.g.theme.dart
  • packages/stream_chat_flutter/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • sample_app/lib/app.dart
  • packages/stream_chat_flutter/pubspec.yaml
  • packages/stream_chat_flutter/lib/src/scroll_view/channel_scroll_view/stream_channel_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart
  • packages/stream_chat_flutter/lib/src/misc/back_button.dart
  • packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart
  • packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/stream_chat_flutter/lib/src/channel/channel_header.dart (1)

151-164: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resolve avatar floating state from the same header theme source used by StreamAppBar.

Line 151 computes effectiveAppBarBehavior from ambient StreamAppBarTheme, but this widget later applies headerTheme via StreamAppBarTheme(data: headerTheme, ...). If channelHeaderTheme.style.behavior is set, avatar shadow state can mismatch the rendered app bar behavior.

Suggested fix
-    final effectiveAppBarBehavior =
-        style?.behavior ??
-        StreamAppBarTheme.of(context).style?.behavior ??
-        (StreamTheme.of(context).appStyle.isFloating ? .floating : .regular);
+    final effectiveAppBarBehavior =
+        style?.behavior ??
+        headerTheme.style?.behavior ??
+        StreamAppBarTheme.of(context).style?.behavior ??
+        (StreamTheme.of(context).appStyle.isFloating ? .floating : .regular);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart` around
lines 151 - 164, The effectiveAppBarBehavior computation uses the ambient
StreamAppBarTheme context, but the headerTheme applied later via
StreamAppBarTheme(data: headerTheme, ...) can override this. If
channelHeaderTheme.style.behavior is set, the showAvatarShadow state for
_DefaultChannelAvatar may mismatch the actual rendered app bar behavior. Modify
the logic that determines showAvatarShadow to resolve the floating state from
the same headerTheme source that will be applied to StreamAppBar, ensuring the
avatar shadow state always matches the app bar behavior that will actually be
rendered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart`:
- Line 213: The const constructor _DefaultChannelAvatar exceeds the
120-character line length limit. Refactor the constructor by wrapping the
parameters across multiple lines, placing each parameter (required this.channel,
this.onPressed, and this.isFloating) on separate lines or grouping them
logically to ensure no single line exceeds 120 characters while maintaining
proper indentation and formatting.

In `@packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart`:
- Line 137: The _DefaultUserAvatar constructor call on line 137 exceeds the 120
character line length limit. Break this constructor invocation across multiple
lines by placing each named parameter (client, onPressed, isFloating) on
separate lines with appropriate indentation. Apply the same line-breaking
approach to the similar constructor call on line 191 to ensure both lines comply
with the 120 character coding guideline.
- Around line 128-137: The effectiveAppBarBehavior derivation in the fallback
chain is missing the channelListHeaderTheme.style?.behavior reference. Update
the null coalescing chain starting at the effectiveAppBarBehavior assignment to
include channelListHeaderTheme.style?.behavior between style?.behavior and
StreamAppBarTheme.of(context).style?.behavior, ensuring the header theme's
behavior is considered before falling back to the context app style's floating
state. This will ensure the avatar floating visuals remain consistent with the
actual app bar behavior since the bar is rendered under StreamAppBarTheme(data:
headerTheme).

In `@packages/stream_chat_flutter/lib/stream_chat_flutter.dart`:
- Around line 4-18: The export statement for stream_core_flutter/chat.dart in
the lib/stream_chat_flutter.dart file currently uses a hide allowlist approach,
which exports everything by default and only hides specific items. This
conflicts with package guidelines that require using a show allowlist instead.
Replace the hide-based export with a show-based export that explicitly lists
only the types that should be exported from stream_core_flutter/chat.dart,
providing better control over the public API surface and ensuring consistency
with the coding guidelines for this file.

---

Outside diff comments:
In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart`:
- Around line 151-164: The effectiveAppBarBehavior computation uses the ambient
StreamAppBarTheme context, but the headerTheme applied later via
StreamAppBarTheme(data: headerTheme, ...) can override this. If
channelHeaderTheme.style.behavior is set, the showAvatarShadow state for
_DefaultChannelAvatar may mismatch the actual rendered app bar behavior. Modify
the logic that determines showAvatarShadow to resolve the floating state from
the same headerTheme source that will be applied to StreamAppBar, ensuring the
avatar shadow state always matches the app bar behavior that will actually be
rendered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d5ef7494-8a39-4941-899f-d8133a3f1e47

📥 Commits

Reviewing files that changed from the base of the PR and between 738d676 and 7bd0db2.

📒 Files selected for processing (23)
  • docs/docs_screenshots/pubspec.yaml
  • melos.yaml
  • packages/stream_chat_flutter/CHANGELOG.md
  • packages/stream_chat_flutter/lib/src/channel/channel_header.dart
  • packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_channel_avatar.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar.dart
  • packages/stream_chat_flutter/lib/src/components/avatar/stream_user_avatar_group.dart
  • packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart
  • packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart
  • packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart
  • packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart
  • packages/stream_chat_flutter/lib/src/misc/back_button.dart
  • packages/stream_chat_flutter/lib/src/scroll_view/channel_scroll_view/stream_channel_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/scroll_view/thread_scroll_view/stream_thread_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/theme/message_composer_theme.dart
  • packages/stream_chat_flutter/lib/src/theme/message_composer_theme.g.theme.dart
  • packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart
  • packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.g.theme.dart
  • packages/stream_chat_flutter/lib/src/theme/themes.dart
  • packages/stream_chat_flutter/lib/stream_chat_flutter.dart
  • packages/stream_chat_flutter/pubspec.yaml
  • sample_app/lib/app.dart
✅ Files skipped from review due to trivial changes (4)
  • packages/stream_chat_flutter/lib/src/scroll_view/thread_scroll_view/stream_thread_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/theme/themes.dart
  • packages/stream_chat_flutter/lib/src/theme/message_composer_theme.g.theme.dart
  • packages/stream_chat_flutter/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • sample_app/lib/app.dart
  • packages/stream_chat_flutter/pubspec.yaml
  • packages/stream_chat_flutter/lib/src/scroll_view/channel_scroll_view/stream_channel_list_skeleton_loading.dart
  • packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart
  • packages/stream_chat_flutter/lib/src/misc/back_button.dart
  • packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart
  • packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart
🛑 Comments failed to post (4)
packages/stream_chat_flutter/lib/src/channel/channel_header.dart (1)

213-213: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Wrap the constructor parameters to satisfy the 120-char limit.

Line 213 exceeds the configured max line length.

As per coding guidelines, “**/*.{dart,dart.bak}: Line length must not exceed 120 characters”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/src/channel/channel_header.dart` at line
213, The const constructor _DefaultChannelAvatar exceeds the 120-character line
length limit. Refactor the constructor by wrapping the parameters across
multiple lines, placing each parameter (required this.channel, this.onPressed,
and this.isFloating) on separate lines or grouping them logically to ensure no
single line exceeds 120 characters while maintaining proper indentation and
formatting.

Source: Coding guidelines

packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart (2)

128-137: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include channelListHeaderTheme.style.behavior when deriving floating state.

Lines 128-131 derive effectiveAppBarBehavior without headerTheme.style?.behavior, but the actual bar is rendered under StreamAppBarTheme(data: headerTheme). This can produce inconsistent avatar floating visuals vs app-bar behavior.

Suggested fix
     final effectiveAppBarBehavior =
         style?.behavior ??
+        headerTheme.style?.behavior ??
         StreamAppBarTheme.of(context).style?.behavior ??
         (StreamTheme.of(context).appStyle.isFloating ? .floating : .regular);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    final effectiveAppBarBehavior =
        style?.behavior ??
        headerTheme.style?.behavior ??
        StreamAppBarTheme.of(context).style?.behavior ??
        (StreamTheme.of(context).appStyle.isFloating ? .floating : .regular);
    final hasAvatarShadow = switch (effectiveAppBarBehavior) {
      .floating => true,
      .regular => false,
    };

    final leading = _DefaultUserAvatar(client: _client, onPressed: onUserAvatarPressed, isFloating: hasAvatarShadow);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart` around
lines 128 - 137, The effectiveAppBarBehavior derivation in the fallback chain is
missing the channelListHeaderTheme.style?.behavior reference. Update the null
coalescing chain starting at the effectiveAppBarBehavior assignment to include
channelListHeaderTheme.style?.behavior between style?.behavior and
StreamAppBarTheme.of(context).style?.behavior, ensuring the header theme's
behavior is considered before falling back to the context app style's floating
state. This will ensure the avatar floating visuals remain consistent with the
actual app bar behavior since the bar is rendered under StreamAppBarTheme(data:
headerTheme).

137-137: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Break long constructor calls across lines to stay within 120 chars.

Lines 137 and 191 exceed the line-length limit.

As per coding guidelines, “**/*.{dart,dart.bak}: Line length must not exceed 120 characters”.

Also applies to: 191-191

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart` at
line 137, The _DefaultUserAvatar constructor call on line 137 exceeds the 120
character line length limit. Break this constructor invocation across multiple
lines by placing each named parameter (client, onPressed, isFloating) on
separate lines with appropriate indentation. Apply the same line-breaking
approach to the similar constructor call on line 191 to ensure both lines comply
with the 120 character coding guideline.

Source: Coding guidelines

packages/stream_chat_flutter/lib/stream_chat_flutter.dart (1)

4-18: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Use a show allowlist for stream_core_flutter exports instead of hide.

Line 4 switches to a broad export with selective hide, which expands public-surface risk over time and conflicts with the package rule for this file.

As per coding guidelines, “When adding new types from stream_core_flutter, add them to the show allowlist in lib/stream_chat_flutter.dart”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter/lib/stream_chat_flutter.dart` around lines 4 -
18, The export statement for stream_core_flutter/chat.dart in the
lib/stream_chat_flutter.dart file currently uses a hide allowlist approach,
which exports everything by default and only hides specific items. This
conflicts with package guidelines that require using a show allowlist instead.
Replace the hide-based export with a show-based export that explicitly lists
only the types that should be exported from stream_core_flutter/chat.dart,
providing better control over the public API surface and ensuring consistency
with the coding guidelines for this file.

Source: Coding guidelines

@renefloor renefloor force-pushed the feat/channel-page branch from 7bd0db2 to 38a0c59 Compare June 19, 2026 12:19
@renefloor renefloor force-pushed the feat/channel-page branch from 93dcbac to c8d7cf2 Compare June 19, 2026 13:11
@renefloor renefloor force-pushed the feat/channel-page branch from c8d7cf2 to 5730ff6 Compare June 19, 2026 13:12
@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 46.84015% with 143 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.21%. Comparing base (7941081) to head (017e9c4).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...eam_chat_flutter/lib/src/channel/channel_page.dart 0.00% 53 Missing ⚠️
...ream_chat_flutter/lib/src/channel/thread_page.dart 0.00% 45 Missing ⚠️
...lib/src/message_input/stream_message_composer.dart 60.22% 35 Missing ⚠️
..._flutter/lib/src/theme/message_composer_theme.dart 36.36% 7 Missing ⚠️
...r/lib/src/message_list_view/message_list_view.dart 95.12% 2 Missing ⚠️
...croll_view/photo_gallery/stream_photo_gallery.dart 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2748      +/-   ##
==========================================
- Coverage   69.48%   69.21%   -0.28%     
==========================================
  Files         426      429       +3     
  Lines       25665    25834     +169     
==========================================
+ Hits        17834    17880      +46     
- Misses       7831     7954     +123     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant