mirror of
https://github.com/Iconica-Development/flutter_form_wizard.git
synced 2025-05-19 10:53:49 +02:00
Merge branch 'fix/add_ci_linter'
This commit is contained in:
commit
650418a36f
23 changed files with 417 additions and 374 deletions
14
.github/workflows/component-ci.yml
vendored
Normal file
14
.github/workflows/component-ci.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
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
|
32
.github/workflows/flutter.yml
vendored
32
.github/workflows/flutter.yml
vendored
|
@ -1,32 +0,0 @@
|
|||
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
|
|
@ -114,4 +114,8 @@
|
|||
- Pass on the `initialValue` property to FlutterFormMultiLine
|
||||
|
||||
## 6.2.2 - February 6th 2024
|
||||
- Updated the `flutter_input_library` from 2.6.0 to 3.0.0
|
||||
- Updated the `flutter_input_library` from 2.6.0 to 3.0.0
|
||||
|
||||
## 6.2.3 - February 7th 2024
|
||||
|
||||
- Added CI and linter
|
|
@ -1,4 +1,9 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
include: package:flutter_iconica_analysis/analysis_options.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
# Possible to overwrite the rules from the package
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
|
||||
linter:
|
||||
rules:
|
||||
|
|
|
@ -68,7 +68,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "6.2.1"
|
||||
version: "6.2.2"
|
||||
flutter_input_library:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
export 'package:flutter_input_library/flutter_input_library.dart'
|
||||
show FlutterFormDateTimeType;
|
||||
|
||||
export 'src/form.dart';
|
||||
export 'src/widgets/input/abstractions.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/translation_service.dart';
|
||||
|
|
|
@ -3,18 +3,23 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../flutter_form.dart';
|
||||
import 'utils/form_page_controller.dart';
|
||||
import 'utils/formstate.dart' as fs;
|
||||
import 'package:flutter_form_wizard/flutter_form.dart';
|
||||
import 'package:flutter_form_wizard/src/utils/form_page_controller.dart';
|
||||
import 'package:flutter_form_wizard/src/utils/formstate.dart' as fs;
|
||||
|
||||
/// A wrapper for flutters [Form] that can be controlled by a controller and provides multiple pre-defined input types/fields
|
||||
/// [FlutterForm] also provides multi page forms and a check page for validation.
|
||||
/// A wrapper for flutters [Form] that can be controlled by a controller and
|
||||
/// provides multiple pre-defined input types/fields
|
||||
/// [FlutterForm] also provides multi page forms and a check page
|
||||
/// for validation.
|
||||
///
|
||||
/// A [FlutterFormController] has to be given to control what happens to values and pages within the FlutterForm.
|
||||
/// A [FlutterFormController] has to be given to control what happens to values
|
||||
/// and pages within the FlutterForm.
|
||||
///
|
||||
/// [FlutterFormOptions] have to be provided to control the appearance of the form.
|
||||
/// [FlutterFormOptions] have to be provided to control the appearance of
|
||||
/// the form.
|
||||
///
|
||||
/// WARNING Define your FormInputController above your FlutterForm. Otherwise when rebuild the controller will differ from the registered ones.
|
||||
/// WARNING Define your FormInputController above your FlutterForm. Otherwise
|
||||
/// when rebuild the controller will differ from the registered ones.
|
||||
/// ``` dart
|
||||
/// FlutterFormInputEmailController emailController =
|
||||
/// FlutterFormInputEmailController(id: 'email');
|
||||
|
@ -180,10 +185,10 @@ import 'utils/formstate.dart' as fs;
|
|||
/// ```
|
||||
class FlutterForm extends StatefulWidget {
|
||||
const FlutterForm({
|
||||
Key? key,
|
||||
required this.options,
|
||||
required this.formController,
|
||||
}) : super(key: key);
|
||||
super.key,
|
||||
});
|
||||
|
||||
final FlutterFormOptions options;
|
||||
final FlutterFormController formController;
|
||||
|
@ -203,9 +208,9 @@ class _FlutterFormState extends State<FlutterForm> {
|
|||
|
||||
_formController.setFlutterFormOptions(widget.options);
|
||||
|
||||
List<GlobalKey<FormState>> keys = [];
|
||||
var keys = <GlobalKey<FormState>>[];
|
||||
|
||||
for (FlutterFormPage _ in widget.options.pages) {
|
||||
for (var _ in widget.options.pages) {
|
||||
keys.add(GlobalKey<FormState>());
|
||||
}
|
||||
|
||||
|
@ -215,9 +220,9 @@ class _FlutterFormState extends State<FlutterForm> {
|
|||
setState(() {});
|
||||
});
|
||||
|
||||
List<FlutterFormPageController> controllers = [];
|
||||
var controllers = <FlutterFormPageController>[];
|
||||
|
||||
for (int i = 0; i < widget.options.pages.length; i++) {
|
||||
for (var i = 0; i < widget.options.pages.length; i++) {
|
||||
controllers.add(FlutterFormPageController());
|
||||
}
|
||||
|
||||
|
@ -278,27 +283,37 @@ class _FlutterFormState extends State<FlutterForm> {
|
|||
),
|
||||
],
|
||||
),
|
||||
widget.options.nextButton != null
|
||||
? widget.options.nextButton!(_formController.getCurrentStep(),
|
||||
_formController.getCheckpages())
|
||||
: Align(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 40, vertical: 15),
|
||||
textStyle: const TextStyle(
|
||||
fontSize: 20, fontWeight: FontWeight.bold)),
|
||||
onPressed: () async {
|
||||
await _formController.autoNextStep();
|
||||
},
|
||||
child: Text(_formController.getCurrentStep() >=
|
||||
widget.options.pages.length - 1
|
||||
? "Finish"
|
||||
: "Next"),
|
||||
if (widget.options.nextButton != null)
|
||||
widget.options.nextButton!(
|
||||
_formController.getCurrentStep(),
|
||||
_formController.getCheckpages(),
|
||||
)
|
||||
else
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 40,
|
||||
vertical: 15,
|
||||
),
|
||||
textStyle: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
await _formController.autoNextStep();
|
||||
},
|
||||
child: Text(
|
||||
_formController.getCurrentStep() >=
|
||||
widget.options.pages.length - 1
|
||||
? 'Finish'
|
||||
: 'Next',
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.options.backButton != null)
|
||||
widget.options.backButton!(
|
||||
_formController.getCurrentStep(),
|
||||
|
@ -310,12 +325,12 @@ class _FlutterFormState extends State<FlutterForm> {
|
|||
}
|
||||
|
||||
List<Widget> getResultWidgets() {
|
||||
List<Widget> widgets = [];
|
||||
var widgets = <Widget>[];
|
||||
|
||||
_formController.getAllResults().forEach(
|
||||
(pageNumber, pageResults) {
|
||||
pageResults.forEach((inputId, inputResult) {
|
||||
FlutterFormInputController? inputController = _formController
|
||||
var inputController = _formController
|
||||
.getFormPageControllers()[pageNumber]
|
||||
.getController(inputId);
|
||||
|
||||
|
@ -327,10 +342,8 @@ class _FlutterFormState extends State<FlutterForm> {
|
|||
inputController.checkPageTitle != null
|
||||
? inputController.checkPageTitle!(inputController.value)
|
||||
: inputController.value.toString(),
|
||||
inputController.checkPageDescription != null
|
||||
? inputController
|
||||
.checkPageDescription!(inputController.value)
|
||||
: null,
|
||||
inputController.checkPageDescription
|
||||
?.call(inputController.value),
|
||||
() async {
|
||||
await _formController.jumpToPage(pageNumber);
|
||||
},
|
||||
|
@ -378,7 +391,7 @@ class _FlutterFormState extends State<FlutterForm> {
|
|||
Text(
|
||||
inputController.checkPageDescription!(inputResult),
|
||||
style: const TextStyle(fontSize: 16),
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -412,15 +425,14 @@ class FlutterFormController extends ChangeNotifier {
|
|||
|
||||
late List<FlutterFormPageController> _formPageControllers;
|
||||
|
||||
List<FlutterFormPageController> getFormPageControllers() {
|
||||
return _formPageControllers;
|
||||
}
|
||||
List<FlutterFormPageController> getFormPageControllers() =>
|
||||
_formPageControllers;
|
||||
|
||||
setFormPageControllers(List<FlutterFormPageController> controllers) {
|
||||
void setFormPageControllers(List<FlutterFormPageController> controllers) {
|
||||
_formPageControllers = controllers;
|
||||
}
|
||||
|
||||
disableCheckingPages() {
|
||||
void voidisableCheckingPages() {
|
||||
_checkingPages = false;
|
||||
|
||||
for (var controller in _formPageControllers) {
|
||||
|
@ -436,7 +448,9 @@ class FlutterFormController extends ChangeNotifier {
|
|||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
|
||||
_options.onNext(
|
||||
_currentStep, _formPageControllers[_currentStep].getAllValues());
|
||||
_currentStep,
|
||||
_formPageControllers[_currentStep].getAllValues(),
|
||||
);
|
||||
|
||||
if (_currentStep >= _options.pages.length - 1 &&
|
||||
_options.checkPage == null ||
|
||||
|
@ -449,9 +463,11 @@ class FlutterFormController extends ChangeNotifier {
|
|||
|
||||
notifyListeners();
|
||||
|
||||
await _pageController.animateToPage(_currentStep,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.ease);
|
||||
await _pageController.animateToPage(
|
||||
_currentStep,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.ease,
|
||||
);
|
||||
} else {
|
||||
_currentStep += 1;
|
||||
|
||||
|
@ -462,9 +478,11 @@ class FlutterFormController extends ChangeNotifier {
|
|||
|
||||
notifyListeners();
|
||||
|
||||
await _pageController.animateToPage(_currentStep,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.ease);
|
||||
await _pageController.animateToPage(
|
||||
_currentStep,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.ease,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -507,13 +525,14 @@ class FlutterFormController extends ChangeNotifier {
|
|||
return false;
|
||||
}
|
||||
|
||||
Map<String, dynamic> getCurrentStepResults() {
|
||||
return _formPageControllers[_currentStep].getAllValues();
|
||||
}
|
||||
Map<String, dynamic> getCurrentStepResults() =>
|
||||
_formPageControllers[_currentStep].getAllValues();
|
||||
|
||||
Future<void> nextStep() async {
|
||||
_options.onNext(
|
||||
_currentStep, _formPageControllers[_currentStep].getAllValues());
|
||||
_currentStep,
|
||||
_formPageControllers[_currentStep].getAllValues(),
|
||||
);
|
||||
|
||||
_currentStep += 1;
|
||||
|
||||
|
@ -523,16 +542,19 @@ class FlutterFormController extends ChangeNotifier {
|
|||
|
||||
notifyListeners();
|
||||
|
||||
await _pageController.animateToPage(_currentStep,
|
||||
duration: const Duration(milliseconds: 250), curve: Curves.ease);
|
||||
await _pageController.animateToPage(
|
||||
_currentStep,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.ease,
|
||||
);
|
||||
}
|
||||
|
||||
finishForm() {
|
||||
void finishForm() {
|
||||
_options.onFinished(getAllResults());
|
||||
}
|
||||
|
||||
Map<int, Map<String, dynamic>> getAllResults() {
|
||||
Map<int, Map<String, dynamic>> allValues = {};
|
||||
var allValues = <int, Map<String, dynamic>>{};
|
||||
|
||||
for (var i = 0; i < _options.pages.length; i++) {
|
||||
allValues.addAll({i: _formPageControllers[i].getAllValues()});
|
||||
|
@ -540,27 +562,19 @@ class FlutterFormController extends ChangeNotifier {
|
|||
return allValues;
|
||||
}
|
||||
|
||||
setFlutterFormOptions(FlutterFormOptions options) {
|
||||
void setFlutterFormOptions(FlutterFormOptions options) {
|
||||
_options = options;
|
||||
}
|
||||
|
||||
setKeys(List<GlobalKey<FormState>> keys) {
|
||||
void setKeys(List<GlobalKey<FormState>> keys) {
|
||||
_keys = keys;
|
||||
}
|
||||
|
||||
List<GlobalKey<FormState>> getKeys() {
|
||||
return _keys;
|
||||
}
|
||||
List<GlobalKey<FormState>> getKeys() => _keys;
|
||||
|
||||
int getCurrentStep() {
|
||||
return _currentStep;
|
||||
}
|
||||
int getCurrentStep() => _currentStep;
|
||||
|
||||
bool getCheckpages() {
|
||||
return _checkingPages;
|
||||
}
|
||||
bool getCheckpages() => _checkingPages;
|
||||
|
||||
PageController getPageController() {
|
||||
return _pageController;
|
||||
}
|
||||
PageController getPageController() => _pageController;
|
||||
}
|
||||
|
|
|
@ -11,13 +11,12 @@ class FlutterFormPageController {
|
|||
_controllers.add(inputController);
|
||||
}
|
||||
|
||||
clearControllers() {
|
||||
void clearControllers() {
|
||||
_controllers = [];
|
||||
}
|
||||
|
||||
bool _isRegisteredById(String id) {
|
||||
return _controllers.any((element) => (element.id == id));
|
||||
}
|
||||
bool _isRegisteredById(String id) =>
|
||||
_controllers.any((element) => element.id == id);
|
||||
|
||||
FlutterFormInputController? getController(String key) {
|
||||
if (_isRegisteredById(key)) {
|
||||
|
@ -27,9 +26,9 @@ class FlutterFormPageController {
|
|||
}
|
||||
|
||||
Map<String, dynamic> getAllValues() {
|
||||
Map<String, dynamic> values = {};
|
||||
var values = <String, dynamic>{};
|
||||
|
||||
for (FlutterFormInputController controller in _controllers) {
|
||||
for (var controller in _controllers) {
|
||||
if (controller.value != null) {
|
||||
values.addAll({controller.id!: controller.value});
|
||||
}
|
||||
|
|
|
@ -3,20 +3,19 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'form_page_controller.dart';
|
||||
import 'package:flutter_form_wizard/src/utils/form_page_controller.dart';
|
||||
|
||||
class FormState extends InheritedWidget {
|
||||
const FormState({
|
||||
Key? key,
|
||||
required Widget child,
|
||||
required super.child,
|
||||
required this.formController,
|
||||
}) : super(key: key, child: child);
|
||||
super.key,
|
||||
});
|
||||
|
||||
final FlutterFormPageController formController;
|
||||
|
||||
static FormState of(BuildContext context) {
|
||||
final FormState? result =
|
||||
context.dependOnInheritedWidgetOfExactType<FormState>();
|
||||
var result = context.dependOnInheritedWidgetOfExactType<FormState>();
|
||||
assert(result != null, 'No FormStat found in context');
|
||||
return result!;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '/src/utils/formstate.dart' as fs;
|
||||
import 'package:flutter_form_wizard/src/utils/formstate.dart' as fs;
|
||||
|
||||
/// Abstract class for the input widgets used in a [FlutterForm].
|
||||
///
|
||||
|
@ -12,18 +12,19 @@ import '/src/utils/formstate.dart' as fs;
|
|||
///
|
||||
/// label is a standard parameter to normally sets the label of the input.
|
||||
///
|
||||
/// [registerController] should be called to register the given [controller] to the form page.
|
||||
/// [registerController] should be called to register the given [controller] to
|
||||
/// the form page.
|
||||
abstract class FlutterFormInputWidget<T> extends StatelessWidget {
|
||||
const FlutterFormInputWidget({
|
||||
Key? key,
|
||||
required this.controller,
|
||||
super.key,
|
||||
this.focusNode,
|
||||
this.label,
|
||||
this.enabled = true,
|
||||
String? hintText,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
/// The [controller] which determines how the value is handled and how the value is shown on the checkpage.
|
||||
/// The [controller] which determines how the value is handled and how the
|
||||
/// value is shown on the checkpage.
|
||||
final FlutterFormInputController<T> controller;
|
||||
|
||||
/// [label] is a standard parameter to normally sets the label of the input.
|
||||
|
@ -33,9 +34,10 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
|
|||
|
||||
final bool enabled;
|
||||
|
||||
/// [registerController] should be called to register the given [controller] to the form page.
|
||||
registerController(BuildContext context) {
|
||||
FlutterFormInputController? localController =
|
||||
/// [registerController] should be called to register the given [controller]
|
||||
/// to the form page.
|
||||
void registerController(BuildContext context) {
|
||||
var localController =
|
||||
fs.FormState.of(context).formController.getController(controller.id!);
|
||||
|
||||
if (localController == null) {
|
||||
|
@ -48,11 +50,13 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
|
|||
///
|
||||
/// 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 by the user.
|
||||
/// [value] is a way to set a initial value and will be the value when change
|
||||
/// by the user.
|
||||
///
|
||||
/// [mandatory] determines if the input is mandatory.
|
||||
///
|
||||
/// [checkPageTitle] is a function where you can transform the value from the input into something representable.
|
||||
/// [checkPageTitle] is a function where you can transform the value from the
|
||||
/// input into something representable.
|
||||
/// This value will be given when defining the check page widgets.
|
||||
/// If this function is not set, the value will be used as is.
|
||||
/// Example:
|
||||
|
@ -62,27 +66,32 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
|
|||
/// },
|
||||
/// ```
|
||||
///
|
||||
/// [checkPageDescription] is the same as checkPageTitle but for the description.
|
||||
/// If null no description will be shown.
|
||||
/// [checkPageDescription] is the same as checkPageTitle but for the
|
||||
/// description. If null no description will be shown.
|
||||
///
|
||||
/// [onChanged] can be set to get the value whenever the user changes it. Should not be used to save the value.
|
||||
/// [onChanged] can be set to get the value whenever the user changes it.
|
||||
/// Should not be used to save the value.
|
||||
///
|
||||
/// [onSubmit] can be set to get the value whenever the user submits it. Should not be used to save the value.
|
||||
/// [onSubmit] can be set to get the value whenever the user submits it.
|
||||
/// Should not be used to save the value.
|
||||
///
|
||||
/// [onSaved] goes of when the save function is called for the page if [onValidate] return null.
|
||||
/// [onSaved] goes of when the save function is called for the page if
|
||||
/// [onValidate] return null.
|
||||
///
|
||||
/// [onValidate] is used to validate the given input by the user.
|
||||
abstract class FlutterFormInputController<T> {
|
||||
/// The [id] determines the key in the [Map] returned by the [FlutterForm].
|
||||
String? id;
|
||||
|
||||
/// [value] is a way to set a initial value and will be the value when change by the user.
|
||||
/// [value] is a way to set a initial value and will be the value when
|
||||
/// change by the user.
|
||||
T? value;
|
||||
|
||||
/// [mandatory] determines if the input is mandatory.
|
||||
bool mandatory = false;
|
||||
|
||||
/// [checkPageTitle] is a function where you can transform the value from the input into something representable.
|
||||
/// [checkPageTitle] is a function where you can transform the value from the
|
||||
/// input into something representable.
|
||||
/// This value will be given when defining the check page widgets.
|
||||
/// If this function is not set, the value will be used as is.
|
||||
/// Example:
|
||||
|
@ -93,20 +102,26 @@ abstract class FlutterFormInputController<T> {
|
|||
/// ```
|
||||
String Function(T? value)? checkPageTitle;
|
||||
|
||||
/// [checkPageDescription] is the same as checkPageTitle but for the description.
|
||||
/// [checkPageDescription] is the same as checkPageTitle but for the
|
||||
/// description.
|
||||
/// If null no description will be shown.
|
||||
String Function(T? value)? checkPageDescription;
|
||||
|
||||
/// [onChanged] can be set to get the value whenever the user changes it. Should not be used to save the value.
|
||||
/// [onChanged] can be set to get the value whenever the user changes it.
|
||||
/// Should not be used to save the value.
|
||||
void Function(T? value)? onChanged;
|
||||
|
||||
/// [onSubmit] can be set to get the value whenever the user submits it. Should not be used to save the value.
|
||||
/// [onSubmit] can be set to get the value whenever the user submits it.
|
||||
/// Should not be used to save the value.
|
||||
void Function(T? value)? onSubmit;
|
||||
|
||||
/// [onSaved] goes of when the save function is called for the page if [onValidate] return null.
|
||||
/// [onSaved] goes of when the save function is called for the page if
|
||||
/// [onValidate] return null.
|
||||
void onSaved(T? value);
|
||||
|
||||
/// [onValidate] is used to validate the given input by the user.
|
||||
String? onValidate(
|
||||
T? value, String Function(String, {List<String>? params}) translator);
|
||||
T? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,24 +15,24 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
|
|||
/// Height sets the height of the inputfield. Default to 425.
|
||||
class FlutterFormInputCarousel extends FlutterFormInputWidget<int> {
|
||||
const FlutterFormInputCarousel({
|
||||
Key? key,
|
||||
required FlutterFormInputController<int> controller,
|
||||
Widget? label,
|
||||
required super.controller,
|
||||
required this.items,
|
||||
super.key,
|
||||
super.label,
|
||||
this.height = 425,
|
||||
}) : super(key: key, controller: controller, label: label);
|
||||
});
|
||||
|
||||
final List<Widget> items;
|
||||
final double height;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
super.registerController(context);
|
||||
|
||||
return input.FlutterFormInputCarousel(
|
||||
onSaved: (value) => controller.onSaved(value),
|
||||
onSaved: controller.onSaved,
|
||||
validator: (value) => controller.onValidate(value, _),
|
||||
onChanged: controller.onChanged,
|
||||
initialValue: controller.value ?? 0,
|
||||
|
@ -42,7 +42,8 @@ class FlutterFormInputCarousel extends FlutterFormInputWidget<int> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Controller for the carousel used by a [FlutterFormInputWidget] used in a [FlutterForm].
|
||||
/// Controller for the carousel used by a [FlutterFormInputWidget] used in
|
||||
/// a [FlutterForm].
|
||||
///
|
||||
/// Mainly used by [FlutterFormInputCarousel].
|
||||
class FlutterFormInputCarouselController
|
||||
|
@ -84,7 +85,9 @@ class FlutterFormInputCarouselController
|
|||
|
||||
@override
|
||||
String? onValidate(
|
||||
int? value, String Function(String, {List<String>? params}) translator) {
|
||||
int? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) {
|
||||
if (mandatory) {}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -5,22 +5,21 @@
|
|||
// ignore_for_file: overridden_fields, annotate_overrides
|
||||
|
||||
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:intl/intl.dart';
|
||||
|
||||
import '../../../../../flutter_form.dart';
|
||||
|
||||
/// Input for a dateTime used in a [FlutterForm].
|
||||
///
|
||||
/// Standard controller is [FlutterFormInputDateController].
|
||||
class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
|
||||
const FlutterFormInputDateTime({
|
||||
Key? key,
|
||||
required FlutterFormInputController<String> controller,
|
||||
Widget? label,
|
||||
this.showIcon = true,
|
||||
required super.controller,
|
||||
required this.inputType,
|
||||
required this.dateFormat,
|
||||
super.key,
|
||||
super.label,
|
||||
this.showIcon = true,
|
||||
this.firstDate,
|
||||
this.lastDate,
|
||||
this.initialDate,
|
||||
|
@ -28,11 +27,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
|
|||
this.icon = Icons.calendar_today,
|
||||
this.enabled = true,
|
||||
this.onTapEnabled = true,
|
||||
}) : super(
|
||||
key: key,
|
||||
controller: controller,
|
||||
label: label,
|
||||
);
|
||||
});
|
||||
final bool showIcon;
|
||||
final input.FlutterFormDateTimeType inputType;
|
||||
final DateFormat dateFormat;
|
||||
|
@ -46,7 +41,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
super.registerController(context);
|
||||
|
||||
return input.FlutterFormInputDateTime(
|
||||
|
@ -59,7 +54,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
|
|||
lastDate: lastDate,
|
||||
inputType: inputType,
|
||||
onChanged: (value) => controller.onChanged?.call(value),
|
||||
onSaved: (value) => controller.onSaved(value),
|
||||
onSaved: controller.onSaved,
|
||||
validator: (value) => controller.onValidate(value, _),
|
||||
initialValue: controller.value,
|
||||
dateFormat: dateFormat,
|
||||
|
@ -69,21 +64,22 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Controller for dates used by a [FlutterFormInputWidget] used in a [FlutterForm].
|
||||
/// Controller for dates used by a [FlutterFormInputWidget] used in a
|
||||
/// [FlutterForm].
|
||||
///
|
||||
/// Mainly used by [FlutterFormInputDateTime].
|
||||
class FlutterFormInputDateTimeController
|
||||
implements FlutterFormInputController<String> {
|
||||
FlutterFormInputDateTimeController({
|
||||
required this.id,
|
||||
required this.dateTimeType,
|
||||
required this.dateFormat,
|
||||
this.mandatory = true,
|
||||
this.value,
|
||||
this.checkPageTitle,
|
||||
this.checkPageDescription,
|
||||
this.initialDate,
|
||||
this.initialDateTimeRange,
|
||||
required this.dateTimeType,
|
||||
required this.dateFormat,
|
||||
this.onChanged,
|
||||
}) {
|
||||
if (value != null) {
|
||||
|
@ -118,13 +114,15 @@ class FlutterFormInputDateTimeController
|
|||
void Function(String? value)? onSubmit;
|
||||
|
||||
@override
|
||||
void onSaved(dynamic value) {
|
||||
void onSaved(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@override
|
||||
String? onValidate(String? value,
|
||||
String Function(String, {List<String>? params}) translator) {
|
||||
String? onValidate(
|
||||
String? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) {
|
||||
if (mandatory) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return translator('shell.form.error.empty');
|
||||
|
|
|
@ -3,31 +3,26 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
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 '../../../../flutter_form.dart';
|
||||
|
||||
/// Input for an email used in a [FlutterForm].
|
||||
///
|
||||
/// Standard controller is [FlutterFormInputEmailController].
|
||||
class FlutterFormInputEmail extends FlutterFormInputWidget<String> {
|
||||
const FlutterFormInputEmail({
|
||||
Key? key,
|
||||
required FlutterFormInputController<String> controller,
|
||||
FocusNode? focusNode,
|
||||
Widget? label,
|
||||
required super.controller,
|
||||
super.key,
|
||||
super.focusNode,
|
||||
super.label,
|
||||
bool? enabled,
|
||||
}) : super(
|
||||
key: key,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
label: label,
|
||||
enabled: enabled ?? true,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
super.registerController(context);
|
||||
|
||||
|
@ -42,13 +37,14 @@ class FlutterFormInputEmail extends FlutterFormInputWidget<String> {
|
|||
onChanged: (value) => controller.onChanged?.call(value),
|
||||
decoration: InputDecoration(
|
||||
focusColor: Theme.of(context).primaryColor,
|
||||
label: label ?? const Text("Email"),
|
||||
label: label ?? const Text('Email'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Controller for emails used by a [FlutterFormInputWidget] used in a [FlutterForm].
|
||||
/// Controller for emails used by a [FlutterFormInputWidget] used in
|
||||
/// a [FlutterForm].
|
||||
///
|
||||
/// Mainly used by [FlutterFormInputEmail].
|
||||
class FlutterFormInputEmailController
|
||||
|
@ -85,21 +81,23 @@ class FlutterFormInputEmailController
|
|||
void Function(String? value)? onSubmit;
|
||||
|
||||
@override
|
||||
void onSaved(dynamic value) {
|
||||
void onSaved(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@override
|
||||
String? onValidate(String? value,
|
||||
String Function(String, {List<String>? params}) translator) {
|
||||
String? onValidate(
|
||||
String? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) {
|
||||
if (mandatory) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return translator('shell.form.error.empty');
|
||||
}
|
||||
|
||||
if (!RegExp(
|
||||
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
|
||||
.hasMatch(value)) {
|
||||
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+",
|
||||
).hasMatch(value)) {
|
||||
return translator('shell.form.error.email.notValid');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
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 '../../../../../flutter_form.dart';
|
||||
|
||||
/// Input for a number used in a [FlutterForm].
|
||||
///
|
||||
|
@ -14,28 +14,26 @@ import '../../../../../flutter_form.dart';
|
|||
/// Standard controller is [FlutterFormInputNumberPickerController].
|
||||
class FlutterFormInputNumberPicker extends FlutterFormInputWidget<int> {
|
||||
const FlutterFormInputNumberPicker({
|
||||
Key? key,
|
||||
required FlutterFormInputController<int> controller,
|
||||
Widget? label,
|
||||
FocusNode? focusNode,
|
||||
required super.controller,
|
||||
super.key,
|
||||
super.label,
|
||||
this.minValue = 0,
|
||||
this.maxValue = 100,
|
||||
}) : assert(minValue < maxValue),
|
||||
super(key: key, controller: controller, label: label);
|
||||
}) : assert(minValue < maxValue, 'minValue must be less than maxValue');
|
||||
|
||||
final int minValue;
|
||||
final int maxValue;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
super.registerController(context);
|
||||
|
||||
return input.FlutterFormInputNumberPicker(
|
||||
minValue: minValue,
|
||||
maxValue: maxValue,
|
||||
onSaved: (value) => controller.onSaved(value),
|
||||
onSaved: controller.onSaved,
|
||||
validator: (value) => controller.onValidate(value, _),
|
||||
onChanged: (value) => controller.onChanged?.call(value),
|
||||
initialValue: controller.value ?? minValue,
|
||||
|
@ -82,7 +80,9 @@ class FlutterFormInputNumberPickerController
|
|||
|
||||
@override
|
||||
String? onValidate(
|
||||
int? value, String Function(String, {List<String>? params}) translator) {
|
||||
int? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) {
|
||||
if (mandatory) {}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -3,24 +3,20 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
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 '../../../../../flutter_form.dart';
|
||||
|
||||
/// Input for a password used in a [FlutterForm].
|
||||
///
|
||||
/// Standard controller is [FlutterFormInputEmailController].
|
||||
class FlutterFormInputPassword extends FlutterFormInputWidget<String> {
|
||||
const FlutterFormInputPassword({
|
||||
Key? key,
|
||||
required FlutterFormInputController<String> controller,
|
||||
FocusNode? focusNode,
|
||||
Widget? label,
|
||||
required super.controller,
|
||||
super.key,
|
||||
super.focusNode,
|
||||
super.label,
|
||||
bool? enabled,
|
||||
}) : super(
|
||||
key: key,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
label: label,
|
||||
enabled: enabled ?? true,
|
||||
);
|
||||
|
||||
|
@ -28,13 +24,13 @@ class FlutterFormInputPassword extends FlutterFormInputWidget<String> {
|
|||
Widget build(BuildContext context) {
|
||||
super.registerController(context);
|
||||
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
return input.FlutterFormInputPassword(
|
||||
enabled: enabled,
|
||||
initialValue: controller.value,
|
||||
focusNode: focusNode,
|
||||
onSaved: (value) => controller.onSaved(value),
|
||||
onSaved: controller.onSaved,
|
||||
validator: (value) => controller.onValidate(value, _),
|
||||
onChanged: (value) => controller.onChanged?.call(value),
|
||||
onFieldSubmitted: (value) => controller.onSubmit?.call(value),
|
||||
|
@ -42,7 +38,8 @@ class FlutterFormInputPassword extends FlutterFormInputWidget<String> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Controller for passwords used by a [FlutterFormInputWidget] used in a [ShellFrom].
|
||||
/// Controller for passwords used by a [FlutterFormInputWidget] used in a
|
||||
/// [ShellFrom].
|
||||
///
|
||||
/// Mainly used by [FlutterFormInputPassword].
|
||||
class FlutterFormInputPasswordController
|
||||
|
@ -79,13 +76,15 @@ class FlutterFormInputPasswordController
|
|||
void Function(String? value)? onSubmit;
|
||||
|
||||
@override
|
||||
void onSaved(dynamic value) {
|
||||
void onSaved(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@override
|
||||
String? onValidate(String? value,
|
||||
String Function(String, {List<String>? params}) translator) {
|
||||
String? onValidate(
|
||||
String? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) {
|
||||
if (mandatory) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return translator('Field can not be empty');
|
||||
|
|
|
@ -5,19 +5,18 @@
|
|||
// 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;
|
||||
|
||||
import '../../../../flutter_form.dart';
|
||||
|
||||
/// Input for plain text input used in a [FlutterForm].
|
||||
///
|
||||
/// Standard controller is [FlutterFormInputPlainTextController].
|
||||
class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
|
||||
const FlutterFormInputPlainText({
|
||||
Key? key,
|
||||
required FlutterFormInputController<String> controller,
|
||||
FocusNode? focusNode,
|
||||
Widget? label,
|
||||
required super.controller,
|
||||
super.key,
|
||||
super.focusNode,
|
||||
super.label,
|
||||
this.decoration,
|
||||
this.textAlignVertical,
|
||||
this.expands = false,
|
||||
|
@ -28,11 +27,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
|
|||
this.enabled = true,
|
||||
this.style,
|
||||
this.textCapitalization = TextCapitalization.none,
|
||||
}) : super(
|
||||
key: key,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
label: label);
|
||||
});
|
||||
|
||||
final InputDecoration? decoration;
|
||||
final TextAlignVertical? textAlignVertical;
|
||||
|
@ -48,13 +43,13 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
super.registerController(context);
|
||||
|
||||
InputDecoration inputDecoration = decoration ??
|
||||
var inputDecoration = decoration ??
|
||||
InputDecoration(
|
||||
label: label ?? const Text("Plain text"),
|
||||
label: label ?? const Text('Plain text'),
|
||||
);
|
||||
|
||||
return input.FlutterFormInputPlainText(
|
||||
|
@ -63,7 +58,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
|
|||
scrollPadding: scrollPadding ?? const EdgeInsets.all(20.0),
|
||||
initialValue: controller.value,
|
||||
focusNode: focusNode,
|
||||
onSaved: (value) => controller.onSaved(value),
|
||||
onSaved: controller.onSaved,
|
||||
validator: (value) => controller.onValidate(value, _),
|
||||
onChanged: (value) => controller.onChanged?.call(value),
|
||||
onFieldSubmitted: (value) => controller.onSubmit?.call(value),
|
||||
|
@ -87,15 +82,15 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
|
|||
/// MaxCharacters can be set to set a maximum amount of characters.
|
||||
class FlutterFormInputMultiLine extends StatelessWidget {
|
||||
const FlutterFormInputMultiLine({
|
||||
Key? key,
|
||||
required this.controller,
|
||||
super.key,
|
||||
this.focusNode,
|
||||
this.label,
|
||||
this.hint,
|
||||
this.maxCharacters,
|
||||
this.enabled = true,
|
||||
this.textCapitalization = TextCapitalization.sentences,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final FlutterFormInputController<String> controller;
|
||||
final Widget? label;
|
||||
|
@ -108,7 +103,7 @@ class FlutterFormInputMultiLine extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
return input.FlutterFormInputMultiLine(
|
||||
enabled: enabled,
|
||||
|
@ -125,7 +120,8 @@ class FlutterFormInputMultiLine extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
/// Controller for plain text used by a [FlutterFormInputWidget] used in a [FlutterForm].
|
||||
/// Controller for plain text used by a [FlutterFormInputWidget] used in a
|
||||
/// [FlutterForm].
|
||||
///
|
||||
/// Mainly used by [FlutterFormInputPlainText].
|
||||
class FlutterFormInputPlainTextController
|
||||
|
@ -167,8 +163,10 @@ class FlutterFormInputPlainTextController
|
|||
}
|
||||
|
||||
@override
|
||||
String? onValidate(String? value,
|
||||
String Function(String, {List<String>? params}) translator) {
|
||||
String? onValidate(
|
||||
String? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) {
|
||||
if (mandatory) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return translator('Field can not be empty');
|
||||
|
|
|
@ -3,46 +3,42 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
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 '../../../../../flutter_form.dart';
|
||||
|
||||
/// Input for a number value between two values via a slider. Used in a [FlutterForm].
|
||||
/// Input for a number value between two values via a slider. Used in a
|
||||
/// [FlutterForm].
|
||||
///
|
||||
/// Standard controller is [FlutterFormInputSliderController].
|
||||
class FlutterFormInputSlider extends FlutterFormInputWidget<double> {
|
||||
const FlutterFormInputSlider({
|
||||
Key? key,
|
||||
required FlutterFormInputController<double> controller,
|
||||
FocusNode? focusNode,
|
||||
Widget? label,
|
||||
required super.controller,
|
||||
super.key,
|
||||
super.focusNode,
|
||||
super.label,
|
||||
this.minValue = 0,
|
||||
this.maxValue = 100,
|
||||
}) : assert(minValue < maxValue),
|
||||
super(
|
||||
key: key,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
label: label);
|
||||
}) : assert(minValue < maxValue, 'minValue must be less than maxValue');
|
||||
|
||||
final int minValue;
|
||||
final int maxValue;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
super.registerController(context);
|
||||
|
||||
return input.FlutterFormInputSlider(
|
||||
focusNode: focusNode,
|
||||
onSaved: (value) => controller.onSaved(value),
|
||||
onSaved: controller.onSaved,
|
||||
validator: (value) => controller.onValidate(value, _),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Controller for slider used by a [FlutterFormInputWidget] used in a [FlutterForm].
|
||||
/// Controller for slider used by a [FlutterFormInputWidget] used in a
|
||||
/// [FlutterForm].
|
||||
///
|
||||
/// Mainly used by [FlutterFormInputSlider].
|
||||
class FlutterFormInputSliderController
|
||||
|
@ -83,8 +79,10 @@ class FlutterFormInputSliderController
|
|||
}
|
||||
|
||||
@override
|
||||
String? onValidate(double? value,
|
||||
String Function(String, {List<String>? params}) translator) {
|
||||
String? onValidate(
|
||||
double? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) {
|
||||
if (mandatory) {}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// ignore_for_file: avoid_positional_boolean_parameters
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_wizard/flutter_form.dart';
|
||||
import 'package:flutter_input_library/flutter_input_library.dart' as input;
|
||||
|
@ -11,25 +13,21 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
|
|||
/// Standard controller is [FlutterFormInputSwitchController].
|
||||
class FlutterFormInputSwitch extends FlutterFormInputWidget<bool> {
|
||||
const FlutterFormInputSwitch({
|
||||
Key? key,
|
||||
required FlutterFormInputController<bool> controller,
|
||||
FocusNode? focusNode,
|
||||
Widget? label,
|
||||
}) : super(
|
||||
key: key,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
label: label);
|
||||
required super.controller,
|
||||
super.key,
|
||||
super.focusNode,
|
||||
super.label,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String Function(String, {List<String>? params}) _ = getTranslator(context);
|
||||
var _ = getTranslator(context);
|
||||
|
||||
super.registerController(context);
|
||||
|
||||
return input.FlutterFormInputBool(
|
||||
focusNode: focusNode,
|
||||
onSaved: (value) => controller.onSaved(value),
|
||||
onSaved: controller.onSaved,
|
||||
onChanged: controller.onChanged,
|
||||
validator: (value) => controller.onValidate(value, _),
|
||||
initialValue: controller.value ?? false,
|
||||
|
@ -38,7 +36,8 @@ class FlutterFormInputSwitch extends FlutterFormInputWidget<bool> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Controller for the switch used by a [FlutterFormInputWidget] used in a [FlutterForm].
|
||||
/// Controller for the switch used by a [FlutterFormInputWidget] used in a
|
||||
/// [FlutterForm].
|
||||
///
|
||||
/// Mainly used by [FlutterFormInputSwitch].
|
||||
class FlutterFormInputSwitchController
|
||||
|
@ -80,7 +79,8 @@ class FlutterFormInputSwitchController
|
|||
|
||||
@override
|
||||
String? onValidate(
|
||||
bool? value, String Function(String, {List<String>? params}) translator) {
|
||||
return null;
|
||||
}
|
||||
bool? value,
|
||||
String Function(String, {List<String>? params}) translator,
|
||||
) =>
|
||||
null;
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
export 'input_carousel/input_carousel.dart';
|
||||
export 'input_date_picker/input_date_picker.dart';
|
||||
export 'input_email.dart';
|
||||
export 'input_number_picker/input_number_picker.dart';
|
||||
export 'input_password/input_password.dart';
|
||||
export 'input_plain_text.dart';
|
||||
export 'input_slider/input_slider.dart';
|
||||
export 'input_switch/input_switch.dart';
|
||||
export 'input_date_picker/input_date_picker.dart';
|
||||
|
|
|
@ -2,27 +2,45 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// ignore_for_file: avoid_positional_boolean_parameters
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// The options used to set parameters to a [FlutterForm].
|
||||
///
|
||||
/// The pages determine what pages the pageview will contain via a [List] of [FlutterFormPage]s.
|
||||
/// The pages determine what pages the pageview will contain via a [List] of
|
||||
/// [FlutterFormPage]s.
|
||||
///
|
||||
/// Using a checkpage gives the ability for the user to check all input values before commiting by [CheckPage].
|
||||
/// Using a checkpage gives the ability for the user to check all input values
|
||||
/// before commiting by [CheckPage].
|
||||
/// If [checkPage] is null no check page will be shown.
|
||||
///
|
||||
/// [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 aligned where ever.
|
||||
/// Both are just plain widgets used in a [Stack]. So the widgets can be
|
||||
/// aligned where ever.
|
||||
/// 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.
|
||||
/// [onNext] is called when the user goes to the next 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 slides. Defaults to horizontal.
|
||||
/// [scrollDirection] can be set to change the Axis on which the pageview
|
||||
/// slides. Defaults to horizontal.
|
||||
///
|
||||
/// [scrollPhysics] can be set to set the scroll phyisics of the scroll views in each page. Default to [ClampingScrollPhysics].
|
||||
/// [scrollPhysics] can be set to set the scroll phyisics of the scroll views
|
||||
/// in each page. Default to [ClampingScrollPhysics].
|
||||
class FlutterFormOptions {
|
||||
const FlutterFormOptions({
|
||||
required this.pages,
|
||||
required this.onFinished,
|
||||
required this.onNext,
|
||||
this.checkPage,
|
||||
this.nextButton,
|
||||
this.backButton,
|
||||
this.scrollDirection = Axis.horizontal,
|
||||
this.scrollPhysics,
|
||||
});
|
||||
final List<FlutterFormPage> pages;
|
||||
|
||||
final CheckPage? checkPage;
|
||||
|
@ -33,30 +51,19 @@ class FlutterFormOptions {
|
|||
final void Function(int pageNumber, Map<String, dynamic>) onNext;
|
||||
final Axis scrollDirection;
|
||||
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].
|
||||
class FlutterFormPage {
|
||||
final Widget child;
|
||||
|
||||
FlutterFormPage({
|
||||
required this.child,
|
||||
});
|
||||
final Widget child;
|
||||
}
|
||||
|
||||
/// [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 commiting.
|
||||
/// A [CheckPage] is a page where the user can check all input values before
|
||||
/// commiting.
|
||||
///
|
||||
/// [title] is the widget shown at the top of the page.
|
||||
///
|
||||
|
@ -64,22 +71,28 @@ class FlutterFormPage {
|
|||
///
|
||||
/// [inputCheckWidget] determines how every input is represented on the page.
|
||||
/// [title] is the value given in the input.
|
||||
/// This input can be modified by setting the [checkPageTitle] of that input controller.
|
||||
/// This input can be modified by setting the [checkPageTitle] of that input
|
||||
/// controller.
|
||||
///
|
||||
/// Same for the [description] but if the description is not set in the input controller no description will be given.
|
||||
/// Same for the [description] but if the description is not set in the input
|
||||
/// controller no description will be given.
|
||||
///
|
||||
/// [onPressed] can be set so that when the user triggers it the user will be 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.
|
||||
/// [onPressed] can be set so that when the user triggers it the user will be
|
||||
/// 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.
|
||||
class CheckPage {
|
||||
final Widget? title;
|
||||
final MainAxisAlignment mainAxisAlignment;
|
||||
final Widget Function(
|
||||
String id, String title, String? description, Function onPressed)?
|
||||
inputCheckWidget;
|
||||
|
||||
const CheckPage({
|
||||
this.title,
|
||||
this.inputCheckWidget,
|
||||
this.mainAxisAlignment = MainAxisAlignment.start,
|
||||
});
|
||||
final Widget? title;
|
||||
final MainAxisAlignment mainAxisAlignment;
|
||||
final Widget Function(
|
||||
String id,
|
||||
String title,
|
||||
String? description,
|
||||
Function onPressed,
|
||||
)? inputCheckWidget;
|
||||
}
|
||||
|
|
|
@ -23,14 +23,11 @@ typedef Translator = String Function(
|
|||
|
||||
class ShellTranslationService implements TranslationService {
|
||||
@override
|
||||
String number(double value) {
|
||||
return value.toStringAsFixed(2);
|
||||
}
|
||||
String number(double value) => value.toStringAsFixed(2);
|
||||
|
||||
@override
|
||||
String translate(BuildContext context, String key, {List<String>? params}) {
|
||||
return key;
|
||||
}
|
||||
String translate(BuildContext context, String key, {List<String>? params}) =>
|
||||
key;
|
||||
}
|
||||
|
||||
Translator getTranslator(BuildContext context) {
|
||||
|
@ -39,15 +36,13 @@ Translator getTranslator(BuildContext context) {
|
|||
return (
|
||||
String key, {
|
||||
List<String>? params,
|
||||
}) {
|
||||
return translator(context, key, params: params);
|
||||
};
|
||||
} catch (e) {
|
||||
}) =>
|
||||
translator(context, key, params: params);
|
||||
} on Exception catch (_) {
|
||||
return (
|
||||
String key, {
|
||||
List<String>? params,
|
||||
}) {
|
||||
return key;
|
||||
};
|
||||
}) =>
|
||||
key;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_form_wizard
|
||||
description: A new Flutter package project.
|
||||
version: 6.2.2
|
||||
version: 6.2.3
|
||||
homepage: https://github.com/Iconica-Development/flutter_form_wizard
|
||||
|
||||
publish_to: none
|
||||
|
@ -23,7 +23,10 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 6.0.0
|
||||
|
||||
flutter:
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
|
||||
void main() {
|
||||
testWidgets('Normal walk through without check page', (tester) async {
|
||||
FlutterFormController formController = FlutterFormController();
|
||||
var formController = FlutterFormController();
|
||||
|
||||
var testField1Controller = FlutterFormInputPlainTextController(
|
||||
id: 'Field1',
|
||||
|
@ -28,21 +28,21 @@ void main() {
|
|||
home: Material(
|
||||
child: FlutterForm(
|
||||
options: FlutterFormOptions(
|
||||
nextButton: (pageNumber, checkingPages) {
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await formController.autoNextStep();
|
||||
},
|
||||
child: Text(pageNumber == 0
|
||||
nextButton: (pageNumber, checkingPages) => Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await formController.autoNextStep();
|
||||
},
|
||||
child: Text(
|
||||
pageNumber == 0
|
||||
? 'next1'
|
||||
: pageNumber == 1
|
||||
? 'next2'
|
||||
: 'finish'),
|
||||
: 'finish',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
onFinished: (Map<int, Map<String, dynamic>> results) {
|
||||
onFinishResults = results;
|
||||
},
|
||||
|
@ -76,7 +76,9 @@ void main() {
|
|||
);
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input');
|
||||
find.widgetWithText(TextFormField, 'Field1Label'),
|
||||
'Field1Input',
|
||||
);
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
@ -84,21 +86,26 @@ void main() {
|
|||
expect({'Field1': 'Field1Input'}, onNextResults);
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Field2Label'), 'Field2Input');
|
||||
find.widgetWithText(TextFormField, 'Field2Label'),
|
||||
'Field2Input',
|
||||
);
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'next2'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(1, onNextPageNumber);
|
||||
expect({'Field2': 'Field2Input'}, onNextResults);
|
||||
|
||||
expect({
|
||||
0: {'Field1': 'Field1Input'},
|
||||
1: {'Field2': 'Field2Input'}
|
||||
}, onFinishResults);
|
||||
expect(
|
||||
{
|
||||
0: {'Field1': 'Field1Input'},
|
||||
1: {'Field2': 'Field2Input'},
|
||||
},
|
||||
onFinishResults,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Normal walk through with check page', (tester) async {
|
||||
FlutterFormController formController = FlutterFormController();
|
||||
var formController = FlutterFormController();
|
||||
|
||||
var testField1Controller = FlutterFormInputPlainTextController(
|
||||
id: 'Field1',
|
||||
|
@ -119,21 +126,21 @@ void main() {
|
|||
child: FlutterForm(
|
||||
options: FlutterFormOptions(
|
||||
checkPage: const CheckPage(),
|
||||
nextButton: (pageNumber, checkingPages) {
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await formController.autoNextStep();
|
||||
},
|
||||
child: Text(pageNumber == 0
|
||||
nextButton: (pageNumber, checkingPages) => Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await formController.autoNextStep();
|
||||
},
|
||||
child: Text(
|
||||
pageNumber == 0
|
||||
? 'next1'
|
||||
: pageNumber == 1
|
||||
? 'next2'
|
||||
: 'finish'),
|
||||
: 'finish',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
onFinished: (Map<int, Map<String, dynamic>> results) {
|
||||
onFinishResults = results;
|
||||
},
|
||||
|
@ -167,7 +174,9 @@ void main() {
|
|||
);
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input');
|
||||
find.widgetWithText(TextFormField, 'Field1Label'),
|
||||
'Field1Input',
|
||||
);
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
@ -175,7 +184,9 @@ void main() {
|
|||
expect({'Field1': 'Field1Input'}, onNextResults);
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Field2Label'), 'Field2Input');
|
||||
find.widgetWithText(TextFormField, 'Field2Label'),
|
||||
'Field2Input',
|
||||
);
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'next2'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
@ -186,24 +197,29 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input2');
|
||||
find.widgetWithText(TextFormField, 'Field1Label'),
|
||||
'Field1Input2',
|
||||
);
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(0, onNextPageNumber);
|
||||
expect({'Field1': 'Field1Input2'}, onNextResults);
|
||||
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, "finish"));
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'finish'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect({
|
||||
0: {'Field1': 'Field1Input2'},
|
||||
1: {'Field2': 'Field2Input'}
|
||||
}, onFinishResults);
|
||||
expect(
|
||||
{
|
||||
0: {'Field1': 'Field1Input2'},
|
||||
1: {'Field2': 'Field2Input'},
|
||||
},
|
||||
onFinishResults,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Wrong input with mandatory validator', (tester) async {
|
||||
FlutterFormController formController = FlutterFormController();
|
||||
var formController = FlutterFormController();
|
||||
|
||||
var testField1Controller = FlutterFormInputPlainTextController(
|
||||
id: 'Field1',
|
||||
|
@ -220,17 +236,15 @@ void main() {
|
|||
home: Material(
|
||||
child: FlutterForm(
|
||||
options: FlutterFormOptions(
|
||||
nextButton: (pageNumber, checkingPages) {
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await formController.autoNextStep();
|
||||
},
|
||||
child: const Text('finish'),
|
||||
),
|
||||
);
|
||||
},
|
||||
nextButton: (pageNumber, checkingPages) => Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await formController.autoNextStep();
|
||||
},
|
||||
child: const Text('finish'),
|
||||
),
|
||||
),
|
||||
onFinished: (Map<int, Map<String, dynamic>> results) {
|
||||
// print('finished results: $results');
|
||||
onFinishResults = results;
|
||||
|
@ -263,20 +277,25 @@ void main() {
|
|||
expect(null, onNextPageNumber);
|
||||
expect(null, onNextResults);
|
||||
|
||||
final errorMessageFinder = find.text('Field can not be empty');
|
||||
var errorMessageFinder = find.text('Field can not be empty');
|
||||
|
||||
expect(errorMessageFinder, findsOneWidget);
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input');
|
||||
find.widgetWithText(TextFormField, 'Field1Label'),
|
||||
'Field1Input',
|
||||
);
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'finish'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(0, onNextPageNumber);
|
||||
expect({'Field1': 'Field1Input'}, onNextResults);
|
||||
|
||||
expect({
|
||||
0: {'Field1': 'Field1Input'},
|
||||
}, onFinishResults);
|
||||
expect(
|
||||
{
|
||||
0: {'Field1': 'Field1Input'},
|
||||
},
|
||||
onFinishResults,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue