Skip to content

Commit 1c2232b

Browse files
agordn52Anthony Gordon
authored andcommitted
chore(release): bump version to 7.24.1
1 parent 7b40345 commit 1c2232b

6 files changed

Lines changed: 679 additions & 39 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## [7.24.1] - 2026-05-10
2+
3+
### Fixed
4+
5+
* **`CollectionView` no longer crashes mid-refresh on long lists** - `_onRefresh` previously assigned `_data = []` synchronously *before* awaiting the new data, which could leave the live `SliverList` pointing at an empty list mid-frame and throw `RangeError` when cached children relayed out. `_data` is now mutated only inside `setState` after the new data resolves
6+
* **`CollectionView` accepts `List<dynamic>` returned from JSON-decoded API responses** - previously a `List<dynamic>` (the typical shape from `jsonDecode`) would trip an internal `List<T>` assertion. The widget now lazily casts via `List.cast<T>()`, so callers no longer have to call `.cast<T>()` themselves
7+
* **`CollectionView.stateActions(name).refreshData()` no longer clears the list mid-fetch** - `_data` was being cleared synchronously before the new data resolved, briefly showing an empty state. The list is now preserved until the new data is ready
8+
* **Null result from `paginatedData` on pull-to-refresh now preserves the existing list** instead of incorrectly calling `loadNoData()`. The refresh indicator settles and the previous data remains visible
9+
110
## [7.24.0] - 2026-05-07
211

312
### Added

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import 'package:nylo_support/widgets/ny_widgets.dart';
4949

5050
```yaml
5151
dependencies:
52-
nylo_support: ^7.24.0
52+
nylo_support: ^7.24.1
5353
```
5454
5555
### Documentation

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ packages:
483483
path: ".."
484484
relative: true
485485
source: path
486-
version: "7.23.0"
486+
version: "7.24.1"
487487
objective_c:
488488
dependency: transitive
489489
description:

lib/widgets/src/collection_view.dart

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,7 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
555555
_data = [];
556556
return;
557557
}
558-
assert(data is List<T>, "Data must be a List<$T>");
559-
_data = data;
558+
_data = _coerceToList(data);
560559
} else {
561560
awaitData(
562561
perform: () async {
@@ -565,8 +564,7 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
565564
_data = [];
566565
return;
567566
}
568-
assert(data is List<T>, "Data must be a List<$T>");
569-
_data = data;
567+
_data = _coerceToList(data);
570568
},
571569
);
572570
}
@@ -576,10 +574,10 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
576574
final data = widget.data!();
577575
if (data == null) {
578576
_data = [];
579-
return;
577+
} else {
578+
_data = _coerceToList(data);
580579
}
581-
assert(data is List<T>, "Data must be a List<$T>");
582-
_data = data;
580+
_syncDataInitialized = true;
583581
return;
584582
}
585583
awaitData(
@@ -589,8 +587,7 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
589587
_data = [];
590588
return;
591589
}
592-
assert(data is List<T>, "Data must be a List<$T>");
593-
_data = data;
590+
_data = _coerceToList(data);
594591
},
595592
);
596593
}
@@ -622,9 +619,7 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
622619
},
623620
'refreshData': (_) async {
624621
setLoading(true);
625-
_data = [];
626622
_iteration = 1;
627-
_syncDataInitialized = false;
628623
if (widget.isPullable) {
629624
_refreshController.refreshCompleted(resetFooterState: true);
630625
}
@@ -636,10 +631,8 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
636631
} else if (widget.data != null) {
637632
result = await Future.value(widget.data!());
638633
}
639-
if (result != null) {
640-
assert(result is List<T>, "Data must be a List<$T>");
641-
_data = result;
642-
}
634+
_data = result == null ? [] : _coerceToList(result);
635+
_syncDataInitialized = true;
643636
} catch (e) {
644637
NyLogger.error(e.toString());
645638
}
@@ -675,55 +668,60 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
675668
/// Refresh the list (for pullable mode)
676669
Future<void> _onRefresh() async {
677670
_iteration = 1;
678-
_data = [];
679671

680672
if (widget.beforeRefresh != null) {
681673
await widget.beforeRefresh!();
682674
}
683675

684-
List<T>? newData = [];
676+
dynamic rawData;
685677
if (widget.paginatedData is! Future Function(int)) {
686-
newData = widget.paginatedData!(_iteration);
678+
rawData = widget.paginatedData!(_iteration);
687679
} else {
688-
newData = await widget.paginatedData!(_iteration);
680+
rawData = await widget.paginatedData!(_iteration);
689681
}
690-
if (newData == null) {
691-
_refreshController.loadNoData();
682+
if (rawData == null) {
683+
if (mounted) {
684+
_refreshController.refreshCompleted(resetFooterState: true);
685+
}
692686
return;
693687
}
694688

695-
_data = newData;
696-
689+
List<T> resolved = _coerceToList(rawData);
697690
if (widget.afterRefresh != null) {
698-
_data = widget.afterRefresh!(_data);
691+
final after = widget.afterRefresh!(resolved);
692+
if (after is List<T>) {
693+
resolved = after;
694+
} else if (after is List) {
695+
resolved = after.cast<T>();
696+
}
699697
}
700698

701-
if (widget.onRefresh == null) {
702-
_refreshController.refreshCompleted(resetFooterState: true);
703-
setState(() {});
704-
return;
699+
if (widget.onRefresh != null) {
700+
await widget.onRefresh!();
705701
}
706-
await widget.onRefresh!();
707702

703+
if (!mounted) return;
704+
setState(() {
705+
_data = resolved;
706+
});
708707
_refreshController.refreshCompleted(resetFooterState: true);
709-
710-
setState(() {});
711708
}
712709

713710
/// Load more data (for pullable mode)
714711
Future<void> _onLoading() async {
715712
_iteration++;
716713

717-
List<T>? newData = [];
714+
dynamic rawData;
718715
if (widget.paginatedData is! Future Function(int)) {
719-
newData = widget.paginatedData!(_iteration);
716+
rawData = widget.paginatedData!(_iteration);
720717
} else {
721-
newData = await widget.paginatedData!(_iteration);
718+
rawData = await widget.paginatedData!(_iteration);
722719
}
723-
if (newData == null) {
720+
if (rawData == null) {
724721
_refreshController.loadNoData();
725722
return;
726723
}
724+
final List<T> newData = _coerceToList(rawData);
727725
if (newData.isEmpty) {
728726
_refreshController.loadNoData();
729727
return;
@@ -782,6 +780,16 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
782780
return result;
783781
}
784782

783+
/// Coerces a raw value into a `List<T>`. Accepts a `List<T>` directly, casts
784+
/// a generic `List` (e.g. `List<dynamic>` decoded from a JSON API response)
785+
/// to `List<T>`, and falls back to an empty list otherwise.
786+
List<T> _coerceToList(dynamic data) {
787+
if (data is List<T>) return data;
788+
if (data is List) return data.cast<T>();
789+
assert(false, "Data must be a List<$T>");
790+
return [];
791+
}
792+
785793
/// Returns the header widget based on headerStyle
786794
Widget _headerType() {
787795
return switch (widget.headerStyle) {
@@ -829,7 +837,8 @@ class _CollectionViewState<T> extends NyState<CollectionView<T>> {
829837
Widget _buildRegularView(Widget loadingWidget) {
830838
if (widget.data is! Future Function()) {
831839
if (!_syncDataInitialized) {
832-
_data = widget.data!() ?? [];
840+
final raw = widget.data!();
841+
_data = raw == null ? [] : _coerceToList(raw);
833842
_syncDataInitialized = true;
834843
}
835844
if (_data.isEmpty) {

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: nylo_support
22
description: Support library for the Nylo framework. This library supports routing, widgets, localization, cli, storage and more.
3-
version: 7.24.0
3+
version: 7.24.1
44
homepage: https://nylo.dev
55
repository: https://github.com/nylo-core/support/tree/7.x
66
issue_tracker: https://github.com/nylo-core/support/issues

0 commit comments

Comments
 (0)