refactor(ui)!: update design for context menu and message action#2517
refactor(ui)!: update design for context menu and message action#2517xsahil03x merged 6 commits intofeat/design-refreshfrom
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR redesigns the message actions system: replaces StreamMessageAction/StreamMessageActionItem with StreamContextMenuAction and a builder-based MessageActionsBuilder; renames context menu builder types; routes action selection via dialog returns/onSelected; updates modals, message widget, context menus, exports, docs, tests, and sample app. Changes
Sequence DiagramsequenceDiagram
participant User
participant MessageWidget as Message Widget
participant ActionsBuilder as Actions Builder
participant ContextMenu as Context Menu Region
participant Dialog as Modal/Dialog
participant Handler as _onActionTap
User->>MessageWidget: trigger context menu (long press / click)
MessageWidget->>ActionsBuilder: actionsBuilder(context, defaultActions)
ActionsBuilder-->>MessageWidget: List<StreamContextMenuAction/Widget>
MessageWidget->>ContextMenu: show menu (menuBuilder / menuItems)
User->>ContextMenu: select action item
ContextMenu->>Dialog: open modal OR pop with action value
Dialog-->>ContextMenu: pop with MessageAction result
ContextMenu->>MessageWidget: onSelected(action)
MessageWidget->>Handler: _onActionTap(context, channel, action)
Handler-->Handler: execute action (edit, delete, reaction...)
Handler-->>User: action applied
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
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 (3)
packages/stream_chat_flutter/test/src/message_action/message_actions_builder_test.dart (1)
136-167:⚠️ Potential issue | 🟡 MinorTest named "includes/excludes…" never tests the exclusion side for
EditMessageon other-user messages.Both
ownActionsandotherUserActionsare built withallChannelCapabilities(which includesupdateAnyMessage) and both callexpects<EditMessage>. The test never verifies thatEditMessageis absent whenupdateAnyMessageis missing for another user's message, which is the most important authorship-based boundary.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/stream_chat_flutter/test/src/message_action/message_actions_builder_test.dart` around lines 136 - 167, The test wrongly asserts EditMessage exists for both own and other-user messages; update the second part to verify exclusion by creating a channel without the updateAnyMessage capability (e.g., use a variant like channelWithoutUpdateAny or remove updateAnyMessage from allChannelCapabilities) and call StreamMessageActionsBuilder.buildActions with that channel for the other-user message, then assert the EditMessage action is absent (use the appropriate negative assertion helper instead of expects<EditMessage>) to confirm authorship-based exclusion.packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart (1)
98-106:⚠️ Potential issue | 🟠 MajorRetry-delete action maps to resend instead of delete.
When
isDeletingFailedis true, this action usesResendMessage, which routes tochannel.retryMessageand re-sends the message rather than retrying deletion. It should invoke the delete flow instead.🔧 Proposed fix
- StreamContextMenuAction.destructive( - value: ResendMessage(message: message), + StreamContextMenuAction.destructive( + value: DeleteMessage(message: message), leading: Icon(icons.trashBin), label: Text( context.translations.toggleDeleteRetryDeleteMessageText( isDeleteFailed: true, ), ), ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart` around lines 98 - 106, The destructive context menu entry currently uses ResendMessage when message.state.isDeletingFailed, causing a resend instead of retrying deletion; change the action value passed to StreamContextMenuAction.destructive from ResendMessage(message: message) to the message-deletion retry action (e.g., DeleteMessage(message: message) or the existing retry-delete command used elsewhere) so the menu triggers the delete flow rather than channel.retryMessage/resend; update any import/usages accordingly to reference the correct Delete/RetryDelete action class.packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart (1)
769-801:⚠️ Potential issue | 🟡 Minor
showPinButton/showDeleteMessagedon’t filter Unpin/HardDelete actions.The filter only checks
PinMessageandDeleteMessage, soUnpinMessage(pinned state) andHardDeleteMessage(failed send/delete flows) still appear even when those flags are false.🔧 Proposed fix
- )..retainWhere( - (it) => switch (it.props.value) { - QuotedReply() => widget.showReplyMessage, - ThreadReply() => widget.showThreadReplyMessage, - MarkUnread() => widget.showMarkUnreadMessage, - ResendMessage() => widget.showResendMessage, - EditMessage() => widget.showEditMessage, - CopyMessage() => widget.showCopyMessage, - FlagMessage() => widget.showFlagButton, - PinMessage() => widget.showPinButton, - DeleteMessage() => widget.showDeleteMessage, - _ => true, // Retain all the remaining actions. - }, - ); + )..retainWhere( + (it) => switch (it.props.value) { + QuotedReply() => widget.showReplyMessage, + ThreadReply() => widget.showThreadReplyMessage, + MarkUnread() => widget.showMarkUnreadMessage, + ResendMessage() => widget.showResendMessage, + EditMessage() => widget.showEditMessage, + CopyMessage() => widget.showCopyMessage, + FlagMessage() => widget.showFlagButton, + PinMessage() || UnpinMessage() => widget.showPinButton, + DeleteMessage() || HardDeleteMessage() => widget.showDeleteMessage, + _ => true, // Retain all the remaining actions. + }, + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart` around lines 769 - 801, The message actions filtering in _buildMessageActions currently checks only PinMessage and DeleteMessage, so UnpinMessage and HardDeleteMessage still appear; update the retainWhere switch (inside StreamMessageActionsBuilder.buildActions()..retainWhere) to treat UnpinMessage the same as PinMessage (guard with widget.showPinButton) and HardDeleteMessage the same as DeleteMessage (guard with widget.showDeleteMessage), ensuring both UnpinMessage and HardDeleteMessage are covered alongside their counterparts.
🧹 Nitpick comments (1)
packages/stream_chat_flutter/test/src/message_action/message_actions_builder_test.dart (1)
68-68: Remove commented-out fallback registration.♻️ Proposed fix
setUpAll(() { registerFallbackValue(Message()); - // registerFallbackValue(const StreamMessageActionType('any')); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/stream_chat_flutter/test/src/message_action/message_actions_builder_test.dart` at line 68, Remove the commented-out fallback registration line so tests don't contain dead/commented code: delete the commented call to registerFallbackValue(const StreamMessageActionType('any')) from message_actions_builder_test.dart (the commented symbol is registerFallbackValue and StreamMessageActionType) leaving only active test setup code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/stream_chat_flutter/lib/src/context_menu/context_menu.dart`:
- Line 2: Replace the public barrel import in context_menu.dart with a direct
import from the core package to avoid the circular dependency: remove the import
of package:stream_chat_flutter/stream_chat_flutter.dart and instead import only
the symbol you need (StreamContextMenu) from the stream_core_flutter package
(the direct package that exposes StreamContextMenu); update any references in
this file to use the imported StreamContextMenu and ensure no other barrel
symbols are pulled in so message_widget.dart no longer causes a cyclic import
chain.
In `@packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart`:
- Line 159: Update the StreamReactionPicker parameter docs and CHANGELOG to call
out the behavioral change: in the StreamReactionPicker constructor/doc for the
backgroundColor parameter, replace the terse "Background color for the reaction
picker." with a clear note that when backgroundColor is null the picker now
defaults to StreamColors.transparent (fully transparent, equivalent to
Colors.transparent / Color(0x00000000)), which is a visual breaking change
compared to the previous themed barsBg; advise consumers using the widget
standalone to pass an explicit backgroundColor if they require an opaque or
themed background. Also update the CHANGELOG entry that added
reactionIconBuilder and backgroundColor to explicitly state the
breaking/default-change: that backgroundColor now defaults to fully transparent
(StreamColors.transparent) rather than the previous themed barsBg, and that
callers must supply an explicit backgroundColor to preserve prior visuals.
- Line 159: Update the StreamReactionPicker widget's doc comment to explicitly
state that the backgroundColor parameter defaults to fully transparent
(StreamColors.transparent) and that consumers who relied on the previous opaque
themed barsBg must pass an explicit backgroundColor to retain the old
appearance; locate the StreamReactionPicker class/constructor in
reaction_picker.dart and amend the top-of-widget/docblock text to mention the
new default for backgroundColor and the migration guidance (pass
backgroundColor: StreamTheme.of(context).colorTheme.barsBg to restore prior
look).
---
Outside diff comments:
In
`@packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart`:
- Around line 98-106: The destructive context menu entry currently uses
ResendMessage when message.state.isDeletingFailed, causing a resend instead of
retrying deletion; change the action value passed to
StreamContextMenuAction.destructive from ResendMessage(message: message) to the
message-deletion retry action (e.g., DeleteMessage(message: message) or the
existing retry-delete command used elsewhere) so the menu triggers the delete
flow rather than channel.retryMessage/resend; update any import/usages
accordingly to reference the correct Delete/RetryDelete action class.
In `@packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart`:
- Around line 769-801: The message actions filtering in _buildMessageActions
currently checks only PinMessage and DeleteMessage, so UnpinMessage and
HardDeleteMessage still appear; update the retainWhere switch (inside
StreamMessageActionsBuilder.buildActions()..retainWhere) to treat UnpinMessage
the same as PinMessage (guard with widget.showPinButton) and HardDeleteMessage
the same as DeleteMessage (guard with widget.showDeleteMessage), ensuring both
UnpinMessage and HardDeleteMessage are covered alongside their counterparts.
In
`@packages/stream_chat_flutter/test/src/message_action/message_actions_builder_test.dart`:
- Around line 136-167: The test wrongly asserts EditMessage exists for both own
and other-user messages; update the second part to verify exclusion by creating
a channel without the updateAnyMessage capability (e.g., use a variant like
channelWithoutUpdateAny or remove updateAnyMessage from allChannelCapabilities)
and call StreamMessageActionsBuilder.buildActions with that channel for the
other-user message, then assert the EditMessage action is absent (use the
appropriate negative assertion helper instead of expects<EditMessage>) to
confirm authorship-based exclusion.
---
Nitpick comments:
In
`@packages/stream_chat_flutter/test/src/message_action/message_actions_builder_test.dart`:
- Line 68: Remove the commented-out fallback registration line so tests don't
contain dead/commented code: delete the commented call to
registerFallbackValue(const StreamMessageActionType('any')) from
message_actions_builder_test.dart (the commented symbol is registerFallbackValue
and StreamMessageActionType) leaving only active test setup code.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (21)
migrations/redesign/README.mdpackages/stream_chat_flutter/lib/src/context_menu/context_menu.dartpackages/stream_chat_flutter/lib/src/context_menu/context_menu_region.dartpackages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dartpackages/stream_chat_flutter/lib/src/message_action/message_action.dartpackages/stream_chat_flutter/lib/src/message_action/message_action_item.dartpackages/stream_chat_flutter/lib/src/message_action/message_action_type.dartpackages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dartpackages/stream_chat_flutter/lib/src/message_modal/message_actions_modal.dartpackages/stream_chat_flutter/lib/src/message_modal/message_reactions_modal.dartpackages/stream_chat_flutter/lib/src/message_modal/moderated_message_actions_modal.dartpackages/stream_chat_flutter/lib/src/message_widget/message_widget.dartpackages/stream_chat_flutter/lib/src/misc/stream_modal.dartpackages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dartpackages/stream_chat_flutter/lib/stream_chat_flutter.dartpackages/stream_chat_flutter/test/src/message_action/message_action_item_test.dartpackages/stream_chat_flutter/test/src/message_action/message_actions_builder_test.dartpackages/stream_chat_flutter/test/src/message_modal/message_actions_modal_test.dartpackages/stream_chat_flutter/test/src/message_modal/message_reactions_modal_test.dartpackages/stream_chat_flutter/test/src/message_modal/moderated_message_actions_modal_test.dartsample_app/lib/pages/channel_page.dart
💤 Files with no reviewable changes (3)
- packages/stream_chat_flutter/lib/src/message_action/message_action_type.dart
- packages/stream_chat_flutter/lib/src/message_action/message_action_item.dart
- packages/stream_chat_flutter/test/src/message_action/message_action_item_test.dart
| @@ -1,16 +1,16 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:stream_chat_flutter/stream_chat_flutter.dart'; | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate the context_menu.dart file
find . -name "context_menu.dart" -type f | head -20Repository: GetStream/stream-chat-flutter
Length of output: 142
🏁 Script executed:
# Find the main barrel file
find . -path "*stream_chat_flutter/lib/stream_chat_flutter.dart" -type fRepository: GetStream/stream-chat-flutter
Length of output: 132
🏁 Script executed:
# Search for imports of context_menu across the codebase
rg -n "import.*context_menu" --type=dartRepository: GetStream/stream-chat-flutter
Length of output: 700
🏁 Script executed:
cat -n packages/stream_chat_flutter/lib/src/context_menu/context_menu.dart | head -50Repository: GetStream/stream-chat-flutter
Length of output: 2228
🏁 Script executed:
cat -n packages/stream_chat_flutter/lib/stream_chat_flutter.dart | head -100Repository: GetStream/stream-chat-flutter
Length of output: 6071
🏁 Script executed:
cat -n packages/stream_chat_flutter/lib/src/context_menu/context_menu.dart | tail -50Repository: GetStream/stream-chat-flutter
Length of output: 2040
🏁 Script executed:
rg -n "StreamContextMenu" packages/stream_chat_flutter/lib/src/context_menu/context_menu.dartRepository: GetStream/stream-chat-flutter
Length of output: 185
Replace the public barrel import with a direct stream_core_flutter import to avoid a circular dependency.
context_menu.dart needs only StreamContextMenu from stream_core_flutter but imports the package's public barrel. Since message_widget.dart (exported by the barrel) imports context_menu.dart, this creates a circular dependency: context_menu.dart → stream_chat_flutter.dart → message_widget.dart → context_menu.dart. While Dart tolerates this, it can slow compilation and surface in static-analysis tools.
♻️ Proposed fix
-import 'package:stream_chat_flutter/stream_chat_flutter.dart';
+import 'package:stream_core_flutter/stream_core_flutter.dart' show StreamContextMenu;📝 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.
| import 'package:stream_chat_flutter/stream_chat_flutter.dart'; | |
| import 'package:stream_core_flutter/stream_core_flutter.dart' show StreamContextMenu; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/stream_chat_flutter/lib/src/context_menu/context_menu.dart` at line
2, Replace the public barrel import in context_menu.dart with a direct import
from the core package to avoid the circular dependency: remove the import of
package:stream_chat_flutter/stream_chat_flutter.dart and instead import only the
symbol you need (StreamContextMenu) from the stream_core_flutter package (the
direct package that exposes StreamContextMenu); update any references in this
file to use the imported StreamContextMenu and ensure no other barrel symbols
are pulled in so message_widget.dart no longer causes a cyclic import chain.
| borderRadius: borderRadius, | ||
| clipBehavior: Clip.antiAlias, | ||
| color: backgroundColor ?? theme.colorTheme.barsBg, | ||
| color: backgroundColor ?? StreamColors.transparent, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate the relevant files
fd -t f "stream_colors.dart" --type f 2>/dev/null | head -10Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Also look for the reaction_picker file
fd -t f "reaction_picker.dart" --type f 2>/dev/nullRepository: GetStream/stream-chat-flutter
Length of output: 147
🏁 Script executed:
# Search for StreamColors.transparent definition
rg -n "transparent" --type dart -B 2 -A 2 | grep -A 5 -B 5 "StreamColors" | head -50Repository: GetStream/stream-chat-flutter
Length of output: 1206
🏁 Script executed:
# Check imports and context in reaction_picker.dart
cat packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart | head -30Repository: GetStream/stream-chat-flutter
Length of output: 1306
🏁 Script executed:
# Search for where StreamColors is defined/imported
rg -n "class StreamColors\|StreamColors\.transparent" --type dart -B 2 -A 2Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Find all references to barsBg to understand the previous default
rg -n "barsBg" --type dart | head -20Repository: GetStream/stream-chat-flutter
Length of output: 2872
🏁 Script executed:
# Search more broadly for StreamColors
rg -n "StreamColors\." --type dart | head -30Repository: GetStream/stream-chat-flutter
Length of output: 209
🏁 Script executed:
# Get broader context around line 159 in reaction_picker.dart
sed -n '130,180p' packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dartRepository: GetStream/stream-chat-flutter
Length of output: 1372
🏁 Script executed:
# Check what's in stream_core_flutter imports
rg -n "from 'package:stream_core_flutter'" --type dart -A 5 | head -40Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Search for StreamColors definition anywhere in dart files
rg -n "^\s*(class|const|final|static).*StreamColors" --type dartRepository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Check if stream_core_flutter is in this repository
fd -t d "stream_core_flutter" 2>/dev/nullRepository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Search for CHANGELOG files and look for reaction picker changes
fd -t f "CHANGELOG*" | head -10Repository: GetStream/stream-chat-flutter
Length of output: 289
🏁 Script executed:
# Look for the previous version to understand what changed
rg -n "barsBg" packages/stream_chat_flutter/lib/src/reactions/picker/ --type dartRepository: GetStream/stream-chat-flutter
Length of output: 203
🏁 Script executed:
# Search CHANGELOG for reaction picker changes
rg -n "reaction.picker|backgroundColor|transparent" packages/stream_chat_flutter/CHANGELOG.md -i -B 2 -A 2 | head -50Repository: GetStream/stream-chat-flutter
Length of output: 3087
🏁 Script executed:
# Look at the StreamReactionPicker class doc comment
sed -n '25,100p' packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dartRepository: GetStream/stream-chat-flutter
Length of output: 2752
🏁 Script executed:
# Check the widget constructor to see if backgroundColor is documented
sed -n '100,145p' packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dartRepository: GetStream/stream-chat-flutter
Length of output: 1532
Improve documentation for the backgroundColor default change in StreamReactionPicker.
The background color default change from themed barsBg to StreamColors.transparent is confirmed and represents a visual breaking change. However, the documentation is insufficient:
-
The
backgroundColorparameter doc comment (currently "Background color for the reaction picker.") should explain that whennull, it defaults to a transparent background, which may require explicit passing ofbackgroundColorfor consumers using this widget standalone. -
The CHANGELOG entry (line 86) only notes "Added
reactionIconBuilderandbackgroundColorparameters" but doesn't communicate the breaking nature or visual impact of the default behavior change.
Update both the parameter documentation and the CHANGELOG entry to clearly state that the default background is now transparent (vs. previously themed), ensuring consumers understand they must supply backgroundColor explicitly if they need an opaque background.
Additionally, StreamColors.transparent should be documented as fully transparent to confirm it matches Colors.transparent / Color(0x00000000) and not a partially-transparent tint.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart`
at line 159, Update the StreamReactionPicker parameter docs and CHANGELOG to
call out the behavioral change: in the StreamReactionPicker constructor/doc for
the backgroundColor parameter, replace the terse "Background color for the
reaction picker." with a clear note that when backgroundColor is null the picker
now defaults to StreamColors.transparent (fully transparent, equivalent to
Colors.transparent / Color(0x00000000)), which is a visual breaking change
compared to the previous themed barsBg; advise consumers using the widget
standalone to pass an explicit backgroundColor if they require an opaque or
themed background. Also update the CHANGELOG entry that added
reactionIconBuilder and backgroundColor to explicitly state the
breaking/default-change: that backgroundColor now defaults to fully transparent
(StreamColors.transparent) rather than the previous themed barsBg, and that
callers must supply an explicit backgroundColor to preserve prior visuals.
🧩 Analysis chain
🏁 Script executed:
# First, let me find the StreamColors definition
find . -name "*.dart" -type f | xargs grep -l "StreamColors" | grep -E "(stream_core|colors)" | head -5Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Check the reaction_picker.dart file around line 159
find . -name "reaction_picker.dart" -type fRepository: GetStream/stream-chat-flutter
Length of output: 149
🏁 Script executed:
# Search for StreamColors class definition
rg "class StreamColors|const.*transparent" -A 5 -B 2 --type dartRepository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Read the reaction_picker.dart file to see the context around line 159
cat -n ./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart | sed -n '150,170p'Repository: GetStream/stream-chat-flutter
Length of output: 878
🏁 Script executed:
# Search for StreamColors definition in all dart files
rg "class StreamColors" --type dart -A 20Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Look for barsBg usage to understand the previous default
rg "barsBg" --type dartRepository: GetStream/stream-chat-flutter
Length of output: 13793
🏁 Script executed:
# Search for StreamColors definition more broadly
rg "StreamColors" --type dart -B 2 -A 10 | head -100Repository: GetStream/stream-chat-flutter
Length of output: 1468
🏁 Script executed:
# Look for where StreamColors is imported from
rg "import.*StreamColors|from.*StreamColors" --type dartRepository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Check CHANGELOG files for this change
find . -name "CHANGELOG*" -type fRepository: GetStream/stream-chat-flutter
Length of output: 299
🏁 Script executed:
# Search for StreamColors class or const definition
rg "StreamColors\s*=" --type dartRepository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Look for all files with StreamColors in them to find where it's defined
fd ".*\.dart" -x rg -l "StreamColors" {} \;Repository: GetStream/stream-chat-flutter
Length of output: 149
🏁 Script executed:
# Check the imports at the top of reaction_picker.dart
head -50 ./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dartRepository: GetStream/stream-chat-flutter
Length of output: 2036
🏁 Script executed:
# Search CHANGELOG for reaction picker changes
grep -i "reaction\|picker" ./packages/stream_chat_flutter/CHANGELOG.md | head -30Repository: GetStream/stream-chat-flutter
Length of output: 3119
🏁 Script executed:
# Look for stream_core_flutter in the project
find . -type d -name "stream_core_flutter"Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Check if stream_core_flutter is in pubspec or as a package
find . -name "pubspec.yaml" | xargs grep -l "stream_core_flutter"Repository: GetStream/stream-chat-flutter
Length of output: 116
🏁 Script executed:
# Search for StreamColors in stream_core_flutter if it's part of this repo
find . -path "*/stream_core*" -name "*.dart" | xargs grep -l "StreamColors" 2>/dev/nullRepository: GetStream/stream-chat-flutter
Length of output: 57
🏁 Script executed:
# Let's check the exact CHANGELOG entry for reaction picker and backgroundColor
grep -B 5 -A 5 "backgroundColor.*StreamReactionPicker\|StreamReactionPicker.*backgroundColor" ./packages/stream_chat_flutter/CHANGELOG.mdRepository: GetStream/stream-chat-flutter
Length of output: 384
🏁 Script executed:
# Check stream_chat_flutter pubspec.yaml to see if stream_core_flutter is a local package or external
cat ./packages/stream_chat_flutter/pubspec.yaml | grep -A 5 "stream_core_flutter"Repository: GetStream/stream-chat-flutter
Length of output: 581
🏁 Script executed:
# Check if there's a git history of this file to see what the previous default was
git log --oneline -20 -- ./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart 2>/dev/null | head -10Repository: GetStream/stream-chat-flutter
Length of output: 147
🏁 Script executed:
# Look at the full CHANGELOG section around the breaking change
grep -B 20 "🛑️ Breaking" ./packages/stream_chat_flutter/CHANGELOG.md | tail -40Repository: GetStream/stream-chat-flutter
Length of output: 1669
🏁 Script executed:
# Get the git diff for the reaction picker file to see what changed
git show 74026ef3:./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart | grep -A 5 -B 5 "color:" | tail -20Repository: GetStream/stream-chat-flutter
Length of output: 408
🏁 Script executed:
# Check the current version of the file in git to see if there's an older version
git log --all --format="%H %s" -- ./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart | head -10Repository: GetStream/stream-chat-flutter
Length of output: 345
🏁 Script executed:
# Look for references to StreamColors.transparent in stream_core_flutter (external dependency)
# First, let's check if there's documentation or source files visible
find . -type f -name "*.md" | xargs grep -l "StreamColors" 2>/dev/nullRepository: GetStream/stream-chat-flutter
Length of output: 57
🏁 Script executed:
# Try to find the definition of StreamColors in any dart files
rg "static.*transparent|const.*transparent.*Color" --type dart | head -20Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Show the git history more completely for the reaction_picker file
git log --all --format="%H %s" --follow -- ./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dartRepository: GetStream/stream-chat-flutter
Length of output: 345
🏁 Script executed:
# Get the previous version of the file before the merge
git show 74026ef3^:./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart 2>/dev/null | grep -A 10 -B 10 "color:" | tail -30Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Check the breaking changes section in CHANGELOG to see if backgroundColor change is mentioned
grep -A 100 "🛑️ Breaking" ./packages/stream_chat_flutter/CHANGELOG.md | grep -B 5 -A 5 "backgroundColor\|StreamReactionPicker" | head -30Repository: GetStream/stream-chat-flutter
Length of output: 1478
🏁 Script executed:
# Look for the issue or PR that introduced this change
git log --all --grep="reaction.*picker\|backgroundColor" --oneline -- ./packages/stream_chat_flutter/lib/src/reactions/picker/ | head -10Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Look at the previous commit before the merge to see what changed
git show e03a1c05a:./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart 2>/dev/null | grep -A 10 -B 10 "color:" | tail -30Repository: GetStream/stream-chat-flutter
Length of output: 730
🏁 Script executed:
# Check if there's a reaction_picker.dart in an older state
git log --all --format="%H" -- ./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart | while read commit; do echo "=== Commit $commit ==="; git show $commit:./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart 2>/dev/null | grep -A 3 "color:" | grep -v "^--$" | head -5; done | head -50Repository: GetStream/stream-chat-flutter
Length of output: 561
🏁 Script executed:
# Check the feat/design-refresh branch mentioned in the merge
git log --all --oneline --grep="design-refresh\|context-menu-refresh" | head -20Repository: GetStream/stream-chat-flutter
Length of output: 232
🏁 Script executed:
# Look for what the previous default was - check if barsBg was used
git log -p --all -- ./packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart 2>/dev/null | grep -B 5 -A 5 "barsBg\|backgroundColor.*??" | head -50Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Perfect! Now let's verify what StreamColors.transparent actually is
# Check if stream_core_flutter source is available in this repo
find . -path "*stream_core_flutter*" -name "*.dart" -type f | head -20Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Let's check if there's a pubspec lock or similar that might show stream_core_flutter
cat ./packages/stream_chat_flutter/pubspec.lock 2>/dev/null | grep -A 10 "stream_core_flutter" | head -20Repository: GetStream/stream-chat-flutter
Length of output: 55
🏁 Script executed:
# Search for any color definitions in the codebase that might hint at StreamColors
rg "StreamColors" -B 5 -A 15 --type dart | head -100Repository: GetStream/stream-chat-flutter
Length of output: 1960
🌐 Web query:
stream_core_flutter StreamColors.transparent Flutter color definition
💡 Result:
In Flutter, the fully transparent color is defined as:
const Color transparent = Color(0x00000000);You can use it via Colors.transparent (from package:flutter/material.dart). [1]
Color(0xAARRGGBB) uses the top byte (AA) as the alpha channel, so 00 means fully transparent. [2]
Sources: [1] [2]
Breaking default: reaction picker background is now transparent.
The backgroundColor default changed from the themed opaque barsBg color to StreamColors.transparent (fully transparent, equivalent to Color(0x00000000)). This is a significant visual change—consumers who did not explicitly pass backgroundColor will render with no background.
While this PR is marked as a breaking change in the CHANGELOG, the specific nature of this default shift (from opaque barsBg to transparent) is not explicitly documented. Update the StreamReactionPicker widget's doc comment to clarify that backgroundColor defaults to transparent, and callers must pass an explicit color to match the previous appearance.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/stream_chat_flutter/lib/src/reactions/picker/reaction_picker.dart`
at line 159, Update the StreamReactionPicker widget's doc comment to explicitly
state that the backgroundColor parameter defaults to fully transparent
(StreamColors.transparent) and that consumers who relied on the previous opaque
themed barsBg must pass an explicit backgroundColor to retain the old
appearance; locate the StreamReactionPicker class/constructor in
reaction_picker.dart and amend the top-of-widget/docblock text to mention the
new default for backgroundColor and the migration guidance (pass
backgroundColor: StreamTheme.of(context).colorTheme.barsBg to restore prior
look).
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@migrations/redesign/message_actions.md`:
- Around line 29-32: Add a brief parenthetical note to the Quick Reference
explaining why StreamMessageActionsModal.messageActions is now List<Widget>
while ModeratedMessageActionsModal.messageActions is
List<StreamContextMenuAction>; update the migration table row or an adjacent
explanatory sentence to say something like: "(accepts arbitrary widgets to allow
custom action UI, unlike the moderated variant which requires
StreamContextMenuAction for built-in moderation behavior)" so readers understand
the intentional type asymmetry and when to use each API. Ensure the note
references StreamMessageActionsModal.messageActions and
ModeratedMessageActionsModal.messageActions by name.
- Around line 196-214: Add a brief introduction or callout for
showStreamDialog<T> under "New Components" (or the first place it appears)
explaining that showStreamDialog is a thin wrapper around Flutter's showDialog
that applies the Stream theme, and note its import
(package:stream_chat_flutter/stream_chat_flutter.dart); mention this once where
StreamMessageActionsModal, StreamMessageReactionsModal, and
ModeratedMessageActionsModal are first shown so readers know what
showStreamDialog is and how it differs from showDialog.
- Around line 448-457: The List declaration for actions is missing the generic
type parameter for StreamContextMenuAction; update the variable declaration and
the type used by StreamMessageActionsBuilder.buildActions to explicitly use the
MessageAction generic (e.g., make actions a
List<StreamContextMenuAction<MessageAction>> and ensure any
StreamContextMenuAction references include <MessageAction>) so the example
matches the rest of the guide and clarifies the expected action type.
- Around line 99-112: The table documents that StreamMessageAction.title:
Widget? became StreamContextMenuAction.label: Widget (now required) but the
Breaking Change section and Migration Checklist don't mention this API polarity
change; update the migration doc to explicitly call out that label is now a
required parameter (so code that relied on a null/omitted title will fail to
compile), add a clear note under the "Breaking Change" heading referencing
StreamMessageAction → StreamContextMenuAction and the required label parameter,
and add an item in the Migration Checklist instructing developers to add a
non-null label wherever they previously omitted title.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
migrations/redesign/message_actions.md
| | `StreamMessageActionsModal.messageActions` | **Type changed**: `List<StreamMessageAction>` → `List<Widget>` | | ||
| | `StreamMessageReactionsModal.onReactionPicked` | **Removed** — await the dialog return value (`SelectReaction`) | | ||
| | `ModeratedMessageActionsModal.onActionTap` | **Removed** — use `onTap` per-action or await the dialog return value | | ||
| | `ModeratedMessageActionsModal.messageActions` | **Type changed**: `List<StreamMessageAction>` → `List<StreamContextMenuAction>` | |
There was a problem hiding this comment.
Add a note explaining the intentional type asymmetry between the two modals.
StreamMessageActionsModal.messageActions becomes List<Widget> while ModeratedMessageActionsModal.messageActions becomes List<StreamContextMenuAction> — the Quick Reference table surfaces this inconsistency without any rationale. A brief parenthetical (e.g. "accepts arbitrary widgets, unlike the moderated variant") would prevent confusion.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@migrations/redesign/message_actions.md` around lines 29 - 32, Add a brief
parenthetical note to the Quick Reference explaining why
StreamMessageActionsModal.messageActions is now List<Widget> while
ModeratedMessageActionsModal.messageActions is List<StreamContextMenuAction>;
update the migration table row or an adjacent explanatory sentence to say
something like: "(accepts arbitrary widgets to allow custom action UI, unlike
the moderated variant which requires StreamContextMenuAction for built-in
moderation behavior)" so readers understand the intentional type asymmetry and
when to use each API. Ensure the note references
StreamMessageActionsModal.messageActions and
ModeratedMessageActionsModal.messageActions by name.
| | `StreamMessageAction` | `StreamContextMenuAction` | | ||
| |-----------------------|--------------------------| | ||
| | `action: T` | `value: T?` | | ||
| | `title: Widget?` | `label: Widget` (required) | | ||
| | `leading: Widget?` | `leading: Widget?` | | ||
| | `isDestructive: bool` | `isDestructive: bool` (or use `.destructive` constructor) | | ||
| | `iconColor: Color?` | Controlled via `StreamContextMenuActionTheme` | | ||
| | `titleTextColor: Color?` | Controlled via `StreamContextMenuActionTheme` | | ||
| | `titleTextStyle: TextStyle?` | Controlled via `StreamContextMenuActionTheme` | | ||
| | `backgroundColor: Color?` | Controlled via `StreamContextMenuActionTheme` | | ||
| | — | `onTap: VoidCallback?` (new) | | ||
| | — | `trailing: Widget?` (new) | | ||
| | — | `enabled: bool` (new) | | ||
|
|
There was a problem hiding this comment.
Explicitly call out that label is now a required parameter.
The table shows title: Widget? (optional) → label: Widget (required), but neither the "Breaking Change" sub-heading on line 53 nor the Migration Checklist (line 537) mentions this polarity change. Any code that created StreamMessageAction without title will fail to compile with the new API. Add a note here and in the checklist, e.g.:
> **Important:**
+> - `label` is now **required** (previously `title` was optional) — every action must supply a label
> - `onTap` signature changed from `void Function(MessageAction)` to `VoidCallback?` ...And in the checklist:
- - [ ] Replace all `StreamMessageAction(action: ..., title: ..., leading: ...)` with `StreamContextMenuAction(value: ..., label: ..., leading: ...)`
+ - [ ] Replace all `StreamMessageAction(action: ..., title: ..., leading: ...)` with `StreamContextMenuAction(value: ..., label: ..., leading: ...)` — note `label` is now **required**🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@migrations/redesign/message_actions.md` around lines 99 - 112, The table
documents that StreamMessageAction.title: Widget? became
StreamContextMenuAction.label: Widget (now required) but the Breaking Change
section and Migration Checklist don't mention this API polarity change; update
the migration doc to explicitly call out that label is now a required parameter
(so code that relied on a null/omitted title will fail to compile), add a clear
note under the "Breaking Change" heading referencing StreamMessageAction →
StreamContextMenuAction and the required label parameter, and add an item in the
Migration Checklist instructing developers to add a non-null label wherever they
previously omitted title.
| **After (await return value):** | ||
| ```dart | ||
| final action = await showStreamDialog<MessageAction>( | ||
| context: context, | ||
| builder: (_) => StreamMessageActionsModal( | ||
| message: message, | ||
| messageWidget: messageWidget, | ||
| messageActions: [ | ||
| StreamContextMenuAction<MessageAction>( | ||
| value: CopyMessage(message: message), | ||
| leading: Icon(context.streamIcons.copy), | ||
| label: Text(context.translations.copyMessageLabel), | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
|
|
||
| if (action is CopyMessage) _copyMessage(action.message); | ||
| ``` |
There was a problem hiding this comment.
showStreamDialog is used in three examples but never introduced.
It appears in the "await return value" patterns for StreamMessageActionsModal (line 198), StreamMessageReactionsModal (line 243), and ModeratedMessageActionsModal (line 319), but there is no mention of this helper in New Components or anywhere else in the guide. Readers need to know the package it comes from and how it differs from showDialog. Add at minimum a brief entry under New Components or a callout note the first time it appears, e.g.:
showStreamDialog<T>is a thin wrapper aroundshowDialogfromstream_chat_flutterthat pre-applies the Stream theme; import it frompackage:stream_chat_flutter/stream_chat_flutter.dart.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@migrations/redesign/message_actions.md` around lines 196 - 214, Add a brief
introduction or callout for showStreamDialog<T> under "New Components" (or the
first place it appears) explaining that showStreamDialog is a thin wrapper
around Flutter's showDialog that applies the Stream theme, and note its import
(package:stream_chat_flutter/stream_chat_flutter.dart); mention this once where
StreamMessageActionsModal, StreamMessageReactionsModal, and
ModeratedMessageActionsModal are first shown so readers know what
showStreamDialog is and how it differs from showDialog.
| ```dart | ||
| // buildActions no longer accepts customActions — add extras via actionsBuilder | ||
| final List<StreamContextMenuAction> actions = | ||
| StreamMessageActionsBuilder.buildActions( | ||
| context: context, | ||
| message: message, | ||
| channel: channel, | ||
| currentUser: currentUser, | ||
| ); | ||
| ``` |
There was a problem hiding this comment.
Specify the type argument on List<StreamContextMenuAction> for clarity.
The "After" snippet leaves StreamContextMenuAction without its type parameter, which is inconsistent with the rest of the guide and may mislead readers about the expected generic type. Since buildActions returns actions for message handling, the type should be <MessageAction>:
📝 Proposed fix
-final List<StreamContextMenuAction> actions =
+final List<StreamContextMenuAction<MessageAction>> actions =
StreamMessageActionsBuilder.buildActions(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@migrations/redesign/message_actions.md` around lines 448 - 457, The List
declaration for actions is missing the generic type parameter for
StreamContextMenuAction; update the variable declaration and the type used by
StreamMessageActionsBuilder.buildActions to explicitly use the MessageAction
generic (e.g., make actions a List<StreamContextMenuAction<MessageAction>> and
ensure any StreamContextMenuAction references include <MessageAction>) so the
example matches the rest of the guide and clarifies the expected action type.
Summary by CodeRabbit
New Features
Breaking Changes
Improvements