From 9f14775105efa198bc466c40e036b4d9834fe888 Mon Sep 17 00:00:00 2001 From: Joons Date: Wed, 12 Oct 2022 11:43:37 +0200 Subject: [PATCH 1/4] add input date picker --- CHANGELOG.md | 4 +- example/lib/example_pages/age_page.dart | 2 +- example/lib/example_pages/carousel_page.dart | 2 +- example/lib/example_pages/date_page.dart | 42 ++++++++++ example/lib/example_pages/name_page.dart | 2 +- example/lib/form_example.dart | 16 ++++ example/pubspec.lock | 2 +- example/pubspec.yaml | 1 + .../input_date_picker/date_picker.dart | 63 ++++++++++++++ .../input_date_picker/input_date_picker.dart | 83 +++++++++++++++++++ .../input/input_types/input_types.dart | 1 + pubspec.yaml | 4 +- 12 files changed, 214 insertions(+), 8 deletions(-) create mode 100644 example/lib/example_pages/date_page.dart create mode 100644 lib/src/widgets/input/input_types/input_date_picker/date_picker.dart create mode 100644 lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index d7a448f..3b1dc3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,3 @@ -## 0.0.1 - September 29th 2022 +## 0.0.2 - October 10th 2022 -- Initial release +- Add input date picker diff --git a/example/lib/example_pages/age_page.dart b/example/lib/example_pages/age_page.dart index 83d6c93..66f0f92 100644 --- a/example/lib/example_pages/age_page.dart +++ b/example/lib/example_pages/age_page.dart @@ -25,7 +25,7 @@ class _AgePageState extends State { fontSize: fontSize, title: "What is your age?", pageNumber: 1, - amountOfPages: 3, + amountOfPages: 4, flutterFormWidgets: [ FlutterFormInputNumberPicker( minValue: 12, diff --git a/example/lib/example_pages/carousel_page.dart b/example/lib/example_pages/carousel_page.dart index ac763c4..01d567b 100644 --- a/example/lib/example_pages/carousel_page.dart +++ b/example/lib/example_pages/carousel_page.dart @@ -27,7 +27,7 @@ class _CarouselPageState extends State { fontSize: fontSize, title: "What's your favorite car?", pageNumber: 3, - amountOfPages: 3, + amountOfPages: 4, flutterFormWidgets: [ FlutterFormInputCarousel( controller: widget.inputController, items: getCars()) diff --git a/example/lib/example_pages/date_page.dart b/example/lib/example_pages/date_page.dart new file mode 100644 index 0000000..ee3a498 --- /dev/null +++ b/example/lib/example_pages/date_page.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form/flutter_form.dart'; +import 'package:form_example/template_page.dart'; +import 'package:intl/intl.dart'; + +class DatePage extends StatefulWidget { + const DatePage({ + required this.dateController, + super.key, + }); + + final FlutterFormInputPlainTextController dateController; + + @override + State createState() => _DatePageState(); +} + +class _DatePageState extends State { + @override + Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; + var fontSize = size.height / 40; + + return TemplatePage( + size: size, + fontSize: fontSize, + pageNumber: 4, + amountOfPages: 4, + title: "Please enter a date", + flutterFormWidgets: [ + Padding( + padding: const EdgeInsets.fromLTRB(40, 0, 40, 40), + child: FlutterFormInputDate( + dateFormat: DateFormat.yMd(), + label: const Text("Date"), + controller: widget.dateController, + ), + ), + ], + ); + } +} diff --git a/example/lib/example_pages/name_page.dart b/example/lib/example_pages/name_page.dart index 0b8edcf..d3e2772 100644 --- a/example/lib/example_pages/name_page.dart +++ b/example/lib/example_pages/name_page.dart @@ -28,7 +28,7 @@ class _NamePageState extends State { size: size, fontSize: fontSize, pageNumber: 2, - amountOfPages: 3, + amountOfPages: 4, title: "Please enter your name", flutterFormWidgets: [ Padding( diff --git a/example/lib/form_example.dart b/example/lib/form_example.dart index 0d7c025..92e8723 100644 --- a/example/lib/form_example.dart +++ b/example/lib/form_example.dart @@ -6,6 +6,8 @@ import 'package:form_example/example_pages/carousel_page.dart'; import 'package:form_example/example_pages/check_page.dart'; import 'package:form_example/example_pages/name_page.dart'; +import 'example_pages/date_page.dart'; + class FormExample extends ConsumerStatefulWidget { const FormExample({Key? key}) : super(key: key); @@ -60,6 +62,15 @@ class _FormExampleState extends ConsumerState { }, ); + FlutterFormInputPlainTextController dateController = + FlutterFormInputPlainTextController( + mandatory: true, + id: "date", + checkPageTitle: (dynamic date) { + return "Date: $date"; + }, + ); + @override void initState() { super.initState(); @@ -189,6 +200,11 @@ class _FormExampleState extends ConsumerState { cars: cars, ), ), + FlutterFormPage( + child: DatePage( + dateController: dateController, + ), + ), ], checkPage: CheckPageExample() .showCheckpage(context, size, fontSize, checkPageText), diff --git a/example/pubspec.lock b/example/pubspec.lock index c0b7486..0ae6b69 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -94,7 +94,7 @@ packages: source: sdk version: "0.0.0" intl: - dependency: transitive + dependency: "direct main" description: name: intl url: "https://pub.dartlang.org" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c13fe9e..2d60953 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: flutter_riverpod: ^1.0.4 flutter_form: path: ../ + intl: ^0.17.0 dev_dependencies: diff --git a/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart b/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart new file mode 100644 index 0000000..b3b3686 --- /dev/null +++ b/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form/utils/translation_service.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; +import '../../../../../flutter_form.dart'; + +/// Generates a [TextFormField] for passwords. It requires a [FlutterFormInputController] +/// as the [controller] parameter and an optional [Widget] as [label] +class DateInputField extends ConsumerStatefulWidget { + const DateInputField( + {Key? key, + required this.controller, + this.label, + this.showIcon = true, + this.icon = Icons.calendar_today, + required this.dateFormat}) + : super( + key: key, + ); + final FlutterFormInputController controller; + final DateFormat dateFormat; + final bool showIcon; + final IconData icon; + final Widget? label; + @override + ConsumerState createState() => _DateInputFieldState(); +} + +class _DateInputFieldState extends ConsumerState { + @override + Widget build(BuildContext context) { + String Function(String, {List? params}) _ = + getTranslator(context, ref); + + return TextFormField( + key: Key(widget.controller.value.toString()), + initialValue: widget.controller.value, + onSaved: (value) { + widget.controller.onSaved(value); + }, + onTap: () async { + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime.now(), + lastDate: DateTime.now().add( + const Duration(days: 2000), + ), + ); + if (pickedDate != null) { + widget.controller.value = widget.dateFormat.format(pickedDate); + setState(() {}); + } + }, + validator: (value) => widget.controller.onValidate(value, _), + decoration: InputDecoration( + suffixIcon: widget.showIcon ? Icon(widget.icon) : null, + focusColor: Theme.of(context).primaryColor, + label: widget.label ?? const Text("Date"), + ), + ); + } +} 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 new file mode 100644 index 0000000..80d6416 --- /dev/null +++ b/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form/src/widgets/input/input_types/input_date_picker/date_picker.dart'; +import 'package:flutter_form/utils/translation_service.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; + +import '../../../../../flutter_form.dart'; + +/// Input for a date used in a [FlutterForm]. +/// +/// Standard controller is [FlutterFormInputDateController]. +class FlutterFormInputDate extends FlutterFormInputWidget { + const FlutterFormInputDate( + {Key? key, + required FlutterFormInputController controller, + Widget? label, + this.showIcon = true, + this.icon = Icons.calendar_today, + required this.dateFormat}) + : super( + key: key, + controller: controller, + label: label, + ); + final DateFormat dateFormat; + final bool showIcon; + final IconData icon; + + @override + Widget build(BuildContext context, WidgetRef ref) { + String Function(String, {List? params}) _ = + getTranslator(context, ref); + super.registerController(context); + + return DateInputField(controller: controller, dateFormat: dateFormat); + } +} + +/// Controller for dates used by a [FlutterFormInputWidget] used in a [FlutterForm]. +/// +/// Mainly used by [FlutterFormInputDate]. +class FlutterFormInputDateController + implements FlutterFormInputController { + FlutterFormInputDateController({ + required this.id, + this.mandatory = true, + this.value, + this.checkPageTitle, + this.checkPageDescription, + }); + + @override + String? id; + + @override + String? value; + + @override + bool mandatory; + + @override + String Function(String value)? checkPageTitle; + + @override + String Function(String value)? checkPageDescription; + + @override + void onSaved(dynamic value) { + this.value = value; + } + + @override + String? onValidate(String? value, + String Function(String, {List? params}) translator) { + if (mandatory) { + if (value == null || value.isEmpty) { + return translator('shell.form.error.empty'); + } + } + + return null; + } +} diff --git a/lib/src/widgets/input/input_types/input_types.dart b/lib/src/widgets/input/input_types/input_types.dart index 8920d92..2966836 100644 --- a/lib/src/widgets/input/input_types/input_types.dart +++ b/lib/src/widgets/input/input_types/input_types.dart @@ -4,3 +4,4 @@ export 'input_number_picker/input_number_picker.dart'; export 'input_password/input_password.dart'; export 'input_plain_text.dart'; export 'input_slider/input_slider.dart'; +export 'input_date_picker/input_date_picker.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 6cf096c..90f7de4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ homepage: publish_to: none environment: - sdk: '>=2.18.0 <3.0.0' + sdk: ">=2.18.0 <3.0.0" flutter: ">=1.17.0" dependencies: @@ -15,8 +15,8 @@ dependencies: flutter_localizations: sdk: flutter flutter_riverpod: ^1.0.4 + intl: ^0.17.0 localization: ^2.1.0 - sliding_up_panel: ^2.0.0+1 uuid: ^3.0.6 From a83b32bf527bed3550eddbe08bed0dccd664cebe Mon Sep 17 00:00:00 2001 From: Joons Date: Wed, 12 Oct 2022 11:43:37 +0200 Subject: [PATCH 2/4] add input date picker --- CHANGELOG.md | 3 +- example/lib/example_pages/age_page.dart | 2 +- example/lib/example_pages/carousel_page.dart | 2 +- example/lib/example_pages/date_page.dart | 42 ++++++++++ example/lib/example_pages/name_page.dart | 2 +- example/lib/form_example.dart | 16 ++++ example/pubspec.lock | 2 +- example/pubspec.yaml | 1 + .../input_date_picker/date_picker.dart | 63 ++++++++++++++ .../input_date_picker/input_date_picker.dart | 83 +++++++++++++++++++ .../input/input_types/input_types.dart | 1 + pubspec.yaml | 4 +- 12 files changed, 214 insertions(+), 7 deletions(-) create mode 100644 example/lib/example_pages/date_page.dart create mode 100644 lib/src/widgets/input/input_types/input_date_picker/date_picker.dart create mode 100644 lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a6ea9..fa4ea98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ -## 0.0.1 - September 29th 2022 +## 0.0.2 - October 10th 2022 - Initial release ## 0.0.2 - October 12th 2022 - Added a multi line plain text input widget +- Added date input widget - Ability to set the scrolldirection of the pageview - Ability to set the scrollphysics of the pages' scrollview. diff --git a/example/lib/example_pages/age_page.dart b/example/lib/example_pages/age_page.dart index 83d6c93..66f0f92 100644 --- a/example/lib/example_pages/age_page.dart +++ b/example/lib/example_pages/age_page.dart @@ -25,7 +25,7 @@ class _AgePageState extends State { fontSize: fontSize, title: "What is your age?", pageNumber: 1, - amountOfPages: 3, + amountOfPages: 4, flutterFormWidgets: [ FlutterFormInputNumberPicker( minValue: 12, diff --git a/example/lib/example_pages/carousel_page.dart b/example/lib/example_pages/carousel_page.dart index ac763c4..01d567b 100644 --- a/example/lib/example_pages/carousel_page.dart +++ b/example/lib/example_pages/carousel_page.dart @@ -27,7 +27,7 @@ class _CarouselPageState extends State { fontSize: fontSize, title: "What's your favorite car?", pageNumber: 3, - amountOfPages: 3, + amountOfPages: 4, flutterFormWidgets: [ FlutterFormInputCarousel( controller: widget.inputController, items: getCars()) diff --git a/example/lib/example_pages/date_page.dart b/example/lib/example_pages/date_page.dart new file mode 100644 index 0000000..ee3a498 --- /dev/null +++ b/example/lib/example_pages/date_page.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form/flutter_form.dart'; +import 'package:form_example/template_page.dart'; +import 'package:intl/intl.dart'; + +class DatePage extends StatefulWidget { + const DatePage({ + required this.dateController, + super.key, + }); + + final FlutterFormInputPlainTextController dateController; + + @override + State createState() => _DatePageState(); +} + +class _DatePageState extends State { + @override + Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; + var fontSize = size.height / 40; + + return TemplatePage( + size: size, + fontSize: fontSize, + pageNumber: 4, + amountOfPages: 4, + title: "Please enter a date", + flutterFormWidgets: [ + Padding( + padding: const EdgeInsets.fromLTRB(40, 0, 40, 40), + child: FlutterFormInputDate( + dateFormat: DateFormat.yMd(), + label: const Text("Date"), + controller: widget.dateController, + ), + ), + ], + ); + } +} diff --git a/example/lib/example_pages/name_page.dart b/example/lib/example_pages/name_page.dart index 0b8edcf..d3e2772 100644 --- a/example/lib/example_pages/name_page.dart +++ b/example/lib/example_pages/name_page.dart @@ -28,7 +28,7 @@ class _NamePageState extends State { size: size, fontSize: fontSize, pageNumber: 2, - amountOfPages: 3, + amountOfPages: 4, title: "Please enter your name", flutterFormWidgets: [ Padding( diff --git a/example/lib/form_example.dart b/example/lib/form_example.dart index 0d7c025..92e8723 100644 --- a/example/lib/form_example.dart +++ b/example/lib/form_example.dart @@ -6,6 +6,8 @@ import 'package:form_example/example_pages/carousel_page.dart'; import 'package:form_example/example_pages/check_page.dart'; import 'package:form_example/example_pages/name_page.dart'; +import 'example_pages/date_page.dart'; + class FormExample extends ConsumerStatefulWidget { const FormExample({Key? key}) : super(key: key); @@ -60,6 +62,15 @@ class _FormExampleState extends ConsumerState { }, ); + FlutterFormInputPlainTextController dateController = + FlutterFormInputPlainTextController( + mandatory: true, + id: "date", + checkPageTitle: (dynamic date) { + return "Date: $date"; + }, + ); + @override void initState() { super.initState(); @@ -189,6 +200,11 @@ class _FormExampleState extends ConsumerState { cars: cars, ), ), + FlutterFormPage( + child: DatePage( + dateController: dateController, + ), + ), ], checkPage: CheckPageExample() .showCheckpage(context, size, fontSize, checkPageText), diff --git a/example/pubspec.lock b/example/pubspec.lock index c0b7486..0ae6b69 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -94,7 +94,7 @@ packages: source: sdk version: "0.0.0" intl: - dependency: transitive + dependency: "direct main" description: name: intl url: "https://pub.dartlang.org" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c13fe9e..2d60953 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: flutter_riverpod: ^1.0.4 flutter_form: path: ../ + intl: ^0.17.0 dev_dependencies: diff --git a/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart b/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart new file mode 100644 index 0000000..b3b3686 --- /dev/null +++ b/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form/utils/translation_service.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; +import '../../../../../flutter_form.dart'; + +/// Generates a [TextFormField] for passwords. It requires a [FlutterFormInputController] +/// as the [controller] parameter and an optional [Widget] as [label] +class DateInputField extends ConsumerStatefulWidget { + const DateInputField( + {Key? key, + required this.controller, + this.label, + this.showIcon = true, + this.icon = Icons.calendar_today, + required this.dateFormat}) + : super( + key: key, + ); + final FlutterFormInputController controller; + final DateFormat dateFormat; + final bool showIcon; + final IconData icon; + final Widget? label; + @override + ConsumerState createState() => _DateInputFieldState(); +} + +class _DateInputFieldState extends ConsumerState { + @override + Widget build(BuildContext context) { + String Function(String, {List? params}) _ = + getTranslator(context, ref); + + return TextFormField( + key: Key(widget.controller.value.toString()), + initialValue: widget.controller.value, + onSaved: (value) { + widget.controller.onSaved(value); + }, + onTap: () async { + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime.now(), + lastDate: DateTime.now().add( + const Duration(days: 2000), + ), + ); + if (pickedDate != null) { + widget.controller.value = widget.dateFormat.format(pickedDate); + setState(() {}); + } + }, + validator: (value) => widget.controller.onValidate(value, _), + decoration: InputDecoration( + suffixIcon: widget.showIcon ? Icon(widget.icon) : null, + focusColor: Theme.of(context).primaryColor, + label: widget.label ?? const Text("Date"), + ), + ); + } +} 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 new file mode 100644 index 0000000..80d6416 --- /dev/null +++ b/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form/src/widgets/input/input_types/input_date_picker/date_picker.dart'; +import 'package:flutter_form/utils/translation_service.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; + +import '../../../../../flutter_form.dart'; + +/// Input for a date used in a [FlutterForm]. +/// +/// Standard controller is [FlutterFormInputDateController]. +class FlutterFormInputDate extends FlutterFormInputWidget { + const FlutterFormInputDate( + {Key? key, + required FlutterFormInputController controller, + Widget? label, + this.showIcon = true, + this.icon = Icons.calendar_today, + required this.dateFormat}) + : super( + key: key, + controller: controller, + label: label, + ); + final DateFormat dateFormat; + final bool showIcon; + final IconData icon; + + @override + Widget build(BuildContext context, WidgetRef ref) { + String Function(String, {List? params}) _ = + getTranslator(context, ref); + super.registerController(context); + + return DateInputField(controller: controller, dateFormat: dateFormat); + } +} + +/// Controller for dates used by a [FlutterFormInputWidget] used in a [FlutterForm]. +/// +/// Mainly used by [FlutterFormInputDate]. +class FlutterFormInputDateController + implements FlutterFormInputController { + FlutterFormInputDateController({ + required this.id, + this.mandatory = true, + this.value, + this.checkPageTitle, + this.checkPageDescription, + }); + + @override + String? id; + + @override + String? value; + + @override + bool mandatory; + + @override + String Function(String value)? checkPageTitle; + + @override + String Function(String value)? checkPageDescription; + + @override + void onSaved(dynamic value) { + this.value = value; + } + + @override + String? onValidate(String? value, + String Function(String, {List? params}) translator) { + if (mandatory) { + if (value == null || value.isEmpty) { + return translator('shell.form.error.empty'); + } + } + + return null; + } +} diff --git a/lib/src/widgets/input/input_types/input_types.dart b/lib/src/widgets/input/input_types/input_types.dart index 8920d92..2966836 100644 --- a/lib/src/widgets/input/input_types/input_types.dart +++ b/lib/src/widgets/input/input_types/input_types.dart @@ -4,3 +4,4 @@ export 'input_number_picker/input_number_picker.dart'; export 'input_password/input_password.dart'; export 'input_plain_text.dart'; export 'input_slider/input_slider.dart'; +export 'input_date_picker/input_date_picker.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 6cf096c..90f7de4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ homepage: publish_to: none environment: - sdk: '>=2.18.0 <3.0.0' + sdk: ">=2.18.0 <3.0.0" flutter: ">=1.17.0" dependencies: @@ -15,8 +15,8 @@ dependencies: flutter_localizations: sdk: flutter flutter_riverpod: ^1.0.4 + intl: ^0.17.0 localization: ^2.1.0 - sliding_up_panel: ^2.0.0+1 uuid: ^3.0.6 From 564f30b53c70c3b8818020b7d995bd8143866ad5 Mon Sep 17 00:00:00 2001 From: Jacques Doeleman Date: Wed, 12 Oct 2022 17:01:35 +0200 Subject: [PATCH 3/4] Changed readme --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa4ea98..71e0586 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,12 @@ - Initial release -## 0.0.2 - October 12th 2022 +## 0.1.0 - October 12th 2022 - Added a multi line plain text input widget -- Added date input widget - Ability to set the scrolldirection of the pageview - Ability to set the scrollphysics of the pages' scrollview. + +## 0.2.0 - October 13th 2022 + +- Added date input widget From 81b2f079c759285c139bca6f59a5e6038e7ab071 Mon Sep 17 00:00:00 2001 From: Joons Date: Thu, 13 Oct 2022 10:08:52 +0200 Subject: [PATCH 4/4] add enums to date picker --- example/lib/example_pages/date_page.dart | 4 +- .../input_date_picker/date_picker.dart | 116 ++++++++++++++---- .../input_date_picker/input_date_picker.dart | 55 ++++++--- 3 files changed, 134 insertions(+), 41 deletions(-) diff --git a/example/lib/example_pages/date_page.dart b/example/lib/example_pages/date_page.dart index ee3a498..169e946 100644 --- a/example/lib/example_pages/date_page.dart +++ b/example/lib/example_pages/date_page.dart @@ -30,8 +30,10 @@ class _DatePageState extends State { flutterFormWidgets: [ Padding( padding: const EdgeInsets.fromLTRB(40, 0, 40, 40), - child: FlutterFormInputDate( + child: FlutterFormInputDateTime( + inputType: FlutterFormDateTimeType.dateTime, dateFormat: DateFormat.yMd(), + firstDate: DateTime.now(), label: const Text("Date"), controller: widget.dateController, ), diff --git a/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart b/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart index b3b3686..f651353 100644 --- a/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart +++ b/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart @@ -1,56 +1,122 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_form/utils/translation_service.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import '../../../../../flutter_form.dart'; -/// Generates a [TextFormField] for passwords. It requires a [FlutterFormInputController] -/// as the [controller] parameter and an optional [Widget] as [label] -class DateInputField extends ConsumerStatefulWidget { - const DateInputField( - {Key? key, - required this.controller, - this.label, - this.showIcon = true, - this.icon = Icons.calendar_today, - required this.dateFormat}) - : super( +/// Generates a [DateTimeInputField] for DateTimes/Dates/Times/DateRanges. +/// It requires a [FlutterFormInputController], [inputType], [dateFormat], [firstDate], and [lastDate] +class DateTimeInputField extends ConsumerStatefulWidget { + const DateTimeInputField({ + Key? key, + required this.inputType, + required this.controller, + this.label, + this.showIcon = true, + this.icon = Icons.calendar_today, + required this.dateFormat, + required this.firstDate, + required this.lastDate, + }) : super( key: key, ); + final FlutterFormDateTimeType inputType; final FlutterFormInputController controller; final DateFormat dateFormat; final bool showIcon; + final DateTime? firstDate; + final DateTime? lastDate; final IconData icon; final Widget? label; @override - ConsumerState createState() => _DateInputFieldState(); + ConsumerState createState() => _DateInputFieldState(); } -class _DateInputFieldState extends ConsumerState { +class _DateInputFieldState extends ConsumerState { + late final DateTime firstDate; + late final DateTime lastDate; + + @override + void initState() { + firstDate = widget.firstDate ?? + DateTime.now().subtract( + const Duration(days: 1000), + ); + lastDate = widget.lastDate ?? + DateTime.now().add( + const Duration(days: 1000), + ); + + super.initState(); + } + @override Widget build(BuildContext context) { String Function(String, {List? params}) _ = getTranslator(context, ref); + Future getInputFromUser(FlutterFormDateTimeType inputType) async { + String userInput = ''; + switch (inputType) { + case FlutterFormDateTimeType.date: + DateTime? unformatted = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: firstDate, + lastDate: lastDate, + ); + userInput = unformatted != null + ? widget.dateFormat.format(unformatted) + : userInput; + break; + case FlutterFormDateTimeType.dateTime: + await getInputFromUser(FlutterFormDateTimeType.date) + .then((value) async { + if (value != '') { + String secondInput = + await getInputFromUser(FlutterFormDateTimeType.time); + if (secondInput != '') { + userInput = '$value $secondInput'; + } + } + }); + break; + case FlutterFormDateTimeType.range: + userInput = (await showDateRangePicker( + context: context, + firstDate: firstDate, + lastDate: lastDate, + ).then((value) { + return value != null + ? '${widget.dateFormat.format(value.start)} - ${widget.dateFormat.format(value.end)}' + : ''; + })) + .toString(); + break; + case FlutterFormDateTimeType.time: + userInput = await showTimePicker( + context: context, initialTime: TimeOfDay.now()) + .then((value) => value == null ? '' : value.format(context)); + } + return userInput; + } + return TextFormField( + keyboardType: TextInputType.none, + readOnly: true, key: Key(widget.controller.value.toString()), initialValue: widget.controller.value, onSaved: (value) { widget.controller.onSaved(value); }, onTap: () async { - DateTime? pickedDate = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime.now(), - lastDate: DateTime.now().add( - const Duration(days: 2000), - ), - ); - if (pickedDate != null) { - widget.controller.value = widget.dateFormat.format(pickedDate); - setState(() {}); - } + String userInput = await getInputFromUser(widget.inputType); + setState(() { + widget.controller.value = + userInput != '' ? userInput : widget.controller.value; + }); }, validator: (value) => widget.controller.onValidate(value, _), decoration: InputDecoration( 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 80d6416..02d7203 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 @@ -6,24 +6,38 @@ import 'package:intl/intl.dart'; import '../../../../../flutter_form.dart'; -/// Input for a date used in a [FlutterForm]. +/// Select Input Types in a [FlutterFormInputDateTime] +enum FlutterFormDateTimeType { + date, + time, + dateTime, + range, +} + +/// Input for a dateTime used in a [FlutterForm]. /// /// Standard controller is [FlutterFormInputDateController]. -class FlutterFormInputDate extends FlutterFormInputWidget { - const FlutterFormInputDate( - {Key? key, - required FlutterFormInputController controller, - Widget? label, - this.showIcon = true, - this.icon = Icons.calendar_today, - required this.dateFormat}) - : super( +class FlutterFormInputDateTime extends FlutterFormInputWidget { + const FlutterFormInputDateTime({ + Key? key, + required FlutterFormInputController controller, + Widget? label, + this.showIcon = true, + required this.inputType, + required this.dateFormat, + this.firstDate, + this.lastDate, + this.icon = Icons.calendar_today, + }) : super( key: key, controller: controller, label: label, ); - final DateFormat dateFormat; final bool showIcon; + final FlutterFormDateTimeType inputType; + final DateFormat dateFormat; + final DateTime? firstDate; + final DateTime? lastDate; final IconData icon; @override @@ -32,23 +46,34 @@ class FlutterFormInputDate extends FlutterFormInputWidget { getTranslator(context, ref); super.registerController(context); - return DateInputField(controller: controller, dateFormat: dateFormat); + return DateTimeInputField( + firstDate: firstDate, + lastDate: lastDate, + inputType: inputType, + controller: controller, + dateFormat: dateFormat, + ); } } /// Controller for dates used by a [FlutterFormInputWidget] used in a [FlutterForm]. /// -/// Mainly used by [FlutterFormInputDate]. -class FlutterFormInputDateController +/// Mainly used by [FlutterFormInputDateTime]. +class FlutterFormInputDateTimeController implements FlutterFormInputController { - FlutterFormInputDateController({ + FlutterFormInputDateTimeController({ required this.id, this.mandatory = true, this.value, this.checkPageTitle, this.checkPageDescription, + required this.dateTimeType, + required this.dateFormat, }); + final DateFormat dateFormat; + final FlutterFormDateTimeType dateTimeType; + @override String? id;