-
Notifications
You must be signed in to change notification settings - Fork 371
feat(repo)!: v10.0.0 #2280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(repo)!: v10.0.0 #2280
Conversation
Co-authored-by: xsahil03x <[email protected]>
Co-authored-by: xsahil03x <[email protected]>
Co-authored-by: xsahil03x <[email protected]>
# Conflicts: # packages/stream_chat_flutter/CHANGELOG.md
WalkthroughAdds live location sharing and persistence, scoped message deletion (delete-for-me), Reaction API refactor to use Reaction objects, an EventController with resolvers, CDN upload/remove endpoints, many model/serialization updates, UI refactors (polls, voice-recording removals), tests, and migration docs. Changes
Sequence Diagram(s)sequenceDiagram
participant UI
participant Channel
participant API
participant EventController
participant Client
participant Persistence
Note over UI,Channel: Start live location sharing
UI->>Channel: startLiveLocationSharing(coords, endAt)
Channel->>API: POST /messages (shared_location payload)
API-->>EventController: WS message_new event
EventController->>EventController: locationSharedResolver -> transforms to location.shared
EventController-->>Client: emit location.shared
Client->>Channel: merge location into activeLiveLocations
Client->>Persistence: updateLocations([...])
sequenceDiagram
participant UI
participant Channel
participant API
participant Client
participant Persistence
Note over UI,API: Delete message for me
UI->>Channel: deleteMessage(messageId, scope: deleteForMe)
Channel->>API: DELETE /messages/{id}?delete_for_me=true
API-->>Client: user.messages.deleted event
Client->>Persistence: deleteMessagesFromUser(userId, cid?, deleteForMe)
Client->>Channel: mark message.deletedForMe and update state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Areas to pay extra attention:
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
⛔ Files ignored due to path filters (68)
📒 Files selected for processing (7)
🚧 Files skipped from review as they are similar to previous changes (5)
🧰 Additional context used🧠 Learnings (4)📓 Common learnings📚 Learning: 2025-09-25T08:19:01.469ZApplied to files:
📚 Learning: 2025-09-25T08:19:01.469ZApplied to files:
📚 Learning: 2025-08-08T14:27:59.621ZApplied to files:
🔇 Additional comments (5)
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 |
Co-authored-by: xsahil03x <[email protected]>
# Conflicts: # packages/stream_chat_flutter/CHANGELOG.md
# Conflicts: # packages/stream_chat_flutter/CHANGELOG.md # packages/stream_chat_flutter_core/CHANGELOG.md
# Conflicts: # melos.yaml # packages/stream_chat/CHANGELOG.md # packages/stream_chat/example/pubspec.yaml # packages/stream_chat/lib/version.dart # packages/stream_chat/pubspec.yaml # packages/stream_chat_flutter/example/pubspec.yaml # packages/stream_chat_flutter/pubspec.yaml # packages/stream_chat_flutter_core/example/pubspec.yaml # packages/stream_chat_flutter_core/pubspec.yaml # packages/stream_chat_localizations/CHANGELOG.md # packages/stream_chat_localizations/example/pubspec.yaml # packages/stream_chat_localizations/pubspec.yaml # packages/stream_chat_persistence/CHANGELOG.md # packages/stream_chat_persistence/example/pubspec.yaml # packages/stream_chat_persistence/pubspec.yaml # sample_app/pubspec.yaml
# Conflicts: # packages/stream_chat/CHANGELOG.md # packages/stream_chat_flutter_core/CHANGELOG.md
# Conflicts: # melos.yaml # packages/stream_chat/CHANGELOG.md # packages/stream_chat/example/pubspec.yaml # packages/stream_chat/lib/version.dart # packages/stream_chat/pubspec.yaml # packages/stream_chat_flutter/CHANGELOG.md # packages/stream_chat_flutter/example/pubspec.yaml # packages/stream_chat_flutter/pubspec.yaml # packages/stream_chat_flutter_core/example/pubspec.yaml # packages/stream_chat_flutter_core/pubspec.yaml # packages/stream_chat_localizations/CHANGELOG.md # packages/stream_chat_localizations/example/pubspec.yaml # packages/stream_chat_localizations/pubspec.yaml # packages/stream_chat_persistence/CHANGELOG.md # packages/stream_chat_persistence/example/pubspec.yaml # packages/stream_chat_persistence/pubspec.yaml # sample_app/pubspec.yaml
Co-authored-by: xsahil03x <[email protected]>
# Conflicts: # packages/stream_chat/CHANGELOG.md # packages/stream_chat_flutter_core/CHANGELOG.md
# Conflicts: # packages/stream_chat_flutter/CHANGELOG.md # packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart # packages/stream_chat_persistence/CHANGELOG.md
The animation curves and durations for the reaction picker and message modal have been updated for a smoother user experience. - The `reaction_picker_icon_list.dart` animation curve is now `Curves.easeOutBack` and the duration is 335 milliseconds. - The `message_modal.dart` transition duration is now 335 milliseconds, and the scale animation curve is `Curves.easeOutBack`.
# Conflicts: # melos.yaml # packages/stream_chat/CHANGELOG.md # packages/stream_chat/example/pubspec.yaml # packages/stream_chat/lib/src/client/channel.dart # packages/stream_chat/lib/src/core/models/channel_config.dart # packages/stream_chat/lib/src/core/models/channel_config.g.dart # packages/stream_chat/lib/src/core/models/message.dart # packages/stream_chat/lib/src/core/models/message.g.dart # packages/stream_chat/lib/version.dart # packages/stream_chat/pubspec.yaml # packages/stream_chat_flutter/CHANGELOG.md # packages/stream_chat_flutter/example/pubspec.yaml # packages/stream_chat_flutter/pubspec.yaml # packages/stream_chat_flutter_core/CHANGELOG.md # packages/stream_chat_flutter_core/example/pubspec.yaml # packages/stream_chat_flutter_core/pubspec.yaml # packages/stream_chat_localizations/CHANGELOG.md # packages/stream_chat_localizations/example/pubspec.yaml # packages/stream_chat_localizations/pubspec.yaml # packages/stream_chat_persistence/CHANGELOG.md # packages/stream_chat_persistence/example/pubspec.yaml # packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart # packages/stream_chat_persistence/pubspec.yaml # sample_app/pubspec.yaml
# Conflicts: # melos.yaml # packages/stream_chat/CHANGELOG.md # packages/stream_chat/example/pubspec.yaml # packages/stream_chat/lib/version.dart # packages/stream_chat/pubspec.yaml # packages/stream_chat_flutter/CHANGELOG.md # packages/stream_chat_flutter/example/pubspec.yaml # packages/stream_chat_flutter/pubspec.yaml # packages/stream_chat_flutter_core/CHANGELOG.md # packages/stream_chat_flutter_core/example/pubspec.yaml # packages/stream_chat_flutter_core/pubspec.yaml # packages/stream_chat_localizations/CHANGELOG.md # packages/stream_chat_localizations/example/pubspec.yaml # packages/stream_chat_localizations/pubspec.yaml # packages/stream_chat_persistence/CHANGELOG.md # packages/stream_chat_persistence/example/pubspec.yaml # packages/stream_chat_persistence/pubspec.yaml # sample_app/pubspec.yaml
# Conflicts: # melos.yaml # packages/stream_chat/CHANGELOG.md # packages/stream_chat/example/pubspec.yaml # packages/stream_chat/lib/src/client/channel.dart # packages/stream_chat/lib/src/client/client.dart # packages/stream_chat/lib/src/core/models/channel_config.dart # packages/stream_chat/lib/src/core/models/channel_config.g.dart # packages/stream_chat/lib/src/event_type.dart # packages/stream_chat/lib/stream_chat.dart # packages/stream_chat/lib/version.dart # packages/stream_chat/pubspec.yaml # packages/stream_chat/test/src/client/channel_test.dart # packages/stream_chat_flutter/CHANGELOG.md # packages/stream_chat_flutter/example/pubspec.yaml # packages/stream_chat_flutter/lib/src/channel/stream_message_preview_text.dart # packages/stream_chat_flutter/lib/src/stream_chat_configuration.dart # packages/stream_chat_flutter/pubspec.yaml # packages/stream_chat_flutter/test/src/indicators/goldens/ci/sending_indicator_1.png # packages/stream_chat_flutter/test/src/indicators/goldens/ci/sending_indicator_2.png # packages/stream_chat_flutter/test/src/theme/message_theme_test.dart # packages/stream_chat_flutter_core/CHANGELOG.md # packages/stream_chat_flutter_core/example/pubspec.yaml # packages/stream_chat_flutter_core/pubspec.yaml # packages/stream_chat_localizations/CHANGELOG.md # packages/stream_chat_localizations/example/pubspec.yaml # packages/stream_chat_localizations/pubspec.yaml # packages/stream_chat_persistence/CHANGELOG.md # packages/stream_chat_persistence/example/pubspec.yaml # packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart # packages/stream_chat_persistence/pubspec.yaml # sample_app/lib/pages/channel_page.dart # sample_app/pubspec.yaml
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2280 +/- ##
==========================================
+ Coverage 64.62% 66.50% +1.88%
==========================================
Files 420 428 +8
Lines 26210 26566 +356
==========================================
+ Hits 16938 17668 +730
+ Misses 9272 8898 -374 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
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/lib/src/core/api/sort_order.dart (1)
37-65: Update class-level documentation example to use new constructor APIMigration from the unnamed constructor and
SortOption.fromJsonis complete across the codebase. All test and library code consistently uses the newSortOption.desc()andSortOption.asc()constructors, and the generated.g.dartfile correctly omitsfromJsondue tocreateFactory: false.However, the class-level documentation (before line 37) still references the old unnamed constructor syntax
SortOption<ChannelState>("last_message_at"). Update this example to use the new API: eitherSortOption.desc(...)orSortOption.asc(...)for consistency with the constructor-level docs and to avoid misleading developers.packages/stream_chat_flutter/lib/src/icons/stream_svg_icon.dart (1)
100-110: Add null check before passing icon to SvgIcon widget.The
SvgIconwidget from thesvg_icon_widgetpackage does not accept null parameters. However, the code at line 103 passesicon(a nullable parameter) directly without checking, and the documentation claims the widget should render empty space when icon is null. This will cause a runtime crash if icon is null.Fix: Wrap the SvgIcon call in a null check:
@override Widget build(BuildContext context) { return icon != null ? SvgIcon( icon, size: size, color: color, textDirection: textDirection, applyTextScaling: applyTextScaling, semanticLabel: semanticLabel, ) : SizedBox(width: size, height: size); }packages/stream_chat/lib/src/core/models/message_state.dart (1)
755-825:FailedStatePatternMatching.whenOrNull/maybeWhenmakepartialUpdatingFailedmandatoryIn
FailedStatePatternMatching:
whenOrNullandmaybeWhendeclarepartialUpdatingFailedas arequiredparameter and call it directly (not via?.call), while the other callbacks are optional and null-checked.This means callers cannot use
whenOrNull/maybeWhento intentionally ignore thepartialUpdatingFailedcase the way they can for the other variants, which is inconsistent with the rest of the pattern-matching API and may cause surprising compile-time breakage for existing uses that only care about a subset of failure kinds.Consider making
partialUpdatingFailedoptional here as well:TResult? whenOrNull<TResult extends Object?>({ TResult? Function(bool skipPush, bool skipEnrichUrl)? sendingFailed, TResult? Function(bool skipPush, bool skipEnrichUrl)? updatingFailed, TResult? Function( Map<String, Object?>? set, List<String>? unset, bool skipEnrichUrl, )? partialUpdatingFailed, TResult? Function(MessageDeleteScope scope)? deletingFailed, }) { final failedState = this; return switch (failedState) { SendingFailed() => sendingFailed?.call(failedState.skipPush, failedState.skipEnrichUrl), UpdatingFailed() => updatingFailed?.call(failedState.skipPush, failedState.skipEnrichUrl), PartialUpdatingFailed() => partialUpdatingFailed?.call( failedState.set, failedState.unset, failedState.skipEnrichUrl, ), DeletingFailed() => deletingFailed?.call(failedState.scope), }; }and similarly for
maybeWhen.
🧹 Nitpick comments (25)
packages/stream_chat_flutter/lib/src/message_action/message_action.dart (1)
48-55: Aligntitledocs with itsWidget?type.Docs talk specifically about using
TextandText.maxLines, buttitleis a genericWidget?; consider either tightening the type toText?or slightly rephrasing the doc to note thatTextis the typical usage while still allowing arbitrary widgets.packages/stream_chat_flutter/lib/platform_widget_builder/src/platform_widget_builder.dart (1)
43-47: Well-documented fallback field.The field declaration and documentation clearly explain the fallback behavior. Consider adding a usage example to illustrate when
desktopOrWebis beneficial:/// Example: /// ```dart /// PlatformWidgetBuilder( /// mobile: (context, child) => MobileView(child: child), /// desktopOrWeb: (context, child) => DesktopWebView(child: child), /// ) /// ```packages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dart (1)
392-436: Download menu item implementation is sound; consider decoupling frommaybePopThe new
_DownloadMenuItemcorrectly builds aStreamMessageActionItemusingCustomMessageActionandStreamAttachmentHandler.instance.downloadAttachment, with safe type checks onactionandattachment. Implementation looks solid.One small improvement you might consider later: calling
downloadAttachmenteven whenmaybePopreturnsfalse, so the download isn’t tightly coupled to the ability to pop the current route (e.g., if the menu is not on its own navigator). This can be done by awaitingmaybePoponly to close the menu, but always triggering the download afterward.packages/stream_chat/lib/src/core/api/sort_order.dart (1)
32-36: Update docs/examples to match new constructors and null ordering defaultsThere are a few documentation inconsistencies after introducing
SortOption.desc/SortOption.asc:
- Lines 32–36 and 98–100 still show the old unnamed constructor, which no longer exists.
- Lines 81–82 say the default is always
NullOrdering.nullsFirst, butSortOption.ascnow defaults toNullOrdering.nullsLastwhileSortOption.desckeepsNullOrdering.nullsFirst.Consider updating the comments, for example:
/// Example: /// ```dart -/// // Sort channels by last message date in descending order -/// final sort = SortOption<ChannelState>("last_message_at"); +/// // Sort channels by last message date in descending order +/// final sort = SortOption.desc<ChannelState>("last_message_at"); /// ``` @@ - /// Defaults to `NullOrdering.nullsFirst`, which treats null values as less - /// than any non-null value. + /// Default depends on the constructor: + /// - `SortOption.desc`: `NullOrdering.nullsFirst` + /// - `SortOption.asc`: `NullOrdering.nullsLast` + /// In both cases, nulls are treated consistently regardless of sort direction. @@ - /// ```dart - /// final sortOption = SortOption<ChannelState>("last_message_at"); - /// final sortedChannels = channels.sort(sortOption.compare); - /// ``` + /// ```dart + /// final sortOption = SortOption.desc<ChannelState>("last_message_at"); + /// final sortedChannels = channels..sort(sortOption.compare); + /// ```This will prevent confusion for users upgrading to v10 who rely on the inline examples and docs.
Also applies to: 79-85, 98-100
packages/stream_chat/lib/src/core/models/location_coordinates.dart (1)
3-7: Fix documentation template tag mismatch.The template tag uses
locationInfobut should match the class nameLocationCoordinatesfor consistency with Dart documentation conventions.Apply this diff:
-/// {@template locationInfo} +/// {@template locationCoordinates} /// A model class representing a location with latitude and longitude. /// {@endtemplate} class LocationCoordinates extends Equatable { - /// {@macro locationInfo} + /// {@macro locationCoordinates} const LocationCoordinates({packages/stream_chat/CHANGELOG.md (1)
1-7: Consider versioning the "Upcoming Beta" section.The "Upcoming Beta" header suggests an unreleased fix for
Location.endAtUTC conversion. Consider assigning this a proper version number (e.g.,10.0.0-beta.9) to maintain clear version history.packages/stream_chat/lib/src/db/chat_persistence_client.dart (1)
90-95: Consider explicit lifecycle handling for persistedLocationrows.The new location APIs and the
updateChannelStatesintegration (collectingmessage.sharedLocation/pinnedMessage.sharedLocationinto alocationslist and callingupdateLocations(locations)) make sense, but the deletion story is less explicit:
- There’s no call to
deleteLocationsByCid/deleteLocationsByMessageIdsinupdateChannelStates, unlike the explicit cleanup used for drafts and poll votes.- If a message’s
sharedLocationcan transition from non-null to null (e.g., location share ended and the field is cleared), you may end up with staleLocationrows unlessupdateLocationsor FK cascades handle this internally.If the intended behavior is “locations are immutable and only expire via flags, not by removing
sharedLocation,” this is fine; otherwise, it may be worth either:
- Documenting that
updateLocationsis expected to fully reconcile state (e.g., by deleting missing entries for the affected cids/messageIds), or- Adding calls to
deleteLocationsByCid/deleteLocationsByMessageIdsanalogous to drafts/pollVotes beforeupdateLocations.Also applies to: 176-192, 201-206, 267-268, 345-347, 397-401, 441-447
packages/stream_chat/test/src/core/util/event_controller_test.dart (2)
9-20: Avoid leaking theEventControllercreated insetUpwhen reassigningYou create a fresh
EventControllerinsetUp, but several tests later reassigncontroller = EventController<Event>(...)without closing the original instance first.tearDownonly closes the last assigned controller, so the initial one fromsetUpis effectively leaked in those tests.In practice this is unlikely to break anything, but for cleanliness you could either:
- Instantiate the controller only in tests that need custom configuration (and skip the
setUpdefault there), or- Explicitly
await controller.close()before reassigning in those tests.
35-64: Clarify resolver semantics in test descriptionGiven
EventControllershort‑circuits on the first resolver that returns a non‑null event (as verified by the next test), this test:test('should apply resolvers in order', () async { ... });asserts that only the first resolver’s transformation (
message.new→poll.created) is applied, even though a second resolver exists.To better reflect the behavior under test, consider renaming the description to something like “applies the first matching resolver” or adjusting the scenario if you want to truly test ordered fall‑through behavior.
packages/stream_chat/test/src/core/models/message_test.dart (1)
290-307: Good constructor coverage forreactionGroups(minor duplication only)The new test verifying that
Messageuses thereactionGroupsprovided directly in the constructor is helpful and checks bothcountandsumScoresfor multiple keys.If you want to DRY it up slightly, you could reuse the
reactionGroupLike/reactionGroupLoveinstances defined above instead of constructing newReactionGroups inline, but that’s purely cosmetic.migrations/v10-migration.md (1)
1-916: Migration guide content is clear; only minor markdown‑lint nitsThe guide is thorough and aligns with the code changes (Reaction object, delete‑for‑me, attachment picker refactors, etc.). The only issues I see are markdown‑lint/style nits (e.g., bold “Example:” / “Important:” lines being treated as headings, and a couple of minor grammar suggestions from LanguageTool). If you care about a clean markdownlint run, you could:
- Turn repeated
**Example: ...**blocks into lower‑level headings (e.g.,#### Example: ...) or disable MD036 for this file.- Optionally tweak a few phrases where the linter suggested hyphenation or alternative wording.
None of this blocks merging; it’s purely cosmetic.
packages/stream_chat/lib/src/core/models/location.dart (1)
71-85: Doc comments still reference “reminder” instead of locationThe docs for
createdByDeviceId,createdAt, andupdatedAttalk about “the reminder” rather than “the shared location”, which looks like copy‑paste from another model. Updating those to refer to “location” will avoid confusion in the public API docs.packages/stream_chat/lib/src/core/api/message_api.dart (1)
216-233: UpdatesendReactiondocs to match the newReaction‑based signatureThe implementation now correctly accepts a
Reactionobject and forwardsreaction.toJson()along withskip_push/enforce_unique, matching the v10 migration guide. The method docs still reference a[reactionType]parameter, though, which is misleading.Recommend updating the comment block to describe:
- The
reactionparameter (fullReactionobject, including optionalemojiCode,score,extraData, etc.).- That
skipPushandenforceUniqueremain as separate flags.Behavior is fine; this is just an API documentation cleanup.
packages/stream_chat/lib/src/core/models/member.dart (1)
29-31: Member.deletedMessages wiring looks consistent with the new delete-for-me semantics
- Field is correctly defaulted, added to
_topLevelFields, threaded throughcopyWith, and included inprops, so (de)serialization and equality should behave as expected.- Minor optional nit: the docstring “for himself” (Line 103) could be made gender-neutral (“for themselves”) for consistency with typical docs style, but it’s not functionally significant.
Also applies to: 57-59, 103-107, 129-149, 172-173
packages/stream_chat/lib/src/core/models/message.dart (2)
83-104: Deleted-for-me and shared-location modelling and state derivation look coherent
deletedForMeis correctly plumbed through constructor, field,topLevelFields,copyWith,merge, andprops, andfromJsonprioritizesdeletedForMeoverdeletedAtwhen deriving bothtypeandstate. That matches the intended semantics of a per-user delete overriding global soft-delete handling.sharedLocation’s addition (including import, field,@JsonKey(includeIfNull: false),topLevelFields,copyWith,merge, andprops) lines up with the new location-sharing feature and the event resolvers that depend onmessage.sharedLocation.- Note that
copyWith(sharedLocation: null)andcopyWith(deletedForMe: null)will keep the existing values (standard pattern in this class). If you ever need to actively clear these fields withcopyWith, you’d need a sentinel approach similar toquotedMessage/draft—but this can stay as-is if all clearing flows come from fresh server payloads.Also applies to: 55-56, 331-341, 391-393, 452-454, 532-534, 580-582, 648-650
134-168: Reaction group backfill from legacy counts/scores is reasonable; consider stricter guards
_reactionGroupsReadValuecorrectly prefers an existingreaction_groupsmap, and otherwise reconstructs groups fromreaction_counts/reaction_scores, which should smooth migration without breaking consumers ofreactionGroups.- You currently skip any type where either
countorsumScoresis0. If the backend ever sendsreaction_countswithoutreaction_scores, that would drop valid reactions. If that’s a realistic scenario, consider treating a missingreaction_scores[type]ascount(or at least not skipping whencount > 0andsumScores == 0).- Using
DateTime.timestamp()for bothfirst_reaction_atandlast_reaction_atis fine as a placeholder; if these timestamps ever become user-visible, you might want a comment clarifying that they’re synthesized.Also applies to: 167-168, 845-945
packages/stream_chat/test/src/db/chat_persistence_client_test.dart (1)
9-10: Persistence test stub updates are consistent; consider avoiding UnimplementedError for new API
- The new overrides (
deleteMessagesFromUser, location getters/updaters/deleters, andmessageLimitongetChannelStates) correctly satisfy the updatedChatPersistenceClientinterface and keep existing tests compiling.- Optional: for
deleteMessagesFromUser, you currentlythrow UnimplementedError(), whereas most other “no-op” persistence operations here returnFuture.value(). If this stub ever gets reused beyond this test, aligning it to a no-op implementation would avoid surprising runtime errors.Also applies to: 52-58, 90-95, 193-207
packages/stream_chat/lib/src/core/models/message_delete_scope.dart (1)
1-61: MessageDeleteScope union is cleanly designed and matches the new deletion semantics
- The
deleteForMe/deleteForAll(hard)variants, predefinedsoftDeleteForAll/hardDeleteForAll, andfromJsonfactory give a clear, extensible representation for delete scope.MessageDeleteScopeX.hardcorrectly returnsfalseforDeleteForMeand delegates to thehardflag forDeleteForAll, which will simplify call sites.- Tiny doc nit only if you touch the file again: “Creates a instance” (Line 30) → “Creates an instance”.
packages/stream_chat/test/src/core/api/message_api_test.dart (1)
204-220: Tests correctly exercise delete-for-me and Reaction-based APIs
deleteMessagetest now assertsqueryParameters: {'delete_for_me': true}and callsdeleteMessage(messageId, deleteForMe: true), which matches the new scoped deletion semantics.sendReactiontests now build and pass aReactioninstance and expect the request body to bejsonEncode({'reaction': reaction.toJson(), 'skip_push': false, 'enforce_unique': …}), and validate that the response embedsmessage_idinside the reaction. This aligns with the new Reaction-centric API surface.getReactionstest expects each returned reaction JSON to includemessage_id, and verifies all parsed reactions havemessageId == messageId, which should catch any regressions in the deserialization shape.The stubbing via
jsonEncodemeans the implementation must also encode the payload to a JSON string; that’s fine, just be aware that switching back to a raw map inMessageApiwould require updating these expectations.Also applies to: 255-321, 340-365
packages/stream_chat/lib/src/client/client.dart (2)
948-1008: Minor doc/parameter name mismatch in upload helpersThe docs for
uploadImage/uploadFilereference[onProgress], but the actual parameter is namedonUploadProgressand is forwarded toonSendProgress. It’s purely a documentation mismatch, but updating the references to[onUploadProgress]would avoid confusion for callers.- /// Upload progress can be tracked using [onProgress], and the operation can + /// Upload progress can be tracked using [onUploadProgress], and the operation can @@ - /// Upload progress can be tracked using [onProgress], and the operation can + /// Upload progress can be tracked using [onUploadProgress], and the operation can
1767-1780: Consider asserting consistency betweenmessageIdandreaction.messageId
sendReactionnow takes both amessageIdarg and aReactioninstance; only themessageIdis used for the request path, so calls remain correct even ifreaction.messageIdis null or mismatched. To catch accidental inconsistencies early, you could add a debug assertion that, when set,reaction.messageIdmatchesmessageId.Future<SendReactionResponse> sendReaction( String messageId, Reaction reaction, { bool skipPush = false, bool enforceUnique = false, }) => - _chatApi.message.sendReaction( - messageId, - reaction, - skipPush: skipPush, - enforceUnique: enforceUnique, - ); + _chatApi.message.sendReaction( + (() { + assert( + reaction.messageId == null || reaction.messageId == messageId, + 'reaction.messageId must match messageId', + ); + return messageId; + })(), + reaction, + skipPush: skipPush, + enforceUnique: enforceUnique, + );Also applies to: 3381-3409
packages/stream_chat/lib/src/client/channel.dart (4)
1186-1250: Location sending helpers: consider clarifying device/user requirementsThe
sendStaticLocation/startLiveLocationSharinghelpers build aMessagewith an embeddedLocationusingchannelCid,currentUserId, andcreatedByDeviceId, then delegate tosendMessage. Structurally that’s fine, but it would help to document (or assert) expectations that:
client.state.currentUseris non-null when these are called, andcreatedByDeviceIdshould be non-null when you expect multiple devices per user to share locations concurrently.If those are intentionally optional, no change required; just worth double‑checking the backend expectations.
3213-3232: Message removal now consistently updates all views
updateMessage,cleanUpStaleErrorMessages,removeMessage, anddeleteMessagedelegating into_updateMessages/_removeMessagesis a good consolidation. It guarantees that any addition/removal/change of a message is reflected across:
- channel messages,
- threads,
- pinned messages,
- active live locations,
and persistence, rather than having ad-hoc per-caller logic.
3688-3750: Expired live location cleaner is sensible; verify client-side expiry policy
_startCleaningExpiredLocationsperiodically scansactiveLiveLocations, skips locations from the current user (handled elsewhere), and synthesizeslocationExpiredevents for other users’ expired shares. That’s a neat way to self-heal when explicit expiry events are missed.One thing to confirm is that this “client-side expiry” behavior is aligned with server semantics (e.g., tolerance around clock skew and end time) so we don’t expire locations locally significantly earlier than the backend does.
3770-4147: Unified message merge/remove helpers cover main invariants; slight complexity tradeoffThe new helpers:
_deleteMessagesFromUser+_deleteMessages_updateMessagesand its four subpaths (threads, channel, pinned, active locations)_mergeMessagesIntoExisting/_mergePinnedMessagesIntoExisting/_mergeActiveLocationsIntoExisting_removeMessagesFromExistingand the corresponding remove helpersgive a single source of truth for how messages are added/updated/removed across channel messages, threads, pins, live locations, and persistence, while correctly updating quoted-message references and
lastMessageAt. This significantly improves consistency and maintainability despite increasing the abstraction layer count.Given the complexity here, it’s worth making sure there are dedicated tests around:
- deleting messages that are only in threads vs shown in-channel,
- deleting pinned messages and quoted messages,
- deleting messages that own live locations (ensuring active locations are dropped),
userMessagesDeletedevents for both hard and soft deletes.If those tests already exist or are being added elsewhere in this PR, this structure looks good.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (102)
packages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_idle_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_idle_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playing_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playing_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playlist_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playlist_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/avatars/goldens/ci/gradient_avatar_issue_2369.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/bottom_sheets/goldens/ci/edit_message_sheet_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/bottom_sheets/goldens/ci/error_alert_sheet_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/channel/goldens/ci/channel_header_bottom_widget.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/context_menu_items/goldens/ci/download_menu_item_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/context_menu_items/goldens/ci/stream_chat_context_menu_item_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/dialogs/goldens/ci/confirmation_dialog_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/dialogs/goldens/ci/delete_message_dialog_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/dialogs/goldens/ci/message_dialog_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/dialogs/goldens/ci/message_dialog_1.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/dialogs/goldens/ci/message_dialog_2.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/icons/goldens/ci/stream_svg_icon_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/indicators/goldens/ci/sending_indicator_1.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/indicators/goldens/ci/sending_indicator_2.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/indicators/goldens/ci/sending_indicator_3.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_custom_child_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_custom_child_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_custom_styling_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_custom_styling_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_delete_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_delete_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_reply_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_action/goldens/ci/stream_message_action_item_reply_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_idle_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_idle_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_hold_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_hold_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_locked_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_locked_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_stopped_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_stopped_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/goldens/ci/attachment_button_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_input/goldens/ci/countdown_button_0.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/moderated_message_actions_modal_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/moderated_message_actions_modal_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_reactions_modal_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_reactions_modal_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_reactions_modal_reversed_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_reactions_modal_reversed_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_widget/goldens/ci/deleted_message_custom.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_widget/goldens/ci/deleted_message_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/message_widget/goldens/ci/deleted_message_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/reaction_bubble_2.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/reaction_bubble_3_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/reaction_bubble_3_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/reaction_bubble_like_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/reaction_bubble_like_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_custom_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_custom_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_empty_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_empty_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_inverted_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_inverted_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_less_data_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_less_data_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_progress_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_audio_waveform_slider_progress_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/stream_timestamp_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/system_message_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/misc/goldens/ci/system_message_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_error_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_error_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_error_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_error_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_dialog_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_dialog_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_full_screen_dialog_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_full_screen_dialog_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/poll_option_reorderable_list_view_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/poll_option_reorderable_list_view_error.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/poll_option_reorderable_list_view_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/poll_question_text_field_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/poll_question_text_field_error.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/poll_question_text_field_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_dialog_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_dialog_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_full_screen_dialog_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_full_screen_dialog_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_options_dialog_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_options_dialog_light.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_results_dialog_dark.pngis excluded by!**/*.pngpackages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_results_dialog_light.pngis excluded by!**/*.png
📒 Files selected for processing (107)
melos.yaml(4 hunks)migrations/v10-migration.md(1 hunks)packages/stream_chat/CHANGELOG.md(7 hunks)packages/stream_chat/example/pubspec.yaml(1 hunks)packages/stream_chat/lib/src/client/channel.dart(27 hunks)packages/stream_chat/lib/src/client/client.dart(15 hunks)packages/stream_chat/lib/src/client/event_resolvers.dart(1 hunks)packages/stream_chat/lib/src/client/retry_queue.dart(1 hunks)packages/stream_chat/lib/src/core/api/attachment_file_uploader.dart(2 hunks)packages/stream_chat/lib/src/core/api/call_api.dart(0 hunks)packages/stream_chat/lib/src/core/api/message_api.dart(3 hunks)packages/stream_chat/lib/src/core/api/responses.dart(3 hunks)packages/stream_chat/lib/src/core/api/responses.g.dart(1 hunks)packages/stream_chat/lib/src/core/api/sort_order.dart(1 hunks)packages/stream_chat/lib/src/core/api/sort_order.g.dart(0 hunks)packages/stream_chat/lib/src/core/api/stream_chat_api.dart(0 hunks)packages/stream_chat/lib/src/core/api/user_api.dart(2 hunks)packages/stream_chat/lib/src/core/models/call_payload.dart(0 hunks)packages/stream_chat/lib/src/core/models/call_payload.g.dart(0 hunks)packages/stream_chat/lib/src/core/models/channel_config.dart(2 hunks)packages/stream_chat/lib/src/core/models/channel_config.g.dart(2 hunks)packages/stream_chat/lib/src/core/models/channel_model.dart(1 hunks)packages/stream_chat/lib/src/core/models/channel_state.dart(5 hunks)packages/stream_chat/lib/src/core/models/channel_state.g.dart(2 hunks)packages/stream_chat/lib/src/core/models/event.dart(5 hunks)packages/stream_chat/lib/src/core/models/event.g.dart(2 hunks)packages/stream_chat/lib/src/core/models/location.dart(1 hunks)packages/stream_chat/lib/src/core/models/location.g.dart(1 hunks)packages/stream_chat/lib/src/core/models/location_coordinates.dart(1 hunks)packages/stream_chat/lib/src/core/models/member.dart(6 hunks)packages/stream_chat/lib/src/core/models/member.g.dart(2 hunks)packages/stream_chat/lib/src/core/models/message.dart(14 hunks)packages/stream_chat/lib/src/core/models/message.g.dart(4 hunks)packages/stream_chat/lib/src/core/models/message_delete_scope.dart(1 hunks)packages/stream_chat/lib/src/core/models/message_delete_scope.freezed.dart(1 hunks)packages/stream_chat/lib/src/core/models/message_delete_scope.g.dart(1 hunks)packages/stream_chat/lib/src/core/models/message_state.dart(27 hunks)packages/stream_chat/lib/src/core/models/message_state.freezed.dart(15 hunks)packages/stream_chat/lib/src/core/models/message_state.g.dart(2 hunks)packages/stream_chat/lib/src/core/models/reaction.dart(4 hunks)packages/stream_chat/lib/src/core/models/reaction.g.dart(1 hunks)packages/stream_chat/lib/src/core/models/reaction_group.dart(1 hunks)packages/stream_chat/lib/src/core/util/event_controller.dart(1 hunks)packages/stream_chat/lib/src/core/util/extension.dart(2 hunks)packages/stream_chat/lib/src/core/util/message_rules.dart(1 hunks)packages/stream_chat/lib/src/db/chat_persistence_client.dart(8 hunks)packages/stream_chat/lib/src/event_type.dart(3 hunks)packages/stream_chat/lib/src/permission_type.dart(0 hunks)packages/stream_chat/lib/stream_chat.dart(1 hunks)packages/stream_chat/lib/version.dart(1 hunks)packages/stream_chat/pubspec.yaml(1 hunks)packages/stream_chat/test/fixtures/channel_state_to_json.json(25 hunks)packages/stream_chat/test/fixtures/member.json(1 hunks)packages/stream_chat/test/fixtures/message.json(1 hunks)packages/stream_chat/test/fixtures/message_to_json.json(0 hunks)packages/stream_chat/test/fixtures/reaction.json(1 hunks)packages/stream_chat/test/src/client/client_test.dart(10 hunks)packages/stream_chat/test/src/client/event_resolvers_test.dart(1 hunks)packages/stream_chat/test/src/client/retry_queue_test.dart(2 hunks)packages/stream_chat/test/src/core/api/attachment_file_uploader_test.dart(1 hunks)packages/stream_chat/test/src/core/api/call_api_test.dart(0 hunks)packages/stream_chat/test/src/core/api/message_api_test.dart(4 hunks)packages/stream_chat/test/src/core/api/responses_test.dart(0 hunks)packages/stream_chat/test/src/core/api/sort_order_test.dart(0 hunks)packages/stream_chat/test/src/core/api/user_api_test.dart(1 hunks)packages/stream_chat/test/src/core/models/call_payload_test.dart(0 hunks)packages/stream_chat/test/src/core/models/channel_state_test.dart(1 hunks)packages/stream_chat/test/src/core/models/location_test.dart(1 hunks)packages/stream_chat/test/src/core/models/member_test.dart(1 hunks)packages/stream_chat/test/src/core/models/message_state_test.dart(7 hunks)packages/stream_chat/test/src/core/models/message_test.dart(2 hunks)packages/stream_chat/test/src/core/models/reaction_test.dart(7 hunks)packages/stream_chat/test/src/core/util/event_controller_test.dart(1 hunks)packages/stream_chat/test/src/core/util/message_rules_test.dart(1 hunks)packages/stream_chat/test/src/db/chat_persistence_client_test.dart(4 hunks)packages/stream_chat/test/src/mocks.dart(2 hunks)packages/stream_chat_flutter/CHANGELOG.md(7 hunks)packages/stream_chat_flutter/dart_test.yaml(1 hunks)packages/stream_chat_flutter/example/pubspec.yaml(1 hunks)packages/stream_chat_flutter/lib/platform_widget_builder/src/platform_widget_builder.dart(2 hunks)packages/stream_chat_flutter/lib/src/attachment/attachment.dart(1 hunks)packages/stream_chat_flutter/lib/src/attachment/attachment_widget_catalog.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/attachment_widget_builder.dart(3 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/poll_attachment_builder.dart(1 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/url_attachment_builder.dart(1 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_list_player.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_loading.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_player.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_slider.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/voice_recording_attachment_builder.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_base.dart(1 hunks)packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_html.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_io.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment/poll_attachment.dart(3 hunks)packages/stream_chat_flutter/lib/src/attachment/voice_recording_attachment_playlist.dart(0 hunks)packages/stream_chat_flutter/lib/src/attachment_actions_modal/attachment_actions_modal.dart(1 hunks)packages/stream_chat_flutter/lib/src/autocomplete/stream_command_autocomplete_options.dart(1 hunks)packages/stream_chat_flutter/lib/src/bottom_sheets/edit_message_sheet.dart(0 hunks)packages/stream_chat_flutter/lib/src/channel/stream_channel_avatar.dart(1 hunks)packages/stream_chat_flutter/lib/src/context_menu_items/context_menu_reaction_picker.dart(0 hunks)packages/stream_chat_flutter/lib/src/context_menu_items/download_menu_item.dart(0 hunks)packages/stream_chat_flutter/lib/src/context_menu_items/stream_chat_context_menu_item.dart(0 hunks)packages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dart(3 hunks)packages/stream_chat_flutter/lib/src/icons/stream_svg_icon.dart(2 hunks)packages/stream_chat_flutter/lib/src/indicators/unread_indicator.dart(1 hunks)packages/stream_chat_flutter/lib/src/localization/translations.dart(5 hunks)packages/stream_chat_flutter/lib/src/message_action/message_action.dart(1 hunks)
⛔ Files not processed due to max files limit (40)
- packages/stream_chat_flutter/lib/src/message_action/message_action_item.dart
- packages/stream_chat_flutter/lib/src/message_action/message_action_type.dart
- packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/copy_message_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/delete_message_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/edit_message_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/flag_message_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/mam_widgets.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/mark_unread_message_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/message_action.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/message_actions_modal.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/moderated_message_actions_modal.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/pin_message_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/reply_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/resend_message_button.dart
- packages/stream_chat_flutter/lib/src/message_actions_modal/thread_reply_button.dart
- packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_file_picker.dart
- packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_gallery_picker.dart
- packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart
- packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart
- packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_controller.dart
- packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_option.dart
- packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_result.dart
- packages/stream_chat_flutter/lib/src/message_input/dm_checkbox.dart
- packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart
- packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart
- packages/stream_chat_flutter/lib/src/message_input/stream_message_send_button.dart
- packages/stream_chat_flutter/lib/src/message_list_view/floating_date_divider.dart
- packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart
- packages/stream_chat_flutter/lib/src/message_modal/message_action_confirmation_modal.dart
- packages/stream_chat_flutter/lib/src/message_modal/message_actions_modal.dart
- packages/stream_chat_flutter/lib/src/message_modal/message_modal.dart
- packages/stream_chat_flutter/lib/src/message_modal/message_reactions_modal.dart
- packages/stream_chat_flutter/lib/src/message_modal/moderated_message_actions_modal.dart
- packages/stream_chat_flutter/lib/src/message_widget/ephemeral_message.dart
- packages/stream_chat_flutter/lib/src/message_widget/giphy_ephemeral_message.dart
- packages/stream_chat_flutter/lib/src/message_widget/message_card.dart
- packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart
- packages/stream_chat_flutter/lib/src/message_widget/message_widget_content.dart
- packages/stream_chat_flutter/lib/src/message_widget/message_widget_content_components.dart
💤 Files with no reviewable changes (24)
- packages/stream_chat/lib/src/permission_type.dart
- packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_loading.dart
- packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_slider.dart
- packages/stream_chat/lib/src/core/api/stream_chat_api.dart
- packages/stream_chat/test/fixtures/message_to_json.json
- packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_io.dart
- packages/stream_chat_flutter/lib/src/context_menu_items/context_menu_reaction_picker.dart
- packages/stream_chat_flutter/lib/src/attachment/attachment_widget_catalog.dart
- packages/stream_chat_flutter/lib/src/attachment/voice_recording_attachment_playlist.dart
- packages/stream_chat_flutter/lib/src/context_menu_items/stream_chat_context_menu_item.dart
- packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_html.dart
- packages/stream_chat/lib/src/core/api/sort_order.g.dart
- packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_player.dart
- packages/stream_chat_flutter/lib/src/context_menu_items/download_menu_item.dart
- packages/stream_chat/test/src/core/api/sort_order_test.dart
- packages/stream_chat/lib/src/core/api/call_api.dart
- packages/stream_chat/lib/src/core/models/call_payload.g.dart
- packages/stream_chat/test/src/core/api/responses_test.dart
- packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/stream_voice_recording_list_player.dart
- packages/stream_chat_flutter/lib/src/attachment/builder/voice_recording_attachment_builder/voice_recording_attachment_builder.dart
- packages/stream_chat/lib/src/core/models/call_payload.dart
- packages/stream_chat_flutter/lib/src/bottom_sheets/edit_message_sheet.dart
- packages/stream_chat/test/src/core/api/call_api_test.dart
- packages/stream_chat/test/src/core/models/call_payload_test.dart
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-25T08:19:01.469Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message that hasn't been sent to the server yet (message.remoteCreatedAt == null) or is bounced with error, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.
Applied to files:
packages/stream_chat/lib/src/core/models/event.g.dartpackages/stream_chat/lib/stream_chat.dartpackages/stream_chat/example/pubspec.yamlpackages/stream_chat/lib/src/core/models/message_delete_scope.g.dartpackages/stream_chat/test/src/mocks.dartpackages/stream_chat/lib/src/event_type.dartpackages/stream_chat/pubspec.yamlpackages/stream_chat/lib/src/core/api/message_api.dartpackages/stream_chat/lib/src/client/retry_queue.dartpackages/stream_chat/lib/src/core/api/responses.dartpackages/stream_chat/lib/src/core/models/message_delete_scope.dartpackages/stream_chat_flutter/lib/src/message_action/message_action.dartpackages/stream_chat/test/src/core/models/message_state_test.dartpackages/stream_chat/lib/src/core/models/event.dartpackages/stream_chat/test/src/client/retry_queue_test.dartpackages/stream_chat/lib/src/core/models/message_state.g.dartpackages/stream_chat/lib/src/core/models/message.g.dartpackages/stream_chat/test/src/core/models/message_test.dartpackages/stream_chat/test/src/db/chat_persistence_client_test.dartpackages/stream_chat/CHANGELOG.mdpackages/stream_chat/test/src/core/api/message_api_test.dartpackages/stream_chat/lib/src/db/chat_persistence_client.dartpackages/stream_chat/lib/src/core/models/message_delete_scope.freezed.dartpackages/stream_chat_flutter/lib/src/channel/stream_channel_avatar.dartpackages/stream_chat/lib/src/core/models/member.dartpackages/stream_chat_flutter/lib/src/attachment_actions_modal/attachment_actions_modal.dartpackages/stream_chat/test/src/core/models/member_test.dartpackages/stream_chat_flutter/CHANGELOG.mdpackages/stream_chat/lib/src/core/models/member.g.dartpackages/stream_chat_flutter/example/pubspec.yamlpackages/stream_chat/test/src/client/client_test.dartpackages/stream_chat/lib/src/core/models/message_state.dartpackages/stream_chat/lib/src/client/client.dartpackages/stream_chat_flutter/lib/src/localization/translations.dartpackages/stream_chat/lib/src/client/channel.dartpackages/stream_chat/lib/src/core/models/message_state.freezed.dartpackages/stream_chat/lib/src/core/models/message.dart
📚 Learning: 2025-09-25T08:19:01.469Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message with MessageSendingStatus.failed or MessageSendingStatus.failed_update status, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.
Applied to files:
packages/stream_chat/lib/stream_chat.dartpackages/stream_chat/example/pubspec.yamlpackages/stream_chat/lib/src/core/models/message_delete_scope.g.dartmelos.yamlpackages/stream_chat/test/src/mocks.dartpackages/stream_chat/lib/src/event_type.dartpackages/stream_chat/pubspec.yamlpackages/stream_chat/lib/src/core/api/message_api.dartpackages/stream_chat/lib/src/client/retry_queue.dartpackages/stream_chat/lib/src/core/api/responses.dartpackages/stream_chat/lib/src/core/models/message_delete_scope.dartpackages/stream_chat_flutter/lib/src/message_action/message_action.dartpackages/stream_chat/test/src/core/models/message_state_test.dartpackages/stream_chat/lib/src/core/models/event.dartpackages/stream_chat/test/src/client/retry_queue_test.dartpackages/stream_chat/lib/src/core/models/message_state.g.dartpackages/stream_chat/lib/src/core/models/message.g.dartpackages/stream_chat/test/src/core/models/message_test.dartpackages/stream_chat/test/src/db/chat_persistence_client_test.dartpackages/stream_chat/CHANGELOG.mdpackages/stream_chat/test/src/core/api/message_api_test.dartpackages/stream_chat/lib/src/db/chat_persistence_client.dartpackages/stream_chat/lib/src/core/models/message_delete_scope.freezed.dartpackages/stream_chat_flutter/lib/src/channel/stream_channel_avatar.dartpackages/stream_chat/lib/src/core/models/member.dartpackages/stream_chat_flutter/lib/src/attachment_actions_modal/attachment_actions_modal.dartpackages/stream_chat/test/src/core/models/member_test.dartpackages/stream_chat_flutter/CHANGELOG.mdpackages/stream_chat/lib/src/core/models/member.g.dartpackages/stream_chat_flutter/example/pubspec.yamlpackages/stream_chat/test/src/client/client_test.dartpackages/stream_chat/lib/src/core/models/message_state.dartpackages/stream_chat/lib/src/client/client.dartpackages/stream_chat/lib/src/core/util/message_rules.dartpackages/stream_chat_flutter/lib/src/localization/translations.dartpackages/stream_chat/lib/src/client/channel.dartpackages/stream_chat/lib/src/core/models/message_state.freezed.dartpackages/stream_chat/lib/src/core/models/message.dart
📚 Learning: 2025-08-08T14:27:59.621Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2348
File: packages/stream_chat_flutter_core/lib/src/stream_channel.dart:383-406
Timestamp: 2025-08-08T14:27:59.621Z
Learning: In stream_chat_flutter_core/lib/src/stream_channel.dart, threads (replies) do not support around-anchor loading. Thread replies are fetched as: initial latest page via StreamChannelState.getReplies(), and further pagination via StreamChannelState.queryReplies(parentId, direction: top|bottom). Anchored loads apply only to channel messages, not to threads.
Applied to files:
packages/stream_chat/pubspec.yamlpackages/stream_chat_flutter/CHANGELOG.mdpackages/stream_chat/lib/src/client/channel.dart
🪛 LanguageTool
migrations/v10-migration.md
[style] ~263-~263: Try using a synonym here to strengthen your writing.
Context: ...Important:* > - The builder pattern gives you access to default options, allowing mor...
(GIVE_PROVIDE)
[grammar] ~900-~900: Use a hyphen to join words.
Context: ...eleteScopeparameter - ✅ Update pattern matching callbacks to handleMessageDel...
(QB_NEW_EN_HYPHEN)
[grammar] ~902-~902: Use a hyphen to join words.
Context: ...eMessageForMe` methods - ✅ Use new state checking methods for delete-for-me opera...
(QB_NEW_EN_HYPHEN)
🪛 markdownlint-cli2 (0.18.1)
migrations/v10-migration.md
87-87: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
222-222: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
232-232: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test
- GitHub Check: build (ios)
- GitHub Check: build (android)
| /// This builder is used when a message contains a poll. | ||
| /// {@endtemplate} | ||
| class PollAttachmentBuilder extends StreamAttachmentWidgetBuilder { | ||
| /// {@macro urlAttachmentBuilder} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the documentation macro reference.
The documentation references {@macro urlAttachmentBuilder} but should reference {@macro pollAttachmentBuilder} to match the template defined at line 7.
Apply this diff to fix the macro reference:
- /// {@macro urlAttachmentBuilder}
+ /// {@macro pollAttachmentBuilder}📝 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.
| /// {@macro urlAttachmentBuilder} | |
| /// {@macro pollAttachmentBuilder} |
🤖 Prompt for AI Agents
In
packages/stream_chat_flutter/lib/src/attachment/builder/poll_attachment_builder.dart
around line 13, the documentation macro reference is incorrect: it uses {@macro
urlAttachmentBuilder} but the template defined at line 7 is
pollAttachmentBuilder; update the macro reference to {@macro
pollAttachmentBuilder} so the Dartdoc links to the correct template.
| List<String>? allowedExtensions, | ||
| Function(FilePickerStatus)? onFileLoading, | ||
| bool allowCompression = true, | ||
| int compressionQuality = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Document the compressionQuality parameter semantics.
The new compressionQuality parameter lacks documentation, making its semantics ambiguous:
- What does a value of 0 represent? (no compression, minimum quality, or something else?)
- What is the valid range? (0-100, 0-1, or other?)
- How does the value map to compression behavior?
This is critical for implementers of this abstract class and consumers of the API to use it correctly.
Add inline documentation to clarify the parameter:
/// Pick a file from the device.
Future<Attachment?> pickFile({
String? dialogTitle,
String? initialDirectory,
FileType type = FileType.any,
List<String>? allowedExtensions,
Function(FilePickerStatus)? onFileLoading,
+ /// The compression quality to apply to the picked file.
+ /// Valid range is 0-100, where:
+ /// - 0: no compression (original quality)
+ /// - 100: maximum compression (lowest quality)
+ /// Defaults to 0 (no compression).
int compressionQuality = 0,
bool withData = true,
bool withReadStream = false,
bool lockParentWindow = true,
}) {Please verify the actual semantics by checking the implementation in the HTML and IO handler files:
🏁 Script executed:
#!/bin/bash
# Find and examine how compressionQuality is used in implementations
rg -A 10 -B 2 'compressionQuality' packages/stream_chat_flutter/lib/src/attachment/handler/Length of output: 7452
Good news! I found the official file_picker package documentation. The compressionQuality parameter defines the compression quality percentage to use when compressing images, with values ranging from 0 (no compression) to 100.
However, there's a critical issue with the documentation suggested in the original review comment. The phrasing "100: maximum compression (lowest quality)" is misleading. In typical usage semantics, a higher "quality" number usually means better quality, not maximum compression. The file_picker documentation doesn't explicitly clarify whether the scale represents "quality level" (higher = better) or "compression ratio" (higher = more compressed). This ambiguity needs to be resolved.
Let me verify the actual behavior by checking if there are any code comments or tests in the repository that clarify this:
Based on my verification, I've found a critical issue with the suggested documentation in the original review comment:
The file_picker documentation states the compressionQuality value ranges from 0 (no compression) to 100. However, the suggested documentation in the review comment is backwards. In related Flutter packages, 0 means compress for small size, and 100 means compress for max quality — meaning higher numbers represent better quality, not maximum compression.
The original review suggested documenting compressionQuality as:
0: no compression (original quality)100: maximum compression (lowest quality)
This is incorrect. The correct semantics should be:
0: no compression (original quality)100: maximum quality (least compression)
Add corrected parameter documentation to clarify compressionQuality semantics.
The parameter lacks documentation, and the suggested values were reversed. The valid range is 0 (no compression) to 100, where higher values represent better quality, not maximum compression.
/// Pick a file from the device.
Future<Attachment?> pickFile({
String? dialogTitle,
String? initialDirectory,
FileType type = FileType.any,
List<String>? allowedExtensions,
Function(FilePickerStatus)? onFileLoading,
+ /// The compression quality to apply to the picked file.
+ /// Valid range is 0–100, where:
+ /// - 0: no compression (original quality)
+ /// - 100: maximum quality (least compression)
+ /// Only affects image compression on mobile platforms.
+ /// Defaults to 0 (no compression).
int compressionQuality = 0,
bool withData = true,
bool withReadStream = false,
bool lockParentWindow = true,
}) {📝 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.
| int compressionQuality = 0, | |
| /// The compression quality to apply to the picked file. | |
| /// Valid range is 0–100, where: | |
| /// - 0: no compression (original quality) | |
| /// - 100: maximum quality (least compression) | |
| /// Only affects image compression on mobile platforms. | |
| /// Defaults to 0 (no compression). | |
| int compressionQuality = 0, |
🤖 Prompt for AI Agents
In
packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_base.dart
around line 34, the parameter documentation for compressionQuality is missing
and previous wording reversed semantics; update the doc comment for the int
compressionQuality parameter to state the valid range is 0–100 and that higher
values mean better image quality (less compression) while 0 means no
compression/original quality, replacing any text that implied 100 means maximum
compression/lowest quality.
| /// Resolves casted or changed poll vote events into more specific | ||
| /// `pollAnswerCasted` events for easier downstream state handling. | ||
| /// | ||
| /// Applies when: | ||
| /// - `event.type` is `pollVoteCasted` or `pollVoteChanged`, and | ||
| /// - `event.pollVote?.isAnswer == true` | ||
| /// | ||
| /// Returns a modified event with type `pollAnswerCasted`, | ||
| /// or `null` if not applicable. | ||
| Event? pollAnswerCastedResolver(Event event) { | ||
| final validTypes = {EventType.pollVoteCasted, EventType.pollVoteChanged}; | ||
| if (!validTypes.contains(event.type)) return null; | ||
|
|
||
| final pollVote = event.pollVote; | ||
| if (pollVote?.isAnswer == false) return null; | ||
|
|
||
| // If the event is a poll vote casted or changed and it's an answer | ||
| // we can resolve it to a poll answer casted event. | ||
| return event.copyWith(type: EventType.pollAnswerCasted); | ||
| } | ||
|
|
||
| /// Resolves removed poll vote events into more specific | ||
| /// `pollAnswerRemoved` events for easier downstream state handling. | ||
| /// | ||
| /// Applies when: | ||
| /// - `event.type` is `pollVoteRemoved`, and | ||
| /// - `event.pollVote?.isAnswer == true` | ||
| /// | ||
| /// Returns a modified event with type `pollAnswerRemoved`, | ||
| /// or `null` if not applicable. | ||
| Event? pollAnswerRemovedResolver(Event event) { | ||
| if (event.type != EventType.pollVoteRemoved) return null; | ||
|
|
||
| final pollVote = event.pollVote; | ||
| if (pollVote?.isAnswer == false) return null; | ||
|
|
||
| // If the event is a poll vote removed and it's an answer | ||
| // we can resolve it to a poll answer removed event. | ||
| return event.copyWith(type: EventType.pollAnswerRemoved); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard poll vote resolvers against null pollVote to avoid misclassifying events
In both pollAnswerCastedResolver and pollAnswerRemovedResolver you only reject the event when pollVote?.isAnswer == false. If pollVote is null, the condition is false and you still convert the event, even though there is no vote payload:
final pollVote = event.pollVote;
if (pollVote?.isAnswer == false) return null;
// null pollVote falls through and becomes pollAnswerCasted/Removed
return event.copyWith(...);Safer is to require isAnswer == true explicitly:
Event? pollAnswerCastedResolver(Event event) {
final validTypes = {EventType.pollVoteCasted, EventType.pollVoteChanged};
if (!validTypes.contains(event.type)) return null;
final pollVote = event.pollVote;
- if (pollVote?.isAnswer == false) return null;
+ if (pollVote?.isAnswer != true) return null;
return event.copyWith(type: EventType.pollAnswerCasted);
}
Event? pollAnswerRemovedResolver(Event event) {
if (event.type != EventType.pollVoteRemoved) return null;
final pollVote = event.pollVote;
- if (pollVote?.isAnswer == false) return null;
+ if (pollVote?.isAnswer != true) return null;
return event.copyWith(type: EventType.pollAnswerRemoved);
}This prevents spurious pollAnswer* events if the backend ever emits vote events without a pollVote payload.
🤖 Prompt for AI Agents
In packages/stream_chat/lib/src/client/event_resolvers.dart around lines 25 to
64, the resolvers currently only bail out when pollVote?.isAnswer == false which
allows a null pollVote to fall through and incorrectly convert events; change
the guards to explicitly require pollVote?.isAnswer == true (i.e. return null if
pollVote is null or isAnswer is not true) in both pollAnswerCastedResolver and
pollAnswerRemovedResolver so only events with a present pollVote marked as an
answer are converted to pollAnswerCasted/pollAnswerRemoved.
| // region Standalone upload methods | ||
|
|
||
| /// Uploads an image file to the CDN. | ||
| /// | ||
| /// Upload progress can be tracked using [onProgress], and the operation can | ||
| /// be cancelled using [cancelToken]. | ||
| /// | ||
| /// Returns a [UploadImageResponse] once uploaded successfully. | ||
| Future<UploadImageResponse> uploadImage( | ||
| AttachmentFile image, { | ||
| ProgressCallback? onSendProgress, | ||
| CancelToken? cancelToken, | ||
| }); | ||
|
|
||
| /// Uploads a file to the CDN. | ||
| /// | ||
| /// Upload progress can be tracked using [onProgress], and the operation can | ||
| /// be cancelled using [cancelToken]. | ||
| /// | ||
| /// Returns a [UploadFileResponse] once uploaded successfully. | ||
| Future<UploadFileResponse> uploadFile( | ||
| AttachmentFile file, { | ||
| ProgressCallback? onSendProgress, | ||
| CancelToken? cancelToken, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix doc comment parameter name for standalone upload methods.
The new uploadImage/uploadFile docs mention [onProgress], but the actual parameter is onSendProgress (consistent with the channel-scoped methods). This is only a documentation mismatch but can be confusing when using IDE tooling.
You can fix this by updating the references in the doc comments:
- /// Upload progress can be tracked using [onProgress], and the operation can
+ /// Upload progress can be tracked using [onSendProgress], and the operation can
@@
- /// Upload progress can be tracked using [onProgress], and the operation can
+ /// Upload progress can be tracked using [onSendProgress], and the operation canNo changes are needed in the implementations; the new CDN endpoints and response types look correct.
Also applies to: 191-221
🤖 Prompt for AI Agents
In packages/stream_chat/lib/src/core/api/attachment_file_uploader.dart around
lines 65-89 (and similarly update lines 191-221), the doc comments reference
[onProgress] which does not match the actual parameter name onSendProgress;
update the doc comments to refer to [onSendProgress] (and any inline mentions of
onProgress) so the parameter name in the documentation matches the method
signature and IDE tooling links correctly.
| /// Model response for [StreamChatClient.updateDraft] api call | ||
| @JsonSerializable(createToJson: false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the documentation comment.
The doc comment references updateDraft but the class is GetActiveLiveLocationsResponse.
Apply this diff to fix the documentation:
-/// Model response for [StreamChatClient.updateDraft] api call
+/// Model response for [StreamChatClient.getActiveLiveLocations] api call
@JsonSerializable(createToJson: false)
class GetActiveLiveLocationsResponse extends _BaseResponse {🤖 Prompt for AI Agents
In packages/stream_chat/lib/src/core/api/responses.dart around lines 825 to 826,
the documentation comment incorrectly references updateDraft for this class;
update the doc comment to reference GetActiveLiveLocationsResponse (or a neutral
description of the response) so it accurately documents the class
purpose—replace "Model response for [StreamChatClient.updateDraft] api call"
with a correct description mentioning GetActiveLiveLocationsResponse (or the API
call it represents) and ensure spelling/casing matches project style.
| /// Returns true if the live location is still active (end_at > now) | ||
| bool get isActive { | ||
| final endAt = this.endAt; | ||
| if (endAt == null) return false; | ||
|
|
||
| return endAt.isAfter(DateTime.now()); | ||
| } | ||
|
|
||
| /// Returns true if the live location is expired (end_at <= now) | ||
| bool get isExpired => !isActive; | ||
|
|
||
| /// Returns true if this is a live location (has end_at) | ||
| bool get isLive => endAt != null; | ||
|
|
||
| /// Returns true if this is a static location (no end_at) | ||
| bool get isStatic => endAt == null; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isExpired incorrectly flags static locations as expired
isExpired is currently implemented as !isActive, and isActive returns false when endAt is null. That means static locations (no endAt) will be treated as expired, which contradicts the docs (“live location is expired (end_at <= now)”) and likely semantics where static locations are neither “active live” nor “expired”.
Consider constraining expiry to live locations only, e.g.:
bool get isExpired => endAt != null && !isActive;This keeps isLive / isStatic orthogonal and avoids misclassifying static locations as expired.
🤖 Prompt for AI Agents
In packages/stream_chat/lib/src/core/models/location.dart around lines 87 to
103, isExpired is implemented as !isActive which causes static locations (endAt
== null) to be marked expired; change the getter so it only considers live
locations expired by requiring endAt != null and that the end time is not after
now (i.e., return true only when there is an endAt and it is <= now) — update
the isExpired getter accordingly so static locations are not flagged expired.
| test( | ||
| 'MessageState.softDeletingFailed should create a MessageFailed instance with DeletingFailed state and not hard deleting', | ||
| 'MessageState.partialUpdatingFailed should create a MessageFailed instance with UpdatingFailed state', | ||
| () { | ||
| final messageState = MessageState.partialUpdatingFailed( | ||
| skipEnrichUrl: false, | ||
| ); | ||
| expect(messageState, isA<MessageFailed>()); | ||
| expect( | ||
| (messageState as MessageFailed).state, | ||
| isA<PartialUpdatingFailed>(), | ||
| ); | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix partialUpdatingFailed test description to match the actual state
The partialUpdatingFailed test description says:
'MessageState.partialUpdatingFailed should create a MessageFailed instance with UpdatingFailed state'
but the assertion correctly checks for isA<PartialUpdatingFailed>():
expect(
(messageState as MessageFailed).state,
isA<PartialUpdatingFailed>(),
);To avoid confusion for future readers, it would be better to update the description to mention PartialUpdatingFailed instead of UpdatingFailed.
🤖 Prompt for AI Agents
packages/stream_chat/test/src/core/models/message_state_test.dart around lines
381 to 393: the test description incorrectly says "UpdatingFailed" while the
assertions check for PartialUpdatingFailed; update the test description string
to mention "PartialUpdatingFailed" so it matches the actual asserted state and
avoids confusion for future readers.
|
Hello, Taha — big fan. |
# Conflicts: # packages/stream_chat/CHANGELOG.md # packages/stream_chat_flutter/CHANGELOG.md # packages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dart # packages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_idle_dark.png # packages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_idle_light.png # packages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playing_dark.png # packages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playing_light.png # packages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playlist_dark.png # packages/stream_chat_flutter/test/src/attachment/goldens/ci/stream_voice_recording_attachment_playlist_light.png # packages/stream_chat_flutter/test/src/avatars/goldens/ci/gradient_avatar_issue_2369.png # packages/stream_chat_flutter/test/src/bottom_sheets/goldens/ci/edit_message_sheet_0.png # packages/stream_chat_flutter/test/src/bottom_sheets/goldens/ci/error_alert_sheet_0.png # packages/stream_chat_flutter/test/src/channel/goldens/ci/channel_header_bottom_widget.png # packages/stream_chat_flutter/test/src/context_menu_items/goldens/ci/download_menu_item_0.png # packages/stream_chat_flutter/test/src/context_menu_items/goldens/ci/stream_chat_context_menu_item_0.png # packages/stream_chat_flutter/test/src/dialogs/goldens/ci/confirmation_dialog_0.png # packages/stream_chat_flutter/test/src/dialogs/goldens/ci/delete_message_dialog_0.png # packages/stream_chat_flutter/test/src/dialogs/goldens/ci/message_dialog_0.png # packages/stream_chat_flutter/test/src/dialogs/goldens/ci/message_dialog_1.png # packages/stream_chat_flutter/test/src/dialogs/goldens/ci/message_dialog_2.png # packages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_hold_dark.png # packages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_hold_light.png # packages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_locked_dark.png # packages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_locked_light.png # packages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_stopped_dark.png # packages/stream_chat_flutter/test/src/message_input/audio_recorder/goldens/ci/stream_audio_recorder_button_recording_stopped_light.png # packages/stream_chat_flutter/test/src/message_input/goldens/ci/countdown_button_0.png # packages/stream_chat_flutter/test/src/message_widget/goldens/ci/deleted_message_custom.png # packages/stream_chat_flutter/test/src/message_widget/goldens/ci/deleted_message_dark.png # packages/stream_chat_flutter/test/src/message_widget/goldens/ci/deleted_message_light.png # packages/stream_chat_flutter/test/src/misc/goldens/ci/stream_timestamp_light.png # packages/stream_chat_flutter/test/src/misc/goldens/ci/system_message_dark.png # packages/stream_chat_flutter/test/src/misc/goldens/ci/system_message_light.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_dark.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_error_dark.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_error_light.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_option_reorderable_list_view_light.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_dark.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_error_dark.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_error_light.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/poll_question_text_field_light.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_dialog_light.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_full_screen_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/creator/goldens/ci/stream_poll_creator_full_screen_dialog_light.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/poll_option_reorderable_list_view_dark.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/poll_option_reorderable_list_view_error.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/poll_option_reorderable_list_view_light.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/poll_question_text_field_dark.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/poll_question_text_field_error.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/poll_question_text_field_light.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_dialog_light.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_full_screen_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_creator_full_screen_dialog_light.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_options_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_options_dialog_light.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_results_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_results_dialog_light.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_results_dialog_with_show_all_dark.png # packages/stream_chat_flutter/test/src/poll/goldens/ci/stream_poll_results_dialog_with_show_all_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_add_comment_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_add_comment_dialog_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_add_comment_dialog_with_initial_value_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_add_comment_dialog_with_initial_value_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_end_vote_dialog_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_long_question_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_long_question_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_all_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_all_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_disabled_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_disabled_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_limited_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_limited_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_unique_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_header_subtitle_voting_mode_unique_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_suggest_option_dialog_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_suggest_option_dialog_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_suggest_option_dialog_with_initial_option_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/poll_suggest_option_dialog_with_initial_option_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/stream_poll_interactor_closed_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/stream_poll_interactor_closed_light.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/stream_poll_interactor_dark.png # packages/stream_chat_flutter/test/src/poll/interactor/goldens/ci/stream_poll_interactor_light.png # packages/stream_chat_flutter/test/src/scroll_view/draft_scroll_view/goldens/ci/stream_draft_list_tile_dark.png # packages/stream_chat_flutter/test/src/scroll_view/draft_scroll_view/goldens/ci/stream_draft_list_tile_light.png # packages/stream_chat_flutter/test/src/scroll_view/thread_scroll_view/goldens/ci/stream_thread_list_tile_dark.png # packages/stream_chat_flutter/test/src/scroll_view/thread_scroll_view/goldens/ci/stream_thread_list_tile_light.png # packages/stream_chat_flutter/test/src/scroll_view/thread_scroll_view/goldens/ci/stream_unread_threads_banner_light.png
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dart (1)
419-419: Address the TODO: refactor to callback-based pattern.The TODO comment indicates the current
onTapimplementation should be replaced with a callback-based approach for better architecture.Do you want me to help design the callback-based implementation or open an issue to track this technical debt?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
melos.yaml(4 hunks)packages/stream_chat/CHANGELOG.md(7 hunks)packages/stream_chat_flutter/CHANGELOG.md(7 hunks)packages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dart(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/stream_chat/CHANGELOG.md
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-25T08:19:01.469Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message with MessageSendingStatus.failed or MessageSendingStatus.failed_update status, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.
Applied to files:
melos.yamlpackages/stream_chat_flutter/CHANGELOG.md
📚 Learning: 2025-09-25T08:19:01.469Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message that hasn't been sent to the server yet (message.remoteCreatedAt == null) or is bounced with error, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.
Applied to files:
packages/stream_chat_flutter/CHANGELOG.md
📚 Learning: 2025-08-08T14:27:59.621Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2348
File: packages/stream_chat_flutter_core/lib/src/stream_channel.dart:383-406
Timestamp: 2025-08-08T14:27:59.621Z
Learning: In stream_chat_flutter_core/lib/src/stream_channel.dart, threads (replies) do not support around-anchor loading. Thread replies are fetched as: initial latest page via StreamChannelState.getReplies(), and further pagination via StreamChannelState.queryReplies(parentId, direction: top|bottom). Anchored loads apply only to channel messages, not to threads.
Applied to files:
packages/stream_chat_flutter/CHANGELOG.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: update_goldens
- GitHub Check: stream_chat_localizations
- GitHub Check: build (ios)
- GitHub Check: analyze_legacy_versions
- GitHub Check: test
- GitHub Check: build (android)
- GitHub Check: stream_chat_flutter
- GitHub Check: stream_chat_flutter_core
- GitHub Check: stream_chat_persistence
🔇 Additional comments (5)
packages/stream_chat_flutter/CHANGELOG.md (1)
8-77: Significant discrepancy between the AI-generated summary and the documented changelog entries.The enriched AI summary describes substantial changes including live location sharing, scoped message deletion (delete-for-me), Reaction API refactors, EventController with resolvers, CDN upload/remove endpoints, and extensive model/serialization updates. However, the v10.0.0-beta.9 changelog section only documents reaction indicator customizations and two breaking changes.
Additionally, the PR objective references a specific memory heap fix (adding
.truncate()to channel.dart) recommended by a reviewer, which is not reflected in the changelog.Please verify:
- Whether all substantial changes described in the AI summary should be documented in the beta.9 changelog
- Whether the memory heap fix warrants a changelog entry in the "Fixed" section
- If the changelog is intentionally minimal or if major feature entries are missing
If changes are confirmed but not yet documented, consider adding entries for:
- Location/live location features
- Message deletion scope refactoring
- Event type expansions
- Attachment file uploader API enhancements
- Memory heap optimization
melos.yaml (2)
87-91: Stream Chat 10.0.0-beta.9 is reasonably stable for pre-release.All five Stream Chat packages are consistently updated to
10.0.0-beta.9. This beta includes targeted fixes (Location.endAt UTC conversion, cached message clearing for offline channels, UI/core fixes) and no critical blockers have been reported. The known compatibility issues (Flutter 3.22, transitive dependency conflicts) are pre-existing and unrelated to the package version pins themselves.
27-99: No version conflicts or incompatible transitive dependencies detected.The new geolocation, mapping, and Stream Chat packages integrate cleanly with existing dependencies. Verification confirms: (1) version constraints are consistent across melos.yaml and all workspace pubspecs; (2) geolocator and device_info_plus share no overlapping transitive dependencies; (3) platform-specific implementations are properly isolated. The current dependency set appears sound. If additional validation is needed, run
melos bootstrap --validatein your environment to confirm resolution against the latest pub.dev versions.packages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dart (2)
125-132: LGTM! Context menu builder correctly captures current state.The context menu builder properly captures the current page index and retrieves the corresponding media attachment when the menu is shown.
360-370: LGTM! Context menu correctly references attachment from outer scope.The context menu builder properly uses
currentAttachmentPackagefrom the enclosingitemBuilderscope.
| # List of all the dependencies used in the project. | ||
| dependencies: | ||
| async: ^2.11.0 | ||
| avatar_glow: ^3.0.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
geolocator 13.0.0 Flutter known issues security concerns
💡 Result:
Short summary — geolocator 13.0.0 (Flutter)
-
What changed in 13.0.0
- Breaking changes: deprecates getCurrentPosition parameters (desiredAccuracy, forceAndroidLocationManager, timeLimit) in favor of a LocationSettings class; exposes WebSettings; updated federated subpackage deps (android/apple/web/windows/platform_interface). [1]
-
Known functional issues (reported & fixed soon after)
- 13.0.1/13.0.2/13.0.3 quickly followed to fix compilation/example issues (13.0.1 fixed illegal reference to dart:js_interop on non‑web builds; other 13.x releases updated dependencies and example configs). If you hit build/compiler issues, upgrade to the patched 13.x or newer. [1]
-
Security vulnerabilities to be aware of
- There is a public CVE (CVE‑2024‑52443) for a WordPress plugin named “Geolocator” (PHP object‑injection / deserialization) — this affects that WordPress plugin (versions ≤1.1), not the Flutter geolocator package. The Flutter geolocator package has no CVE record shown by the public databases for 13.0.0. Do not conflate the two projects. [2][3]
-
Other security/privacy notes (general, relevant to any location plugin)
- Browser geolocation requires secure origins (HTTPS); geolocation APIs are deprecated on insecure origins. For web builds, serve over HTTPS. [4]
- Review platform permission settings (foreground vs background location), Android 13+/iOS 14+ permission behavior, and limit how long/location granularity is requested in production apps. Also audit third‑party subpackages (geolocator_android, geolocator_apple, geolocator_web) for updates. [1]
-
Recommendation
- If you use 13.0.0: upgrade to the latest stable geolocator (14.x as of the package page) or at least 13.0.4+ (which contains quick fixes) and test builds on all target platforms. Audit your app’s permission requests and ensure web builds are served over HTTPS. [1]
Sources
- geolocator changelog (pub.dev). [1]
- NVD / CVE records and aggregators for CVE‑2024‑52443 (WordPress Geolocator plugin). [2][3]
- Chromium/DevTools note on geolocation requiring secure origins (HTTPS). [4]
If you want, I can:
- check the exact latest geolocator version now and provide upgrade guidance for your pubspec, or
- scan your project for usages of the deprecated getCurrentPosition parameters and produce a small migration patch.
🌐 Web query:
flutter_map 8.1.1 stability production usage
💡 Result:
Short answer: flutter_map 8.1.1 is a bug‑fix release (published 2025‑03‑08) that addresses an infinite‑loop bug with polygon labels on rotated maps; it’s part of an actively maintained 8.x line and is generally fine for production if you pin and test it in your app. [1][2][3]
Details & recommendation:
- Release: 8.1.1 — 2025‑03‑08; changelog lists the polygon‑label infinite‑loop fix. Test your polygon/rotation code path. [1]
- Maintenance: the project is community‑maintained with frequent 8.x fixes/patches (see repo releases). Keep an eye on later 8.x bugfixes (e.g., 8.2.x) and update when appropriate. [2][3]
- Practical advice: pin the exact package version in pubspec.yaml, run your full test matrix (Android/iOS/web, device/OS versions you support), and check upstream issues for any regressions specific to your use (e.g., tile caching, vector tile plugins). If you rely on related plugins (tile caching, vector tiles), verify compatibility with their versions too.
Sources:
[1] flutter_map changelog (pub.dev) — 8.1.1 entry.
[2] fleaflet/flutter_map GitHub releases.
[3] flutter_map docs (fleaflet).
🌐 Web query:
avatar_glow flutter package security maintenance
💡 Result:
Short summary
- Current package: avatar_glow — latest published release on pub.dev is v3.0.1. [1]
- Source: GitHub repo apgapg/avatar_glow (repository and live demo linked from pub.dev). [1][3]
- Maintenance signals: recent pub.dev metadata shows infrequent updates (latest release published ~24 months ago on pub.dev listings) and a small issue count on the repo — active but low-maintenance. [1][2]
- Security posture: no public CVEs or security advisories listed on pub.dev or Libraries.io; package is MIT-licensed, has no external native/unsafe dependencies (pure Flutter widget), so attack surface is small — but no formal audit found. [1][2]
- Practical recommendations:
- Pin the package version in pubspec.yaml (avoid floating ranges) and vendor or audit the code if you rely on it in production. [1]
- Review the GitHub issues/PRs before upgrading; consider using the GitHub repo directly if you need an unpushed fix. [1][3]
- If you need long-term maintenance guarantees, either fork and maintain the widget in your repo or implement the simple glow effect yourself (widget is small). [2][3]
Sources
[1] pub.dev/avatar_glow package page (metadata, versions, repo link).
[2] Libraries.io / pub listing for avatar_glow (package metadata, license, maintenance info).
[3] GitHub repository referenced by package (apgapg/avatar_glow).
🌐 Web query:
flutter_map_animations latlong2 compatibility issues
💡 Result:
Short answer — common compatibility causes and fixes
-
Root cause: flutter_map and many related plugins (including flutter_map_animations) use the LatLng type from the latlong2 package; mismatched versions or having multiple LatLng types (from latlong, latlong2, google_maps_flutter, etc.) produce type errors. (docs.fleaflet.dev)
-
Quick checks/fixes:
- Add latlong2 to your pubspec (same major version expected by your flutter_map/flutter_map_animations). Example: flutter pub add latlong2. (docs.fleaflet.dev)
- Import the correct symbol where used: import 'package:latlong2/latlong.dart'; or import it with an alias if another LatLng exists: import 'package:latlong2/latlong.dart' as ll2; then use ll2.LatLng(...). This resolves ambiguous/assignability errors. (stackoverflow.com)
- Make sure flutter_map_animations and flutter_map versions target the same latlong2 major version — if not, upgrade/downgrade or add a dependency_override for latlong2 (temporarily) so all packages use the same package version. Then run flutter clean && flutter pub get. (docs.fleaflet.dev)
- If upgrading to flutter_map v5+ or other major releases, read migration notes — latlong2 had updates (const constructors, version bumps) that can cause small breaking changes. Apply suggested migration fixes (dart fix, update constructors/usages). (docs.fleaflet.dev)
-
If you still get errors: inspect pub deps (flutter pub deps --style=compact) to find multiple latlong/LatLng providers; remove the old latlong package or unify versions. Stack Overflow and flutter_map docs show this is the usual resolution. (stackoverflow.com)
If you want, tell me the pubspec.yaml and exact error message and I’ll give step‑by‑step edits.
Citations:
- 1: https://docs.fleaflet.dev/v5/getting-started/migrating-to-v5?utm_source=openai
- 2: https://docs.fleaflet.dev/v6/getting-started/installation?utm_source=openai
- 3: https://stackoverflow.com/questions/73572403/the-argument-type-latlng-cant-be-assigned-to-the-parameter-type-latlng?utm_source=openai
- 4: https://docs.fleaflet.dev/v5/getting-started/migrating-to-v5?utm_source=openai
- 5: https://docs.fleaflet.dev/v5/getting-started/migrating-to-v5?utm_source=openai
- 6: https://stackoverflow.com/questions/73572403/the-argument-type-latlng-cant-be-assigned-to-the-parameter-type-latlng?utm_source=openai
Upgrade geolocator to version 13.0.4 or later; other new dependencies are stable.
The addition of avatar_glow, flutter_map, flutter_map_animations, and latlong2 aligns well with the live location sharing feature and poses no known security or stability concerns. However, geolocator 13.0.0 has known breaking changes and required multiple bugfix patches (13.0.1–13.0.3). Upgrade to at least 13.0.4+ or the latest stable version (14.x) to avoid compilation issues and benefit from critical fixes. Also ensure web builds are served over HTTPS and audit your app's location permission scopes (foreground vs. background, especially for Android 13+ and iOS 14+).
Also applies to: 47-48, 56-56, 66-66
🤖 Prompt for AI Agents
In melos.yaml around line 28 (also applies to lines 47-48, 56, and 66), the
project references geolocator 13.0.0 which has known breaking changes and
required bugfixes; update the geolocator dependency entries to at least 13.0.4
or preferably the latest stable 14.x release, ensure the version constraint
reflects a minimum of 13.0.4 (e.g., ^13.0.4 or ^14.0.0), and run pub get to
verify resolution; additionally confirm your web builds are served over HTTPS
and audit Android/iOS location permission scopes (foreground vs background) for
Android 13+ and iOS 14+ to match the updated geolocator behavior.
| onTap: (action) async { | ||
| if (action is! CustomMessageAction) return; | ||
| final attachment = action.extraData[_attachmentKey] as Attachment?; | ||
| if (attachment == null) return; | ||
|
|
||
| final popped = await Navigator.of(context).maybePop(); | ||
| if (popped) { | ||
| final handler = StreamAttachmentHandler.instance; | ||
| return handler.downloadAttachment(attachment).ignore(); | ||
| } | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "*.dart" | xargs grep -l "class StreamAttachmentHandler" | head -5Repository: GetStream/stream-chat-flutter
Length of output: 352
🏁 Script executed:
cat -n packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_base.dart | head -150Repository: GetStream/stream-chat-flutter
Length of output: 3178
🏁 Script executed:
cat -n packages/stream_chat_flutter/lib/src/attachment/handler/stream_attachment_handler_io.dartRepository: GetStream/stream-chat-flutter
Length of output: 8489
🏁 Script executed:
grep -rn "downloadAttachmentData" packages/stream_chat_flutter/lib/src/attachment/handler/ --include="*.dart" -A 20 | head -80Repository: GetStream/stream-chat-flutter
Length of output: 9142
🏁 Script executed:
cat -n packages/stream_chat_flutter/lib/src/attachment/handler/common.dart | head -150Repository: GetStream/stream-chat-flutter
Length of output: 3266
Add error handling for download failures instead of silently suppressing them.
The .ignore() call at line 428 suppresses all errors from the download operation. Since StreamAttachmentHandler.downloadAttachment() has no internal error handling (file I/O and network operations can fail), any download or save failure will be silently swallowed, leaving users without feedback. Handle the error explicitly with logging or user-facing notifications.
🤖 Prompt for AI Agents
In
packages/stream_chat_flutter/lib/src/fullscreen_media/full_screen_media_desktop.dart
around lines 420 to 430, the call to
handler.downloadAttachment(attachment).ignore() swallows any errors; replace it
with an awaited try/catch that handles failures: await the download call inside
a try block, catch exceptions, log the error (use existing logger or debugPrint)
and surface a user-facing notification (e.g.,
ScaffoldMessenger.of(context).showSnackBar or the package's error UI) with a
clear message, and ensure the catch does not rethrow unless needed.
Corrects the version number from `10.0-beta.10` to `10.0.0-beta.10` in the `stream_chat_localizations` changelog.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.