-
Notifications
You must be signed in to change notification settings - Fork 367
feat(ui): add optionsBuilder to custom attachment options #2363
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(ui): add optionsBuilder to custom attachment options #2363
Conversation
WalkthroughAdds an optionsBuilder API to the attachment picker (mobile and web/desktop), wires it through the modal bottom sheet, introduces typedefs, enforces exclusivity with customOptions, refactors default/final options computation, updates signatures, adds tests, and documents the change in CHANGELOG.md. Changes
Sequence Diagram(s)sequenceDiagram
participant App
participant Modal as showStreamAttachmentPickerModalBottomSheet
participant Builder as AttachmentPickerBuilder (Mobile/Web)
participant Sheet as AttachmentPickerBottomSheet
App->>Modal: open(..., customOptions?, optionsBuilder?)
Note over Modal: Assert: not (customOptions && optionsBuilder)
alt optionsBuilder provided
Modal->>Builder: call with optionsBuilder
Note over Builder: build defaultOptions → optionsBuilder(context, defaultOptions)
Builder->>Builder: finalOptions = optionsBuilder(...)
else legacy path
Modal->>Builder: call with customOptions?
Note over Builder: finalOptions = (customOptions? + defaultOptions)
end
Builder->>Sheet: present(finalOptions)
Sheet-->>App: selection or dismiss
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
⏰ 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). (4)
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal). Please share your feedback with us on this Discord post. 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 |
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: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart (1)
279-282
: Null key will crash Set/hash operations
AttachmentPickerOption.hashCode
callskey.hashCode
unconditionally, butkey
is nullable. Several code paths convert lists toSet<AttachmentPickerOption>
; if a developer returns an option without a key viaoptionsBuilder
, this will throw.Make
hashCode
null-safe. This is critical given the new extension points.- @override - int get hashCode => - key.hashCode ^ const IterableEquality().hash(supportedTypes); + @override + int get hashCode => + (key?.hashCode ?? 0) ^ const IterableEquality().hash(supportedTypes);
🧹 Nitpick comments (10)
packages/stream_chat_flutter/CHANGELOG.md (1)
5-7
: Clarify mutual exclusivity and tighten wordingPlease call out that
optionsBuilder
andcustomOptions
are mutually exclusive (asserted in code) and thatoptionsBuilder
takes precedence if both are provided in release mode. Also prefer “ordering and display” over the slashed phrasing.Proposed edit:
- - Added `optionsBuilder` to `showStreamAttachmentPickerModalBottomSheet`, - `mobileAttachmentPickerBuilder`, and `webOrDesktopAttachmentPickerBuilder` - to allow full control over the attachment picker options ordering / display. + - Added `optionsBuilder` to `showStreamAttachmentPickerModalBottomSheet`, + `mobileAttachmentPickerBuilder`, and `webOrDesktopAttachmentPickerBuilder`, + allowing full control over the attachment picker options ordering and display. + Note: `optionsBuilder` and `customOptions` are mutually exclusive. If both + are supplied (e.g., in release where asserts are disabled), `optionsBuilder` + takes precedence and `customOptions` are ignored.packages/stream_chat_flutter/test/src/message_input/attachment_picker/options_builder_test.dart (4)
65-89
: Assert coverage on reordering is solid; consider adding a guard on key assumptionsThe test hard-codes
'gallery-picker'
. That's fine for stability, but if keys ever change this test will fail for unrelated reasons. Consider verifying by type (supportedTypes) as a fallback in an additional assertion.
97-114
: Typedef smoke test is fine; prefer a compile-time use site in real widget contextThis ensures the typedef compiles. If you want stronger guarantees, add a tiny widget that accepts
AttachmentPickerOptionsBuilder
and invokes it once. Not required here.
116-136
: Web/Desktop typedef test exists; add an integration test for the web/desktop builder pathYou validate the typedef, but there’s no integration case that exercises
webOrDesktopAttachmentPickerBuilder(optionsBuilder: ...)
. Adding one will guard the mapping logic introduced in the modal and the builder.Happy to draft a test that pumps a minimal app, calls
webOrDesktopAttachmentPickerBuilder
with anoptionsBuilder
that filters to a single option, and asserts the bottom sheet options and titles.
174-200
: Assertion test is good; consider documenting release-mode behaviorThis asserts the mutual exclusivity in debug. In release, both can be passed and
optionsBuilder
wins silently. Consider a doc comment or an error log to make this explicit.packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart (5)
223-231
: Docstring nit: spacing and clarityMinor grammar/punctuation issues in the typedef docs.
-/// The [defaultOptions] parameter contains the standard attachment picker -/// options(gallery, file, image, video, poll pickers). Developers can use -/// these as-is, reorder them, or combine them with custom options. +/// The [defaultOptions] parameter contains the standard attachment picker +/// options (gallery, file, image, video, poll pickers). Developers can use +/// these as-is, reorder them, or combine them with custom options.
236-244
: Docstring nit: spacingMinor spacing fix.
-/// picker options (image, video, file, poll pickers). Developers can use these -/// as-is,reorder them, or combine them with custom options. +/// picker options (image, video, file, poll pickers). Developers can use these +/// as-is, reorder them, or combine them with custom options.
915-921
: Consider reapplying allowedTypes after optionsBuilderA user-provided
optionsBuilder
can introduce options whosesupportedTypes
are not inallowedTypes
. IfallowedTypes
should be authoritative, re-filterfinalOptions
post-build. If it’s purely an advisory default and customization should override it, leave as-is, but document the precedence.- final finalOptions = optionsBuilder != null - ? optionsBuilder(context, defaultOptions).toSet() - : { - if (customOptions != null) ...customOptions, - ...defaultOptions, - }; + final built = optionsBuilder != null + ? optionsBuilder(context, defaultOptions) + : [ + if (customOptions != null) ...customOptions, + ...defaultOptions, + ]; + final finalOptions = built + .where((o) => o.supportedTypes.every(allowedTypes.contains)) + .toSet();
982-991
: Optional: enforce allowedTypes after custom builder on web/desktopSame consideration as mobile: if
allowedTypes
should remain authoritative even with a custom builder, re-filter after building the final list.- if (optionsBuilder != null) { - finalOptions = optionsBuilder(context, defaultOptions).toSet(); - } else { + if (optionsBuilder != null) { + finalOptions = optionsBuilder(context, defaultOptions) + .where((o) => o.supportedTypes.every(allowedTypes.contains)) + .toSet(); + } else { // Legacy behavior: combine custom and default options finalOptions = { if (customOptions != null) ...customOptions, ...defaultOptions, }; }
604-606
: Typo in doc commentStray character in the docstring.
- /// The callback that is called when the end of the frame is reached.x + /// The callback that is called when the end of the frame is reached.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
packages/stream_chat_flutter/CHANGELOG.md
(1 hunks)packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart
(3 hunks)packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart
(4 hunks)packages/stream_chat_flutter/test/src/message_input/attachment_picker/options_builder_test.dart
(1 hunks)
⏰ 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: stream_chat_flutter_core
- GitHub Check: stream_chat_localizations
- GitHub Check: stream_chat_persistence
- GitHub Check: stream_chat_flutter
- GitHub Check: analyze_legacy_versions
- GitHub Check: build (ios)
- GitHub Check: test
- GitHub Check: build (android)
- GitHub Check: analyze
🔇 Additional comments (10)
packages/stream_chat_flutter/test/src/message_input/attachment_picker/options_builder_test.dart (1)
22-33
: Good coverage for mobile builder happy pathThese tests validate ordering and inclusion semantics when
optionsBuilder
is provided and ensure the returned widget type. Nice.Also applies to: 34-48
packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart (2)
95-101
: Assert for mutual exclusivity: good guardThe assert preventing simultaneous
optionsBuilder
andcustomOptions
is appropriate and consistent with the builders.
171-185
: ForwardingoptionsBuilder
to the mobile path is correctPassing through
optionsBuilder
keeps behavior consistent across platforms.packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart (7)
911-913
: Confirm intended filtering semantics for compound options (gallery)
gallery-picker
supports both images and videos. Withevery(allowedTypes.contains)
, it is included only when both are allowed. If you wantgallery
shown when either images or videos are allowed (and internally restrict selection), changeevery
toany
and ensure the view enforces filtering. If the current behavior is intentional to avoid exposing disallowed media, keep as-is.Would you like me to draft a small test to lock the intended behavior and avoid regressions?
951-979
: Web/desktop default options look good and respect allowedTypesThe web/desktop defaults are localized and filtered.
996-1025
: Error handling is consistent and user-friendlyCatching errors, popping the sheet, and delegating to
onError
maintains UX and developer control.
793-910
: Mobile default option implementations: solid, with consistent error handlingThe option view builders are cohesive and consistently guard errors. Nice work.
496-575
: Options row UX logic is cleanEnablement based on
filterEnabledTypes
, selected color, and send button gating onisValueChanged
reads well.
314-358
: Equality and enablement helpers are helpful; just fix the null key hash noted aboveThe helpers reduce duplication and centralize semantics.
369-413
: Web/desktop bottom sheet list rendering is correctUsing
ListTile
and enablement by type works well with the proposed title assert.
...t_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart
Outdated
Show resolved
Hide resolved
@xsahil03x @renefloor - unsure if anything needs to be fixed here - the only CodeRabbit comment is outside of my diff and not a part of these changes. |
c022b22
to
1ef2cb5
Compare
Rebased on the tip and fixed analyze nit. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2363 +/- ##
==========================================
+ Coverage 63.76% 63.85% +0.08%
==========================================
Files 412 412
Lines 25821 25834 +13
==========================================
+ Hits 16466 16496 +30
+ Misses 9355 9338 -17 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Hey @dballance, I will review this PR this week. Can you also allow edits from maintainers if I had to do any change before merging it. |
@xsahil03x - I do not see that option in my UI for this PR. Happy to turn it on - but I just don't see it anywhere. I think it's because of this: https://github.com/orgs/community/discussions/5634 Our fork lives within our organization, so it isn't available. Best bet may be to simply copy these commits over into another branch you own. Edit: Which, to be clear, would be totally fine with me. I've signed the CLA and certainly don't require that I'm the author of these commits if the overall approach works! |
CLA
Description of the pull request
Adds
optionsBuilder
tomobileAttachmentPickerBuilder
,webOrDesktopAttachmentPickerBuilder
, andshowStreamAttachmentPickerModalBottomSheet
so that the order of the options can be fully controlled.Today, options are strictly prepended, with no option to control ordering custom options after the default options.
Screenshots
Would also allow interspersing, or putting an exact picker in an exact index location, or reversing the list, etc. Below, the red indicate dummy options interspersed with

defaultOptions
Summary by CodeRabbit
New Features
Documentation
Tests