|
@@ -0,0 +1,177 @@
|
|
|
+import 'package:flutter/material.dart';
|
|
|
+
|
|
|
+import '../alert_dialog.dart';
|
|
|
+import 'cell.dart';
|
|
|
+
|
|
|
+typedef VCheckBoxCellGroupItemBuilder<T> = Widget Function(T data);
|
|
|
+
|
|
|
+typedef VCheckBoxCellGroupCheckChanged<T, TValue> = void Function(
|
|
|
+ TValue value,
|
|
|
+ bool isChecked,
|
|
|
+ T data,
|
|
|
+ List<TValue> checkedValues,
|
|
|
+);
|
|
|
+
|
|
|
+class VDialogCheckBoxCellGroup<T, TValue> extends StatefulWidget {
|
|
|
+ final String? title;
|
|
|
+ final List<CheckBoxCellGroupItem<T>> source;
|
|
|
+
|
|
|
+ /// 选项文本提取函数
|
|
|
+ final String Function(T data) labelGetter;
|
|
|
+
|
|
|
+ /// 选项值提取函数
|
|
|
+ final TValue Function(T data) valueGetter;
|
|
|
+
|
|
|
+ final VCheckBoxCellGroupCheckChanged<T, TValue>? onChanged;
|
|
|
+
|
|
|
+ const VDialogCheckBoxCellGroup({
|
|
|
+ super.key,
|
|
|
+ this.title,
|
|
|
+ required this.source,
|
|
|
+ required this.labelGetter,
|
|
|
+ required this.valueGetter,
|
|
|
+ this.onChanged,
|
|
|
+ });
|
|
|
+
|
|
|
+ Future<List<V>> show<V>() async {
|
|
|
+ final result = await VAlertDialog.showDialog<List<V>>(this);
|
|
|
+ return result!;
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ State<StatefulWidget> createState() => _DialogGroupState<T, TValue>();
|
|
|
+}
|
|
|
+
|
|
|
+class _DialogGroupState<T, TValue>
|
|
|
+ extends State<VDialogCheckBoxCellGroup<T, TValue>> {
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return VAlertDialog(
|
|
|
+ title: widget.title,
|
|
|
+ // contentPadding: EdgeInsets.symmetric(horizontal: 20),
|
|
|
+ content: Scrollbar(
|
|
|
+ thumbVisibility: true,
|
|
|
+ child: VCheckBoxCellGroup<T, TValue>(
|
|
|
+ labelGetter: widget.labelGetter,
|
|
|
+ valueGetter: widget.valueGetter,
|
|
|
+ source: widget.source,
|
|
|
+ onChanged: widget.onChanged,
|
|
|
+ isScrollable: true,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class CheckBoxCellGroupItem<T> {
|
|
|
+ final T data;
|
|
|
+ final bool isChecked;
|
|
|
+ final bool isDisabled;
|
|
|
+
|
|
|
+ CheckBoxCellGroupItem(
|
|
|
+ this.data, {
|
|
|
+ this.isChecked = false,
|
|
|
+ this.isDisabled = false,
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+class VCheckBoxCellGroup<T, TValue> extends StatefulWidget {
|
|
|
+ final List<CheckBoxCellGroupItem<T>> source;
|
|
|
+
|
|
|
+ /// 选项文本提取函数
|
|
|
+ final String Function(T data) labelGetter;
|
|
|
+
|
|
|
+ /// 选项值提取函数
|
|
|
+ final TValue Function(T data) valueGetter;
|
|
|
+
|
|
|
+ final VCheckBoxCellGroupCheckChanged<T, TValue>? onChanged;
|
|
|
+
|
|
|
+ final bool isScrollable;
|
|
|
+
|
|
|
+ const VCheckBoxCellGroup({
|
|
|
+ super.key,
|
|
|
+ required this.source,
|
|
|
+ required this.labelGetter,
|
|
|
+ required this.valueGetter,
|
|
|
+ this.onChanged,
|
|
|
+ this.isScrollable = true,
|
|
|
+ });
|
|
|
+
|
|
|
+ @override
|
|
|
+ State<StatefulWidget> createState() => _VCheckBoxCellGroupState<T, TValue>();
|
|
|
+}
|
|
|
+
|
|
|
+class _VCheckBoxCellGroupState<T, TValue>
|
|
|
+ extends State<VCheckBoxCellGroup<T, TValue>> {
|
|
|
+ List<TValue> _checkedValues = [];
|
|
|
+
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ _checkedValues = widget.source
|
|
|
+ .where((e) => e.isChecked)
|
|
|
+ .map((e) => widget.valueGetter.call(e.data))
|
|
|
+ .toList();
|
|
|
+
|
|
|
+ super.initState();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final divider = Divider(
|
|
|
+ thickness: 1,
|
|
|
+ color: Colors.grey.shade300,
|
|
|
+ height: 2,
|
|
|
+ );
|
|
|
+
|
|
|
+ final children = <Widget>[];
|
|
|
+ final count = widget.source.length;
|
|
|
+ for (var i = 0; i < count; i++) {
|
|
|
+ if (i > 0) {
|
|
|
+ children.add(divider);
|
|
|
+ }
|
|
|
+ final item = widget.source[i];
|
|
|
+ children.add(_buildItemWidget(item));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (widget.isScrollable) {
|
|
|
+ return ListView(
|
|
|
+ shrinkWrap: true,
|
|
|
+ children: children,
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ return Column(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
+ children: children,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildItemWidget(CheckBoxCellGroupItem<T> item) {
|
|
|
+ final label = widget.labelGetter.call(item.data);
|
|
|
+ final value = widget.valueGetter.call(item.data);
|
|
|
+ final isChecked = _checkedValues.contains(value);
|
|
|
+ return VCheckBoxCell<TValue>(
|
|
|
+ label: label,
|
|
|
+ value: value,
|
|
|
+ isChecked: isChecked,
|
|
|
+ isDisabled: item.isDisabled,
|
|
|
+ onChanged: (_, isChecked) {
|
|
|
+ _onCheckChanged(value, item.data, isChecked);
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ void _onCheckChanged(TValue value, T data, bool isChecked) {
|
|
|
+ setState(() {
|
|
|
+ if (isChecked) {
|
|
|
+ if (_checkedValues.contains(value) == false) {
|
|
|
+ _checkedValues.add(value);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ _checkedValues.remove(value);
|
|
|
+ }
|
|
|
+ widget.onChanged?.call(value, isChecked, data, _checkedValues);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|