11part of 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart' ;
22
3-
4-
53/// The type of function that builds a child widget for a ParseLiveList element.
64typedef ChildBuilder <T extends sdk.ParseObject > = Widget Function (
75 BuildContext context, sdk.ParseLiveListElementSnapshot <T > snapshot, [int ? index]);
@@ -210,7 +208,8 @@ class _ParseLiveListWidgetState<T extends sdk.ParseObject>
210208 }
211209
212210 _items.clear ();
213- _noDataNotifier.value = true ;
211+ _noDataNotifier.value = true ; // Assume no data initially
212+ // Set loading state visually *before* async work
214213 if (mounted) setState (() {});
215214
216215 final initialQuery = QueryBuilder <T >.copy (widget.query);
@@ -237,40 +236,46 @@ class _ParseLiveListWidgetState<T extends sdk.ParseObject>
237236 _liveList? .dispose ();
238237 _liveList = liveList;
239238
239+ // --- Refactored Initial Item Handling ---
240+ final List <T > initialItems = [];
241+ final List <T > itemsToFetchAndCache = []; // Items needing background processing
242+
240243 if (liveList.size > 0 ) {
241244 for (int i = 0 ; i < liveList.size; i++ ) {
242245 final item = liveList.getPreLoadedAt (i);
243246 if (item != null ) {
247+ initialItems.add (item); // Add preloaded item for immediate display
248+ // If offline mode is on, mark for background fetch/cache
244249 if (widget.offlineMode) {
245- try {
246- if (widget.lazyLoading) {
247- await item.fetch ();
248- }
249- await item.saveToLocalCache ();
250- } catch (e) {
251- debugPrint ('$connectivityLogPrefix Error saving initial object ${item .objectId } to cache: $e ' );
252- }
250+ itemsToFetchAndCache.add (item);
253251 }
254- _items.add (item);
255252 }
256253 }
257254 }
258255
256+ // Update the UI immediately with preloaded items
257+ _items.addAll (initialItems);
259258 _noDataNotifier.value = _items.isEmpty;
260-
261259 if (mounted) {
262260 setState (() {});
263261 }
262+ // --- End Refactored Initial Item Handling ---
264263
264+ // --- Start Background Fetching and Caching (if needed) ---
265+ if (itemsToFetchAndCache.isNotEmpty) {
266+ // Don't await this block, let it run in the background
267+ _fetchAndCacheItemsInBackground (itemsToFetchAndCache);
268+ }
269+ // --- End Background Fetching and Caching ---
270+
271+ // --- Stream Listener (remains the same) ---
265272 liveList.stream.listen ((event) {
266273 T ? objectToCache;
267274
268275 if (event is sdk.ParseLiveListAddEvent <sdk.ParseObject >) {
269- final addedItem = event.object as T ;
276+ final addedItem = event.object as T ; // Cast needed
270277 if (mounted) {
271- setState (() {
272- _items.insert (event.index, addedItem);
273- });
278+ setState (() { _items.insert (event.index, addedItem); });
274279 }
275280 objectToCache = addedItem;
276281 } else if (event is sdk.ParseLiveListDeleteEvent <sdk.ParseObject >) {
@@ -286,25 +291,27 @@ class _ParseLiveListWidgetState<T extends sdk.ParseObject>
286291 debugPrint ('$connectivityLogPrefix LiveList Delete Event: Invalid index ${event .index }, list size ${_items .length }' );
287292 }
288293 } else if (event is sdk.ParseLiveListUpdateEvent <sdk.ParseObject >) {
289- final updatedItem = event.object as T ;
294+ final updatedItem = event.object as T ; // Cast needed
290295 if (event.index >= 0 && event.index < _items.length) {
291296 if (mounted) {
292- setState (() {
293- _items[event.index] = updatedItem;
294- });
297+ setState (() { _items[event.index] = updatedItem; });
295298 }
296299 objectToCache = updatedItem;
297300 } else {
298301 debugPrint ('$connectivityLogPrefix LiveList Update Event: Invalid index ${event .index }, list size ${_items .length }' );
299302 }
300303 }
301304
305+ // Save updates from stream immediately (usually less performance critical than initial load)
302306 if (widget.offlineMode && objectToCache != null ) {
307+ // Consider if fetch is needed for stream events too, though often they are complete
303308 objectToCache.saveToLocalCache ();
304309 }
305310
306311 _noDataNotifier.value = _items.isEmpty;
307312 });
313+ // --- End Stream Listener ---
314+
308315 } catch (e) {
309316 debugPrint ('$connectivityLogPrefix Error loading data: $e ' );
310317 _noDataNotifier.value = _items.isEmpty;
@@ -314,6 +321,30 @@ class _ParseLiveListWidgetState<T extends sdk.ParseObject>
314321 }
315322 }
316323
324+ // --- Helper for Background Caching ---
325+ Future <void > _fetchAndCacheItemsInBackground (List <T > items) async {
326+ debugPrint ('$connectivityLogPrefix Starting background fetch/cache for ${items .length } items...' );
327+ for (final item in items) {
328+ try {
329+ // Check if still mounted within the loop if operations are long
330+ if (! mounted) return ;
331+
332+ // Fetch *only* if lazy loading is enabled to ensure cached data is complete
333+ if (widget.lazyLoading) {
334+ // Fetch the full object data before saving to cache when lazy loading.
335+ // We assume that if lazy loading is on, the initial object might be incomplete.
336+ await item.fetch ();
337+ }
338+ await item.saveToLocalCache ();
339+ } catch (e) {
340+ // Log error but continue with the next item
341+ debugPrint ('$connectivityLogPrefix Error background saving object ${item .objectId } to cache: $e ' );
342+ }
343+ }
344+ debugPrint ('$connectivityLogPrefix Finished background fetch/cache.' );
345+ }
346+ // --- End Helper ---
347+
317348 Future <void > _loadMoreData () async {
318349 if (isOffline) {
319350 debugPrint ('$connectivityLogPrefix Cannot load more data while offline.' );
@@ -354,7 +385,6 @@ class _ParseLiveListWidgetState<T extends sdk.ParseObject>
354385 }
355386
356387 if (widget.offlineMode) {
357- debugPrint ('$connectivityLogPrefix Saving ${results .length } more items to cache...' );
358388 for (final item in results) {
359389 try {
360390 if (widget.lazyLoading) {
@@ -391,7 +421,7 @@ class _ParseLiveListWidgetState<T extends sdk.ParseObject>
391421 return ;
392422 }
393423 final scrollController = widget.scrollController ?? _scrollController;
394- if (! scrollController.hasClients || scrollController.position.maxScrollExtent == null ) {
424+ if (! scrollController.hasClients) {
395425 return ;
396426 }
397427 final offset = scrollController.position.maxScrollExtent - scrollController.position.pixels;
@@ -570,7 +600,6 @@ class _ParseLiveListElementWidgetState<T extends sdk.ParseObject>
570600 @override
571601 void initState () {
572602 super .initState ();
573- debugPrint ('ElementWidget ${widget .index }: initState' );
574603 _snapshot = sdk.ParseLiveListElementSnapshot <T >(
575604 loadedData: widget.loadedData? .call (),
576605 preLoadedData: widget.preLoadedData? .call (),
@@ -605,7 +634,6 @@ class _ParseLiveListElementWidgetState<T extends sdk.ParseObject>
605634
606635 @override
607636 Widget build (BuildContext context) {
608- debugPrint ('ElementWidget ${widget .index }: build' );
609637 return SizeTransition (
610638 sizeFactor: widget.sizeFactor,
611639 child: widget.index != null
0 commit comments