Compare commits

..

No commits in common. "master" and "6.2.2" have entirely different histories.

38 changed files with 735 additions and 1336 deletions

View file

@ -1,14 +0,0 @@
name: Iconica Standard Component CI Workflow
# Workflow Caller version: 2.0.0
on:
pull_request:
workflow_dispatch:
jobs:
call-global-iconica-workflow:
uses: Iconica-Development/.github/.github/workflows/component-ci.yml@master
secrets: inherit
permissions: write-all
with:
subfolder: "." # add optional subfolder to run workflow in

View file

@ -1,14 +0,0 @@
name: Iconica Standard Component Documentation Workflow
# Workflow Caller version: 1.0.0
on:
release:
types: [published]
workflow_dispatch:
jobs:
call-iconica-component-documentation-workflow:
uses: Iconica-Development/.github/.github/workflows/component-documentation.yml@master
secrets: inherit
permissions: write-all

32
.github/workflows/flutter.yml vendored Normal file
View file

@ -0,0 +1,32 @@
name: CI
on:
push:
branches: [master]
pull_request:
branches:
- master
- feature/*
- bugfix/*
- hotfix/*
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: |
~/.gradle/wrapper
/opt/hostedtoolcache/flutter
key: ${{ runner.OS }}-flutter-install-cache
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- name: Flutter pub get
run: flutter pub get
- name: Dart format
run: dart format -o none --set-exit-if-changed .
- name: Flutter analyze
run: flutter analyze

View file

@ -1,14 +0,0 @@
name: Iconica Standard Component Release Workflow
# Workflow Caller version: 1.0.0
on:
release:
types: [published]
workflow_dispatch:
jobs:
call-global-iconica-workflow:
uses: Iconica-Development/.github/.github/workflows/component-release.yml@master
secrets: inherit
permissions: write-all

7
.gitignore vendored
View file

@ -19,7 +19,7 @@ migrate_working_dir/
# The .vscode folder contains launch configuration and tasks you configure in # The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line # VS Code which you may wish to be included in version control, so this line
# is commented out by default. # is commented out by default.
.vscode/ #.vscode/
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
@ -28,8 +28,3 @@ migrate_working_dir/
.dart_tool/ .dart_tool/
.packages .packages
build/ build/
.metadata
# FVM Version Cache
.fvm/
.fvmrc

10
.metadata Normal file
View file

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
channel: stable
project_type: package

View file

@ -1,129 +1,117 @@
## 6.6.0 - September 5th 2024 ## 0.0.2 - October 10th 2022
- Added `onBack` callback to the `FlutterFormOptions` to detect when the back button is pressed
## 6.5.0 - July 1st 2024 - Initial release
- Added `FlutterFormMultipleChoice` for multiple choice selection
## 6.4.0 - June 28th 2024 ## 0.1.0 - October 12th 2022
- Added `FlutterFormInputDropdown` for dropdown selection
- Added style property to `FlutterFormInputEmail`
## 6.3.2 - May 15th 2024 - Added a multi line plain text input widget
- Loosened the dependency on intl to be more compatible with several Flutter versions - Ability to set the scrolldirection of the pageview
- Ability to set the scrollphysics of the pages' scrollview.
## 6.3.1 - February 29th 2024 ## 0.2.0 - October 13th 2022
- Removed `TranslationService` and add `validationMessage` property to fields with validation.
- Added a way to override a input field validator.
- Exposed all properties for `FlutterFormInputDateTime` provided by `flutter_input_library`.
## 6.3.0 - February 21st 2024 - Added date input widget
- 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 input fields: `FlutterFormInputEmail` and `FlutterFormInputPassword`
## 6.2.5 - February 15th 2024 ## 1.0.0 - October 13th 2022
- Updated the `flutter_input_library` from 3.0.1 to 3.1.0
## 6.2.4 - February 9th 2024 - Fix: Proper use of generics
- Updated the `flutter_input_library` from 3.0.0 to 3.0.1 - Inputcontrollers now have an onChange.
- Added switch input field
## 6.2.3 - February 7th 2024 ## 1.0.1 - October 13th 2022
- Added CI and linter
## 6.2.2 - February 6th 2024 - Added forgotten onChanged parameter on date input field
- Updated the `flutter_input_library` from 2.6.0 to 3.0.0
## 6.2.1 - January 12th 2024 ## 1.0.2 - October 13th 2022
- Pass on the `initialValue` property to FlutterFormMultiLine
## 6.2.0 - December 14th 2023 - Added forgotten icon parameter on date input field and scrollpadding on text inputfield
- Pass on the `textCapitalization` property to FlutterFormPlainText and FlutterFormMultiLine ## 2.0.0 - October 26th 2022
- Added the id of the input field on the input check widget.
- Ability to set the height of the carousel input field.
- InputController now contains the onSubmit callback.
## 2.0.1 - October 27th 2022
- onChange of switch input not firing fixed
## 4.0.2 - November 29th 2022
- Name change to flutter_form_wizard
## 4.0.3 - November 29th 2022
- Change from input to `flutter_input_library`
## 5.0.0 - November 29th 2022
- `flutter_input_library` now enforces 24h time requirements
## 5.0.4 - January 12th 2023
- Add FocusNode option to inputs
## 5.0.5 - January 12th 2023
- Expose translations
## 5.0.6 - January 12th 2023
- `flutter_input_library` datetime validator fix
## 5.0.7 - January 12th 2023
- `flutter_input_library` add styling text datetime fix
## 5.0.8 - January 18th 2023
- `flutter_input_library` add focusNode option to `FlutterFormInputMultiLine`
## 5.0.9 - January 18th 2023
- `flutter_input_library` add initial time picker parameter
## 6.0.0 - march 28th 2023
- Bump `flutter_input_library` to version 2.0.0
- Remove unnecessary `riverpod` dependency
## 6.1.0 - May 12th 2023
- Make compatible to flutter 3.10
## 6.1.1 - August 10th 2023
- Bump `flutter_input_library` to version 2.2.0
## 6.1.2 - August 11th 2023
- Bump `flutter_input_library` to version 2.2.1
## 6.1.3 - September 26th 2023
- Fix date format for datecontroller
## 6.1.4 - October 26th 2023
- Bump `flutter_input_library` to version 2.3.0
## 6.1.5 - October 26th 2023
- Bump `flutter_input_library` to version 2.4.0
## 6.1.6 - October 26th 2023
- Add enabled property to FlutterFormInputPlainText and FlutterFormInputDateTime
## 6.1.7 - November 1st 2023
- pass on the show icon property to flutter form input date time widget
## 6.1.8 - December 6th 2023 ## 6.1.8 - December 6th 2023
- Pass on the style property to the FlutterFormPlainText input widget - Pass on the style property to the FlutterFormPlainText input widget
- Bump `flutter_input_library` to version 2.5.0 - Bump `flutter_input_library` to version 2.5.0
## 6.1.7 - November 1st 2023 ## 6.2.0 - December 14th 2023
- Pass on the show icon property to flutter form input date time widget - Pass on the `textCapitalization` property to FlutterFormPlainText and FlutterFormMultiLine
## 6.1.6 - October 26th 2023 ## 6.2.1 - January 12th 2024
- Add enabled property to FlutterFormInputPlainText and FlutterFormInputDateTime - Pass on the `initialValue` property to FlutterFormMultiLine
## 6.1.5 - October 26th 2023 ## 6.2.2 - February 6th 2024
- Bump `flutter_input_library` to version 2.4.0 - Updated the `flutter_input_library` from 2.6.0 to 3.0.0
## 6.1.4 - October 26th 2023
- Bump `flutter_input_library` to version 2.3.0
## 6.1.3 - September 26th 2023
- Fix date format for date controller
## 6.1.2 - August 11th 2023
- Bump `flutter_input_library` to version 2.2.1
## 6.1.1 - August 10th 2023
- Bump `flutter_input_library` to version 2.2.0
## 6.1.0 - May 12th 2023
- Make compatible with Flutter 3.10
## 6.0.0 - March 28th 2023
- Bump `flutter_input_library` to version 2.0.0
- Remove unnecessary `riverpod` dependency
## 5.0.9 - January 18th 2023
- `flutter_input_library` add initial time picker parameter
## 5.0.8 - January 18th 2023
- `flutter_input_library` add focusNode option to `FlutterFormInputMultiLine`
## 5.0.7 - January 12th 2023
- `flutter_input_library` add styling text datetime fix
## 5.0.6 - January 12th 2023
- `flutter_input_library` datetime validator fix
## 5.0.5 - January 12th 2023
- Expose translations
## 5.0.4 - January 12th 2023
- Add FocusNode option to inputs
## 5.0.0 - November 29th 2022
- `flutter_input_library` now enforces 24h time requirements
## 4.0.3 - November 29th 2022
- Change from input to `flutter_input_library`
## 4.0.2 - November 29th 2022
- Name change to flutter_form_wizard
## 2.0.1 - October 27th 2022
- onChange of switch input not firing fixed
## 2.0.0 - October 26th 2022
- Added the id of the input field on the input check widget.
- Ability to set the height of the carousel input field.
- InputController now contains the onSubmit callback.
## 1.0.2 - October 13th 2022
- Added forgotten icon parameter on date input field and scroll padding on text input field
## 1.0.1 - October 13th 2022
- Added forgotten onChanged parameter on date input field
## 1.0.0 - October 13th 2022
- Fix: Proper use of generics
- Input controllers now have an onChange.
- Added switch input field
## 0.2.0 - October 13th 2022
- Added date input widget
## 0.1.0 - October 12th 2022
- Added a multi-line plain text input widget
- Ability to set the scroll direction of the page view
- Ability to set the scroll physics of the pages' scroll view.
## 0.0.2 - October 10th 2022
- Initial release

View file

@ -1,9 +1,4 @@
include: package:flutter_iconica_analysis/analysis_options.yaml include: package:flutter_lints/flutter.yaml
# Possible to overwrite the rules from the package # Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
analyzer:
exclude:
linter:
rules:

45
example/.metadata Normal file
View file

@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
- platform: android
create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
- platform: ios
create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
- platform: linux
create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
- platform: macos
create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
- platform: web
create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
- platform: windows
create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View file

@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
tasks.register("clean", Delete) { task clean(type: Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

View file

@ -35,7 +35,6 @@ class _AgePageState extends State<AgePage> {
minValue: 12, minValue: 12,
maxValue: 120, maxValue: 120,
controller: widget.inputController, controller: widget.inputController,
validationMessage: 'Please fill in your age.',
), ),
], ],
); );

View file

@ -34,10 +34,7 @@ class _CarouselPageState extends State<CarouselPage> {
amountOfPages: 4, amountOfPages: 4,
flutterFormWidgets: [ flutterFormWidgets: [
FlutterFormInputCarousel( FlutterFormInputCarousel(
controller: widget.inputController, controller: widget.inputController, items: getCars())
items: getCars(),
validationMessage: 'Validation error message.',
)
], ],
); );
} }

View file

@ -46,7 +46,6 @@ class _DatePageState extends State<DatePage> {
), ),
label: const Text("Custom date label"), label: const Text("Custom date label"),
controller: widget.dateController, controller: widget.dateController,
validationMessage: 'Please fill in a date.',
), ),
), ),
], ],

View file

@ -40,7 +40,6 @@ class _NamePageState extends State<NamePage> {
child: FlutterFormInputPlainText( child: FlutterFormInputPlainText(
label: const Text("First Name"), label: const Text("First Name"),
controller: widget.firstNameController, controller: widget.firstNameController,
validationMessage: 'Please fill in your first name.',
), ),
), ),
if (widget.showLastName) if (widget.showLastName)
@ -49,7 +48,6 @@ class _NamePageState extends State<NamePage> {
child: FlutterFormInputPlainText( child: FlutterFormInputPlainText(
label: const Text("Last Name"), label: const Text("Last Name"),
controller: widget.lastNameController, controller: widget.lastNameController,
validationMessage: 'Please fill in your last name.',
), ),
), ),
], ],

View file

@ -25,14 +25,6 @@ class _FormExampleState extends ConsumerState<FormExample> {
final String checkPageText = "All entered info: "; 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( final ageInputController = FlutterFormInputNumberPickerController(
id: "age", id: "age",
checkPageTitle: (dynamic amount) { checkPageTitle: (dynamic amount) {
@ -185,14 +177,6 @@ class _FormExampleState extends ConsumerState<FormExample> {
return Container(); return Container();
}, },
pages: [ pages: [
FlutterFormPage(
child: Center(
child: FlutterFormInputPhone(
controller: phoneInputController,
validationMessage: 'Please fill in a valid phone number',
),
),
),
FlutterFormPage( FlutterFormPage(
child: AgePage( child: AgePage(
inputController: ageInputController, inputController: ageInputController,

View file

@ -45,10 +45,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: cupertino_icons name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.5"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -68,24 +68,24 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "6.5.0" version: "6.2.1"
flutter_input_library: flutter_input_library:
dependency: transitive dependency: transitive
description: description:
path: "." path: "."
ref: "3.4.0" ref: "3.0.0"
resolved-ref: cdc06bbb7933ba7ac2835e29d2c8fabf69e5f5a6 resolved-ref: "7024fb7e404fbeae0331bfe8f7c115283d0951ce"
url: "https://github.com/Iconica-Development/flutter_input_library" url: "https://github.com/Iconica-Development/flutter_input_library"
source: git source: git
version: "3.4.0" version: "3.0.0"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.3" version: "2.0.1"
flutter_localizations: flutter_localizations:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -95,10 +95,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_riverpod name: flutter_riverpod
sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d" sha256: "371f6e8acb69dbe8aa3e0a50c8a65f8a9352b599134d585cc4923261cb5ae4d6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.1" version: "2.1.1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -108,82 +108,58 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.19.0" version: "0.18.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.0.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.16+1" version: "0.12.16"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.11.1" version: "0.5.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.15.0" version: "1.10.0"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" version: "1.8.3"
riverpod: riverpod:
dependency: transitive dependency: transitive
description: description:
name: riverpod name: riverpod
sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d sha256: "899cd0999b2f3b798349d9b5639cfea81d406c011bd914097145ff92e91b29f9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.1" version: "2.1.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -209,10 +185,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: state_notifier name: state_notifier
sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "0.7.2+1"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
@ -241,10 +217,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.2" version: "0.6.1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -253,14 +229,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
vm_service: web:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: web
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.5" version: "0.3.0"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=3.2.0-194.0.dev <4.0.0"
flutter: ">=3.18.0-18.0.pre.54" flutter: ">=3.0.0"

View file

@ -16,7 +16,7 @@ dependencies:
flutter_riverpod: ^2.1.1 flutter_riverpod: ^2.1.1
flutter_form_wizard: flutter_form_wizard:
path: ../ path: ../
intl: any intl: ^0.18.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -2,10 +2,10 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
export 'package:flutter_input_library/flutter_input_library.dart'
show FlutterFormDateTimeType;
export 'src/form.dart'; export 'src/form.dart';
export 'src/widgets/input/abstractions.dart'; export 'src/widgets/input/abstractions.dart';
export 'src/widgets/input/input_types/input_types.dart'; export 'src/widgets/input/input_types/input_types.dart';
export 'package:flutter_input_library/flutter_input_library.dart'
show FlutterFormDateTimeType;
export 'utils/translation_service.dart';
export 'utils/form.dart'; export 'utils/form.dart';

View file

@ -3,23 +3,18 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart'; import '../flutter_form.dart';
import 'package:flutter_form_wizard/src/utils/form_page_controller.dart'; import 'utils/form_page_controller.dart';
import 'package:flutter_form_wizard/src/utils/formstate.dart' as fs; import 'utils/formstate.dart' as fs;
/// A wrapper for flutters [Form] that can be controlled by a controller and /// A wrapper for flutters [Form] that can be controlled by a controller and provides multiple pre-defined input types/fields
/// provides multiple pre-defined input types/fields /// [FlutterForm] also provides multi page forms and a check page for validation.
/// [FlutterForm] also provides multi page forms and a check page
/// for validation.
/// ///
/// A [FlutterFormController] has to be given to control what happens to values /// A [FlutterFormController] has to be given to control what happens to values and pages within the FlutterForm.
/// and pages within the FlutterForm.
/// ///
/// [FlutterFormOptions] have to be provided to control the appearance of /// [FlutterFormOptions] have to be provided to control the appearance of the form.
/// the form.
/// ///
/// WARNING Define your FormInputController above your FlutterForm. Otherwise /// WARNING Define your FormInputController above your FlutterForm. Otherwise when rebuild the controller will differ from the registered ones.
/// when rebuild the controller will differ from the registered ones.
/// ``` dart /// ``` dart
/// FlutterFormInputEmailController emailController = /// FlutterFormInputEmailController emailController =
/// FlutterFormInputEmailController(id: 'email'); /// FlutterFormInputEmailController(id: 'email');
@ -185,10 +180,10 @@ import 'package:flutter_form_wizard/src/utils/formstate.dart' as fs;
/// ``` /// ```
class FlutterForm extends StatefulWidget { class FlutterForm extends StatefulWidget {
const FlutterForm({ const FlutterForm({
Key? key,
required this.options, required this.options,
required this.formController, required this.formController,
super.key, }) : super(key: key);
});
final FlutterFormOptions options; final FlutterFormOptions options;
final FlutterFormController formController; final FlutterFormController formController;
@ -208,9 +203,9 @@ class _FlutterFormState extends State<FlutterForm> {
_formController.setFlutterFormOptions(widget.options); _formController.setFlutterFormOptions(widget.options);
var keys = <GlobalKey<FormState>>[]; List<GlobalKey<FormState>> keys = [];
for (var _ in widget.options.pages) { for (FlutterFormPage _ in widget.options.pages) {
keys.add(GlobalKey<FormState>()); keys.add(GlobalKey<FormState>());
} }
@ -220,9 +215,9 @@ class _FlutterFormState extends State<FlutterForm> {
setState(() {}); setState(() {});
}); });
var controllers = <FlutterFormPageController>[]; List<FlutterFormPageController> controllers = [];
for (var i = 0; i < widget.options.pages.length; i++) { for (int i = 0; i < widget.options.pages.length; i++) {
controllers.add(FlutterFormPageController()); controllers.add(FlutterFormPageController());
} }
@ -230,103 +225,97 @@ class _FlutterFormState extends State<FlutterForm> {
} }
@override @override
Widget build(BuildContext context) => Stack( Widget build(BuildContext context) {
children: [ var _ = getTranslator(context);
PageView(
scrollDirection: _formController._options.scrollDirection, return Stack(
controller: _formController.getPageController(), children: [
physics: const NeverScrollableScrollPhysics(), PageView(
children: [ scrollDirection: _formController._options.scrollDirection,
for (int i = 0; i < widget.options.pages.length; i++) ...[ controller: _formController.getPageController(),
Form( physics: const NeverScrollableScrollPhysics(),
key: _formController.getKeys()[i], children: [
child: fs.FormState( for (int i = 0; i < widget.options.pages.length; i++) ...[
formController: _formController.getFormPageControllers()[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(
child: CustomScrollView( child: CustomScrollView(
physics: _formController._options.scrollPhysics ?? physics: _formController._options.scrollPhysics ??
const ClampingScrollPhysics(), const ClampingScrollPhysics(),
slivers: [ slivers: [
SliverFillRemaining( SliverFillRemaining(
hasScrollBody: false, hasScrollBody: false,
child: widget.options.pages[i].child, child: Column(
mainAxisAlignment:
widget.options.checkPage!.mainAxisAlignment,
children: getResultWidgets(),
),
), ),
], ],
), ),
), ),
), ],
], ),
if (widget.options.checkPage != null) ],
Column( ),
children: [ widget.options.nextButton != null
if (widget.options.checkPage!.title != null) ? widget.options.nextButton!(_formController.getCurrentStep(),
widget.options.checkPage!.title!, _formController.getCheckpages())
Expanded( : Align(
child: CustomScrollView( alignment: AlignmentDirectional.bottomCenter,
physics: _formController._options.scrollPhysics ?? child: ElevatedButton(
const ClampingScrollPhysics(), style: ElevatedButton.styleFrom(
slivers: [ backgroundColor: Theme.of(context).primaryColor,
SliverFillRemaining( padding: const EdgeInsets.symmetric(
hasScrollBody: false, horizontal: 40, vertical: 15),
child: Column( textStyle: const TextStyle(
mainAxisAlignment: fontSize: 20, fontWeight: FontWeight.bold)),
widget.options.checkPage!.mainAxisAlignment, onPressed: () async {
children: getResultWidgets(), await _formController.autoNextStep();
), },
), child: Text(_formController.getCurrentStep() >=
],
),
),
],
),
],
),
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 widget.options.pages.length - 1
? 'Finish' ? "Finish"
: 'Next', : "Next"),
), ),
), ),
), if (widget.options.backButton != null)
if (widget.options.backButton != null) widget.options.backButton!(
widget.options.backButton!( _formController.getCurrentStep(),
_formController.getCurrentStep(), _formController.getCheckpages(),
_formController.getCheckpages(), widget.options.pages.length,
widget.options.pages.length, ),
), ],
], );
); }
List<Widget> getResultWidgets() { List<Widget> getResultWidgets() {
var widgets = <Widget>[]; List<Widget> widgets = [];
_formController.getAllResults().forEach( _formController.getAllResults().forEach(
(pageNumber, pageResults) { (pageNumber, pageResults) {
pageResults.forEach((inputId, inputResult) { pageResults.forEach((inputId, inputResult) {
var inputController = _formController FlutterFormInputController? inputController = _formController
.getFormPageControllers()[pageNumber] .getFormPageControllers()[pageNumber]
.getController(inputId); .getController(inputId);
@ -338,8 +327,10 @@ class _FlutterFormState extends State<FlutterForm> {
inputController.checkPageTitle != null inputController.checkPageTitle != null
? inputController.checkPageTitle!(inputController.value) ? inputController.checkPageTitle!(inputController.value)
: inputController.value.toString(), : inputController.value.toString(),
inputController.checkPageDescription inputController.checkPageDescription != null
?.call(inputController.value), ? inputController
.checkPageDescription!(inputController.value)
: null,
() async { () async {
await _formController.jumpToPage(pageNumber); await _formController.jumpToPage(pageNumber);
}, },
@ -387,7 +378,7 @@ class _FlutterFormState extends State<FlutterForm> {
Text( Text(
inputController.checkPageDescription!(inputResult), inputController.checkPageDescription!(inputResult),
style: const TextStyle(fontSize: 16), style: const TextStyle(fontSize: 16),
), )
], ],
), ),
), ),
@ -421,14 +412,15 @@ class FlutterFormController extends ChangeNotifier {
late List<FlutterFormPageController> _formPageControllers; late List<FlutterFormPageController> _formPageControllers;
List<FlutterFormPageController> getFormPageControllers() => List<FlutterFormPageController> getFormPageControllers() {
_formPageControllers; return _formPageControllers;
}
void setFormPageControllers(List<FlutterFormPageController> controllers) { setFormPageControllers(List<FlutterFormPageController> controllers) {
_formPageControllers = controllers; _formPageControllers = controllers;
} }
void voidisableCheckingPages() { disableCheckingPages() {
_checkingPages = false; _checkingPages = false;
for (var controller in _formPageControllers) { for (var controller in _formPageControllers) {
@ -444,9 +436,7 @@ class FlutterFormController extends ChangeNotifier {
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
_options.onNext( _options.onNext(
_currentStep, _currentStep, _formPageControllers[_currentStep].getAllValues());
_formPageControllers[_currentStep].getAllValues(),
);
if (_currentStep >= _options.pages.length - 1 && if (_currentStep >= _options.pages.length - 1 &&
_options.checkPage == null || _options.checkPage == null ||
@ -459,11 +449,9 @@ class FlutterFormController extends ChangeNotifier {
notifyListeners(); notifyListeners();
await _pageController.animateToPage( await _pageController.animateToPage(_currentStep,
_currentStep, duration: const Duration(milliseconds: 250),
duration: const Duration(milliseconds: 250), curve: Curves.ease);
curve: Curves.ease,
);
} else { } else {
_currentStep += 1; _currentStep += 1;
@ -474,11 +462,9 @@ class FlutterFormController extends ChangeNotifier {
notifyListeners(); notifyListeners();
await _pageController.animateToPage( await _pageController.animateToPage(_currentStep,
_currentStep, duration: const Duration(milliseconds: 250),
duration: const Duration(milliseconds: 250), curve: Curves.ease);
curve: Curves.ease,
);
} }
} }
} }
@ -487,7 +473,7 @@ class FlutterFormController extends ChangeNotifier {
Future<void> previousStep() async { Future<void> previousStep() async {
_currentStep -= 1; _currentStep -= 1;
_options.onBack?.call(_currentStep);
_checkingPages = false; _checkingPages = false;
notifyListeners(); notifyListeners();
@ -521,14 +507,13 @@ class FlutterFormController extends ChangeNotifier {
return false; return false;
} }
Map<String, dynamic> getCurrentStepResults() => Map<String, dynamic> getCurrentStepResults() {
_formPageControllers[_currentStep].getAllValues(); return _formPageControllers[_currentStep].getAllValues();
}
Future<void> nextStep() async { Future<void> nextStep() async {
_options.onNext( _options.onNext(
_currentStep, _currentStep, _formPageControllers[_currentStep].getAllValues());
_formPageControllers[_currentStep].getAllValues(),
);
_currentStep += 1; _currentStep += 1;
@ -538,19 +523,16 @@ class FlutterFormController extends ChangeNotifier {
notifyListeners(); notifyListeners();
await _pageController.animateToPage( await _pageController.animateToPage(_currentStep,
_currentStep, duration: const Duration(milliseconds: 250), curve: Curves.ease);
duration: const Duration(milliseconds: 250),
curve: Curves.ease,
);
} }
void finishForm() { finishForm() {
_options.onFinished(getAllResults()); _options.onFinished(getAllResults());
} }
Map<int, Map<String, dynamic>> getAllResults() { Map<int, Map<String, dynamic>> getAllResults() {
var allValues = <int, Map<String, dynamic>>{}; Map<int, Map<String, dynamic>> allValues = {};
for (var i = 0; i < _options.pages.length; i++) { for (var i = 0; i < _options.pages.length; i++) {
allValues.addAll({i: _formPageControllers[i].getAllValues()}); allValues.addAll({i: _formPageControllers[i].getAllValues()});
@ -558,19 +540,27 @@ class FlutterFormController extends ChangeNotifier {
return allValues; return allValues;
} }
void setFlutterFormOptions(FlutterFormOptions options) { setFlutterFormOptions(FlutterFormOptions options) {
_options = options; _options = options;
} }
void setKeys(List<GlobalKey<FormState>> keys) { setKeys(List<GlobalKey<FormState>> keys) {
_keys = keys; _keys = keys;
} }
List<GlobalKey<FormState>> getKeys() => _keys; List<GlobalKey<FormState>> getKeys() {
return _keys;
}
int getCurrentStep() => _currentStep; int getCurrentStep() {
return _currentStep;
}
bool getCheckpages() => _checkingPages; bool getCheckpages() {
return _checkingPages;
}
PageController getPageController() => _pageController; PageController getPageController() {
return _pageController;
}
} }

View file

@ -4,26 +4,21 @@
import 'package:flutter_form_wizard/flutter_form.dart'; import 'package:flutter_form_wizard/flutter_form.dart';
/// Controller class for managing input controllers in a Flutter form.
class FlutterFormPageController { class FlutterFormPageController {
/// List of input controllers.
List<FlutterFormInputController> _controllers = []; List<FlutterFormInputController> _controllers = [];
/// Registers an input controller.
void register(FlutterFormInputController inputController) { void register(FlutterFormInputController inputController) {
_controllers.add(inputController); _controllers.add(inputController);
} }
/// Clears all registered input controllers. clearControllers() {
void clearControllers() {
_controllers = []; _controllers = [];
} }
/// Checks if an input controller is registered with a given ID. bool _isRegisteredById(String id) {
bool _isRegisteredById(String id) => return _controllers.any((element) => (element.id == id));
_controllers.any((element) => element.id == id); }
/// Retrieves the input controller associated with the provided ID.
FlutterFormInputController? getController(String key) { FlutterFormInputController? getController(String key) {
if (_isRegisteredById(key)) { if (_isRegisteredById(key)) {
return _controllers.firstWhere((element) => element.id == key); return _controllers.firstWhere((element) => element.id == key);
@ -31,11 +26,10 @@ class FlutterFormPageController {
return null; return null;
} }
/// Retrieves all values from registered input controllers.
Map<String, dynamic> getAllValues() { Map<String, dynamic> getAllValues() {
var values = <String, dynamic>{}; Map<String, dynamic> values = {};
for (var controller in _controllers) { for (FlutterFormInputController controller in _controllers) {
if (controller.value != null) { if (controller.value != null) {
values.addAll({controller.id!: controller.value}); values.addAll({controller.id!: controller.value});
} }

View file

@ -3,23 +3,20 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/src/utils/form_page_controller.dart'; import 'form_page_controller.dart';
/// Widget for managing form state and providing access to form controller.
class FormState extends InheritedWidget { class FormState extends InheritedWidget {
/// Constructor for FormState.
const FormState({ const FormState({
required super.child, Key? key,
required Widget child,
required this.formController, required this.formController,
super.key, }) : super(key: key, child: child);
});
/// The form controller associated with this FormState.
final FlutterFormPageController formController; final FlutterFormPageController formController;
/// Retrieves the nearest ancestor FormState from the given context.
static FormState of(BuildContext context) { static FormState of(BuildContext context) {
var result = context.dependOnInheritedWidgetOfExactType<FormState>(); final FormState? result =
context.dependOnInheritedWidgetOfExactType<FormState>();
assert(result != null, 'No FormStat found in context'); assert(result != null, 'No FormStat found in context');
return result!; return result!;
} }

View file

@ -3,7 +3,7 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/src/utils/formstate.dart' as fs; import '/src/utils/formstate.dart' as fs;
/// Abstract class for the input widgets used in a [FlutterForm]. /// Abstract class for the input widgets used in a [FlutterForm].
/// ///
@ -12,19 +12,18 @@ import 'package:flutter_form_wizard/src/utils/formstate.dart' as fs;
/// ///
/// label is a standard parameter to normally sets the label of the input. /// label is a standard parameter to normally sets the label of the input.
/// ///
/// [registerController] should be called to register the given [controller] to /// [registerController] should be called to register the given [controller] to the form page.
/// the form page.
abstract class FlutterFormInputWidget<T> extends StatelessWidget { abstract class FlutterFormInputWidget<T> extends StatelessWidget {
const FlutterFormInputWidget({ const FlutterFormInputWidget({
Key? key,
required this.controller, required this.controller,
super.key,
this.focusNode, this.focusNode,
this.label, this.label,
this.enabled = true, this.enabled = true,
}); String? hintText,
}) : super(key: key);
/// The [controller] which determines how the value is handled and how the /// The [controller] which determines how the value is handled and how the value is shown on the checkpage.
/// value is shown on the checkpage.
final FlutterFormInputController<T> controller; final FlutterFormInputController<T> controller;
/// [label] is a standard parameter to normally sets the label of the input. /// [label] is a standard parameter to normally sets the label of the input.
@ -34,10 +33,9 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
final bool enabled; final bool enabled;
/// [registerController] should be called to register the given [controller] /// [registerController] should be called to register the given [controller] to the form page.
/// to the form page. registerController(BuildContext context) {
void registerController(BuildContext context) { FlutterFormInputController? localController =
var localController =
fs.FormState.of(context).formController.getController(controller.id!); fs.FormState.of(context).formController.getController(controller.id!);
if (localController == null) { if (localController == null) {
@ -50,13 +48,11 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
/// ///
/// The [id] determines the key in the [Map] returned by the [FlutterForm]. /// The [id] determines the key in the [Map] returned by the [FlutterForm].
/// ///
/// [value] is a way to set a initial value and will be the value when change /// [value] is a way to set a initial value and will be the value when change by the user.
/// by the user.
/// ///
/// [mandatory] determines if the input is mandatory. /// [mandatory] determines if the input is mandatory.
/// ///
/// [checkPageTitle] is a function where you can transform the value from the /// [checkPageTitle] is a function where you can transform the value from the input into something representable.
/// input into something representable.
/// This value will be given when defining the check page widgets. /// This value will be given when defining the check page widgets.
/// If this function is not set, the value will be used as is. /// If this function is not set, the value will be used as is.
/// Example: /// Example:
@ -66,32 +62,27 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
/// }, /// },
/// ``` /// ```
/// ///
/// [checkPageDescription] is the same as checkPageTitle but for the /// [checkPageDescription] is the same as checkPageTitle but for the description.
/// description. If null no description will be shown. /// If null no description will be shown.
/// ///
/// [onChanged] can be set to get the value whenever the user changes it. /// [onChanged] can be set to get the value whenever the user changes it. Should not be used to save the value.
/// Should not be used to save the value.
/// ///
/// [onSubmit] can be set to get the value whenever the user submits it. /// [onSubmit] can be set to get the value whenever the user submits it. Should not be used to save the value.
/// Should not be used to save the value.
/// ///
/// [onSaved] goes of when the save function is called for the page if /// [onSaved] goes of when the save function is called for the page if [onValidate] return null.
/// [onValidate] return null.
/// ///
/// [onValidate] is used to validate the given input by the user. /// [onValidate] is used to validate the given input by the user.
abstract class FlutterFormInputController<T> { abstract class FlutterFormInputController<T> {
/// The [id] determines the key in the [Map] returned by the [FlutterForm]. /// The [id] determines the key in the [Map] returned by the [FlutterForm].
String? id; String? id;
/// [value] is a way to set a initial value and will be the value when /// [value] is a way to set a initial value and will be the value when change by the user.
/// change by the user.
T? value; T? value;
/// [mandatory] determines if the input is mandatory. /// [mandatory] determines if the input is mandatory.
bool mandatory = false; bool mandatory = false;
/// [checkPageTitle] is a function where you can transform the value from the /// [checkPageTitle] is a function where you can transform the value from the input into something representable.
/// input into something representable.
/// This value will be given when defining the check page widgets. /// This value will be given when defining the check page widgets.
/// If this function is not set, the value will be used as is. /// If this function is not set, the value will be used as is.
/// Example: /// Example:
@ -102,26 +93,20 @@ abstract class FlutterFormInputController<T> {
/// ``` /// ```
String Function(T? value)? checkPageTitle; String Function(T? value)? checkPageTitle;
/// [checkPageDescription] is the same as checkPageTitle but for the /// [checkPageDescription] is the same as checkPageTitle but for the description.
/// description.
/// If null no description will be shown. /// If null no description will be shown.
String Function(T? value)? checkPageDescription; String Function(T? value)? checkPageDescription;
/// [onChanged] can be set to get the value whenever the user changes it. /// [onChanged] can be set to get the value whenever the user changes it. Should not be used to save the value.
/// Should not be used to save the value.
void Function(T? value)? onChanged; void Function(T? value)? onChanged;
/// [onSubmit] can be set to get the value whenever the user submits it. /// [onSubmit] can be set to get the value whenever the user submits it. Should not be used to save the value.
/// Should not be used to save the value.
void Function(T? value)? onSubmit; void Function(T? value)? onSubmit;
/// [onSaved] goes of when the save function is called for the page if /// [onSaved] goes of when the save function is called for the page if [onValidate] return null.
/// [onValidate] return null.
void onSaved(T? value); void onSaved(T? value);
/// [onValidate] is used to validate the given input by the user. /// [onValidate] is used to validate the given input by the user.
String? onValidate( String? onValidate(
T? value, T? value, String Function(String, {List<String>? params}) translator);
String validationMessage,
);
} }

View file

@ -15,28 +15,25 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
/// Height sets the height of the inputfield. Default to 425. /// Height sets the height of the inputfield. Default to 425.
class FlutterFormInputCarousel extends FlutterFormInputWidget<int> { class FlutterFormInputCarousel extends FlutterFormInputWidget<int> {
const FlutterFormInputCarousel({ const FlutterFormInputCarousel({
required super.controller, Key? key,
required this.validationMessage, required FlutterFormInputController<int> controller,
Widget? label,
required this.items, required this.items,
super.key,
super.label,
this.validator,
this.height = 425, this.height = 425,
}); }) : super(key: key, controller: controller, label: label);
final List<Widget> items; final List<Widget> items;
final double height; final double height;
final String validationMessage;
final String? Function(int?)? validator;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputCarousel( return input.FlutterFormInputCarousel(
onSaved: controller.onSaved, onSaved: (value) => controller.onSaved(value),
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
onChanged: controller.onChanged, onChanged: controller.onChanged,
initialValue: controller.value ?? 0, initialValue: controller.value ?? 0,
items: items, items: items,
@ -45,8 +42,7 @@ class FlutterFormInputCarousel extends FlutterFormInputWidget<int> {
} }
} }
/// Controller for the carousel used by a [FlutterFormInputWidget] used in /// Controller for the carousel used by a [FlutterFormInputWidget] used in a [FlutterForm].
/// a [FlutterForm].
/// ///
/// Mainly used by [FlutterFormInputCarousel]. /// Mainly used by [FlutterFormInputCarousel].
class FlutterFormInputCarouselController class FlutterFormInputCarouselController
@ -88,9 +84,7 @@ class FlutterFormInputCarouselController
@override @override
String? onValidate( String? onValidate(
int? value, int? value, String Function(String, {List<String>? params}) translator) {
String validationMessage,
) {
if (mandatory) {} if (mandatory) {}
return null; return null;

View file

@ -5,85 +5,53 @@
// ignore_for_file: overridden_fields, annotate_overrides // ignore_for_file: overridden_fields, annotate_overrides
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_input_library/flutter_input_library.dart' as input;
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../../../../../flutter_form.dart';
/// Input for a dateTime used in a [FlutterForm]. /// Input for a dateTime used in a [FlutterForm].
/// ///
/// Standard controller is [FlutterFormInputDateController]. /// Standard controller is [FlutterFormInputDateController].
class FlutterFormInputDateTime extends FlutterFormInputWidget<String> { class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
/// Creates a [FlutterFormInputDateTime].
///
/// The [controller], [inputType], [dateFormat] are required parameters.
/// The [label] parameter specifies the label of the input field.
/// The [showIcon] parameter determines whether to show an icon
/// with the input field.
/// The [firstDate] and [lastDate] parameters specify the range
/// of selectable dates.
/// The [initialDate] parameter specifies the initial date for
/// the input field.
/// The [initialDateTimeRange] parameter specifies the initial
/// date time range for the input field.
/// The [icon] parameter specifies the icon to show with the input field.
/// The [enabled] parameter specifies whether the input field is enabled.
/// The [onTapEnabled] parameter specifies whether tapping on
/// the input field is enabled.
const FlutterFormInputDateTime({ const FlutterFormInputDateTime({
required super.controller, Key? key,
required FlutterFormInputController<String> controller,
Widget? label,
this.showIcon = true,
required this.inputType, required this.inputType,
required this.dateFormat, required this.dateFormat,
required this.validationMessage,
this.decoration,
this.style,
super.key,
this.label,
this.showIcon = true,
this.firstDate, this.firstDate,
this.lastDate, this.lastDate,
this.initialDate, this.initialDate,
this.initialDateTimeRange, this.initialDateTimeRange,
this.initialTime,
this.icon = Icons.calendar_today, this.icon = Icons.calendar_today,
this.initialValue,
this.onChanged,
this.onSaved,
this.validator,
this.autovalidateMode = AutovalidateMode.disabled,
this.timePickerEntryMode = TimePickerEntryMode.dial,
this.enabled = true, this.enabled = true,
this.onTapEnabled = true, this.onTapEnabled = true,
}); }) : super(
final TextStyle? style; key: key,
final InputDecoration? decoration; controller: controller,
final Widget? label; label: label,
);
final bool showIcon; final bool showIcon;
final input.FlutterFormDateTimeType inputType; final input.FlutterFormDateTimeType inputType;
final DateFormat dateFormat; final DateFormat dateFormat;
final DateTime? initialDate; final DateTime? initialDate;
final DateTimeRange? initialDateTimeRange; final DateTimeRange? initialDateTimeRange;
final TimeOfDay? initialTime;
final DateTime? firstDate; final DateTime? firstDate;
final DateTime? lastDate; final DateTime? lastDate;
final IconData icon; final IconData icon;
final String? initialValue;
final String? Function(String?)? validator;
final String validationMessage;
final void Function(String?)? onSaved;
final void Function(String?)? onChanged;
final AutovalidateMode autovalidateMode;
final TimePickerEntryMode timePickerEntryMode;
final bool enabled; final bool enabled;
final bool onTapEnabled; final bool onTapEnabled;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputDateTime( return input.FlutterFormInputDateTime(
enabled: enabled, enabled: enabled,
showIcon: showIcon, showIcon: showIcon,
decoration: decoration,
onTapEnabled: onTapEnabled, onTapEnabled: onTapEnabled,
label: label, label: label,
icon: icon, icon: icon,
@ -91,9 +59,8 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
lastDate: lastDate, lastDate: lastDate,
inputType: inputType, inputType: inputType,
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
onSaved: controller.onSaved, onSaved: (value) => controller.onSaved(value),
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
initialValue: controller.value, initialValue: controller.value,
dateFormat: dateFormat, dateFormat: dateFormat,
initialDate: initialDate, initialDate: initialDate,
@ -102,28 +69,21 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
} }
} }
/// Controller for dates used by a [FlutterFormInputWidget] used in a /// Controller for dates used by a [FlutterFormInputWidget] used in a [FlutterForm].
/// [FlutterForm].
/// ///
/// Mainly used by [FlutterFormInputDateTime]. /// Mainly used by [FlutterFormInputDateTime].
class FlutterFormInputDateTimeController class FlutterFormInputDateTimeController
implements FlutterFormInputController<String> { implements FlutterFormInputController<String> {
/// Creates a [FlutterFormInputDateTimeController].
///
/// The [id], [dateTimeType], and [dateFormat] are required parameters.
/// The [mandatory] parameter specifies whether the input is mandatory.
/// The [value], [initialDate], [initialDateTimeRange], [checkPageTitle],
/// [checkPageDescription], and [onChanged] parameters are optional.
FlutterFormInputDateTimeController({ FlutterFormInputDateTimeController({
required this.id, required this.id,
required this.dateTimeType,
required this.dateFormat,
this.mandatory = true, this.mandatory = true,
this.value, this.value,
this.checkPageTitle, this.checkPageTitle,
this.checkPageDescription, this.checkPageDescription,
this.initialDate, this.initialDate,
this.initialDateTimeRange, this.initialDateTimeRange,
required this.dateTimeType,
required this.dateFormat,
this.onChanged, this.onChanged,
}) { }) {
if (value != null) { if (value != null) {
@ -158,18 +118,16 @@ class FlutterFormInputDateTimeController
void Function(String? value)? onSubmit; void Function(String? value)? onSubmit;
@override @override
void onSaved(value) { void onSaved(dynamic value) {
this.value = value; this.value = value;
} }
@override @override
String? onValidate( String? onValidate(String? value,
String? value, String Function(String, {List<String>? params}) translator) {
String validationMessage,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return validationMessage; return translator('shell.form.error.empty');
} }
} }

View file

@ -1,164 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input;
class FlutterFormInputDropdown extends FlutterFormInputWidget<Object> {
const FlutterFormInputDropdown({
required super.controller,
required this.validationMessage,
this.items,
this.selectedItemBuilder,
this.value,
this.hint,
this.disabledHint,
this.onChanged,
this.onTap,
this.elevation = 8,
this.style,
this.icon,
this.iconDisabledColor,
this.iconEnabledColor,
this.iconSize = 24.0,
this.isDense = false,
this.isExpanded = false,
this.itemHeight,
this.focusColor,
this.autofocus = false,
this.dropdownColor,
this.decoration,
this.onSaved,
this.validator,
this.autovalidateMode,
this.menuMaxHeight,
this.enableFeedback,
this.alignment = Alignment.centerLeft,
this.borderRadius,
this.padding,
super.key,
super.focusNode,
super.label,
});
final List<DropdownMenuItem<Object?>>? items;
final List<Widget> Function(BuildContext)? selectedItemBuilder;
final Object? value;
final Widget? hint;
final Widget? disabledHint;
final void Function(Object?)? onChanged;
final void Function()? onTap;
final int elevation;
final TextStyle? style;
final Widget? icon;
final Color? iconDisabledColor;
final Color? iconEnabledColor;
final double iconSize;
final bool isDense;
final bool isExpanded;
final double? itemHeight;
final Color? focusColor;
final bool autofocus;
final Color? dropdownColor;
final InputDecoration? decoration;
final void Function(Object?)? onSaved;
final String? Function(Object?)? validator;
final AutovalidateMode? autovalidateMode;
final double? menuMaxHeight;
final bool? enableFeedback;
final AlignmentGeometry alignment;
final BorderRadius? borderRadius;
final EdgeInsetsGeometry? padding;
final String validationMessage;
@override
Widget build(BuildContext context) {
super.registerController(context);
return input.FlutterFormInputDropdown(
items: items,
selectedItemBuilder: selectedItemBuilder,
value: value,
hint: hint,
disabledHint: disabledHint,
onChanged: controller.onChanged,
onTap: () => onTap?.call(),
elevation: elevation,
style: style,
icon: icon,
iconDisabledColor: iconDisabledColor,
iconEnabledColor: iconEnabledColor,
iconSize: iconSize,
isDense: isDense,
isExpanded: isExpanded,
itemHeight: itemHeight,
focusColor: focusColor,
focusNode: focusNode,
autofocus: autofocus,
dropdownColor: dropdownColor,
decoration: decoration,
onSaved: controller.onSaved,
validator: validator ??
(value) => controller.onValidate(
value,
validationMessage,
),
autovalidateMode: autovalidateMode,
menuMaxHeight: menuMaxHeight,
enableFeedback: enableFeedback,
alignment: alignment,
borderRadius: borderRadius,
padding: padding,
);
}
}
class FlutterFormInputDropdownController
implements FlutterFormInputController<Object> {
FlutterFormInputDropdownController({
required this.id,
this.mandatory = false,
this.value,
this.checkPageTitle,
this.checkPageDescription,
this.onChanged,
this.onSubmit,
});
@override
String? id;
@override
Object? value;
@override
bool mandatory;
@override
String Function(Object? value)? checkPageTitle;
@override
String Function(Object? value)? checkPageDescription;
@override
void Function(Object? value)? onChanged;
@override
void Function(Object? value)? onSubmit;
@override
void onSaved(Object? value) {
this.value = value;
}
@override
String? onValidate(
Object? value,
String validationMessage,
) {
if (mandatory) {
if (value == null) {
return validationMessage;
}
}
return null;
}
}

View file

@ -3,68 +3,56 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_input_library/flutter_input_library.dart' as input;
import '../../../../flutter_form.dart';
/// Input for an email used in a [FlutterForm]. /// Input for an email used in a [FlutterForm].
/// ///
/// Standard controller is [FlutterFormInputEmailController]. /// Standard controller is [FlutterFormInputEmailController].
class FlutterFormInputEmail extends FlutterFormInputWidget<String> { class FlutterFormInputEmail extends FlutterFormInputWidget<String> {
/// Creates a [FlutterFormInputEmail].
///
/// The [controller] parameter is required.
/// The [key], [focusNode], [label], and [enabled] parameters are optional.
const FlutterFormInputEmail({ const FlutterFormInputEmail({
required super.controller, Key? key,
required this.validationMessage, required FlutterFormInputController<String> controller,
super.key, FocusNode? focusNode,
super.focusNode, Widget? label,
super.label,
bool? enabled, bool? enabled,
this.validator,
this.decoration,
this.style,
}) : super( }) : super(
key: key,
controller: controller,
focusNode: focusNode,
label: label,
enabled: enabled ?? true, enabled: enabled ?? true,
); );
final InputDecoration? decoration;
final String validationMessage;
final String? Function(String?)? validator;
final TextStyle? style;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputPlainText( return input.FlutterFormInputPlainText(
style: style,
enabled: enabled, enabled: enabled,
initialValue: controller.value, initialValue: controller.value,
onSaved: (value) { onSaved: (value) {
controller.onSaved(value); controller.onSaved(value);
}, },
focusNode: focusNode, focusNode: focusNode,
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
decoration: decoration, decoration: InputDecoration(
focusColor: Theme.of(context).primaryColor,
label: label ?? const Text("Email"),
),
); );
} }
} }
/// Controller for emails used by a [FlutterFormInputWidget] used in /// Controller for emails used by a [FlutterFormInputWidget] used in a [FlutterForm].
/// a [FlutterForm].
/// ///
/// Mainly used by [FlutterFormInputEmail]. /// Mainly used by [FlutterFormInputEmail].
class FlutterFormInputEmailController class FlutterFormInputEmailController
implements FlutterFormInputController<String> { implements FlutterFormInputController<String> {
/// Creates a [FlutterFormInputEmailController].
///
/// 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.
FlutterFormInputEmailController({ FlutterFormInputEmailController({
required this.id, required this.id,
this.mandatory = true, this.mandatory = true,
@ -97,24 +85,22 @@ class FlutterFormInputEmailController
void Function(String? value)? onSubmit; void Function(String? value)? onSubmit;
@override @override
void onSaved(value) { void onSaved(dynamic value) {
this.value = value; this.value = value;
} }
@override @override
String? onValidate( String? onValidate(String? value,
String? value, String Function(String, {List<String>? params}) translator) {
String validationMessage,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return validationMessage; return translator('shell.form.error.empty');
} }
if (!RegExp( if (!RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+", r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
).hasMatch(value)) { .hasMatch(value)) {
return validationMessage; return translator('shell.form.error.email.notValid');
} }
} }

View file

@ -3,8 +3,8 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_input_library/flutter_input_library.dart' as input;
import '../../../../../flutter_form.dart';
/// Input for a number used in a [FlutterForm]. /// Input for a number used in a [FlutterForm].
/// ///
@ -14,48 +14,37 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
/// Standard controller is [FlutterFormInputNumberPickerController]. /// Standard controller is [FlutterFormInputNumberPickerController].
class FlutterFormInputNumberPicker extends FlutterFormInputWidget<int> { class FlutterFormInputNumberPicker extends FlutterFormInputWidget<int> {
const FlutterFormInputNumberPicker({ const FlutterFormInputNumberPicker({
required super.controller, Key? key,
required this.validationMessage, required FlutterFormInputController<int> controller,
super.key, Widget? label,
super.label, FocusNode? focusNode,
this.validator,
this.minValue = 0, this.minValue = 0,
this.maxValue = 100, this.maxValue = 100,
}) : assert(minValue < maxValue, 'minValue must be less than maxValue'); }) : assert(minValue < maxValue),
super(key: key, controller: controller, label: label);
final int minValue; final int minValue;
final int maxValue; final int maxValue;
final String validationMessage;
final String? Function(int?)? validator;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputNumberPicker( return input.FlutterFormInputNumberPicker(
minValue: minValue, minValue: minValue,
maxValue: maxValue, maxValue: maxValue,
onSaved: controller.onSaved, onSaved: (value) => controller.onSaved(value),
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
initialValue: controller.value ?? minValue, initialValue: controller.value ?? minValue,
); );
} }
} }
/// Controller for numbers used by a [FlutterFormInputWidget] used in a
/// [FlutterForm].
///
/// Mainly used by [FlutterFormInputNumberPicker].
class FlutterFormInputNumberPickerController class FlutterFormInputNumberPickerController
implements FlutterFormInputController<int> { implements FlutterFormInputController<int> {
/// Creates a [FlutterFormInputNumberPickerController].
///
/// The [id] parameter specifies the unique identifier for the controller.
/// The [mandatory] parameter specifies whether the input is mandatory.
/// The [value], [checkPageTitle], [checkPageDescription],
/// and [onChanged] parameters are optional.
FlutterFormInputNumberPickerController({ FlutterFormInputNumberPickerController({
required this.id, required this.id,
this.mandatory = true, this.mandatory = true,
@ -93,9 +82,7 @@ class FlutterFormInputNumberPickerController
@override @override
String? onValidate( String? onValidate(
int? value, int? value, String Function(String, {List<String>? params}) translator) {
String validationMessage,
) {
if (mandatory) {} if (mandatory) {}
return null; return null;

View file

@ -3,59 +3,50 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_input_library/flutter_input_library.dart' as input;
import '../../../../../flutter_form.dart';
/// Input for a password used in a [FlutterForm]. /// Input for a password used in a [FlutterForm].
/// ///
/// Standard controller is [FlutterFormInputEmailController]. /// Standard controller is [FlutterFormInputEmailController].
class FlutterFormInputPassword extends FlutterFormInputWidget<String> { class FlutterFormInputPassword extends FlutterFormInputWidget<String> {
const FlutterFormInputPassword({ const FlutterFormInputPassword({
required super.controller, Key? key,
required this.validationMessage, required FlutterFormInputController<String> controller,
super.key, FocusNode? focusNode,
super.focusNode, Widget? label,
super.label,
bool? enabled, bool? enabled,
this.validator,
this.decoration,
}) : super( }) : super(
key: key,
controller: controller,
focusNode: focusNode,
label: label,
enabled: enabled ?? true, enabled: enabled ?? true,
); );
final InputDecoration? decoration;
final String validationMessage;
final String? Function(String?)? validator;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.registerController(context); super.registerController(context);
String Function(String, {List<String>? params}) _ = getTranslator(context);
return input.FlutterFormInputPassword( return input.FlutterFormInputPassword(
enabled: enabled, enabled: enabled,
initialValue: controller.value, initialValue: controller.value,
focusNode: focusNode, focusNode: focusNode,
onSaved: controller.onSaved, onSaved: (value) => controller.onSaved(value),
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.call(value), onFieldSubmitted: (value) => controller.onSubmit?.call(value),
decoration: decoration,
); );
} }
} }
/// Controller for passwords used by a [FlutterFormInputWidget] used in a /// Controller for passwords used by a [FlutterFormInputWidget] used in a [ShellFrom].
/// [ShellFrom].
/// ///
/// Mainly used by [FlutterFormInputPassword]. /// Mainly used by [FlutterFormInputPassword].
class FlutterFormInputPasswordController class FlutterFormInputPasswordController
implements FlutterFormInputController<String> { implements FlutterFormInputController<String> {
/// Creates a [FlutterFormInputPasswordController].
///
/// 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.
FlutterFormInputPasswordController({ FlutterFormInputPasswordController({
required this.id, required this.id,
this.mandatory = true, this.mandatory = true,
@ -88,22 +79,20 @@ class FlutterFormInputPasswordController
void Function(String? value)? onSubmit; void Function(String? value)? onSubmit;
@override @override
void onSaved(value) { void onSaved(dynamic value) {
this.value = value; this.value = value;
} }
@override @override
String? onValidate( String? onValidate(String? value,
String? value, String Function(String, {List<String>? params}) translator) {
String validationMessage,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return validationMessage; return translator('Field can not be empty');
} }
if (value.length < 6) { if (value.length < 6) {
return validationMessage; return translator('Field should be atleast 6 characters long');
} }
} }

View file

@ -1,116 +0,0 @@
// 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<input.PhoneNumber?> {
const FlutterFormInputPhone({
required super.controller,
required this.validationMessage,
super.key,
super.focusNode,
super.label,
this.decoration,
this.enabled = true,
this.numberFieldStyle,
this.validator,
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;
final String validationMessage;
final String? Function(PhoneNumber?)? validator;
@override
Widget build(BuildContext 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: validator ??
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.call(value),
decoration: inputDecoration,
dialCodeSelectorPadding: dialCodeSelectorPadding,
textAlignVertical: textAlignVertical,
);
}
}
class FlutterFormInputPhoneController
implements FlutterFormInputController<input.PhoneNumber?> {
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 validationMessage,
) {
if (mandatory) {
if (value == null || value.number == null) {
return validationMessage;
}
}
return null;
}
}

View file

@ -5,25 +5,19 @@
// ignore_for_file: overridden_fields // ignore_for_file: overridden_fields
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_input_library/flutter_input_library.dart' as input;
import '../../../../flutter_form.dart';
/// Input for plain text input used in a [FlutterForm]. /// Input for plain text input used in a [FlutterForm].
/// ///
/// Standard controller is [FlutterFormInputPlainTextController]. /// Standard controller is [FlutterFormInputPlainTextController].
class FlutterFormInputPlainText extends FlutterFormInputWidget<String> { class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
/// Creates a [FlutterFormInputPlainText].
///
/// The [controller] parameter is required.
/// The [key], [focusNode], [label], [decoration], [textAlignVertical],
/// [expands], [maxLines], [scrollPadding], [maxLength], [keyboardType],
/// [enabled], [style], and [textCapitalization] parameters are optional.
const FlutterFormInputPlainText({ const FlutterFormInputPlainText({
required super.controller, Key? key,
required this.validationMessage, required FlutterFormInputController<String> controller,
super.key, FocusNode? focusNode,
super.focusNode, Widget? label,
super.label,
this.decoration, this.decoration,
this.textAlignVertical, this.textAlignVertical,
this.expands = false, this.expands = false,
@ -31,11 +25,14 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
this.scrollPadding, this.scrollPadding,
this.maxLength, this.maxLength,
this.keyboardType, this.keyboardType,
this.validator,
this.enabled = true, this.enabled = true,
this.style, this.style,
this.textCapitalization = TextCapitalization.none, this.textCapitalization = TextCapitalization.none,
}); }) : super(
key: key,
controller: controller,
focusNode: focusNode,
label: label);
final InputDecoration? decoration; final InputDecoration? decoration;
final TextAlignVertical? textAlignVertical; final TextAlignVertical? textAlignVertical;
@ -48,16 +45,16 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
final bool enabled; final bool enabled;
final TextStyle? style; final TextStyle? style;
final TextCapitalization textCapitalization; final TextCapitalization textCapitalization;
final String validationMessage;
final String? Function(String?)? validator;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context);
super.registerController(context); super.registerController(context);
var inputDecoration = decoration ?? InputDecoration inputDecoration = decoration ??
InputDecoration( InputDecoration(
label: label ?? const Text('Plain text'), label: label ?? const Text("Plain text"),
); );
return input.FlutterFormInputPlainText( return input.FlutterFormInputPlainText(
@ -66,9 +63,8 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
scrollPadding: scrollPadding ?? const EdgeInsets.all(20.0), scrollPadding: scrollPadding ?? const EdgeInsets.all(20.0),
initialValue: controller.value, initialValue: controller.value,
focusNode: focusNode, focusNode: focusNode,
onSaved: controller.onSaved, onSaved: (value) => controller.onSaved(value),
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.call(value), onFieldSubmitted: (value) => controller.onSubmit?.call(value),
decoration: inputDecoration, decoration: inputDecoration,
@ -91,71 +87,49 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
/// MaxCharacters can be set to set a maximum amount of characters. /// MaxCharacters can be set to set a maximum amount of characters.
class FlutterFormInputMultiLine extends StatelessWidget { class FlutterFormInputMultiLine extends StatelessWidget {
const FlutterFormInputMultiLine({ const FlutterFormInputMultiLine({
Key? key,
required this.controller, required this.controller,
required this.validationMessage,
super.key,
this.focusNode, this.focusNode,
this.label, this.label,
this.hint, this.hint,
this.validator,
this.maxCharacters, this.maxCharacters,
this.enabled = true, this.enabled = true,
this.textCapitalization = TextCapitalization.sentences, this.textCapitalization = TextCapitalization.sentences,
}); }) : super(key: key);
/// The controller for the multi-line input.
final FlutterFormInputController<String> controller; final FlutterFormInputController<String> controller;
/// The optional label widget for the input.
final Widget? label; final Widget? label;
/// The optional focus node for the input.
final FocusNode? focusNode; final FocusNode? focusNode;
/// The optional hint text displayed inside the input field.
final String? hint; final String? hint;
/// The optional maximum number of characters allowed in the input field.
final int? maxCharacters; final int? maxCharacters;
/// A flag indicating whether the input field is enabled.
final bool enabled; final bool enabled;
/// The capitalization behavior for the input field.
final TextCapitalization textCapitalization; final TextCapitalization textCapitalization;
final String validationMessage;
final String? Function(String?)? validator;
@override @override
Widget build(BuildContext context) => input.FlutterFormInputMultiLine( Widget build(BuildContext context) {
enabled: enabled, String Function(String, {List<String>? params}) _ = getTranslator(context);
label: label,
hint: hint, return input.FlutterFormInputMultiLine(
focusNode: focusNode, enabled: enabled,
initialValue: controller.value, label: label,
maxCharacters: maxCharacters, hint: hint,
onChanged: controller.onChanged, focusNode: focusNode,
onSaved: controller.onSaved, initialValue: controller.value,
validator: validator ?? maxCharacters: maxCharacters,
(value) => controller.onValidate(value, validationMessage), onChanged: controller.onChanged,
textCapitalization: textCapitalization, onSaved: controller.onSaved,
); validator: (v) => controller.onValidate(v, _),
textCapitalization: textCapitalization,
);
}
} }
/// Controller for plain text used by a [FlutterFormInputWidget] used in a /// Controller for plain text used by a [FlutterFormInputWidget] used in a [FlutterForm].
/// [FlutterForm].
/// ///
/// Mainly used by [FlutterFormInputPlainText]. /// Mainly used by [FlutterFormInputPlainText].
class FlutterFormInputPlainTextController class FlutterFormInputPlainTextController
implements FlutterFormInputController<String> { implements FlutterFormInputController<String> {
/// Creates a [FlutterFormInputPlainTextController].
///
/// 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.
FlutterFormInputPlainTextController({ FlutterFormInputPlainTextController({
required this.id, required this.id,
this.mandatory = false, this.mandatory = false,
@ -193,13 +167,11 @@ class FlutterFormInputPlainTextController
} }
@override @override
String? onValidate( String? onValidate(String? value,
String? value, String Function(String, {List<String>? params}) translator) {
String validationMessage,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return validationMessage; return translator('Field can not be empty');
} }
} }

View file

@ -3,61 +3,50 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_input_library/flutter_input_library.dart' as input;
/// Input for a number value between two values via a slider. Used in a import '../../../../../flutter_form.dart';
/// [FlutterForm].
/// Input for a number value between two values via a slider. Used in a [FlutterForm].
/// ///
/// Standard controller is [FlutterFormInputSliderController]. /// Standard controller is [FlutterFormInputSliderController].
class FlutterFormInputSlider extends FlutterFormInputWidget<double> { class FlutterFormInputSlider extends FlutterFormInputWidget<double> {
/// Creates a [FlutterFormInputPassword].
///
/// The [controller] parameter is required.
/// The [focusNode] parameter specifies the focus node of the input field.
/// The [label] parameter specifies the label of the input field.
/// The [enabled] parameter specifies whether the input field is enabled.
const FlutterFormInputSlider({ const FlutterFormInputSlider({
required super.controller, Key? key,
required this.validationMessage, required FlutterFormInputController<double> controller,
super.key, FocusNode? focusNode,
super.focusNode, Widget? label,
super.label,
this.validator,
this.minValue = 0, this.minValue = 0,
this.maxValue = 100, this.maxValue = 100,
}) : assert(minValue < maxValue, 'minValue must be less than maxValue'); }) : assert(minValue < maxValue),
super(
key: key,
controller: controller,
focusNode: focusNode,
label: label);
final int minValue; final int minValue;
final int maxValue; final int maxValue;
final String validationMessage;
final String? Function(double?)? validator;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputSlider( return input.FlutterFormInputSlider(
focusNode: focusNode, focusNode: focusNode,
onSaved: controller.onSaved, onSaved: (value) => controller.onSaved(value),
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
); );
} }
} }
/// Controller for slider used by a [FlutterFormInputWidget] used in a /// Controller for slider used by a [FlutterFormInputWidget] used in a [FlutterForm].
/// [FlutterForm].
/// ///
/// Mainly used by [FlutterFormInputSlider]. /// Mainly used by [FlutterFormInputSlider].
class FlutterFormInputSliderController class FlutterFormInputSliderController
implements FlutterFormInputController<double> { implements FlutterFormInputController<double> {
/// Creates a [FlutterFormInputPasswordController].
///
/// 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.
FlutterFormInputSliderController({ FlutterFormInputSliderController({
required this.id, required this.id,
this.mandatory = true, this.mandatory = true,
@ -94,10 +83,8 @@ class FlutterFormInputSliderController
} }
@override @override
String? onValidate( String? onValidate(double? value,
double? value, String Function(String, {List<String>? params}) translator) {
String validationMessage,
) {
if (mandatory) {} if (mandatory) {}
return null; return null;

View file

@ -2,8 +2,6 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
// ignore_for_file: avoid_positional_boolean_parameters
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart'; import 'package:flutter_form_wizard/flutter_form.dart';
import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_input_library/flutter_input_library.dart' as input;
@ -13,45 +11,38 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
/// Standard controller is [FlutterFormInputSwitchController]. /// Standard controller is [FlutterFormInputSwitchController].
class FlutterFormInputSwitch extends FlutterFormInputWidget<bool> { class FlutterFormInputSwitch extends FlutterFormInputWidget<bool> {
const FlutterFormInputSwitch({ const FlutterFormInputSwitch({
required super.controller, Key? key,
required this.validationMessage, required FlutterFormInputController<bool> controller,
super.key, FocusNode? focusNode,
super.focusNode, Widget? label,
super.label, }) : super(
this.validator, key: key,
}); controller: controller,
focusNode: focusNode,
final String validationMessage; label: label);
final String? Function(bool?)? validator;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputBool( return input.FlutterFormInputBool(
focusNode: focusNode, focusNode: focusNode,
onSaved: controller.onSaved, onSaved: (value) => controller.onSaved(value),
onChanged: controller.onChanged, onChanged: controller.onChanged,
validator: validator ?? validator: (value) => controller.onValidate(value, _),
(value) => controller.onValidate(value, validationMessage),
initialValue: controller.value ?? false, initialValue: controller.value ?? false,
widgetType: input.BoolWidgetType.switchWidget, widgetType: input.BoolWidgetType.switchWidget,
); );
} }
} }
/// Controller for the switch used by a [FlutterFormInputWidget] used in a /// Controller for the switch used by a [FlutterFormInputWidget] used in a [FlutterForm].
/// [FlutterForm].
/// ///
/// Mainly used by [FlutterFormInputSwitch]. /// Mainly used by [FlutterFormInputSwitch].
class FlutterFormInputSwitchController class FlutterFormInputSwitchController
implements FlutterFormInputController<bool> { implements FlutterFormInputController<bool> {
/// Creates a [FlutterFormInputSwitchController].
///
/// The [id] parameter specifies the unique identifier for the controller.
/// The [mandatory] parameter specifies whether the input is mandatory.
/// The [value], [checkPageTitle], [checkPageDescription],
/// and [onChanged] parameters are optional.
FlutterFormInputSwitchController({ FlutterFormInputSwitchController({
required this.id, required this.id,
this.mandatory = true, this.mandatory = true,
@ -89,8 +80,7 @@ class FlutterFormInputSwitchController
@override @override
String? onValidate( String? onValidate(
bool? value, bool? value, String Function(String, {List<String>? params}) translator) {
String validationMessage, return null;
) => }
null;
} }

View file

@ -2,17 +2,11 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // 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_carousel/input_carousel.dart';
export 'input_date_picker/input_date_picker.dart';
export 'input_dropdown.dart';
export 'input_email.dart'; export 'input_email.dart';
export 'input_number_picker/input_number_picker.dart'; export 'input_number_picker/input_number_picker.dart';
export 'input_password/input_password.dart'; export 'input_password/input_password.dart';
export 'input_phone.dart';
export 'input_plain_text.dart'; export 'input_plain_text.dart';
export 'input_slider/input_slider.dart'; export 'input_slider/input_slider.dart';
export 'input_switch/input_switch.dart'; export 'input_switch/input_switch.dart';
export 'multiple_choice.dart'; export 'input_date_picker/input_date_picker.dart';

View file

@ -1,159 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_wizard/flutter_form.dart';
class FlutterFormInputMultipleChoice extends FlutterFormInputWidget<String> {
/// 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<String> 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<int?> selectedIndex,
FlutterFormInputController controller,
List<String> options,
FormFieldState<String> state,
) builder;
final String? Function(String? value, String validationMessage)? validator;
final String validationMessage;
@override
Widget build(BuildContext context) {
super.registerController(context);
var selectedIndex = ValueNotifier<int?>(null);
return FormField<String>(
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<String> {
/// 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;
}
}

View file

@ -2,47 +2,27 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
// ignore_for_file: avoid_positional_boolean_parameters
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// The options used to set parameters to a [FlutterForm]. /// The options used to set parameters to a [FlutterForm].
/// ///
/// The pages determine what pages the pageview will contain via a [List] of /// The pages determine what pages the pageview will contain via a [List] of [FlutterFormPage]s.
/// [FlutterFormPage]s.
/// ///
/// Using a checkpage gives the ability for the user to check all input values /// Using a checkpage gives the ability for the user to check all input values before commiting by [CheckPage].
/// before commiting by [CheckPage].
/// If [checkPage] is null no check page will be shown. /// If [checkPage] is null no check page will be shown.
/// ///
/// [nextButton] and [backButton] are both a way to give controls to user. /// [nextButton] and [backButton] are both a way to give controls to user.
/// Both are just plain widgets used in a [Stack]. So the widgets can be /// Both are just plain widgets used in a [Stack]. So the widgets can be aligned where ever.
/// aligned where ever.
/// The formcontroller of [FlutterForm] should be used to give control to the widgets/buttons. /// The formcontroller of [FlutterForm] should be used to give control to the widgets/buttons.
/// ///
/// [onFinished] and [onNext] are both callbacks which give the users results. /// [onFinished] and [onNext] are both callbacks which give the users results.
/// [onNext] is called when the user goes to the next page. /// [onNext] is called when the user goes to the next page.
/// [onBack] is called when the user goes back a page. /// [onFinished] is called when the form is finished. When checkpage is set [onFinished] is called when the checkpage is finished.
/// [onFinished] is called when the form is finished. When checkpage is set
/// [onFinished] is called when the checkpage is finished.
/// ///
/// [scrollDirection] can be set to change the Axis on which the pageview /// [scrollDirection] can be set to change the Axis on which the pageview slides. Defaults to horizontal.
/// slides. Defaults to horizontal.
/// ///
/// [scrollPhysics] can be set to set the scroll phyisics of the scroll views /// [scrollPhysics] can be set to set the scroll phyisics of the scroll views in each page. Default to [ClampingScrollPhysics].
/// in each page. Default to [ClampingScrollPhysics].
class FlutterFormOptions { class FlutterFormOptions {
const FlutterFormOptions({
required this.pages,
required this.onFinished,
required this.onNext,
this.onBack,
this.checkPage,
this.nextButton,
this.backButton,
this.scrollDirection = Axis.horizontal,
this.scrollPhysics,
});
final List<FlutterFormPage> pages; final List<FlutterFormPage> pages;
final CheckPage? checkPage; final CheckPage? checkPage;
@ -51,26 +31,32 @@ class FlutterFormOptions {
backButton; backButton;
final void Function(Map<int, Map<String, dynamic>>) onFinished; final void Function(Map<int, Map<String, dynamic>>) onFinished;
final void Function(int pageNumber, Map<String, dynamic>) onNext; final void Function(int pageNumber, Map<String, dynamic>) onNext;
/// [onBack] is called when the user goes back a page. The [pageNumber] is the
/// page the user is going back to. Not the page that the user was on when the
/// user pressed the back button.
final void Function(int pageNumber)? onBack;
final Axis scrollDirection; final Axis scrollDirection;
final ScrollPhysics? scrollPhysics; final ScrollPhysics? scrollPhysics;
const FlutterFormOptions({
required this.pages,
this.checkPage,
this.nextButton,
this.backButton,
required this.onFinished,
required this.onNext,
this.scrollDirection = Axis.horizontal,
this.scrollPhysics,
});
} }
/// The defines every page in a [FlutterForm]. /// The defines every page in a [FlutterForm].
class FlutterFormPage { class FlutterFormPage {
final Widget child;
FlutterFormPage({ FlutterFormPage({
required this.child, required this.child,
}); });
final Widget child;
} }
/// [CheckPage] is used to set a check page at the end of a [FlutterForm]. /// [CheckPage] is used to set a check page at the end of a [FlutterForm].
/// A [CheckPage] is a page where the user can check all input values before /// A [CheckPage] is a page where the user can check all input values before commiting.
/// commiting.
/// ///
/// [title] is the widget shown at the top of the page. /// [title] is the widget shown at the top of the page.
/// ///
@ -78,28 +64,22 @@ class FlutterFormPage {
/// ///
/// [inputCheckWidget] determines how every input is represented on the page. /// [inputCheckWidget] determines how every input is represented on the page.
/// [title] is the value given in the input. /// [title] is the value given in the input.
/// This input can be modified by setting the [checkPageTitle] of that input /// This input can be modified by setting the [checkPageTitle] of that input controller.
/// controller.
/// ///
/// Same for the [description] but if the description is not set in the input /// Same for the [description] but if the description is not set in the input controller no description will be given.
/// controller no description will be given.
/// ///
/// [onPressed] can be set so that when the user triggers it the user will be /// [onPressed] can be set so that when the user triggers it the user will be sent back to the page including the input.
/// sent back to the page including the input. /// Here the user can modify the input and save it. Afterwards the user will be sent back to the check page.
/// Here the user can modify the input and save it. Afterwards the user will be
/// sent back to the check page.
class CheckPage { class CheckPage {
final Widget? title;
final MainAxisAlignment mainAxisAlignment;
final Widget Function(
String id, String title, String? description, Function onPressed)?
inputCheckWidget;
const CheckPage({ const CheckPage({
this.title, this.title,
this.inputCheckWidget, this.inputCheckWidget,
this.mainAxisAlignment = MainAxisAlignment.start, this.mainAxisAlignment = MainAxisAlignment.start,
}); });
final Widget? title;
final MainAxisAlignment mainAxisAlignment;
final Widget Function(
String id,
String title,
String? description,
Function onPressed,
)? inputCheckWidget;
} }

View file

@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
abstract class TranslationService {
TranslationService._();
String translate(
BuildContext context,
String key, {
List<String>? params,
});
String number(double value);
}
typedef Translator = String Function(
String, {
List<String>? params,
});
class ShellTranslationService implements TranslationService {
@override
String number(double value) {
return value.toStringAsFixed(2);
}
@override
String translate(BuildContext context, String key, {List<String>? params}) {
return key;
}
}
Translator getTranslator(BuildContext context) {
try {
var translator = ShellTranslationService().translate;
return (
String key, {
List<String>? params,
}) {
return translator(context, key, params: params);
};
} catch (e) {
return (
String key, {
List<String>? params,
}) {
return key;
};
}
}

View file

@ -1,12 +1,12 @@
name: flutter_form_wizard name: flutter_form_wizard
description: A new Flutter package project. description: A new Flutter package project.
version: 6.6.0 version: 6.2.2
homepage: https://github.com/Iconica-Development/flutter_form_wizard homepage: https://github.com/Iconica-Development/flutter_form_wizard
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: none
environment: environment:
sdk: ">=3.0.0 <4.0.0" sdk: ">=2.18.0 <3.0.0"
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
@ -14,16 +14,46 @@ dependencies:
sdk: flutter sdk: flutter
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
intl: ">=0.18.0 <1.0.0" intl: ^0.18.0
flutter_input_library: flutter_input_library:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: ^3.4.0 url: https://github.com/Iconica-Development/flutter_input_library
ref: 3.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_iconica_analysis: flutter_lints: ^2.0.0
git:
url: https://github.com/Iconica-Development/flutter_iconica_analysis flutter:
ref: 6.0.0
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages

View file

@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('Normal walk through without check page', (tester) async { testWidgets('Normal walk through without check page', (tester) async {
var formController = FlutterFormController(); FlutterFormController formController = FlutterFormController();
var testField1Controller = FlutterFormInputPlainTextController( var testField1Controller = FlutterFormInputPlainTextController(
id: 'Field1', id: 'Field1',
@ -28,21 +28,21 @@ void main() {
home: Material( home: Material(
child: FlutterForm( child: FlutterForm(
options: FlutterFormOptions( options: FlutterFormOptions(
nextButton: (pageNumber, checkingPages) => Align( nextButton: (pageNumber, checkingPages) {
alignment: Alignment.bottomCenter, return Align(
child: ElevatedButton( alignment: Alignment.bottomCenter,
onPressed: () async { child: ElevatedButton(
await formController.autoNextStep(); onPressed: () async {
}, await formController.autoNextStep();
child: Text( },
pageNumber == 0 child: Text(pageNumber == 0
? 'next1' ? 'next1'
: pageNumber == 1 : pageNumber == 1
? 'next2' ? 'next2'
: 'finish', : 'finish'),
), ),
), );
), },
onFinished: (Map<int, Map<String, dynamic>> results) { onFinished: (Map<int, Map<String, dynamic>> results) {
onFinishResults = results; onFinishResults = results;
}, },
@ -56,7 +56,6 @@ void main() {
child: FlutterFormInputPlainText( child: FlutterFormInputPlainText(
label: const Text('Field1Label'), label: const Text('Field1Label'),
controller: testField1Controller, controller: testField1Controller,
validationMessage: 'Please fill in this field',
), ),
), ),
), ),
@ -65,7 +64,6 @@ void main() {
child: FlutterFormInputPlainText( child: FlutterFormInputPlainText(
label: const Text('Field2Label'), label: const Text('Field2Label'),
controller: testField2Controller, controller: testField2Controller,
validationMessage: 'Please fill in this field',
), ),
), ),
), ),
@ -78,9 +76,7 @@ void main() {
); );
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input');
'Field1Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next1')); await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -88,26 +84,21 @@ void main() {
expect({'Field1': 'Field1Input'}, onNextResults); expect({'Field1': 'Field1Input'}, onNextResults);
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field2Label'), find.widgetWithText(TextFormField, 'Field2Label'), 'Field2Input');
'Field2Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next2')); await tester.tap(find.widgetWithText(ElevatedButton, 'next2'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(1, onNextPageNumber); expect(1, onNextPageNumber);
expect({'Field2': 'Field2Input'}, onNextResults); expect({'Field2': 'Field2Input'}, onNextResults);
expect( expect({
{ 0: {'Field1': 'Field1Input'},
0: {'Field1': 'Field1Input'}, 1: {'Field2': 'Field2Input'}
1: {'Field2': 'Field2Input'}, }, onFinishResults);
},
onFinishResults,
);
}); });
testWidgets('Normal walk through with check page', (tester) async { testWidgets('Normal walk through with check page', (tester) async {
var formController = FlutterFormController(); FlutterFormController formController = FlutterFormController();
var testField1Controller = FlutterFormInputPlainTextController( var testField1Controller = FlutterFormInputPlainTextController(
id: 'Field1', id: 'Field1',
@ -128,21 +119,21 @@ void main() {
child: FlutterForm( child: FlutterForm(
options: FlutterFormOptions( options: FlutterFormOptions(
checkPage: const CheckPage(), checkPage: const CheckPage(),
nextButton: (pageNumber, checkingPages) => Align( nextButton: (pageNumber, checkingPages) {
alignment: Alignment.bottomCenter, return Align(
child: ElevatedButton( alignment: Alignment.bottomCenter,
onPressed: () async { child: ElevatedButton(
await formController.autoNextStep(); onPressed: () async {
}, await formController.autoNextStep();
child: Text( },
pageNumber == 0 child: Text(pageNumber == 0
? 'next1' ? 'next1'
: pageNumber == 1 : pageNumber == 1
? 'next2' ? 'next2'
: 'finish', : 'finish'),
), ),
), );
), },
onFinished: (Map<int, Map<String, dynamic>> results) { onFinished: (Map<int, Map<String, dynamic>> results) {
onFinishResults = results; onFinishResults = results;
}, },
@ -156,7 +147,6 @@ void main() {
child: FlutterFormInputPlainText( child: FlutterFormInputPlainText(
label: const Text('Field1Label'), label: const Text('Field1Label'),
controller: testField1Controller, controller: testField1Controller,
validationMessage: 'Please fill in this field',
), ),
), ),
), ),
@ -165,7 +155,6 @@ void main() {
child: FlutterFormInputPlainText( child: FlutterFormInputPlainText(
label: const Text('Field2Label'), label: const Text('Field2Label'),
controller: testField2Controller, controller: testField2Controller,
validationMessage: 'Please fill in this field',
), ),
), ),
), ),
@ -178,9 +167,7 @@ void main() {
); );
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input');
'Field1Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next1')); await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -188,9 +175,7 @@ void main() {
expect({'Field1': 'Field1Input'}, onNextResults); expect({'Field1': 'Field1Input'}, onNextResults);
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field2Label'), find.widgetWithText(TextFormField, 'Field2Label'), 'Field2Input');
'Field2Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next2')); await tester.tap(find.widgetWithText(ElevatedButton, 'next2'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -201,29 +186,24 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input2');
'Field1Input2',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next1')); await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(0, onNextPageNumber); expect(0, onNextPageNumber);
expect({'Field1': 'Field1Input2'}, onNextResults); expect({'Field1': 'Field1Input2'}, onNextResults);
await tester.tap(find.widgetWithText(ElevatedButton, 'finish')); await tester.tap(find.widgetWithText(ElevatedButton, "finish"));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect({
{ 0: {'Field1': 'Field1Input2'},
0: {'Field1': 'Field1Input2'}, 1: {'Field2': 'Field2Input'}
1: {'Field2': 'Field2Input'}, }, onFinishResults);
},
onFinishResults,
);
}); });
testWidgets('Wrong input with mandatory validator', (tester) async { testWidgets('Wrong input with mandatory validator', (tester) async {
var formController = FlutterFormController(); FlutterFormController formController = FlutterFormController();
var testField1Controller = FlutterFormInputPlainTextController( var testField1Controller = FlutterFormInputPlainTextController(
id: 'Field1', id: 'Field1',
@ -240,15 +220,17 @@ void main() {
home: Material( home: Material(
child: FlutterForm( child: FlutterForm(
options: FlutterFormOptions( options: FlutterFormOptions(
nextButton: (pageNumber, checkingPages) => Align( nextButton: (pageNumber, checkingPages) {
alignment: Alignment.bottomCenter, return Align(
child: ElevatedButton( alignment: Alignment.bottomCenter,
onPressed: () async { child: ElevatedButton(
await formController.autoNextStep(); onPressed: () async {
}, await formController.autoNextStep();
child: const Text('finish'), },
), child: const Text('finish'),
), ),
);
},
onFinished: (Map<int, Map<String, dynamic>> results) { onFinished: (Map<int, Map<String, dynamic>> results) {
// print('finished results: $results'); // print('finished results: $results');
onFinishResults = results; onFinishResults = results;
@ -264,7 +246,6 @@ void main() {
child: FlutterFormInputPlainText( child: FlutterFormInputPlainText(
label: const Text('Field1Label'), label: const Text('Field1Label'),
controller: testField1Controller, controller: testField1Controller,
validationMessage: 'Field can not be empty',
), ),
), ),
), ),
@ -282,25 +263,20 @@ void main() {
expect(null, onNextPageNumber); expect(null, onNextPageNumber);
expect(null, onNextResults); expect(null, onNextResults);
var errorMessageFinder = find.text('Field can not be empty'); final errorMessageFinder = find.text('Field can not be empty');
expect(errorMessageFinder, findsOneWidget); expect(errorMessageFinder, findsOneWidget);
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input');
'Field1Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'finish')); await tester.tap(find.widgetWithText(ElevatedButton, 'finish'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(0, onNextPageNumber); expect(0, onNextPageNumber);
expect({'Field1': 'Field1Input'}, onNextResults); expect({'Field1': 'Field1Input'}, onNextResults);
expect( expect({
{ 0: {'Field1': 'Field1Input'},
0: {'Field1': 'Field1Input'}, }, onFinishResults);
},
onFinishResults,
);
}); });
} }