diff --git a/lib/bottom_sheet/multi_select_bottom_sheet.dart b/lib/bottom_sheet/multi_select_bottom_sheet.dart index 26d797f..94dc05e 100644 --- a/lib/bottom_sheet/multi_select_bottom_sheet.dart +++ b/lib/bottom_sheet/multi_select_bottom_sheet.dart @@ -24,12 +24,18 @@ class MultiSelectBottomSheet extends StatefulWidget /// Toggles search functionality. final bool searchable; + /// Toggles select all functionality. Default is false. + final bool selectAll; + /// Text on the confirm button. final Text? confirmText; /// Text on the cancel button. final Text? cancelText; + /// Text on the select all button, if enabled. + final Text? selectAllText; + /// An enum that determines which type of list to render. final MultiSelectListType? listType; @@ -88,7 +94,9 @@ class MultiSelectBottomSheet extends StatefulWidget this.listType, this.cancelText, this.confirmText, + this.selectAllText, this.searchable = false, + this.selectAll = false, this.selectedColor, this.initialChildSize, this.minChildSize, @@ -155,14 +163,8 @@ class _MultiSelectBottomSheetState extends State> { controlAffinity: ListTileControlAffinity.leading, onChanged: (checked) { setState(() { - _selectedValues = widget.onItemCheckedChange( - _selectedValues, item.value, checked!); + _setSelectedState(item, checked!); - if (checked) { - item.selected = true; - } else { - item.selected = false; - } if (widget.separateSelectedItems) { _items = widget.separateSelected(_items); } @@ -203,14 +205,8 @@ class _MultiSelectBottomSheetState extends State> { ), selected: item.selected, onSelected: (checked) { - if (checked) { - item.selected = true; - } else { - item.selected = false; - } setState(() { - _selectedValues = widget.onItemCheckedChange( - _selectedValues, item.value, checked); + _setSelectedState(item, checked); }); if (widget.onSelectionChanged != null) { widget.onSelectionChanged!(_selectedValues); @@ -220,6 +216,24 @@ class _MultiSelectBottomSheetState extends State> { ); } + void _setSelectedState(MultiSelectItem item, bool checked) { + _selectedValues = + widget.onItemCheckedChange(_selectedValues, item.value, checked); + + if (checked) { + item.selected = true; + } else { + item.selected = false; + } + } + + void _selectAll(bool checked) { + _items.forEach((item) => _setSelectedState(item, checked)); + if (widget.onSelectionChanged != null) { + widget.onSelectionChanged!(_selectedValues); + } + } + @override Widget build(BuildContext context) { return Container( @@ -344,6 +358,26 @@ class _MultiSelectBottomSheetState extends State> { ), ), SizedBox(width: 10), + if (widget.selectAll) + Expanded( + child: TextButton( + onPressed: () { + setState(() => _selectAll(true)); + }, + child: widget.selectAllText ?? + Text( + "SELECT ALL", + style: TextStyle( + color: (widget.selectedColor != null && + widget.selectedColor != + Colors.transparent) + ? widget.selectedColor!.withOpacity(1) + : Theme.of(context).primaryColor, + ), + ), + ), + ), + if (widget.selectAll) SizedBox(width: 10), Expanded( child: TextButton( onPressed: () { diff --git a/lib/bottom_sheet/multi_select_bottom_sheet_field.dart b/lib/bottom_sheet/multi_select_bottom_sheet_field.dart index 8a1cf46..aed3d7c 100644 --- a/lib/bottom_sheet/multi_select_bottom_sheet_field.dart +++ b/lib/bottom_sheet/multi_select_bottom_sheet_field.dart @@ -35,12 +35,18 @@ class MultiSelectBottomSheetField extends FormField> { /// Toggles search functionality. final bool searchable; + /// Toggles select all functionality. Default is false. + final bool selectAll; + /// Text on the confirm button. final Text? confirmText; /// Text on the cancel button. final Text? cancelText; + /// Text on the select all button, if enabled. + final Text? selectAllText; + /// An enum that determines which type of list to render. final MultiSelectListType? listType; @@ -121,8 +127,10 @@ class MultiSelectBottomSheetField extends FormField> { this.chipDisplay, this.initialValue, this.searchable = false, + this.selectAll = false, this.confirmText, this.cancelText, + this.selectAllText, this.selectedColor, this.initialChildSize, this.minChildSize, @@ -181,6 +189,8 @@ class MultiSelectBottomSheetField extends FormField> { searchHint: searchHint, searchTextStyle: searchTextStyle, searchable: searchable, + selectAll: selectAll, + selectAllText: selectAllText, selectedColor: selectedColor, separateSelectedItems: separateSelectedItems, shape: shape, @@ -202,8 +212,10 @@ class _MultiSelectBottomSheetFieldView extends StatefulWidget { final void Function(List)? onSelectionChanged; final void Function(List)? onConfirm; final bool searchable; + final bool selectAll; final Text? confirmText; final Text? cancelText; + final Text? selectAllText; final MultiSelectListType? listType; final Color? selectedColor; final String? searchHint; @@ -238,8 +250,10 @@ class _MultiSelectBottomSheetFieldView extends StatefulWidget { this.chipDisplay, this.initialValue, this.searchable = false, + this.selectAll = false, this.confirmText, this.cancelText, + this.selectAllText, this.selectedColor, this.initialChildSize, this.minChildSize, @@ -274,8 +288,10 @@ class _MultiSelectBottomSheetFieldView extends StatefulWidget { chipDisplay = field.chipDisplay, initialValue = field.initialValue, searchable = field.searchable, + selectAll = field.selectAll, confirmText = field.confirmText, cancelText = field.cancelText, + selectAllText = field.selectAllText, selectedColor = field.selectedColor, initialChildSize = field.initialChildSize, minChildSize = field.minChildSize, @@ -397,6 +413,7 @@ class __MultiSelectBottomSheetFieldViewState items: widget.items, cancelText: widget.cancelText, confirmText: widget.confirmText, + selectAllText: widget.selectAllText, separateSelectedItems: widget.separateSelectedItems, initialValue: _selectedItems, onConfirm: (selected) { @@ -408,6 +425,7 @@ class __MultiSelectBottomSheetFieldViewState }, onSelectionChanged: widget.onSelectionChanged, searchable: widget.searchable, + selectAll: widget.selectAll, title: widget.title, initialChildSize: widget.initialChildSize, minChildSize: widget.minChildSize, diff --git a/lib/dialog/mult_select_dialog.dart b/lib/dialog/mult_select_dialog.dart index 8d00c2b..349ae83 100644 --- a/lib/dialog/mult_select_dialog.dart +++ b/lib/dialog/mult_select_dialog.dart @@ -23,12 +23,18 @@ class MultiSelectDialog extends StatefulWidget with MultiSelectActions { /// Toggles search functionality. Default is false. final bool searchable; + /// Toggles select all functionality. Default is false. + final bool selectAll; + /// Text on the confirm button. final Text? confirmText; /// Text on the cancel button. final Text? cancelText; + /// Text on the select all button, if enabled. + final Text? selectAllText; + /// An enum that determines which type of list to render. final MultiSelectListType? listType; @@ -86,8 +92,10 @@ class MultiSelectDialog extends StatefulWidget with MultiSelectActions { this.onConfirm, this.listType, this.searchable = false, + this.selectAll = false, this.confirmText, this.cancelText, + this.selectAllText, this.selectedColor, this.searchHint, this.height, @@ -153,14 +161,8 @@ class _MultiSelectDialogState extends State> { controlAffinity: ListTileControlAffinity.leading, onChanged: (checked) { setState(() { - _selectedValues = widget.onItemCheckedChange( - _selectedValues, item.value, checked!); + _setSelectedState(item, checked!); - if (checked) { - item.selected = true; - } else { - item.selected = false; - } if (widget.separateSelectedItems) { _items = widget.separateSelected(_items); } @@ -196,14 +198,8 @@ class _MultiSelectDialogState extends State> { ), selected: item.selected, onSelected: (checked) { - if (checked) { - item.selected = true; - } else { - item.selected = false; - } setState(() { - _selectedValues = widget.onItemCheckedChange( - _selectedValues, item.value, checked); + _setSelectedState(item, checked); }); if (widget.onSelectionChanged != null) { widget.onSelectionChanged!(_selectedValues); @@ -213,6 +209,24 @@ class _MultiSelectDialogState extends State> { ); } + void _setSelectedState(MultiSelectItem item, bool checked) { + _selectedValues = widget.onItemCheckedChange( + _selectedValues, item.value, checked); + + if (checked) { + item.selected = true; + } else { + item.selected = false; + } + } + + void _selectAll(bool checked) { + _items.forEach((item) => _setSelectedState(item, checked)); + if (widget.onSelectionChanged != null) { + widget.onSelectionChanged!(_selectedValues); + } + } + @override Widget build(BuildContext context) { return AlertDialog( @@ -311,6 +325,21 @@ class _MultiSelectDialogState extends State> { widget.onCancelTap(context, widget.initialValue); }, ), + if (widget.selectAll) TextButton( + child: widget.selectAllText ?? + Text( + "SELECT ALL", + style: TextStyle( + color: (widget.selectedColor != null && + widget.selectedColor != Colors.transparent) + ? widget.selectedColor!.withOpacity(1) + : Theme.of(context).primaryColor, + ), + ), + onPressed: () { + setState(()=>_selectAll(true)); + }, + ), TextButton( child: widget.confirmText ?? Text( diff --git a/lib/dialog/multi_select_dialog_field.dart b/lib/dialog/multi_select_dialog_field.dart index ed72e6c..fc38e9d 100644 --- a/lib/dialog/multi_select_dialog_field.dart +++ b/lib/dialog/multi_select_dialog_field.dart @@ -42,12 +42,18 @@ class MultiSelectDialogField extends FormField> { /// Toggles search functionality. final bool searchable; + /// Toggles select all functionality. Default is false. + final bool selectAll; + /// Text on the confirm button. final Text? confirmText; /// Text on the cancel button. final Text? cancelText; + /// Text on the select all button, if enabled. + final Text? selectAllText; + /// Set the color of the space outside the BottomSheet. final Color? barrierColor; @@ -114,8 +120,10 @@ class MultiSelectDialogField extends FormField> { this.onSelectionChanged, this.chipDisplay, this.searchable = false, + this.selectAll = false, this.confirmText, this.cancelText, + this.selectAllText, this.barrierColor, this.selectedColor, this.searchHint, @@ -157,8 +165,10 @@ class MultiSelectDialogField extends FormField> { onSelectionChanged: onSelectionChanged, initialValue: initialValue, searchable: searchable, + selectAll: selectAll, confirmText: confirmText, cancelText: cancelText, + selectAllText: selectAllText, barrierColor: barrierColor, selectedColor: selectedColor, searchHint: searchHint, @@ -193,8 +203,10 @@ class _MultiSelectDialogFieldView extends StatefulWidget { final List? initialValue; final void Function(List)? onConfirm; final bool? searchable; + final bool? selectAll; final Text? confirmText; final Text? cancelText; + final Text? selectAllText; final Color? barrierColor; final Color? selectedColor; final double? dialogHeight; @@ -225,8 +237,10 @@ class _MultiSelectDialogFieldView extends StatefulWidget { this.chipDisplay, this.initialValue, this.searchable, + this.selectAll, this.confirmText, this.cancelText, + this.selectAllText, this.barrierColor, this.selectedColor, this.searchHint, @@ -259,8 +273,10 @@ class _MultiSelectDialogFieldView extends StatefulWidget { chipDisplay = field.chipDisplay, initialValue = field.initialValue, searchable = field.searchable, + selectAll = field.selectAll, confirmText = field.confirmText, cancelText = field.cancelText, + selectAllText = field.selectAllText, barrierColor = field.barrierColor, selectedColor = field.selectedColor, dialogHeight = field.dialogHeight, @@ -380,8 +396,10 @@ class __MultiSelectDialogFieldViewState title: widget.title ?? const Text("Select"), initialValue: _selectedItems, searchable: widget.searchable ?? false, + selectAll: widget.selectAll ?? false, confirmText: widget.confirmText, cancelText: widget.cancelText, + selectAllText: widget.selectAllText, separateSelectedItems: widget.separateSelectedItems, onConfirm: (selected) { if (widget.state != null) {