Skip to content

Commit f412be0

Browse files
feat: ✨ Add Search Debounce Option in ChatViewList (#369)
1 parent c0a1c28 commit f412be0

File tree

6 files changed

+31
-12
lines changed

6 files changed

+31
-12
lines changed

example/lib/chat_view_list_screen.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class _ChatViewListScreenState extends State<ChatViewListScreen> {
9696
),
9797
searchConfig: SearchConfig(
9898
textEditingController: _searchController,
99+
debounceDuration: const Duration(milliseconds: 300),
99100
border: const OutlineInputBorder(
100101
borderRadius: BorderRadius.all(Radius.circular(10)),
101102
),

lib/src/controller/chat_list_view_controller.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ class ChatViewListController {
5454
if (initialChatList[i] case final chat) chat.id: chat,
5555
};
5656

57-
chatListMap = chatsMap;
57+
chatListMap
58+
..clear()
59+
..addAll(chatsMap);
5860

5961
// Adds the current chat map to the stream controller
6062
// after the first frame render.
@@ -67,10 +69,10 @@ class ChatViewListController {
6769
/// Stores and manages chat items by their unique IDs.
6870
/// A map is used for efficient lookup, update, and removal of chats
6971
/// by their unique id.
70-
Map<String, ChatViewListItem> chatListMap = {};
72+
final Map<String, ChatViewListItem> chatListMap = {};
7173

7274
/// Provides scroll controller for chat list.
73-
ScrollController scrollController;
75+
final ScrollController scrollController;
7476

7577
final bool disposeOtherResources;
7678

lib/src/models/config_models/chat_view_list/search_config.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class SearchConfig {
5252
this.border,
5353
this.suffixIcon,
5454
this.onSearch,
55+
this.debounceDuration,
5556
this.decoration,
5657
this.maxLength,
5758
});
@@ -122,6 +123,9 @@ class SearchConfig {
122123
/// Callback function that is called when the search text changes.
123124
final SearchUserCallback? onSearch;
124125

126+
/// Duration to debounce the search callback.
127+
final Duration? debounceDuration;
128+
125129
/// Decoration for the search text field.
126130
final InputDecoration? decoration;
127131

lib/src/utils/debounce.dart

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,17 @@ import 'dart:async';
2525
import 'package:flutter/material.dart';
2626

2727
class Debouncer {
28-
Timer? _debounce;
29-
Duration duration;
30-
3128
Debouncer(this.duration);
3229

33-
void run(VoidCallback callbackAfterTimeLapsed,
34-
VoidCallback callbackBeforeTimeLapsed) {
30+
final Duration duration;
31+
Timer? _debounce;
32+
33+
void run({required VoidCallback onComplete, VoidCallback? onInterrupt}) {
3534
if (_debounce?.isActive ?? false) {
36-
callbackBeforeTimeLapsed();
35+
onInterrupt?.call();
3736
_debounce?.cancel();
3837
}
39-
_debounce = Timer(duration, callbackAfterTimeLapsed);
38+
_debounce = Timer(duration, onComplete);
4039
}
4140

4241
void dispose() {

lib/src/widgets/chat_view_list/search_text_field.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import 'package:flutter/material.dart';
2525

2626
import '../../controller/chat_list_view_controller.dart';
2727
import '../../models/config_models/chat_view_list/search_config.dart';
28+
import '../../utils/debounce.dart';
2829
import '../../utils/package_strings.dart';
2930

3031
class SearchTextField extends StatefulWidget {
@@ -50,6 +51,10 @@ class SearchTextField extends StatefulWidget {
5051
class _SearchTextFieldState extends State<SearchTextField> {
5152
final ValueNotifier<String> _inputText = ValueNotifier('');
5253

54+
late final _debouncer = _config.debounceDuration == null
55+
? null
56+
: Debouncer(_config.debounceDuration!);
57+
5358
SearchConfig get _config => widget.config;
5459

5560
InputBorder get _outlineBorder =>
@@ -121,6 +126,14 @@ class _SearchTextFieldState extends State<SearchTextField> {
121126

122127
FutureOr<void> _onSearchChanged(String value) async {
123128
_inputText.value = value;
129+
if (_debouncer != null) {
130+
_debouncer.run(onComplete: () => _performSearch(value));
131+
} else {
132+
await _performSearch(value);
133+
}
134+
}
135+
136+
FutureOr<void> _performSearch(String value) async {
124137
final chatList = await _config.onSearch?.call(value);
125138
if (chatList != null) {
126139
widget.chatViewListController?.setSearchChats(chatList);

lib/src/widgets/chatui_textfield.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,9 +444,9 @@ class _ChatUITextFieldState extends State<ChatUITextField> {
444444
}
445445

446446
void _onChanged(String inputText) {
447-
debouncer.run(() {
447+
debouncer.run(onComplete: () {
448448
composingStatus.value = TypeWriterStatus.typed;
449-
}, () {
449+
}, onInterrupt: () {
450450
composingStatus.value = TypeWriterStatus.typing;
451451
});
452452
_inputText.value = inputText;

0 commit comments

Comments
 (0)