Skip to content

Commit 85d103a

Browse files
committed
feat: enhance ThemedTable2 with widget tests and performance improvements; remove debug prints
1 parent eb68032 commit 85d103a

4 files changed

Lines changed: 476 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
- Fixed `ThemedTable2` unsendable closure crash: sort keys are now precomputed on the main thread before `compute()`, ensuring `valueBuilder` closures that capture `BuildContext` or `i18n` objects never cross the isolate boundary.
88
- Improved `ThemedTable2` multiselect performance: introduced an internal `Set<T>` mirroring `_selectedItems` for O(1) `contains()` lookups instead of O(n) on the backing `List<T>`.
99
- Improved `ThemedTable2` `didUpdateWidget` performance: replaced `DeepCollectionEquality` (O(n)) with a fast O(1) heuristic using `identical` + length check.
10+
- Removed all `debugPrint` statements from `ThemedTable2._filterAndSort` (startup, precompute, sort, finish, queue logs).
11+
- Added widget tests for `ThemedTable2` covering: renders item values after compute completes, shows loading indicator while computing, renders without errors on empty dataset, column key collision regression (two columns with identical `headerText` show distinct data), search filters by matching query, search matches values from all columns, search restores all items when cleared, `controller.sort` ascending (A→Z), `controller.sort` descending (Z→A), numeric sort as numbers not strings, `controller.refresh` preserves sort order, `didUpdateWidget` reflects new items on rebuild, `didUpdateWidget` handles growing list without losing existing rows.
1012
- Add `ThemedTable2` skill.
1113

1214
## 7.5.21

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ packages:
390390
path: ".."
391391
relative: true
392392
source: path
393-
version: "7.5.21"
393+
version: "7.5.22"
394394
leak_tracker:
395395
dependency: transitive
396396
description:

lib/src/table2/src/table.dart

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,10 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
236236
}
237237

238238
Future<void> _filterAndSort(String source) async {
239-
debugPrint("layrz_theme/ThemedTable2: Starting _filterAndSortAsync from $source...");
240239
if (_isLoading.value) {
241240
// Queue the update instead of silently dropping it.
242241
// _filterAndSort will re-run once the current operation finishes.
243242
_pendingUpdate = true;
244-
debugPrint('layrz_theme/ThemedTable2: Queuing _filterAndSortAsync from $source (already loading)');
245243
return;
246244
}
247245

@@ -250,12 +248,10 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
250248
try {
251249
List<T> items = .from(widget.items, growable: true);
252250
if (items.isEmpty) {
253-
debugPrint("layrz_theme/ThemedTable2: No items to filter and sort from $source.");
254251
_filteredData.value = items;
255252
return;
256253
}
257254

258-
debugPrint("layrz_theme/ThemedTable2: Precomputing data from $source...");
259255
// Key: item.hashCode (stable for value-based domain objects, consistent across isolate boundaries).
260256
// Value: List<String> indexed by column position — avoids col.hashCode collisions
261257
// (e.g. two columns with the same headerText).
@@ -267,7 +263,6 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
267263
}
268264

269265
if (_searchController.text.isNotEmpty) {
270-
debugPrint("layrz_theme/ThemedTable2: Filtering data from $source...");
271266
final searchLower = _searchController.text.toLowerCase();
272267
items = items.where((row) {
273268
final cols = _itemsStrings[row.hashCode];
@@ -279,13 +274,11 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
279274
}).toList();
280275
}
281276

282-
debugPrint("layrz_theme/ThemedTable2: Sorting data...");
283277
// Precompute sort keys on the main thread so that valueBuilder closures
284278
// (which may capture BuildContext or i18n objects) never cross the isolate boundary.
285279
final columnIndex = widget.columns.indexOf(_colSelected);
286280
final sortKeys = [
287-
for (final item in items)
288-
_itemsStrings[item.hashCode]?[columnIndex] ?? _colSelected.valueBuilder(item),
281+
for (final item in items) _itemsStrings[item.hashCode]?[columnIndex] ?? _colSelected.valueBuilder(item),
289282
];
290283
_filteredData.value = await compute(
291284
_sort,
@@ -297,7 +290,6 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
297290
),
298291
);
299292
} finally {
300-
debugPrint("layrz_theme/ThemedTable2: Finished filtering and sorting from $source.");
301293
_isLoading.value = false;
302294
if (mounted) WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
303295
// Process a queued update that arrived while we were loading.
@@ -342,7 +334,6 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
342334
final ascending = event.ascending;
343335

344336
if (columnIndex < 0 || columnIndex >= widget.columns.length) {
345-
debugPrint('layrz_theme/ThemedTable2: Invalid column index $columnIndex for sorting');
346337
return;
347338
}
348339

@@ -357,8 +348,6 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
357348
_filterAndSort('CONTROLLER_REFRESH');
358349
return;
359350
}
360-
361-
debugPrint('layrz_theme/ThemedTable2: Unknown controller event type: ${event.runtimeType}');
362351
}
363352

364353
@override
@@ -650,8 +639,9 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
650639
}
651640
} else {
652641
if (_selectedSet.contains(item)) {
653-
_selectedItems.value =
654-
selectedList.where((i) => i != item).toList();
642+
_selectedItems.value = selectedList
643+
.where((i) => i != item)
644+
.toList();
655645
}
656646
}
657647
},
@@ -701,8 +691,7 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
701691
// Use column index as key (avoids col.hashCode collisions
702692
// when two columns share the same headerText).
703693
String text =
704-
_itemsStrings[data.hashCode]?[colIndex] ??
705-
header.valueBuilder(data);
694+
_itemsStrings[data.hashCode]?[colIndex] ?? header.valueBuilder(data);
706695

707696
Widget child;
708697
if (header.richTextBuilder != null) {

0 commit comments

Comments
 (0)