Skip to content

feat(core): dynamic search debounce based on query length - #2873

Open
xsahil03x wants to merge 1 commit into
masterfrom
sahil/flu-684-dynamic-search-debounce-based-on-query-length
Open

feat(core): dynamic search debounce based on query length#2873
xsahil03x wants to merge 1 commit into
masterfrom
sahil/flu-684-dynamic-search-debounce-based-on-query-length

Conversation

@xsahil03x

@xsahil03x xsahil03x commented Aug 7, 2026

Copy link
Copy Markdown
Member

🎯 Goal

Short search queries (1–2 characters) are low-selectivity and expensive on the backend, causing high latency and timeouts on the search / queryChannels / queryMembers endpoints. This adapts the debounce interval to the query length: short queries wait longer before hitting the backend; longer, more selective queries use the standard delay.

Linear: FLU-684 · cross-SDK initiative, iOS reference: GetStream/stream-chat-swift#4198.

📝 What changed

  • stream_chat_flutter_core: added a search() method to StreamMessageSearchListController, StreamUserListController, and StreamMemberListController.
    • Debounce adapts to query length — 500ms for ≤2 chars, 300ms for 3+ (kept internal, matching iOS).
    • Results from superseded queries are dropped, so a slower, older query can't overwrite a newer one.
    • cancelSearch() cancels a pending search when the input is cleared.
    • Reuses rate_limiter's debounce (two instances picked by length); no hand-rolled Timer.
  • sample_app: migrated the four hand-rolled 350ms Timer search sites (channel list, add-members, new chat, new group) to search().

✅ Non-breaking

Purely additive — new methods only. No existing signatures, defaults, or exports changed; no LLC changes. doInitialLoad gains a "newest-wins" guard (fixes an overlapping-load race; single-load behavior is unchanged).

🚫 Out of scope (follow-ups)

  • Channel-name search (StreamChannelListController's filter is constructor-only; not wired as text search in Flutter).
  • Mention autocomplete (separate UI surface, already 300ms-debounced).
  • Cancelling in-flight HTTP requests (matches the iOS PR's scope).

🧪 Testing

New: search_debouncer_test.dart + controller tests for message/user/member search (debounce timing, length policy, superseded-result guard, cancelSearch). Full stream_chat_flutter_core suite: 345 passing. Analyze clean, formatted.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added debounced search for users, members, and messages.
    • Added support for clearing search results and canceling pending searches.
    • Search results now prioritize the latest query and ignore outdated responses.
    • Added query-length-aware search timing for responsive results.
  • Bug Fixes

    • Prevented slower or superseded requests from overwriting newer results.
    • Improved behavior when clearing results during active searches or pagination.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Added adaptive debounced search and clearResults() support to member, message, and user list controllers. Generation tracking discards stale loads. Sample search widgets now call controller search methods directly.

Changes

Adaptive search and stale-load handling

Layer / File(s) Summary
Search scheduling infrastructure
packages/stream_chat_flutter_core/lib/src/search_debouncer.dart, packages/stream_chat_flutter_core/lib/src/search_debounce_mixin.dart, packages/stream_chat_flutter_core/pubspec.yaml, packages/stream_chat_flutter_core/test/search_debouncer_test.dart
Added adaptive 500 ms and 300 ms debounce delays, cancellation, pending-state detection, generation tracking, disposal cleanup, and asynchronous tests.
Controller search integration
packages/stream_chat_flutter_core/lib/src/stream_member_list_controller.dart, packages/stream_chat_flutter_core/lib/src/stream_message_search_list_controller.dart, packages/stream_chat_flutter_core/lib/src/stream_user_list_controller.dart, packages/stream_chat_flutter_core/CHANGELOG.md
Added debounced search() methods. Initial and paginated loads now ignore stale results and errors after newer searches or result resets.
Controller concurrency validation
packages/stream_chat_flutter_core/test/stream_member_list_controller_test.dart, packages/stream_chat_flutter_core/test/stream_message_search_list_controller_test.dart, packages/stream_chat_flutter_core/test/stream_user_list_controller_test.dart
Added tests for search filters, pending-load suppression, stale responses and errors, pagination, cancellation, and result clearing.
Sample application search wiring
sample_app/lib/pages/new_chat_screen.dart, sample_app/lib/pages/new_group_chat_screen.dart, sample_app/lib/widgets/add_members_sheet.dart, sample_app/lib/widgets/channel_list.dart
Removed local debounce timers. Search inputs now call controller methods directly and clear empty channel queries.

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

Sequence Diagram(s)

sequenceDiagram
  participant SearchInput
  participant StreamUserListController
  participant SearchDebounceMixin
  participant StreamChatClient
  SearchInput->>StreamUserListController: search(query, filter)
  StreamUserListController->>SearchDebounceMixin: schedule adaptive debounce
  SearchDebounceMixin->>StreamUserListController: start current load generation
  StreamUserListController->>StreamChatClient: request filtered users
  StreamChatClient-->>StreamUserListController: return results or error
  StreamUserListController-->>SearchInput: apply only non-stale state
Loading
🚥 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 clearly summarizes the primary change: query-length-based dynamic search debouncing in the core package.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sahil/flu-684-dynamic-search-debounce-based-on-query-length

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.

@xsahil03x
xsahil03x force-pushed the sahil/flu-684-dynamic-search-debounce-based-on-query-length branch 7 times, most recently from c289e72 to ced5307 Compare August 7, 2026 13:27
Add query-length-aware debounced search() to StreamMessageSearchListController,
StreamUserListController, and StreamMemberListController. Short (<=2 char),
low-selectivity queries wait 500ms before hitting the backend; longer queries
use the standard 300ms. Results from superseded queries are dropped so a slower,
older query cannot overwrite a newer one. Adds cancelSearch() to cancel a
pending search when the input is cleared.

Migrates the sample app's four hand-rolled 350ms Timer search sites to search().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@xsahil03x
xsahil03x force-pushed the sahil/flu-684-dynamic-search-debounce-based-on-query-length branch from ced5307 to 4b44e5e Compare August 7, 2026 13:36
@xsahil03x
xsahil03x marked this pull request as ready for review August 7, 2026 13:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/stream_chat_flutter_core/lib/src/search_debounce_mixin.dart`:
- Around line 76-80: Add a Dart doc comment directly above the dispose override
in the debounce mixin, documenting that dispose cancels pending debounced
searches before completing disposal. Keep the existing _searchDebouncer.cancel()
and super.dispose() behavior unchanged.
- Around line 45-55: Update clearResults() to describe invalidating pending and
in-flight searches rather than claiming it cancels them. Keep
_searchDebouncer.cancel() for pending work and retain the _loadGeneration
increment so responses from already-issued requests are discarded.
- Line 35: Update debouncedSearch to increment _loadGeneration before invoking
_searchDebouncer, invalidating any in-flight request as soon as a new query is
scheduled. Add a regression test covering an older request completing during the
newer query’s debounce interval and verify its results are not applied.

In `@packages/stream_chat_flutter_core/pubspec.yaml`:
- Line 33: Remove the direct rate_limiter version constraint from the package
dependency list, and add or update its workspace-managed dependency entry in
melos.yaml. Then run melos bootstrap to synchronize the package manifest without
manually restoring the constraint in pubspec.yaml.

In `@sample_app/lib/widgets/channel_list.dart`:
- Around line 37-41: Add a dispose override to the State class containing
_channelQueryListener and call _messageSearchListController.dispose() before
disposing the remaining controllers, preserving the existing disposal order for
those controllers.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f280d84-1574-42cc-8ca9-d0a42e891840

📥 Commits

Reviewing files that changed from the base of the PR and between 4b4c2ae and 4b44e5e.

📒 Files selected for processing (15)
  • packages/stream_chat_flutter_core/CHANGELOG.md
  • packages/stream_chat_flutter_core/lib/src/search_debounce_mixin.dart
  • packages/stream_chat_flutter_core/lib/src/search_debouncer.dart
  • packages/stream_chat_flutter_core/lib/src/stream_member_list_controller.dart
  • packages/stream_chat_flutter_core/lib/src/stream_message_search_list_controller.dart
  • packages/stream_chat_flutter_core/lib/src/stream_user_list_controller.dart
  • packages/stream_chat_flutter_core/pubspec.yaml
  • packages/stream_chat_flutter_core/test/search_debouncer_test.dart
  • packages/stream_chat_flutter_core/test/stream_member_list_controller_test.dart
  • packages/stream_chat_flutter_core/test/stream_message_search_list_controller_test.dart
  • packages/stream_chat_flutter_core/test/stream_user_list_controller_test.dart
  • sample_app/lib/pages/new_chat_screen.dart
  • sample_app/lib/pages/new_group_chat_screen.dart
  • sample_app/lib/widgets/add_members_sheet.dart
  • sample_app/lib/widgets/channel_list.dart


/// Schedules a debounced reload whose delay adapts to [queryLength].
@internal
void debouncedSearch(int queryLength) => _searchDebouncer(queryLength);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Invalidate active loads when scheduling a new search.

debouncedSearch does not change _loadGeneration. If request A is in flight and query B is scheduled, request A can complete during B's 300 ms or 500 ms delay. Its isStale(generation) check then passes and applies results for the superseded query.

Increment the generation before scheduling the debounce. Add a regression test where an old request completes while a newer query is pending.

Proposed fix
-  void debouncedSearch(int queryLength) => _searchDebouncer(queryLength);
+  void debouncedSearch(int queryLength) {
+    _loadGeneration += 1;
+    _searchDebouncer(queryLength);
+  }
📝 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.

Suggested change
void debouncedSearch(int queryLength) => _searchDebouncer(queryLength);
void debouncedSearch(int queryLength) {
_loadGeneration += 1;
_searchDebouncer(queryLength);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter_core/lib/src/search_debounce_mixin.dart` at line
35, Update debouncedSearch to increment _loadGeneration before invoking
_searchDebouncer, invalidating any in-flight request as soon as a new query is
scheduled. Add a regression test covering an older request completing during the
newer query’s debounce interval and verify its results are not applied.

Comment on lines +45 to +55
/// Cancels any pending or in-flight search and clears the current results.
///
/// Consider calling this when the search input is emptied, so results for an
/// abandoned query are neither shown nor repopulated by a late response.
void clearResults() {
_searchDebouncer.cancel();
// Bump the generation so an already-running load is treated as superseded
// and cannot repopulate the cleared results when its response arrives.
_loadGeneration += 1;
value = PagedValue<Key, Value>.loading();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe invalidation instead of in-flight cancellation.

_searchDebouncer.cancel() only cancels a pending timer. It does not cancel an already-issued controller request. The generation increment discards its response.

Proposed fix
-  /// Cancels any pending or in-flight search and clears the current results.
+  /// Cancels any pending search, invalidates in-flight loads, and clears the
+  /// current results.
📝 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.

Suggested change
/// Cancels any pending or in-flight search and clears the current results.
///
/// Consider calling this when the search input is emptied, so results for an
/// abandoned query are neither shown nor repopulated by a late response.
void clearResults() {
_searchDebouncer.cancel();
// Bump the generation so an already-running load is treated as superseded
// and cannot repopulate the cleared results when its response arrives.
_loadGeneration += 1;
value = PagedValue<Key, Value>.loading();
}
/// Cancels any pending search, invalidates in-flight loads, and clears the
/// current results.
///
/// Consider calling this when the search input is emptied, so results for an
/// abandoned query are neither shown nor repopulated by a late response.
void clearResults() {
_searchDebouncer.cancel();
// Bump the generation so an already-running load is treated as superseded
// and cannot repopulate the cleared results when its response arrives.
_loadGeneration += 1;
value = PagedValue<Key, Value>.loading();
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter_core/lib/src/search_debounce_mixin.dart` around
lines 45 - 55, Update clearResults() to describe invalidating pending and
in-flight searches rather than claiming it cancels them. Keep
_searchDebouncer.cancel() for pending work and retain the _loadGeneration
increment so responses from already-issued requests are discarded.

Comment on lines +76 to +80
@override
void dispose() {
_searchDebouncer.cancel();
super.dispose();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a doc comment for dispose.

dispose is a public override. Document that it cancels pending debounced searches before disposal.

As per coding guidelines, “All public APIs must have doc comments.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter_core/lib/src/search_debounce_mixin.dart` around
lines 76 - 80, Add a Dart doc comment directly above the dispose override in the
debounce mixin, documenting that dispose cancels pending debounced searches
before completing disposal. Keep the existing _searchDebouncer.cancel() and
super.dispose() behavior unchanged.

Source: Coding guidelines

freezed_annotation: ^3.0.0
meta: ^1.9.1
package_info_plus: ">=9.0.1 <11.0.0"
rate_limiter: ^1.0.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Manage rate_limiter through melos.yaml.

Remove this direct constraint. Add or update the workspace dependency in melos.yaml, then run melos bootstrap.

As per coding guidelines, “Do not edit version constraints directly in individual pubspec.yaml files; update melos.yaml instead and run melos bootstrap.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stream_chat_flutter_core/pubspec.yaml` at line 33, Remove the direct
rate_limiter version constraint from the package dependency list, and add or
update its workspace-managed dependency entry in melos.yaml. Then run melos
bootstrap to synchronize the package manifest without manually restoring the
constraint in pubspec.yaml.

Source: Coding guidelines

Comment on lines 37 to +41
void _channelQueryListener() {
if (_debounce?.isActive ?? false) _debounce!.cancel();
_debounce = Timer(const Duration(milliseconds: 350), () {
if (mounted) {
_messageSearchListController.searchQuery = _controller.text;
setState(() {
_isSearchActive = _controller.text.isNotEmpty;
});
if (_isSearchActive) _messageSearchListController.doInitialLoad();
}
});
final query = _controller.text;
setState(() => _isSearchActive = query.isNotEmpty);
if (query.isEmpty) return _messageSearchListController.clearResults();
return _messageSearchListController.search(query);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate file =="
git ls-files | rg '(^|/)channel_list\.dart$' || true

echo "== File excerpt =="
file=$(git ls-files | rg '(^|/)channel_list\.dart$' | head -n1)
if [ -n "${file:-}" ]; then
  wc -l "$file"
  sed -n '1,120p' "$file" | cat -n
fi

echo "== Search for _messageSearchListController declarations/usages =="
rg -n "_messageSearchListController|class .*MessageSearchList|dispose\(\)" sample_app lib . --glob '*.dart' | head -n 200 || true

Repository: GetStream/stream-chat-flutter

Length of output: 1947


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Repository availability =="
pwd
git status --short || true

echo "== Locate file =="
git ls-files | rg '(^|/)channel_list\.dart$' || true

echo "== File excerpt =="
file=$(git ls-files | rg '(^|/)channel_list\.dart$' | head -n1)
if [ -n "${file:-}" ]; then
  wc -l "$file"
  sed -n '1,120p' "$file" | cat -n
fi

echo "== Search for _messageSearchListController declarations/usages =="
rg -n "_messageSearchListController|class .*MessageSearchList|dispose\(\)" sample_app lib . --glob '*.dart' | head -n 200 || true

Repository: GetStream/stream-chat-flutter

Length of output: 1947


🏁 Script executed:

#!/bin/bash
set -u

echo "== Repository availability =="
pwd
git status --short 2>/dev/null || true

echo "== Locate file =="
git ls-files 2>/dev/null | rg '(^|/)channel_list\.dart$' || true

echo "== File excerpt =="
file=$(git ls-files 2>/dev/null | rg '(^|/)channel_list\.dart$' | head -n1 || true)
if [ -n "${file:-}" ] && [ -f "$file" ]; then
  wc -l "$file"
  sed -n '1,140p' "$file" | cat -n
fi

echo "== Search for _messageSearchListController declarations/usages =="
rg -n "_messageSearchListController|MessageSearchList|dispose\(\)" . 2>/dev/null --glob '*.dart' | head -n 200 || true

Repository: GetStream/stream-chat-flutter

Length of output: 1947


🏁 Script executed:

#!/bin/bash
set -u

echo "== Repository availability =="
echo "PWD: $PWD"
git status --short >/tmp/ws_git_status.txt 2>&1 || true
cat /tmp/ws_git_status.txt || true

echo "== Git files availability =="
git ls-files >/tmp/ws_ls_files.txt 2>&1 || true
cat /tmp/ws_ls_files.txt | rg '(^|/)channel_list\.dart$' || true

echo "== List matching path =="
test -f sample_app/lib/widgets/channel_list.dart && echo "exists" || echo "missing"
test -f sample_app/lib/widgets/channel_list.dart && wc -n sample_app/lib/widgets/channel_list.dart || true

Repository: GetStream/stream-chat-flutter

Length of output: 1947


🌐 Web query:

GetStream stream-chat-flutter sample_app lib widgets channel_list.dart _messageSearchListController dispose

💡 Result:

In the Stream Chat Flutter SDK, the StreamMessageSearchListController is a controller class used to manage cross-channel message search operations, including pagination, filtering, and state management [1][2]. When using this controller within a StatefulWidget, it is essential to properly manage its lifecycle to avoid memory leaks [1][2][3]. The dispose method must be called when the controller is no longer needed [1][2]. The implementation pattern for disposing of the StreamMessageSearchListController is as follows: @override void dispose { messageSearchListController.dispose; super.dispose; } This ensures that any resources, such as stream subscriptions or internal state, used by the controller are correctly discarded [4]. While sample applications (such as the one found in the Stream Chat Flutter repository) often utilize StreamChannelListController for managing channel lists, the requirement to explicitly dispose of controllers remains a best practice across the SDK for any controller you instantiate within your widget's state [5][1][2].

Citations:


🌐 Web query:

site:github.com/GetStream/stream-chat-flutter sample_app lib widgets channel_list.dart StreamMessageSearchListController

💡 Result:

StreamMessageSearchListController is a controller class provided by the stream_chat_flutter_core package, which is part of the official GetStream Flutter SDK [1]. It is designed to handle the business logic for searching messages within the Stream Chat infrastructure, allowing developers to build custom search interfaces without interacting with low-level API code [1]. Key aspects of StreamMessageSearchListController include: Role and Usage: The controller is intended to be used in conjunction with the SDK's UI components or for building custom UI widgets [1]. It manages the state and logic for message search queries, including filters, sorting, and pagination [2][3]. Implementation Details: Developers typically instantiate this controller by providing a StreamChatClient and relevant search filters (e.g., filtering by channel, text content, or pinned status) [2][4]. While it simplifies building search features, developers should be aware that the underlying search functionality performs full-text search, not fuzzy search, by design [3]. Context in Sample Apps: While specific file paths like channel_list.dart can vary by implementation, the controller is central to features that require listing and searching message content [1][5]. In common patterns, it is paired with view components such as StreamMessageSearchListView to display the resulting data [6][7]. Technical Considerations: Users of this controller have reported nuances regarding pagination, sorting, and filter application in complex or high-volume datasets [2][7]. When implementing search features, developers are encouraged to review the official Stream Chat Flutter documentation for the latest best practices on query parameters and pagination configuration [7][3].

Citations:


🌐 Web query:

github.com GetStream stream-chat-flutter package stream_chat_flutter_core StreamMessageSearchListController dispose

💡 Result:

In the Stream Chat Flutter SDK, the StreamMessageSearchListController provides a dispose method designed to discard resources held by the controller when it is no longer needed [1][2]. To manage the lifecycle of the StreamMessageSearchListController correctly, you should call its dispose method within the dispose override of your State class. This prevents memory leaks by cleaning up the controller and its associated resources [3][4][5]. Recommended implementation pattern: @override void dispose { // Replace 'messageSearchListController' with your specific instance name messageSearchListController.dispose; super.dispose; } It is also standard practice to call doInitialLoad during the initState of your State class to begin fetching initial search data [3][4][6]. The controller is a subclass of PagedValueNotifier, which allows you to listen to state changes regarding the list of searched messages [5][6].

Citations:


🌐 Web query:

github.com GetStream/stream-chat-flutter/blob/master/sample_app/lib/widgets/channel_list.dart 37-41 _messageSearchListController

💡 Result:

The StreamMessageSearchListController in the GetStream stream-chat-flutter SDK is a controller class used to manage search queries, pagination, and result states for cross-channel message searching [1]. It is designed to be used in conjunction with the StreamMessageSearchListView widget to render search results, though it can also be used independently to build custom search UIs [1]. Key characteristics and usage requirements for StreamMessageSearchListController include: Controller Initialization: You must initialize the controller with a StreamChatClient instance and optionally a filter (typically to scope the search to channels the current user is a member of) [2][1]. Search Configuration: The controller requires exactly one of either searchQuery (a string for full-text search) or messageFilter (a Filter object for structured searching); providing both or neither will result in an assertion error [2]. Lifecycle Management: As with other controllers in the SDK, you must call doInitialLoad to trigger the first data fetch and ensure that dispose is called when the controller is no longer needed to prevent memory leaks [2][1]. Underlying Architecture: It functions as a PagedValueNotifier, which allows you to track changes in the search results and build reactive UIs using components like PagedValueListenableBuilder [1]. In the context of the GetStream sample application, this controller is utilized to enable the message search functionality across channels, distinguishing it from components like StreamChannelListController, which manage lists of channels rather than searching for specific message content [3][1].

Citations:


Dispose _messageSearchListController.

_messageSearchListController is created in State, so dispose() should call _messageSearchListController.dispose() before the remaining controller disposal order. This prevents leaking search-controller resources when the widget is removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sample_app/lib/widgets/channel_list.dart` around lines 37 - 41, Add a dispose
override to the State class containing _channelQueryListener and call
_messageSearchListController.dispose() before disposing the remaining
controllers, preserving the existing disposal order for those controllers.

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.61194% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.41%. Comparing base (4b4c2ae) to head (4b44e5e).

Files with missing lines Patch % Lines
...er_core/lib/src/stream_member_list_controller.dart 50.00% 6 Missing ⚠️
...lib/src/stream_message_search_list_controller.dart 50.00% 6 Missing ⚠️
...tter_core/lib/src/stream_user_list_controller.dart 75.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2873      +/-   ##
==========================================
+ Coverage   73.18%   73.41%   +0.23%     
==========================================
  Files         429      431       +2     
  Lines       27724    27791      +67     
==========================================
+ Hits        20289    20403     +114     
+ Misses       7435     7388      -47     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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