You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
9.7KB

  1. import 'package:farm_tpf/presentation/custom_widgets/button/second_button.dart';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:get/get.dart';
  5. import 'package:multi_select_flutter/multi_select_flutter.dart';
  6. import '../../../models/item_dropdown.dart';
  7. import '../../../themes/app_colors.dart';
  8. import '../../../themes/styles_text.dart';
  9. import '../button/button_2_icon.dart';
  10. class MultipleSelectBottomSheet extends StatefulWidget {
  11. final List<ItemDropDown>? initValue;
  12. final List<ItemDropDown> dataSources;
  13. final Function(List<ItemDropDown>) onSelected;
  14. final Color? borderColor;
  15. final String hint;
  16. final double? height;
  17. final String? errorText;
  18. final bool isDisable;
  19. final EdgeInsetsGeometry? contentPadding;
  20. final Color? disabledColor;
  21. const MultipleSelectBottomSheet({
  22. Key? key,
  23. required this.dataSources,
  24. required this.onSelected,
  25. required this.hint,
  26. this.initValue,
  27. this.borderColor,
  28. this.height,
  29. this.errorText,
  30. this.isDisable = false,
  31. this.contentPadding,
  32. this.disabledColor,
  33. }) : super(key: key);
  34. @override
  35. _MultipleSelectBottomSheetState createState() => _MultipleSelectBottomSheetState();
  36. }
  37. class _MultipleSelectBottomSheetState extends State<MultipleSelectBottomSheet> {
  38. var dataSources = ValueNotifier(<ItemDropDown>[]);
  39. var selectValue = ValueNotifier(<ItemDropDown>[]);
  40. FixedExtentScrollController? scrollController;
  41. var items = <MultiSelectItem<ItemDropDown>>[];
  42. final _searchCtl = TextEditingController();
  43. @override
  44. void initState() {
  45. super.initState();
  46. }
  47. @override
  48. void dispose() {
  49. super.dispose();
  50. }
  51. @override
  52. Widget build(BuildContext context) {
  53. items = widget.dataSources.map((e) => MultiSelectItem(e, e.value ?? '')).toList();
  54. selectValue.value = widget.initValue ?? <ItemDropDown>[];
  55. return ValueListenableBuilder<List<ItemDropDown>>(
  56. valueListenable: selectValue,
  57. builder: (context, selecteds, _) {
  58. return Button2Icon(
  59. leftIcon: CupertinoIcons.slider_horizontal_3,
  60. title: widget.hint,
  61. rightWidget: Container(
  62. width: 16,
  63. height: 16,
  64. decoration: BoxDecoration(
  65. borderRadius: BorderRadius.circular(12),
  66. color: Colors.blue,
  67. ),
  68. child: Center(
  69. child: Text(
  70. '${selecteds.length}',
  71. style: StylesText.caption6.copyWith(color: Colors.white),
  72. ),
  73. ),
  74. ),
  75. onPressed: () {
  76. FocusScope.of(context).requestFocus(FocusNode());
  77. _showMultiSelect(context);
  78. },
  79. );
  80. },
  81. );
  82. }
  83. void _showMultiSelect(BuildContext context) async {
  84. var selectedIds = selectValue.value.map((e) => e.key).toList();
  85. var selecteds = ValueNotifier(
  86. items
  87. .where((element) => selectedIds.contains(element.value.key))
  88. .map(
  89. (e) => e.value,
  90. )
  91. .toList(),
  92. );
  93. // var selectValue = ValueNotifier(<ItemDropDown>[]);
  94. _searchCtl.clear();
  95. dataSources.value = List.of(widget.dataSources);
  96. return showDialog(
  97. context: context,
  98. builder: (context) {
  99. return AlertDialog(
  100. contentPadding: const EdgeInsets.all(8),
  101. content: Container(
  102. width: double.maxFinite,
  103. child: Column(
  104. mainAxisSize: MainAxisSize.min,
  105. children: <Widget>[
  106. _buildSelectAll(selecteds),
  107. Expanded(
  108. child: ValueListenableBuilder<List<ItemDropDown>>(
  109. valueListenable: dataSources,
  110. builder: (context, sources, _) {
  111. return ValueListenableBuilder<List<ItemDropDown>>(
  112. valueListenable: selecteds,
  113. builder: (context, valueSelected, _) {
  114. return ListView.builder(
  115. shrinkWrap: true,
  116. itemBuilder: ((context, index) {
  117. var item = sources[index];
  118. var isSelected = valueSelected.map((e) => e.key ?? '').contains(item.key);
  119. return InkWell(
  120. onTap: () {
  121. if (!isSelected) {
  122. selecteds.value.add(item);
  123. selecteds.notifyListeners();
  124. } else {
  125. selecteds.value.removeWhere((element) => element.key == item.key);
  126. selecteds.notifyListeners();
  127. }
  128. },
  129. child: Row(
  130. children: [
  131. Checkbox(
  132. value: isSelected,
  133. onChanged: (val) {
  134. if (val == true) {
  135. selecteds.value.add(item);
  136. selecteds.notifyListeners();
  137. } else {
  138. selecteds.value.removeWhere((element) => element.key == item.key);
  139. selecteds.notifyListeners();
  140. }
  141. },
  142. ),
  143. Expanded(
  144. child: Text(
  145. item.value ?? '',
  146. style: StylesText.body6,
  147. ),
  148. ),
  149. ],
  150. ),
  151. );
  152. }),
  153. itemCount: sources.length,
  154. );
  155. });
  156. },
  157. ),
  158. ),
  159. Row(
  160. children: [
  161. Expanded(
  162. child: SecondButton(
  163. title: 'Huỷ',
  164. color: AppColors.neutral3,
  165. onPressed: () {
  166. Get.back();
  167. },
  168. ),
  169. ),
  170. const SizedBox(
  171. width: 16,
  172. ),
  173. Expanded(
  174. child: SecondButton(
  175. title: 'Chọn',
  176. color: AppColors.primary1,
  177. onPressed: () {
  178. Get.back();
  179. selectValue.value = selecteds.value;
  180. widget.onSelected(selectValue.value);
  181. },
  182. ),
  183. ),
  184. ],
  185. )
  186. ],
  187. ),
  188. ),
  189. );
  190. },
  191. );
  192. }
  193. Widget _buildSelectAll(ValueNotifier<List<ItemDropDown>> selecteds) {
  194. return ValueListenableBuilder<List<ItemDropDown>>(
  195. valueListenable: dataSources,
  196. builder: (context, sources, _) {
  197. return ValueListenableBuilder<List<ItemDropDown>>(
  198. valueListenable: selecteds,
  199. builder: (context, valueSelected, _) {
  200. final isSelectAll = valueSelected.where((e) => sources.any((t) => t.key == e.key)).length == sources.length && sources.isNotEmpty;
  201. final tristate = valueSelected.where((e) => sources.firstWhereOrNull((t) => t.key == e.key) != null).isNotEmpty;
  202. return Visibility(
  203. visible: sources.isNotEmpty,
  204. child: Container(
  205. decoration: BoxDecoration(
  206. border: Border(
  207. bottom: BorderSide(
  208. color: AppColors.neutral1,
  209. width: 0.5,
  210. ),
  211. ),
  212. ),
  213. child: InkWell(
  214. onTap: () {
  215. if (isSelectAll) {
  216. selecteds.value = List.of(valueSelected)..removeWhere((e) => sources.firstWhereOrNull((t) => t.key == e.key) != null);
  217. } else {
  218. final itemsAdded = List.of(sources)..removeWhere((e) => valueSelected.firstWhereOrNull((t) => t.key == e.key) != null);
  219. selecteds.value = [...valueSelected, ...itemsAdded];
  220. }
  221. },
  222. child: Row(
  223. children: [
  224. Checkbox(
  225. value: isSelectAll ? isSelectAll : (tristate ? null : tristate),
  226. tristate: true,
  227. onChanged: (val) {
  228. if (isSelectAll) {
  229. selecteds.value = List.of(valueSelected)..removeWhere((e) => sources.firstWhereOrNull((t) => t.key == e.key) != null);
  230. } else {
  231. final itemsAdded = List.of(sources)..removeWhere((e) => valueSelected.firstWhereOrNull((t) => t.key == e.key) != null);
  232. selecteds.value = [...valueSelected, ...itemsAdded];
  233. }
  234. },
  235. ),
  236. Text(
  237. 'Tất cả',
  238. style: StylesText.body6,
  239. ),
  240. ],
  241. ),
  242. ),
  243. ),
  244. );
  245. },
  246. );
  247. },
  248. );
  249. }
  250. }