|
|
|
@ -27,10 +27,11 @@ class MultipleSelectionFullScreenDialog<T extends Base> extends StatefulWidget {
|
|
|
|
_SelectionBottomSheetState createState() => _SelectionBottomSheetState<T>();
|
|
|
|
_SelectionBottomSheetState createState() => _SelectionBottomSheetState<T>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _SelectionBottomSheetState<T extends Base> extends State<MultipleSelectionFullScreenDialog<T>> {
|
|
|
|
class _SelectionBottomSheetState<T extends Base> extends State<MultipleSelectionFullScreenDialog<T>> with SingleTickerProviderStateMixin {
|
|
|
|
late List<T> _selectedValue; // Now nullable
|
|
|
|
late List<T> _selectedValue; // Now nullable
|
|
|
|
|
|
|
|
|
|
|
|
String query = "";
|
|
|
|
String query = "";
|
|
|
|
|
|
|
|
late AnimationController _animationController;
|
|
|
|
|
|
|
|
|
|
|
|
List<T>? get filteredList => widget.items?.where((element) => widget.builderString(element).toLowerCase().contains(query.toLowerCase())).toList();
|
|
|
|
List<T>? get filteredList => widget.items?.where((element) => widget.builderString(element).toLowerCase().contains(query.toLowerCase())).toList();
|
|
|
|
|
|
|
|
|
|
|
|
@ -40,12 +41,18 @@ class _SelectionBottomSheetState<T extends Base> extends State<MultipleSelection
|
|
|
|
// This ensures temporary selections don't affect parent until confirmed
|
|
|
|
// This ensures temporary selections don't affect parent until confirmed
|
|
|
|
_selectedValue = List<T>.from(widget.selectedItem);
|
|
|
|
_selectedValue = List<T>.from(widget.selectedItem);
|
|
|
|
super.initState();
|
|
|
|
super.initState();
|
|
|
|
|
|
|
|
_animationController = AnimationController(
|
|
|
|
|
|
|
|
duration: const Duration(milliseconds: 1200),
|
|
|
|
|
|
|
|
vsync: this,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
_animationController.forward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FocusNode searchFocusNode = FocusNode();
|
|
|
|
FocusNode searchFocusNode = FocusNode();
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
void dispose() {
|
|
|
|
|
|
|
|
_animationController.dispose();
|
|
|
|
searchFocusNode.dispose();
|
|
|
|
searchFocusNode.dispose();
|
|
|
|
super.dispose();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -132,8 +139,39 @@ class _SelectionBottomSheetState<T extends Base> extends State<MultipleSelection
|
|
|
|
itemCount: filteredList?.length,
|
|
|
|
itemCount: filteredList?.length,
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
itemBuilder: (cxt, index) {
|
|
|
|
itemBuilder: (cxt, index) {
|
|
|
|
|
|
|
|
// Calculate staggered animation delay
|
|
|
|
|
|
|
|
final delay = index * 0.08;
|
|
|
|
|
|
|
|
final animation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
|
|
|
|
|
|
|
CurvedAnimation(
|
|
|
|
|
|
|
|
parent: _animationController,
|
|
|
|
|
|
|
|
curve: Interval(
|
|
|
|
|
|
|
|
delay.clamp(0.0, 0.8),
|
|
|
|
|
|
|
|
(delay + 0.3).clamp(0.0, 1.0),
|
|
|
|
|
|
|
|
curve: Curves.easeOut,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final slideAnimation = Tween<Offset>(
|
|
|
|
|
|
|
|
begin: const Offset(0.0, 0.3),
|
|
|
|
|
|
|
|
end: Offset.zero,
|
|
|
|
|
|
|
|
).animate(
|
|
|
|
|
|
|
|
CurvedAnimation(
|
|
|
|
|
|
|
|
parent: _animationController,
|
|
|
|
|
|
|
|
curve: Interval(
|
|
|
|
|
|
|
|
delay.clamp(0.0, 0.8),
|
|
|
|
|
|
|
|
(delay + 0.3).clamp(0.0, 1.0),
|
|
|
|
|
|
|
|
curve: Curves.easeOutCubic,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
bool isDisabledItem = widget.disableItem != null && widget.disableItem?.identifier == filteredList![index].identifier;
|
|
|
|
bool isDisabledItem = widget.disableItem != null && widget.disableItem?.identifier == filteredList![index].identifier;
|
|
|
|
return CheckboxListTile(
|
|
|
|
return FadeTransition(
|
|
|
|
|
|
|
|
opacity: animation,
|
|
|
|
|
|
|
|
child: SlideTransition(
|
|
|
|
|
|
|
|
position: slideAnimation,
|
|
|
|
|
|
|
|
child: CheckboxListTile(
|
|
|
|
value: checkItContains(filteredList![index]),
|
|
|
|
value: checkItContains(filteredList![index]),
|
|
|
|
dense: true,
|
|
|
|
dense: true,
|
|
|
|
controlAffinity: ListTileControlAffinity.leading,
|
|
|
|
controlAffinity: ListTileControlAffinity.leading,
|
|
|
|
@ -161,6 +199,8 @@ class _SelectionBottomSheetState<T extends Base> extends State<MultipleSelection
|
|
|
|
widget.builderString(filteredList![index]).cleanupWhitespace.capitalizeFirstOfEach ?? "",
|
|
|
|
widget.builderString(filteredList![index]).cleanupWhitespace.capitalizeFirstOfEach ?? "",
|
|
|
|
style: Theme.of(context).textTheme.bodyLarge,
|
|
|
|
style: Theme.of(context).textTheme.bodyLarge,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|