@@ -57,6 +57,16 @@ class ThemedTable2<T> extends StatefulWidget {
5757 /// [multiselectValue] is the value change listener for the multi-select checkbox list.
5858 final ValueNotifier <List <T >>? multiselectValue;
5959
60+ /// [populateDelay] is the delay in milliseconds before populating the table with data.
61+ final Duration populateDelay;
62+
63+ /// [reloadOnDidUpdate] if true, the table will reload its data when the widget is updated.
64+ /// This is useful on development stages to see changes on hot reload.
65+ /// Defaults to false.
66+ ///
67+ /// Note: This property is ignored on production builds.
68+ final bool reloadOnDidUpdate;
69+
6070 const ThemedTable2 ({
6171 required this .items,
6272 required this .columns,
@@ -75,6 +85,8 @@ class ThemedTable2<T> extends StatefulWidget {
7585 this .multiSelectionContentText = "You have selected multiple items. What do you want to do?" ,
7686 this .multiSelectionCancelLabelText = "Clear" ,
7787 this .multiselectValue,
88+ this .populateDelay = const Duration (milliseconds: 150 ),
89+ this .reloadOnDidUpdate = false ,
7890 }) : assert (columns.length > 0 , 'Columns cant be empty' ),
7991 assert (actionsCount >= 0 , 'Actions count cant be negative' ),
8092 assert (minColumnWidth > 0 , 'Min column width must be greater than 0' ),
@@ -83,8 +95,8 @@ class ThemedTable2<T> extends StatefulWidget {
8395 'If actionsCount is greater than 0, actionsBuilder must be provided' ,
8496 ),
8597 assert (
86- multiselectActions.length > 0 && hasMultiselect && multiselectValue != null ,
87- 'If hasMultiselect is true, multiselectActions and multiselectValue must be provided' ,
98+ multiselectActions.length > 0 && hasMultiselect,
99+ 'If hasMultiselect is true, multiselectActions must be provided' ,
88100 );
89101
90102 @override
@@ -148,6 +160,10 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
148160 /// [isReversed] indicates whether the current sort order is descending (true) or ascending (false).
149161 bool isReversed = false ;
150162
163+ /// [_isLoading] indicates whether the table is currently loading or computing data.
164+ bool _isLoading = false ;
165+
166+ /// [_selectedItems] holds the list of currently selected items in multi-select mode.
151167 late ValueNotifier <List <T >> _selectedItems;
152168
153169 @override
@@ -166,21 +182,32 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
166182
167183 _selectedItems = widget.multiselectValue ?? ValueNotifier <List <T >>([]);
168184
169- _filterAndSort ('INIT_STATE' );
185+ _filterAndSortAsync ('INIT_STATE' );
170186 }
171187
172188 @override
173189 void didUpdateWidget (covariant ThemedTable2 <T > oldWidget) {
174190 super .didUpdateWidget (oldWidget);
175191 final eq = const DeepCollectionEquality ().equals;
176- if (! eq (oldWidget.items, widget.items) ||
177- ! eq (oldWidget.columns, widget.columns) ||
178- oldWidget.actionsCount != widget.actionsCount ||
179- oldWidget.canSearch != widget.canSearch ||
180- kDebugMode) {
181- _filterAndSort ('DID_UPDATE' );
182- WidgetsBinding .instance.addPostFrameCallback ((_) => setState (() {}));
183- }
192+ final bool c1 = ! eq (oldWidget.items, widget.items);
193+ final bool c2 = ! eq (oldWidget.columns, widget.columns);
194+ final bool c3 = oldWidget.actionsCount != widget.actionsCount;
195+ final bool c4 = oldWidget.canSearch != widget.canSearch;
196+ bool c5 = false ;
197+ if (kDebugMode && widget.reloadOnDidUpdate) c5 = true ;
198+
199+ if (c1 || c2 || c3 || c4 || c5) _filterAndSortAsync ('DID_UPDATE' );
200+ }
201+
202+ Future <void > _filterAndSortAsync (String source) async {
203+ _isLoading = true ;
204+ WidgetsBinding .instance.addPostFrameCallback ((_) => setState (() {}));
205+ await Future .delayed (widget.populateDelay);
206+ if (! mounted) return ;
207+ _filterAndSort (source);
208+
209+ _isLoading = false ;
210+ WidgetsBinding .instance.addPostFrameCallback ((_) => setState (() {}));
184211 }
185212
186213 @override
@@ -199,6 +226,22 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
199226
200227 @override
201228 Widget build (BuildContext context) {
229+ if (_isLoading) {
230+ return Center (
231+ child: Column (
232+ mainAxisSize: MainAxisSize .min,
233+ children: [
234+ const CircularProgressIndicator (),
235+ const SizedBox (height: 10 ),
236+ Text (
237+ widget.loadingLabelText,
238+ style: Theme .of (context).textTheme.bodyMedium,
239+ ),
240+ ],
241+ ),
242+ );
243+ }
244+
202245 return LayoutBuilder (
203246 builder: (context, constraints) {
204247 bool isMobile = constraints.maxWidth < widget.actionsMobileBreakpoint;
@@ -657,9 +700,7 @@ class _ThemedTable2State<T> extends State<ThemedTable2<T>> {
657700 debugPrint ("layrz_theme/ThemedTable2: Sorting data..." );
658701 _filteredData.sort (colSelected.customSort ?? _defaultSort);
659702
660- WidgetsBinding .instance.addPostFrameCallback ((_) {
661- if (mounted) setState (() {});
662- });
703+ WidgetsBinding .instance.addPostFrameCallback ((_) => setState (() {}));
663704 }
664705
665706 void _onSearchChanged (String value) {
0 commit comments