Skip to content

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

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

feat(ui): channel page and floating UI#2748
renefloor wants to merge 95 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#146

Screenshots / Videos

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

Summary by CodeRabbit

  • New Features

    • Added ready-to-use channel and thread pages with reply, edit, navigation, and composer support.
    • Added floating or docked composer layouts with customizable themes.
    • Added global and per-view message-list configuration, padding controls, and reaction callbacks.
    • Added improved floating app-bar and avatar presentation.
    • Added optional location sharing in the sample app.
  • Bug Fixes

    • Thread replies are hidden when replies are disabled.
    • Long deleted-message labels now wrap correctly.
    • Thread scroll-to-bottom controls reflect effective configuration.
    • Photo galleries respect bottom safe-area spacing.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

This PR adds reusable channel and thread pages, configurable message-list and composer layouts, floating app-bar avatar styling, and migrates the sample app to StreamScaffold-based navigation and inset-aware screens.

Changes

Library UI and public APIs

Layer / File(s) Summary
Message list defaults and reusable chat pages
packages/stream_chat_flutter/lib/src/stream_chat_configuration.dart, packages/stream_chat_flutter/lib/src/message_list_view/*, packages/stream_chat_flutter/lib/src/channel/*, packages/stream_chat_flutter/lib/stream_chat_flutter.dart
Adds global message-list configuration fallback, top/bottom padding, and reusable channel/thread pages with composer, typing indicator, and thread wiring.
Composer location theme and layout
packages/stream_chat_flutter/lib/src/theme/*, packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart
Adds floating/docked composer theming and placement-specific rendering.
Floating app-bar and avatar styling
packages/stream_chat_flutter/lib/src/channel/*header.dart, packages/stream_chat_flutter/lib/src/misc/back_button.dart, packages/stream_chat_flutter/lib/src/components/avatar/*
Resolves app-bar behavior and propagates floating state to avatar shadows and button styling.
Behavior, loading, and dependency updates
packages/stream_chat_flutter/lib/src/message_action/*, packages/stream_chat_flutter/lib/src/scroll_view/*, packages/stream_chat_flutter/pubspec.yaml, melos.yaml, docs/docs_screenshots/*
Gates thread replies, adjusts loading and padding behavior, updates reply-enabled mocks, and repins stream_core_flutter.

Sample app scaffold migration

Layer / File(s) Summary
App style persistence and theme wiring
sample_app/lib/config/sample_app_config.dart, sample_app/lib/app.dart
Adds persisted regular/floating app style selection and derives themes and message-list defaults from configuration.
Navigation shell and chat entry points
sample_app/lib/pages/channel_list_page.dart, sample_app/lib/widgets/channel_list.dart, sample_app/lib/pages/{draft_list_page,thread_list_page}.dart, sample_app/lib/routes/app_routes.dart
Replaces bottom-navigation primitives and routes channel and thread destinations through the new library pages.
Screen scaffold and inset migration
sample_app/lib/config/sample_app_config_screen.dart, sample_app/lib/pages/*
Replaces screen scaffolds with StreamScaffold and applies scaffold insets to scrollable content and lists.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related PRs

Suggested reviewers: xsahil03x

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: adding channel pages and introducing floating UI across the application.
✨ 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.

@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
Comment thread packages/stream_chat_flutter/lib/src/channel/channel_header.dart Outdated
Comment thread packages/stream_chat_flutter/lib/src/channel/channel_list_header.dart Outdated
Comment thread packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart Outdated
Comment thread packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart Outdated
Comment thread packages/stream_chat_flutter/lib/src/message_input/stream_message_composer.dart Outdated
Comment on lines +849 to +869
if (_isThreadConversation)
ValueListenableBuilder<bool>(
valueListenable: _showScrollToBottom,
child: _buildScrollToBottom(),
builder: (context, value, child) {
if (!snapshot || value) return child!;
if (value) return child!;
return const Empty();
},
)
else
BetterStreamBuilder<bool>(
stream: streamChannel!.channel.state!.isUpToDateStream,
initialData: streamChannel!.channel.state!.isUpToDate,
builder: (context, snapshot) => ValueListenableBuilder<bool>(
valueListenable: _showScrollToBottom,
child: _buildScrollToBottom(),
builder: (context, value, child) {
if (!snapshot || value) return child!;
return const Empty();
},
),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is the value of isUpToDate not correct in case of thread conversations?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

streamChannel.channel.state.isUpToDate tracks the channel's message window (false when you've jumped to an older message and the latest page isn't loaded). A thread's reply list is a separate list with no equivalent flag. So opening a thread after jumping to an old channel message left isUpToDate == false, and the thread's scroll-to-bottom button never appeared even though the thread list was perfectly scrollable. In thread mode the button is gated on _showScrollToBottom alone.

The branch is arguably ugly — an alternative is a single BetterStreamBuilder whose gate is _isThreadConversation || isUpToDate, which collapses the if/else into one widget tree.

Comment thread packages/stream_chat_flutter/lib/src/misc/back_button.dart Outdated
Comment thread packages/stream_chat_flutter/lib/src/misc/thread_header.dart Outdated
Comment thread sample_app/lib/config/sample_app_config.dart Outdated
xsahil03x and others added 17 commits August 6, 2026 18:33
…ter merge)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolutions:
- scrollable_positioned_list/positioned_list.dart: kept the new content*
  edges (contentLeadingEdge/contentTrailingEdge) on top of master's
  anchor-aware getOffsetToReveal (itemOffset = reveal - offset.pixels).
- sample_app pages: dropped the local channel_page/thread_page overrides;
  routing now uses the SDK's StreamChannelPage / StreamThreadPage.
- sample_app ios project.pbxproj: took master's.
- stream_core_flutter dependency (melos.yaml + both pubspec.yaml): kept the
  local path override so the branch builds against the unpublished core
  work on feat/stream-scaffold (PR #146).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- StreamThreadHeader.onBackPressed: note it's also ignored when
  automaticallyImplyLeading is false (not only when leading is set).
- StreamChatConfigurationData.messageListViewConfiguration: fix the dangling
  [config] doc reference to [StreamMessageListView.config].
- MessageComposerInput / StreamChatMessageInput isFloating: document the
  false default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to 277c60e — the previous commit only captured thread_header.dart
because of a bad pathspec.

- StreamChatConfigurationData.messageListViewConfiguration: dangling [config]
  -> [StreamMessageListView.config].
- MessageComposerInput / StreamChatMessageInput isFloating: document the
  false default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Drop the redundant "since no default back button is built" clause (the two
  conditions already imply it) — prefer brevity.
- Link [Navigator.maybePop] instead of backtick-quoting it, so dart doc
  resolves the reference.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The content* edges are always populated by PositionedList (equal to the item*
edges when there's no inset), never null-when-unpadded as the doc claimed —
the null case is only for externally-built ItemPositions that omit them. Fix
the doc to say so and add SPL coverage for the previously-untested fields:

- under a leading inset, content* is content-relative (item 0 flush with the
  content top reads 0) while item* stays viewport-relative (0.25);
- with no inset, content* equals item*.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dependency had been switched to a local absolute path for cross-repo
iteration, which breaks pub get on CI. Restore the git dependency
(core PR #146, ref 8425a0f8) in pubspec.yaml, melos.yaml, and
docs_screenshots. Local dev keeps using the path override in the
gitignored pubspec_overrides.yaml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Added in a WIP checkpoint, these semantics tests assert a merged-summary
behavior with no corresponding implementation on this branch, so they
fail (getSemantics finds no matching node). The a11y work can land in
its own PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace StreamAppStyle / StreamMessageComposerBehavior with the unified
StreamSurfaceStyle across the composer, headers, theme, and sample app,
and drive the composer's collapsing safe area with StreamSafeArea.driven.
Align dartdoc with the style guide (private members use //, US spelling,
contract-not-implementation, documented null fallbacks) and remove dead
code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Commit d07bcf5 intentionally reverted the channel replies-config gating
so ThreadReply is governed solely by the send-reply capability, but this
test was left asserting the old behavior and failed CI. Update it to
assert the shipped behavior: the config flag alone does not hide the
action when the capability is granted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The channel replies-config gating this covered was intentionally reverted
(d07bcf5) and is not on master, so remove the test rather than keep it
asserting a behavior the branch no longer implements. Thread reply
remains covered by the send-reply capability cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Enable `SystemUiMode.edgeToEdge` in `main()` to allow content to flow under system bars.
- Add `_EdgeToEdgeSystemBars` wrapper widget using `AnnotatedRegion` to configure `SystemUiOverlayStyle`.
- Set `statusBarColor` and `systemNavigationBarColor` to transparent.
- Disable `systemNavigationBarContrastEnforced` to allow full edge-to-edge content bleeding.
- Ensure system bar icon brightness automatically updates based on the current `ThemeMode`.
- Implement `WidgetsBindingObserver` in `DefaultStreamMessageComposerState` to trigger rebuilds on metric changes (keyboard opening/closing).
- Update the `StreamSafeArea` bottom padding to dynamically switch between `spacing.safeAreaBottom()` when the keyboard is hidden and `spacing.md` when it is visible.
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.

2 participants