diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c6964..0af7bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -117,12 +117,15 @@ - Updated the `flutter_input_library` from 2.6.0 to 3.0.0 ## 6.2.3 - February 7th 2024 - - Added CI and linter ## 6.2.4 - February 9th 2024 - Updated the `flutter_input_library` from 3.0.0 to 3.0.1 ## 6.2.5 - February 15th 2024 +- Updated the `flutter_input_library` from 3.0.1 to 3.1.0 -- Updated the `flutter_input_library` from 3.0.1 to 3.1.0 \ No newline at end of file +## 6.3.0 - February 21th 2024 +- Updated the `flutter_input_library` from 3.1.0 to 3.2.1 +- Added `FlutterFormInputPhone` for phone number with dial code selection. +- Added `InputDecoration` parameter to the following inputfields: `FlutterFormInputEmail` and `FlutterFormInputPassword` \ No newline at end of file diff --git a/example/android/build.gradle b/example/android/build.gradle index 83ae220..3cdaac9 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/example/lib/form_example.dart b/example/lib/form_example.dart index 1f64507..2d44693 100644 --- a/example/lib/form_example.dart +++ b/example/lib/form_example.dart @@ -25,6 +25,14 @@ class _FormExampleState extends ConsumerState { final String checkPageText = "All entered info: "; + final phoneInputController = FlutterFormInputPhoneController( + id: 'phone', + onChanged: (value) { + debugPrint( + '${value?.dialCode ?? 'no dial'} ${value?.number ?? 'no number'}'); + }, + ); + final ageInputController = FlutterFormInputNumberPickerController( id: "age", checkPageTitle: (dynamic amount) { @@ -177,6 +185,13 @@ class _FormExampleState extends ConsumerState { return Container(); }, pages: [ + FlutterFormPage( + child: Center( + child: FlutterFormInputPhone( + controller: phoneInputController, + ), + ), + ), FlutterFormPage( child: AgePage( inputController: ageInputController, diff --git a/example/pubspec.lock b/example/pubspec.lock index 2ba5c6b..c442c7d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -68,16 +68,14 @@ packages: path: ".." relative: true source: path - version: "6.2.3" + version: "6.2.5" flutter_input_library: dependency: transitive description: - path: "." - ref: "3.0.0" - resolved-ref: "7024fb7e404fbeae0331bfe8f7c115283d0951ce" - url: "https://github.com/Iconica-Development/flutter_input_library" - source: git - version: "3.0.0" + path: "../../flutter_input_library" + relative: true + source: path + version: "3.2.1" flutter_lints: dependency: "direct dev" description: diff --git a/lib/src/form.dart b/lib/src/form.dart index 57fc24a..4a07e84 100644 --- a/lib/src/form.dart +++ b/lib/src/form.dart @@ -230,99 +230,95 @@ class _FlutterFormState extends State { } @override - Widget build(BuildContext context) { - var _ = getTranslator(context); - - return Stack( - children: [ - PageView( - scrollDirection: _formController._options.scrollDirection, - controller: _formController.getPageController(), - physics: const NeverScrollableScrollPhysics(), - children: [ - for (int i = 0; i < widget.options.pages.length; i++) ...[ - Form( - key: _formController.getKeys()[i], - child: fs.FormState( - formController: _formController.getFormPageControllers()[i], - child: CustomScrollView( - physics: _formController._options.scrollPhysics ?? - const ClampingScrollPhysics(), - slivers: [ - SliverFillRemaining( - hasScrollBody: false, - child: widget.options.pages[i].child, - ), - ], - ), - ), - ), - ], - if (widget.options.checkPage != null) - Column( - children: [ - if (widget.options.checkPage!.title != null) - widget.options.checkPage!.title!, - Expanded( + Widget build(BuildContext context) => Stack( + children: [ + PageView( + scrollDirection: _formController._options.scrollDirection, + controller: _formController.getPageController(), + physics: const NeverScrollableScrollPhysics(), + children: [ + for (int i = 0; i < widget.options.pages.length; i++) ...[ + Form( + key: _formController.getKeys()[i], + child: fs.FormState( + formController: _formController.getFormPageControllers()[i], child: CustomScrollView( physics: _formController._options.scrollPhysics ?? const ClampingScrollPhysics(), slivers: [ SliverFillRemaining( hasScrollBody: false, - child: Column( - mainAxisAlignment: - widget.options.checkPage!.mainAxisAlignment, - children: getResultWidgets(), - ), + child: widget.options.pages[i].child, ), ], ), ), - ], - ), - ], - ), - if (widget.options.nextButton != null) - widget.options.nextButton!( - _formController.getCurrentStep(), - _formController.getCheckpages(), - ) - else - Align( - alignment: AlignmentDirectional.bottomCenter, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - padding: const EdgeInsets.symmetric( - horizontal: 40, - vertical: 15, ), - textStyle: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, + ], + if (widget.options.checkPage != null) + Column( + children: [ + if (widget.options.checkPage!.title != null) + widget.options.checkPage!.title!, + Expanded( + child: CustomScrollView( + physics: _formController._options.scrollPhysics ?? + const ClampingScrollPhysics(), + slivers: [ + SliverFillRemaining( + hasScrollBody: false, + child: Column( + mainAxisAlignment: + widget.options.checkPage!.mainAxisAlignment, + children: getResultWidgets(), + ), + ), + ], + ), + ), + ], + ), + ], + ), + if (widget.options.nextButton != null) + widget.options.nextButton!( + _formController.getCurrentStep(), + _formController.getCheckpages(), + ) + else + Align( + alignment: AlignmentDirectional.bottomCenter, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).primaryColor, + padding: const EdgeInsets.symmetric( + horizontal: 40, + vertical: 15, + ), + textStyle: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + onPressed: () async { + await _formController.autoNextStep(); + }, + child: Text( + _formController.getCurrentStep() >= + widget.options.pages.length - 1 + ? 'Finish' + : 'Next', ), - ), - onPressed: () async { - await _formController.autoNextStep(); - }, - child: Text( - _formController.getCurrentStep() >= - widget.options.pages.length - 1 - ? 'Finish' - : 'Next', ), ), - ), - if (widget.options.backButton != null) - widget.options.backButton!( - _formController.getCurrentStep(), - _formController.getCheckpages(), - widget.options.pages.length, - ), - ], - ); - } + if (widget.options.backButton != null) + widget.options.backButton!( + _formController.getCurrentStep(), + _formController.getCheckpages(), + widget.options.pages.length, + ), + ], + ); List getResultWidgets() { var widgets = []; diff --git a/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart b/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart index 941e27f..767c7cb 100644 --- a/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart +++ b/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart @@ -27,13 +27,13 @@ class FlutterFormInputCarousel extends FlutterFormInputWidget { @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); super.registerController(context); return input.FlutterFormInputCarousel( onSaved: controller.onSaved, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), onChanged: controller.onChanged, initialValue: controller.value ?? 0, items: items, diff --git a/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart b/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart index 323f6c5..aa02830 100644 --- a/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart +++ b/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart @@ -41,7 +41,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget { @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); super.registerController(context); return input.FlutterFormInputDateTime( @@ -55,7 +55,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget { inputType: inputType, onChanged: (value) => controller.onChanged?.call(value), onSaved: controller.onSaved, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), initialValue: controller.value, dateFormat: dateFormat, initialDate: initialDate, diff --git a/lib/src/widgets/input/input_types/input_email.dart b/lib/src/widgets/input/input_types/input_email.dart index e99fac2..b222a68 100644 --- a/lib/src/widgets/input/input_types/input_email.dart +++ b/lib/src/widgets/input/input_types/input_email.dart @@ -16,13 +16,16 @@ class FlutterFormInputEmail extends FlutterFormInputWidget { super.focusNode, super.label, bool? enabled, + this.decoration, }) : super( enabled: enabled ?? true, ); + final InputDecoration? decoration; + @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); super.registerController(context); @@ -33,12 +36,9 @@ class FlutterFormInputEmail extends FlutterFormInputWidget { controller.onSaved(value); }, focusNode: focusNode, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), onChanged: (value) => controller.onChanged?.call(value), - decoration: InputDecoration( - focusColor: Theme.of(context).primaryColor, - label: label ?? const Text('Email'), - ), + decoration: decoration, ); } } diff --git a/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart b/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart index c74a803..7b9c0c8 100644 --- a/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart +++ b/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart @@ -26,7 +26,7 @@ class FlutterFormInputNumberPicker extends FlutterFormInputWidget { @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); super.registerController(context); @@ -34,7 +34,7 @@ class FlutterFormInputNumberPicker extends FlutterFormInputWidget { minValue: minValue, maxValue: maxValue, onSaved: controller.onSaved, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), onChanged: (value) => controller.onChanged?.call(value), initialValue: controller.value ?? minValue, ); diff --git a/lib/src/widgets/input/input_types/input_password/input_password.dart b/lib/src/widgets/input/input_types/input_password/input_password.dart index 357abe2..479bafa 100644 --- a/lib/src/widgets/input/input_types/input_password/input_password.dart +++ b/lib/src/widgets/input/input_types/input_password/input_password.dart @@ -16,24 +16,28 @@ class FlutterFormInputPassword extends FlutterFormInputWidget { super.focusNode, super.label, bool? enabled, + this.decoration, }) : super( enabled: enabled ?? true, ); + final InputDecoration? decoration; + @override Widget build(BuildContext context) { super.registerController(context); - var _ = getTranslator(context); + var translator = getTranslator(context); return input.FlutterFormInputPassword( enabled: enabled, initialValue: controller.value, focusNode: focusNode, onSaved: controller.onSaved, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), onChanged: (value) => controller.onChanged?.call(value), onFieldSubmitted: (value) => controller.onSubmit?.call(value), + decoration: decoration, ); } } diff --git a/lib/src/widgets/input/input_types/input_phone.dart b/lib/src/widgets/input/input_types/input_phone.dart new file mode 100644 index 0000000..24afbe1 --- /dev/null +++ b/lib/src/widgets/input/input_types/input_phone.dart @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: 2022 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +// ignore_for_file: overridden_fields + +import 'package:flutter/material.dart'; +import 'package:flutter_form_wizard/flutter_form.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; + +/// Input for plain text input used in a [FlutterForm]. +/// +/// Standard controller is [FlutterFormInputPlainTextController]. +class FlutterFormInputPhone extends FlutterFormInputWidget { + const FlutterFormInputPhone({ + required super.controller, + super.key, + super.focusNode, + super.label, + this.decoration, + this.enabled = true, + this.numberFieldStyle, + this.dialCodeSelectorStyle, + this.dialCodeSelectorPadding = const EdgeInsets.only(top: 6), + this.textAlignVertical = TextAlignVertical.top, + }); + + final InputDecoration? decoration; + @override + final bool enabled; + final TextStyle? numberFieldStyle; + final TextStyle? dialCodeSelectorStyle; + final EdgeInsets dialCodeSelectorPadding; + final TextAlignVertical textAlignVertical; + + @override + Widget build(BuildContext context) { + var translator = getTranslator(context); + + super.registerController(context); + + var inputDecoration = decoration ?? + InputDecoration( + label: label ?? const Text('Phone field'), + ); + + return input.FlutterFormInputPhone( + numberFieldStyle: numberFieldStyle, + dialCodeSelectorStyle: dialCodeSelectorStyle, + enabled: enabled, + initialValue: controller.value, + onSaved: controller.onSaved, + validator: (value) => controller.onValidate(value, translator), + onChanged: (value) => controller.onChanged?.call(value), + onFieldSubmitted: (value) => controller.onSubmit?.call(value), + decoration: inputDecoration, + dialCodeSelectorPadding: dialCodeSelectorPadding, + textAlignVertical: textAlignVertical, + ); + } +} + +class FlutterFormInputPhoneController + implements FlutterFormInputController { + FlutterFormInputPhoneController({ + required this.id, + this.mandatory = true, + this.value, + this.checkPageTitle, + this.checkPageDescription, + this.onChanged, + }); + + @override + String? id; + + @override + input.PhoneNumber? value; + + @override + bool mandatory; + + @override + String Function(input.PhoneNumber? value)? checkPageTitle; + + @override + String Function(input.PhoneNumber? value)? checkPageDescription; + + @override + void Function(input.PhoneNumber? value)? onChanged; + + @override + void Function(input.PhoneNumber? value)? onSubmit; + + @override + void onSaved(input.PhoneNumber? value) { + this.value = value; + } + + @override + String? onValidate( + input.PhoneNumber? value, + String Function(String, {List? params}) translator, + ) { + if (mandatory) { + if (value == null || value.number == null) { + return translator('Field can not be empty'); + } + } + + return null; + } +} diff --git a/lib/src/widgets/input/input_types/input_plain_text.dart b/lib/src/widgets/input/input_types/input_plain_text.dart index 0a54fb2..ed7ffc9 100644 --- a/lib/src/widgets/input/input_types/input_plain_text.dart +++ b/lib/src/widgets/input/input_types/input_plain_text.dart @@ -43,7 +43,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget { @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); super.registerController(context); @@ -59,7 +59,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget { initialValue: controller.value, focusNode: focusNode, onSaved: controller.onSaved, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), onChanged: (value) => controller.onChanged?.call(value), onFieldSubmitted: (value) => controller.onSubmit?.call(value), decoration: inputDecoration, @@ -103,7 +103,7 @@ class FlutterFormInputMultiLine extends StatelessWidget { @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); return input.FlutterFormInputMultiLine( enabled: enabled, @@ -114,7 +114,7 @@ class FlutterFormInputMultiLine extends StatelessWidget { maxCharacters: maxCharacters, onChanged: controller.onChanged, onSaved: controller.onSaved, - validator: (v) => controller.onValidate(v, _), + validator: (v) => controller.onValidate(v, translator), textCapitalization: textCapitalization, ); } diff --git a/lib/src/widgets/input/input_types/input_slider/input_slider.dart b/lib/src/widgets/input/input_types/input_slider/input_slider.dart index 1eab5d5..0dcfe23 100644 --- a/lib/src/widgets/input/input_types/input_slider/input_slider.dart +++ b/lib/src/widgets/input/input_types/input_slider/input_slider.dart @@ -25,14 +25,14 @@ class FlutterFormInputSlider extends FlutterFormInputWidget { @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); super.registerController(context); return input.FlutterFormInputSlider( focusNode: focusNode, onSaved: controller.onSaved, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), ); } } diff --git a/lib/src/widgets/input/input_types/input_switch/input_switch.dart b/lib/src/widgets/input/input_types/input_switch/input_switch.dart index 042b304..33f32f6 100644 --- a/lib/src/widgets/input/input_types/input_switch/input_switch.dart +++ b/lib/src/widgets/input/input_types/input_switch/input_switch.dart @@ -21,7 +21,7 @@ class FlutterFormInputSwitch extends FlutterFormInputWidget { @override Widget build(BuildContext context) { - var _ = getTranslator(context); + var translator = getTranslator(context); super.registerController(context); @@ -29,7 +29,7 @@ class FlutterFormInputSwitch extends FlutterFormInputWidget { focusNode: focusNode, onSaved: controller.onSaved, onChanged: controller.onChanged, - validator: (value) => controller.onValidate(value, _), + validator: (value) => controller.onValidate(value, translator), initialValue: controller.value ?? false, widgetType: input.BoolWidgetType.switchWidget, ); diff --git a/lib/src/widgets/input/input_types/input_types.dart b/lib/src/widgets/input/input_types/input_types.dart index 28e2a94..2ba6335 100644 --- a/lib/src/widgets/input/input_types/input_types.dart +++ b/lib/src/widgets/input/input_types/input_types.dart @@ -2,11 +2,15 @@ // // SPDX-License-Identifier: BSD-3-Clause +export 'package:flutter_input_library/flutter_input_library.dart' + show PhoneNumber; + export 'input_carousel/input_carousel.dart'; export 'input_date_picker/input_date_picker.dart'; export 'input_email.dart'; export 'input_number_picker/input_number_picker.dart'; export 'input_password/input_password.dart'; +export 'input_phone.dart'; export 'input_plain_text.dart'; export 'input_slider/input_slider.dart'; export 'input_switch/input_switch.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index dca5a0e..3d29b45 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_form_wizard description: A new Flutter package project. -version: 6.2.5 +version: 6.3.0 homepage: https://github.com/Iconica-Development/flutter_form_wizard publish_to: none @@ -18,7 +18,7 @@ dependencies: flutter_input_library: git: url: https://github.com/Iconica-Development/flutter_input_library - ref: 3.1.0 + ref: 3.2.1 dev_dependencies: flutter_test: