Skip to content

Feat #168: implement search query field with generic type refactor#173

Merged
koukibadr merged 1 commit into
mainfrom
feat#168-implement-search-query-field
Jul 4, 2026
Merged

Feat #168: implement search query field with generic type refactor#173
koukibadr merged 1 commit into
mainfrom
feat#168-implement-search-query-field

Conversation

@koukibadr

@koukibadr koukibadr commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added searchable item picking with custom item rendering and improved matching for names or IDs.
    • Expanded the example app with a larger sample list and updated picker interactions.
  • Bug Fixes

    • Improved picker type handling so selections, submit actions, and dismiss actions return the expected values.
    • Updated the simple picker to feel more consistent on mobile platforms.
  • Chores

    • Updated the example app’s supported Flutter/Dart version.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@koukibadr, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 62119381-c0d4-42a0-ac00-3eb9017a0df1

📥 Commits

Reviewing files that changed from the base of the PR and between e9fc87c and 1be9cd1.

⛔ Files ignored due to path filters (1)
  • example/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • example/lib/country_data.dart
  • example/lib/main.dart
  • example/pubspec.yaml
  • lib/bottom_picker.dart
  • lib/widgets/simple_picker.dart
  • test/simple_bottom_picker_test.dart
📝 Walkthrough

Walkthrough

BottomPicker and its state class are converted to generic types parameterized by item type T, adding search/filter UI support via new fields (itemBuilder, filterPredicate, textInputAction, searchFieldDecoration) and typed callback dispatch. SimplePicker disables the CupertinoPicker magnifier. The example app is updated to use a new CountryModel dataset with StatefulWidget conversions and typed picker calls, and the SDK constraint is raised.

Changes

Generic typed BottomPicker with search filtering

Layer / File(s) Summary
BottomPicker generic type surface and constructor params
lib/bottom_picker.dart
Widget becomes BottomPicker<T> with new constructor params (itemBuilder, filterPredicate, textInputAction, searchFieldDecoration) and typed public fields for items/callbacks.
BottomPickerState typed selection, filtering UI, and dispatch
lib/bottom_picker.dart
State becomes generic, renders a filter TextField and itemBuilder-based rows, disables onChange for non-simple types, and dispatches typed values on dismiss/submit.
SimplePicker magnifier setting
lib/widgets/simple_picker.dart
CupertinoPicker explicitly sets useMagnifier: false.
Example CountryModel dataset
example/lib/country_data.dart
Adds CountryModel class and a hardcoded countryList of 19 entries.
Example app widgets converted to StatefulWidget and typed picker usage
example/lib/main.dart
MyApp/ExampleApp become StatefulWidgets; imports shared country data; updates _openSimpleItemPicker to use BottomPicker<CountryModel> with id/name filtering, and updates _displayLongListPicker header/callbacks.
Example app cosmetic formatting and SDK bump
example/lib/main.dart, example/pubspec.yaml
Consolidates TextStyle/Duration/Time/gradientColors expressions to single-line forms and raises SDK constraint to >=3.10.0 <4.0.0.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant BottomPickerState
  participant SimplePicker
  User->>BottomPickerState: type text into search TextField
  BottomPickerState->>BottomPickerState: filterPredicate(item, text) filters originalItemList
  BottomPickerState->>SimplePicker: build rows from displayedItemList via itemBuilder
  User->>SimplePicker: select item
  SimplePicker->>BottomPickerState: onChange updates selectedItem
  User->>BottomPickerState: submit or dismiss
  BottomPickerState->>BottomPickerState: onSubmit/onDismiss dispatched with typed selectedItem as T
Loading

Poem

A rabbit hops through generic burrows deep,
Typed carrots (T) now filtered while I peep,
No magnifier glass to blur my view,
Countries listed, Atlantis and Narnia too,
Search field twitching, whiskers set to sort —
Hop hop hooray for this typed-up port! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: a new search field plus a generic refactor of the picker API.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
example/lib/main.dart (1)

245-292: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Misleading parameter name in onChange callback.

onChange: (int index) { print(index); } names the parameter index, but per the generic BottomPicker<T> contract the callback actually receives the selected item value, not its position in the list. It only looks correct here because hugeList[i] == i. Naming it value/item would avoid confusing readers about the new generic callback semantics this PR introduces.

✏️ Suggested rename
-      onChange: (int index) {
-        print(index);
+      onChange: (int value) {
+        print(value);
       },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@example/lib/main.dart` around lines 245 - 292, The `onChange` callback in
`_displayLongListPicker` uses a misleading parameter name: it receives the
selected item value from `BottomPicker<int>`, not the item’s position. Rename
the callback parameter from `index` to something like `item` or `value` in this
method so it matches the generic `BottomPicker<T>` contract and avoids confusion
with the separate list index used elsewhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@example/lib/main.dart`:
- Around line 15-49: The ExampleApp state still carries dead state in the
_ExampleAppState class: the displayedList field is initialized from hugeList but
is never read or updated now that search/filtering is handled inside
BottomPicker and BottomPickerState. Remove the unused displayedList member from
_ExampleAppState and keep the state focused on the active fields such as
buttonWidth and hugeList.

In `@lib/bottom_picker.dart`:
- Around line 793-797: The dismiss callback in dispose() is still casting
timer/dateTime values to T, which can break BottomPicker<String>.timer(...) and
.dateTime(...) at runtime. Update the BottomPicker API so non-simple modes
cannot use an incompatible generic type: either make the timer and dateTime
constructors non-generic, or split the callback/value types so dispose() calls
onDismiss with the correct concrete type without any cast. Use the
BottomPickerType branching in bottom_picker.dart to locate the fix.
- Line 916: The non-simple picker handlers are no longer emitting updates
because the widget.onChange callback is commented out, while the API still
implies DateTime/int change notifications. Restore the typed onChange calls in
the timer, time, dateTime, and year picker flow where widget.onChange is used,
or if this behavior is intentional, update the widget.onChange contract and
related docs/comments to match the new behavior. Use the existing
widget.onChange references in BottomPicker to locate and re-enable the correct
callback emissions.
- Line 901: The initial picker index passed from SimplePicker is using
widget.selectedItemIndex directly even when displayedItemList has been filtered
and may be shorter. Update the SimplePicker initialization logic to derive the
index from the filtered list, using the matching item’s position or 0 when there
are no matches, so FixedExtentScrollController.initialItem always stays within
range and picker setup works for empty-filter cases.
- Around line 756-760: Initialize the timer state in initState for the
BottomPickerType.timer path so selectedTimerDuration is set from
widget.initialTimerDuration before any user interaction. Update the
BottomPickerState.initState logic alongside the existing simple and date/time
branches, and make sure dispose and the submit flow use this initialized value
instead of dispatching a null selectedTimerDuration when the wheel was never
touched.
- Around line 887-899: The picker row builder is re-deriving the original index
with originalItemList!.indexOf(item), which is both O(n) per row and incorrect
for duplicate values. Update the displayedItemList mapping in the bottom picker
widget so each row carries its original index alongside the item, and use that
preserved index in widget.itemBuilder and in onChange instead of searching
originalItemList. Keep the fix localized to the picker list-building logic and
the selectedItemIndex assignment in BottomPicker.

---

Outside diff comments:
In `@example/lib/main.dart`:
- Around line 245-292: The `onChange` callback in `_displayLongListPicker` uses
a misleading parameter name: it receives the selected item value from
`BottomPicker<int>`, not the item’s position. Rename the callback parameter from
`index` to something like `item` or `value` in this method so it matches the
generic `BottomPicker<T>` contract and avoids confusion with the separate list
index used elsewhere.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: af242c7c-2b7d-4172-baf7-f616fd09be55

📥 Commits

Reviewing files that changed from the base of the PR and between 12a54a4 and e9fc87c.

⛔ Files ignored due to path filters (1)
  • example/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • example/lib/country_data.dart
  • example/lib/main.dart
  • example/pubspec.yaml
  • lib/bottom_picker.dart
  • lib/widgets/simple_picker.dart

Comment thread example/lib/main.dart Outdated
Comment thread lib/bottom_picker.dart
Comment thread lib/bottom_picker.dart
Comment thread lib/bottom_picker.dart Outdated
Comment thread lib/bottom_picker.dart
Comment thread lib/bottom_picker.dart Outdated
@koukibadr koukibadr force-pushed the feat#168-implement-search-query-field branch from 00ed027 to 1be9cd1 Compare July 4, 2026 09:26
@koukibadr koukibadr merged commit 3ebcd67 into main Jul 4, 2026
5 checks passed
@koukibadr koukibadr deleted the feat#168-implement-search-query-field branch July 4, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant