@@ -109,6 +109,96 @@ class _ResultsTabState extends material.State<ResultsTab> {
109109 List <List <String >>? _memoEffectiveRows;
110110 List <List <String >> _cachedFilteredRows = const [];
111111 List <int >? _cachedFilteredIndices;
112+ int _filterSeq = 0 ;
113+ Timer ? _filterDebounceTimer;
114+
115+ void _onFilterChanged (String text) {
116+ if (_filterText == text) return ;
117+ _filterText = text;
118+ final effectiveRows = widget.stagingBuffer != null
119+ ? widget.stagingBuffer! .effectiveRows
120+ : widget.rows;
121+ _applyFilter (effectiveRows, widget.columns);
122+ }
123+
124+ void _onFilterClosed () {
125+ _showFilterBar = false ;
126+ _filterDebounceTimer? .cancel ();
127+ _filterSeq++ ;
128+ _filterText = '' ;
129+ final effectiveRows = widget.stagingBuffer != null
130+ ? widget.stagingBuffer! .effectiveRows
131+ : widget.rows;
132+ _memoFilterText = '' ;
133+ _memoEffectiveRows = effectiveRows;
134+ _memoColumns = widget.columns;
135+ _cachedFilteredRows = effectiveRows;
136+ _cachedFilteredIndices = null ;
137+ setState (() {});
138+ }
139+
140+ void _applyFilter (
141+ List <List <String >> effectiveRows,
142+ List <String > columns, {
143+ bool forceSyncIfSmall = true ,
144+ }) {
145+ final seq = ++ _filterSeq;
146+ _filterDebounceTimer? .cancel ();
147+
148+ if (_filterText.trim ().isEmpty) {
149+ _memoFilterText = _filterText;
150+ _memoEffectiveRows = effectiveRows;
151+ _memoColumns = columns;
152+ _cachedFilteredRows = effectiveRows;
153+ _cachedFilteredIndices = null ;
154+ if (mounted) setState (() {});
155+ return ;
156+ }
157+
158+ if (forceSyncIfSmall &&
159+ effectiveRows.length < GridFilterEngine .defaultIsolateThreshold) {
160+ final filteredIndices = GridFilterEngine .filterRowIndices (
161+ filterText: _filterText,
162+ columns: columns,
163+ rows: effectiveRows,
164+ );
165+ final isFiltered = filteredIndices.length != effectiveRows.length;
166+ final filteredRows = ! isFiltered
167+ ? effectiveRows
168+ : filteredIndices.map ((i) => effectiveRows[i]).toList ();
169+
170+ _memoFilterText = _filterText;
171+ _memoEffectiveRows = effectiveRows;
172+ _memoColumns = columns;
173+ _cachedFilteredRows = filteredRows;
174+ _cachedFilteredIndices = isFiltered ? filteredIndices : null ;
175+ if (mounted) setState (() {});
176+ return ;
177+ }
178+
179+ _filterDebounceTimer = Timer (const Duration (milliseconds: 150 ), () {
180+ unawaited (
181+ GridFilterEngine .filterRowIndicesAdaptive (
182+ filterText: _filterText,
183+ columns: columns,
184+ rows: effectiveRows,
185+ ).then ((filteredIndices) {
186+ if (! mounted || seq != _filterSeq) return ;
187+ final isFiltered = filteredIndices.length != effectiveRows.length;
188+ final filteredRows = ! isFiltered
189+ ? effectiveRows
190+ : filteredIndices.map ((i) => effectiveRows[i]).toList ();
191+ setState (() {
192+ _memoFilterText = _filterText;
193+ _memoEffectiveRows = effectiveRows;
194+ _memoColumns = columns;
195+ _cachedFilteredRows = filteredRows;
196+ _cachedFilteredIndices = isFiltered ? filteredIndices : null ;
197+ });
198+ }),
199+ );
200+ });
201+ }
112202
113203 List <List <String >> _getFilteredRows (
114204 List <List <String >> effectiveRows,
@@ -120,24 +210,35 @@ class _ResultsTabState extends material.State<ResultsTab> {
120210 return _cachedFilteredRows;
121211 }
122212
123- final filteredIndices = GridFilterEngine .filterRowIndices (
124- filterText: _filterText,
125- columns: columns,
126- rows: effectiveRows,
127- );
128-
129- final isFiltered = filteredIndices.length != effectiveRows.length;
130- final filteredRows = ! isFiltered
131- ? effectiveRows
132- : filteredIndices.map ((i) => effectiveRows[i]).toList ();
213+ if (_filterText.trim ().isEmpty) {
214+ _memoFilterText = _filterText;
215+ _memoEffectiveRows = effectiveRows;
216+ _memoColumns = columns;
217+ _cachedFilteredRows = effectiveRows;
218+ _cachedFilteredIndices = null ;
219+ return effectiveRows;
220+ }
133221
134- _memoFilterText = _filterText;
135- _memoEffectiveRows = effectiveRows;
136- _memoColumns = columns;
137- _cachedFilteredRows = filteredRows;
138- _cachedFilteredIndices = isFiltered ? filteredIndices : null ;
222+ if (effectiveRows.length < GridFilterEngine .defaultIsolateThreshold) {
223+ final filteredIndices = GridFilterEngine .filterRowIndices (
224+ filterText: _filterText,
225+ columns: columns,
226+ rows: effectiveRows,
227+ );
228+ final isFiltered = filteredIndices.length != effectiveRows.length;
229+ final filteredRows = ! isFiltered
230+ ? effectiveRows
231+ : filteredIndices.map ((i) => effectiveRows[i]).toList ();
232+ _memoFilterText = _filterText;
233+ _memoEffectiveRows = effectiveRows;
234+ _memoColumns = columns;
235+ _cachedFilteredRows = filteredRows;
236+ _cachedFilteredIndices = isFiltered ? filteredIndices : null ;
237+ return filteredRows;
238+ }
139239
140- return filteredRows;
240+ _applyFilter (effectiveRows, columns, forceSyncIfSmall: false );
241+ return _cachedFilteredRows.isNotEmpty ? _cachedFilteredRows : effectiveRows;
141242 }
142243
143244 @override
@@ -150,6 +251,22 @@ class _ResultsTabState extends material.State<ResultsTab> {
150251 void didUpdateWidget (covariant ResultsTab oldWidget) {
151252 super .didUpdateWidget (oldWidget);
152253 _syncGridBridge ();
254+ if (! identical (oldWidget.rows, widget.rows) ||
255+ ! identical (oldWidget.columns, widget.columns) ||
256+ oldWidget.stagingBuffer != widget.stagingBuffer) {
257+ final effectiveRows = widget.stagingBuffer != null
258+ ? widget.stagingBuffer! .effectiveRows
259+ : widget.rows;
260+ if (_filterText.isNotEmpty) {
261+ _applyFilter (effectiveRows, widget.columns);
262+ } else {
263+ _memoFilterText = '' ;
264+ _memoEffectiveRows = effectiveRows;
265+ _memoColumns = widget.columns;
266+ _cachedFilteredRows = effectiveRows;
267+ _cachedFilteredIndices = null ;
268+ }
269+ }
153270 }
154271
155272 void _syncGridBridge () {
@@ -247,6 +364,8 @@ class _ResultsTabState extends material.State<ResultsTab> {
247364
248365 @override
249366 void dispose () {
367+ _filterDebounceTimer? .cancel ();
368+ _filterSeq++ ;
250369 _statsDebounce? .cancel ();
251370 _statsSeq++ ;
252371 _selectedRowIndex.dispose ();
@@ -542,14 +661,11 @@ class _ResultsTabState extends material.State<ResultsTab> {
542661 expanded: _showFilterBar || _filterText.isNotEmpty,
543662 child: DataGridFilterBar (
544663 filterText: _filterText,
545- onFilterChanged: (text) => setState (() => _filterText = text) ,
664+ onFilterChanged: _onFilterChanged ,
546665 totalRowCount: effectiveRows.length,
547666 filteredRowCount: filteredRows.length,
548667 columns: widget.columns,
549- onClose: () => setState (() {
550- _showFilterBar = false ;
551- _filterText = '' ;
552- }),
668+ onClose: _onFilterClosed,
553669 ),
554670 ),
555671
0 commit comments