From a79b0c3ad30a961aaca68d14fe3917aa57a33bb3 Mon Sep 17 00:00:00 2001 From: mike doornenbal Date: Mon, 1 Jul 2024 16:43:36 +0200 Subject: [PATCH] feat: add multiple choice form field --- CHANGELOG.md | 3 + .../input/input_types/input_types.dart | 1 + .../input/input_types/multiple_choice.dart | 159 ++++++++++++++++++ pubspec.yaml | 2 +- 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 lib/src/widgets/input/input_types/multiple_choice.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index f8a22a3..44c400b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -142,3 +142,6 @@ ## 6.4.0 - June 28th 2024 - Added `FlutterFormInputDropdown` for dropdown selection - Added style property to `FlutterFormInputEmail` + +## 6.5.0 - July 1st 2024 +- Added `FlutterFormMultipleChoice` for multiple choice selection diff --git a/lib/src/widgets/input/input_types/input_types.dart b/lib/src/widgets/input/input_types/input_types.dart index bd1b4b1..9972c76 100644 --- a/lib/src/widgets/input/input_types/input_types.dart +++ b/lib/src/widgets/input/input_types/input_types.dart @@ -15,3 +15,4 @@ export 'input_phone.dart'; export 'input_plain_text.dart'; export 'input_slider/input_slider.dart'; export 'input_switch/input_switch.dart'; +export 'multiple_choice.dart'; diff --git a/lib/src/widgets/input/input_types/multiple_choice.dart b/lib/src/widgets/input/input_types/multiple_choice.dart new file mode 100644 index 0000000..d43b62d --- /dev/null +++ b/lib/src/widgets/input/input_types/multiple_choice.dart @@ -0,0 +1,159 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form_wizard/flutter_form.dart'; + +class FlutterFormInputMultipleChoice extends FlutterFormInputWidget { + /// Creates a [FlutterFormInputMultipleChoice]. + /// + /// The [controller], [options], [builder], [validationMessage] parameters + /// are required. + /// The [key], [focusNode], [label] are optional. + const FlutterFormInputMultipleChoice({ + required super.controller, + required this.options, + required this.builder, + required this.validationMessage, + super.focusNode, + super.label, + super.key, + this.mainAxisExtent, + this.childAspectRatio = 1, + this.mainAxisSpacing = 0, + this.crossAxisSpacing = 0, + this.crossAxisCount = 3, + this.height, + this.shrinkwrap = true, + this.validator, + }); + + final List options; + final double? mainAxisExtent; + final double childAspectRatio; + final double mainAxisSpacing; + final double crossAxisSpacing; + final int crossAxisCount; + final double? height; + final bool shrinkwrap; + final Widget Function( + BuildContext context, + int index, + ValueNotifier selectedIndex, + FlutterFormInputController controller, + List options, + FormFieldState state, + ) builder; + final String? Function(String? value, String validationMessage)? validator; + final String validationMessage; + + @override + Widget build(BuildContext context) { + super.registerController(context); + var selectedIndex = ValueNotifier(null); + + return FormField( + onSaved: controller.onSaved, + validator: (value) => + validator?.call(value, validationMessage) ?? + controller.onValidate(value, validationMessage), + builder: (state) => SizedBox( + height: height, + child: Column( + children: [ + GridView.builder( + physics: const NeverScrollableScrollPhysics(), + itemCount: options.length, + shrinkWrap: shrinkwrap, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + mainAxisExtent: mainAxisExtent, + childAspectRatio: childAspectRatio, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + crossAxisCount: crossAxisCount, + ), + itemBuilder: (context, index) => ListenableBuilder( + listenable: selectedIndex, + builder: (context, widget) => builder.call( + context, + index, + selectedIndex, + controller, + options, + state, + ), + ), + ), + if (state.hasError) + Text( + state.errorText!, + style: const TextStyle( + color: Color(0xFFAD3645), + fontSize: 14.0, + fontWeight: FontWeight.bold, + ), + ) + else + const SizedBox.shrink(), + ], + ), + ), + ); + } +} + +class FlutterFormInputMultipleChoiceController + implements FlutterFormInputController { + /// Creates a [FlutterFormInputMultipleChoiceController]. + /// + /// The [id] parameter specifies the unique identifier for the controller. + /// The [mandatory] parameter specifies whether the input is mandatory. + /// The [value], [checkPageTitle], [checkPageDescription], [onChanged], + /// and [onSubmit] parameters are optional. + FlutterFormInputMultipleChoiceController({ + required this.id, + this.mandatory = false, + this.value, + this.checkPageTitle, + this.checkPageDescription, + this.onChanged, + this.onSubmit, + }); + + @override + String? id; + + @override + String? value; + + @override + bool mandatory; + + @override + String Function(String? value)? checkPageTitle; + + @override + String Function(String? value)? checkPageDescription; + + @override + void Function(String? value)? onChanged; + + @override + void Function(String? value)? onSubmit; + + @override + void onSaved(String? value) { + this.value = value; + } + + @override + String? onValidate( + String? value, + String validationMessage, + ) { + if (mandatory) { + if (value == null || value.isEmpty) { + return validationMessage; + } + } + + return null; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 8b07a01..b4737be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_form_wizard description: A new Flutter package project. -version: 6.4.0 +version: 6.5.0 homepage: https://github.com/Iconica-Development/flutter_form_wizard publish_to: none