Merge branch 'fix/add_ci_linter'

This commit is contained in:
mike doornenbal 2024-02-07 12:50:47 +01:00
commit 650418a36f
23 changed files with 417 additions and 374 deletions

14
.github/workflows/component-ci.yml vendored Normal file
View 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

View file

@ -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

View file

@ -115,3 +115,7 @@
## 6.2.2 - February 6th 2024 ## 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

View file

@ -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 # Possible to overwrite the rules from the package
# https://dart.dev/guides/language/analysis-options
analyzer:
exclude:
linter:
rules:

View file

@ -68,7 +68,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "6.2.1" version: "6.2.2"
flutter_input_library: flutter_input_library:
dependency: transitive dependency: transitive
description: description:

View file

@ -2,10 +2,11 @@
// //
// 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';
export 'utils/translation_service.dart';

View file

@ -3,18 +3,23 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../flutter_form.dart'; import 'package:flutter_form_wizard/flutter_form.dart';
import 'utils/form_page_controller.dart'; import 'package:flutter_form_wizard/src/utils/form_page_controller.dart';
import 'utils/formstate.dart' as fs; 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 /// A wrapper for flutters [Form] that can be controlled by a controller and
/// [FlutterForm] also provides multi page forms and a check page for validation. /// 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 /// ``` dart
/// FlutterFormInputEmailController emailController = /// FlutterFormInputEmailController emailController =
/// FlutterFormInputEmailController(id: 'email'); /// FlutterFormInputEmailController(id: 'email');
@ -180,10 +185,10 @@ import '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: key); super.key,
});
final FlutterFormOptions options; final FlutterFormOptions options;
final FlutterFormController formController; final FlutterFormController formController;
@ -203,9 +208,9 @@ class _FlutterFormState extends State<FlutterForm> {
_formController.setFlutterFormOptions(widget.options); _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>()); keys.add(GlobalKey<FormState>());
} }
@ -215,9 +220,9 @@ class _FlutterFormState extends State<FlutterForm> {
setState(() {}); 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()); controllers.add(FlutterFormPageController());
} }
@ -278,25 +283,35 @@ class _FlutterFormState extends State<FlutterForm> {
), ),
], ],
), ),
widget.options.nextButton != null if (widget.options.nextButton != null)
? widget.options.nextButton!(_formController.getCurrentStep(), widget.options.nextButton!(
_formController.getCheckpages()) _formController.getCurrentStep(),
: Align( _formController.getCheckpages(),
)
else
Align(
alignment: AlignmentDirectional.bottomCenter, alignment: AlignmentDirectional.bottomCenter,
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 40, vertical: 15), horizontal: 40,
vertical: 15,
),
textStyle: const TextStyle( textStyle: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)), fontSize: 20,
fontWeight: FontWeight.bold,
),
),
onPressed: () async { onPressed: () async {
await _formController.autoNextStep(); await _formController.autoNextStep();
}, },
child: Text(_formController.getCurrentStep() >= 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)
@ -310,12 +325,12 @@ class _FlutterFormState extends State<FlutterForm> {
} }
List<Widget> getResultWidgets() { List<Widget> getResultWidgets() {
List<Widget> widgets = []; var widgets = <Widget>[];
_formController.getAllResults().forEach( _formController.getAllResults().forEach(
(pageNumber, pageResults) { (pageNumber, pageResults) {
pageResults.forEach((inputId, inputResult) { pageResults.forEach((inputId, inputResult) {
FlutterFormInputController? inputController = _formController var inputController = _formController
.getFormPageControllers()[pageNumber] .getFormPageControllers()[pageNumber]
.getController(inputId); .getController(inputId);
@ -327,10 +342,8 @@ 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 != null inputController.checkPageDescription
? inputController ?.call(inputController.value),
.checkPageDescription!(inputController.value)
: null,
() async { () async {
await _formController.jumpToPage(pageNumber); await _formController.jumpToPage(pageNumber);
}, },
@ -378,7 +391,7 @@ class _FlutterFormState extends State<FlutterForm> {
Text( Text(
inputController.checkPageDescription!(inputResult), inputController.checkPageDescription!(inputResult),
style: const TextStyle(fontSize: 16), style: const TextStyle(fontSize: 16),
) ),
], ],
), ),
), ),
@ -412,15 +425,14 @@ class FlutterFormController extends ChangeNotifier {
late List<FlutterFormPageController> _formPageControllers; late List<FlutterFormPageController> _formPageControllers;
List<FlutterFormPageController> getFormPageControllers() { List<FlutterFormPageController> getFormPageControllers() =>
return _formPageControllers; _formPageControllers;
}
setFormPageControllers(List<FlutterFormPageController> controllers) { void setFormPageControllers(List<FlutterFormPageController> controllers) {
_formPageControllers = controllers; _formPageControllers = controllers;
} }
disableCheckingPages() { void voidisableCheckingPages() {
_checkingPages = false; _checkingPages = false;
for (var controller in _formPageControllers) { for (var controller in _formPageControllers) {
@ -436,7 +448,9 @@ class FlutterFormController extends ChangeNotifier {
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
_options.onNext( _options.onNext(
_currentStep, _formPageControllers[_currentStep].getAllValues()); _currentStep,
_formPageControllers[_currentStep].getAllValues(),
);
if (_currentStep >= _options.pages.length - 1 && if (_currentStep >= _options.pages.length - 1 &&
_options.checkPage == null || _options.checkPage == null ||
@ -449,9 +463,11 @@ class FlutterFormController extends ChangeNotifier {
notifyListeners(); notifyListeners();
await _pageController.animateToPage(_currentStep, await _pageController.animateToPage(
_currentStep,
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
curve: Curves.ease); curve: Curves.ease,
);
} else { } else {
_currentStep += 1; _currentStep += 1;
@ -462,9 +478,11 @@ class FlutterFormController extends ChangeNotifier {
notifyListeners(); notifyListeners();
await _pageController.animateToPage(_currentStep, await _pageController.animateToPage(
_currentStep,
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
curve: Curves.ease); curve: Curves.ease,
);
} }
} }
} }
@ -507,13 +525,14 @@ class FlutterFormController extends ChangeNotifier {
return false; return false;
} }
Map<String, dynamic> getCurrentStepResults() { Map<String, dynamic> getCurrentStepResults() =>
return _formPageControllers[_currentStep].getAllValues(); _formPageControllers[_currentStep].getAllValues();
}
Future<void> nextStep() async { Future<void> nextStep() async {
_options.onNext( _options.onNext(
_currentStep, _formPageControllers[_currentStep].getAllValues()); _currentStep,
_formPageControllers[_currentStep].getAllValues(),
);
_currentStep += 1; _currentStep += 1;
@ -523,16 +542,19 @@ class FlutterFormController extends ChangeNotifier {
notifyListeners(); notifyListeners();
await _pageController.animateToPage(_currentStep, await _pageController.animateToPage(
duration: const Duration(milliseconds: 250), curve: Curves.ease); _currentStep,
duration: const Duration(milliseconds: 250),
curve: Curves.ease,
);
} }
finishForm() { void finishForm() {
_options.onFinished(getAllResults()); _options.onFinished(getAllResults());
} }
Map<int, Map<String, dynamic>> 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++) { for (var i = 0; i < _options.pages.length; i++) {
allValues.addAll({i: _formPageControllers[i].getAllValues()}); allValues.addAll({i: _formPageControllers[i].getAllValues()});
@ -540,27 +562,19 @@ class FlutterFormController extends ChangeNotifier {
return allValues; return allValues;
} }
setFlutterFormOptions(FlutterFormOptions options) { void setFlutterFormOptions(FlutterFormOptions options) {
_options = options; _options = options;
} }
setKeys(List<GlobalKey<FormState>> keys) { void setKeys(List<GlobalKey<FormState>> keys) {
_keys = keys; _keys = keys;
} }
List<GlobalKey<FormState>> getKeys() { List<GlobalKey<FormState>> getKeys() => _keys;
return _keys;
}
int getCurrentStep() { int getCurrentStep() => _currentStep;
return _currentStep;
}
bool getCheckpages() { bool getCheckpages() => _checkingPages;
return _checkingPages;
}
PageController getPageController() { PageController getPageController() => _pageController;
return _pageController;
}
} }

View file

@ -11,13 +11,12 @@ class FlutterFormPageController {
_controllers.add(inputController); _controllers.add(inputController);
} }
clearControllers() { void clearControllers() {
_controllers = []; _controllers = [];
} }
bool _isRegisteredById(String id) { bool _isRegisteredById(String id) =>
return _controllers.any((element) => (element.id == id)); _controllers.any((element) => element.id == id);
}
FlutterFormInputController? getController(String key) { FlutterFormInputController? getController(String key) {
if (_isRegisteredById(key)) { if (_isRegisteredById(key)) {
@ -27,9 +26,9 @@ class FlutterFormPageController {
} }
Map<String, dynamic> getAllValues() { 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) { if (controller.value != null) {
values.addAll({controller.id!: controller.value}); values.addAll({controller.id!: controller.value});
} }

View file

@ -3,20 +3,19 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; 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 { class FormState extends InheritedWidget {
const FormState({ const FormState({
Key? key, required super.child,
required Widget child,
required this.formController, required this.formController,
}) : super(key: key, child: child); super.key,
});
final FlutterFormPageController formController; final FlutterFormPageController formController;
static FormState of(BuildContext context) { static FormState of(BuildContext context) {
final FormState? result = var result = context.dependOnInheritedWidgetOfExactType<FormState>();
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 '/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]. /// 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. /// 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 { 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 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; 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.
@ -33,9 +34,10 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
final bool enabled; final bool enabled;
/// [registerController] should be called to register the given [controller] to the form page. /// [registerController] should be called to register the given [controller]
registerController(BuildContext context) { /// to the form page.
FlutterFormInputController? localController = void registerController(BuildContext context) {
var localController =
fs.FormState.of(context).formController.getController(controller.id!); fs.FormState.of(context).formController.getController(controller.id!);
if (localController == null) { 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]. /// 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. /// [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. /// 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:
@ -62,27 +66,32 @@ abstract class FlutterFormInputWidget<T> extends StatelessWidget {
/// }, /// },
/// ``` /// ```
/// ///
/// [checkPageDescription] is the same as checkPageTitle but for the description. /// [checkPageDescription] is the same as checkPageTitle but for the
/// If null no description will be shown. /// 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. /// [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 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; 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 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. /// 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:
@ -93,20 +102,26 @@ abstract class FlutterFormInputController<T> {
/// ``` /// ```
String Function(T? value)? checkPageTitle; 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. /// 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. 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; 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; 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); 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, String Function(String, {List<String>? params}) translator); T? value,
String Function(String, {List<String>? params}) translator,
);
} }

View file

@ -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. /// Height sets the height of the inputfield. Default to 425.
class FlutterFormInputCarousel extends FlutterFormInputWidget<int> { class FlutterFormInputCarousel extends FlutterFormInputWidget<int> {
const FlutterFormInputCarousel({ const FlutterFormInputCarousel({
Key? key, required super.controller,
required FlutterFormInputController<int> controller,
Widget? label,
required this.items, required this.items,
super.key,
super.label,
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;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputCarousel( return input.FlutterFormInputCarousel(
onSaved: (value) => controller.onSaved(value), onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, _), validator: (value) => controller.onValidate(value, _),
onChanged: controller.onChanged, onChanged: controller.onChanged,
initialValue: controller.value ?? 0, 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]. /// Mainly used by [FlutterFormInputCarousel].
class FlutterFormInputCarouselController class FlutterFormInputCarouselController
@ -84,7 +85,9 @@ class FlutterFormInputCarouselController
@override @override
String? onValidate( String? onValidate(
int? value, String Function(String, {List<String>? params}) translator) { int? value,
String Function(String, {List<String>? params}) translator,
) {
if (mandatory) {} if (mandatory) {}
return null; return null;

View file

@ -5,22 +5,21 @@
// 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> {
const FlutterFormInputDateTime({ const FlutterFormInputDateTime({
Key? key, required super.controller,
required FlutterFormInputController<String> controller,
Widget? label,
this.showIcon = true,
required this.inputType, required this.inputType,
required this.dateFormat, required this.dateFormat,
super.key,
super.label,
this.showIcon = true,
this.firstDate, this.firstDate,
this.lastDate, this.lastDate,
this.initialDate, this.initialDate,
@ -28,11 +27,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
this.icon = Icons.calendar_today, this.icon = Icons.calendar_today,
this.enabled = true, this.enabled = true,
this.onTapEnabled = true, this.onTapEnabled = true,
}) : super( });
key: key,
controller: controller,
label: label,
);
final bool showIcon; final bool showIcon;
final input.FlutterFormDateTimeType inputType; final input.FlutterFormDateTimeType inputType;
final DateFormat dateFormat; final DateFormat dateFormat;
@ -46,7 +41,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputDateTime( return input.FlutterFormInputDateTime(
@ -59,7 +54,7 @@ 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: (value) => controller.onSaved(value), onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, _), validator: (value) => controller.onValidate(value, _),
initialValue: controller.value, initialValue: controller.value,
dateFormat: dateFormat, 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]. /// Mainly used by [FlutterFormInputDateTime].
class FlutterFormInputDateTimeController class FlutterFormInputDateTimeController
implements FlutterFormInputController<String> { implements FlutterFormInputController<String> {
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) {
@ -118,13 +114,15 @@ class FlutterFormInputDateTimeController
void Function(String? value)? onSubmit; void Function(String? value)? onSubmit;
@override @override
void onSaved(dynamic value) { void onSaved(value) {
this.value = value; this.value = value;
} }
@override @override
String? onValidate(String? value, String? onValidate(
String Function(String, {List<String>? params}) translator) { String? value,
String Function(String, {List<String>? params}) translator,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return translator('shell.form.error.empty'); return translator('shell.form.error.empty');

View file

@ -3,31 +3,26 @@
// 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> {
const FlutterFormInputEmail({ const FlutterFormInputEmail({
Key? key, required super.controller,
required FlutterFormInputController<String> controller, super.key,
FocusNode? focusNode, super.focusNode,
Widget? label, super.label,
bool? enabled, bool? enabled,
}) : super( }) : super(
key: key,
controller: controller,
focusNode: focusNode,
label: label,
enabled: enabled ?? true, enabled: enabled ?? true,
); );
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
super.registerController(context); super.registerController(context);
@ -42,13 +37,14 @@ class FlutterFormInputEmail extends FlutterFormInputWidget<String> {
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
decoration: InputDecoration( decoration: InputDecoration(
focusColor: Theme.of(context).primaryColor, 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]. /// Mainly used by [FlutterFormInputEmail].
class FlutterFormInputEmailController class FlutterFormInputEmailController
@ -85,21 +81,23 @@ class FlutterFormInputEmailController
void Function(String? value)? onSubmit; void Function(String? value)? onSubmit;
@override @override
void onSaved(dynamic value) { void onSaved(value) {
this.value = value; this.value = value;
} }
@override @override
String? onValidate(String? value, String? onValidate(
String Function(String, {List<String>? params}) translator) { String? value,
String Function(String, {List<String>? params}) translator,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return translator('shell.form.error.empty'); 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 translator('shell.form.error.email.notValid'); 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,28 +14,26 @@ import '../../../../../flutter_form.dart';
/// Standard controller is [FlutterFormInputNumberPickerController]. /// Standard controller is [FlutterFormInputNumberPickerController].
class FlutterFormInputNumberPicker extends FlutterFormInputWidget<int> { class FlutterFormInputNumberPicker extends FlutterFormInputWidget<int> {
const FlutterFormInputNumberPicker({ const FlutterFormInputNumberPicker({
Key? key, required super.controller,
required FlutterFormInputController<int> controller, super.key,
Widget? label, super.label,
FocusNode? focusNode,
this.minValue = 0, this.minValue = 0,
this.maxValue = 100, this.maxValue = 100,
}) : assert(minValue < maxValue), }) : assert(minValue < maxValue, 'minValue must be less than maxValue');
super(key: key, controller: controller, label: label);
final int minValue; final int minValue;
final int maxValue; final int maxValue;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputNumberPicker( return input.FlutterFormInputNumberPicker(
minValue: minValue, minValue: minValue,
maxValue: maxValue, maxValue: maxValue,
onSaved: (value) => controller.onSaved(value), onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, _), validator: (value) => controller.onValidate(value, _),
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
initialValue: controller.value ?? minValue, initialValue: controller.value ?? minValue,
@ -82,7 +80,9 @@ class FlutterFormInputNumberPickerController
@override @override
String? onValidate( String? onValidate(
int? value, String Function(String, {List<String>? params}) translator) { int? value,
String Function(String, {List<String>? params}) translator,
) {
if (mandatory) {} if (mandatory) {}
return null; return null;

View file

@ -3,24 +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/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({
Key? key, required super.controller,
required FlutterFormInputController<String> controller, super.key,
FocusNode? focusNode, super.focusNode,
Widget? label, super.label,
bool? enabled, bool? enabled,
}) : super( }) : super(
key: key,
controller: controller,
focusNode: focusNode,
label: label,
enabled: enabled ?? true, enabled: enabled ?? true,
); );
@ -28,13 +24,13 @@ class FlutterFormInputPassword extends FlutterFormInputWidget<String> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.registerController(context); super.registerController(context);
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
return input.FlutterFormInputPassword( return input.FlutterFormInputPassword(
enabled: enabled, enabled: enabled,
initialValue: controller.value, initialValue: controller.value,
focusNode: focusNode, focusNode: focusNode,
onSaved: (value) => controller.onSaved(value), onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, _), validator: (value) => controller.onValidate(value, _),
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.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]. /// Mainly used by [FlutterFormInputPassword].
class FlutterFormInputPasswordController class FlutterFormInputPasswordController
@ -79,13 +76,15 @@ class FlutterFormInputPasswordController
void Function(String? value)? onSubmit; void Function(String? value)? onSubmit;
@override @override
void onSaved(dynamic value) { void onSaved(value) {
this.value = value; this.value = value;
} }
@override @override
String? onValidate(String? value, String? onValidate(
String Function(String, {List<String>? params}) translator) { String? value,
String Function(String, {List<String>? params}) translator,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return translator('Field can not be empty'); return translator('Field can not be empty');

View file

@ -5,19 +5,18 @@
// 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> {
const FlutterFormInputPlainText({ const FlutterFormInputPlainText({
Key? key, required super.controller,
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,
@ -28,11 +27,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
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,13 +43,13 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
super.registerController(context); super.registerController(context);
InputDecoration inputDecoration = decoration ?? var inputDecoration = decoration ??
InputDecoration( InputDecoration(
label: label ?? const Text("Plain text"), label: label ?? const Text('Plain text'),
); );
return input.FlutterFormInputPlainText( return input.FlutterFormInputPlainText(
@ -63,7 +58,7 @@ 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: (value) => controller.onSaved(value), onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, _), validator: (value) => controller.onValidate(value, _),
onChanged: (value) => controller.onChanged?.call(value), onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.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. /// 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,
super.key,
this.focusNode, this.focusNode,
this.label, this.label,
this.hint, this.hint,
this.maxCharacters, this.maxCharacters,
this.enabled = true, this.enabled = true,
this.textCapitalization = TextCapitalization.sentences, this.textCapitalization = TextCapitalization.sentences,
}) : super(key: key); });
final FlutterFormInputController<String> controller; final FlutterFormInputController<String> controller;
final Widget? label; final Widget? label;
@ -108,7 +103,7 @@ class FlutterFormInputMultiLine extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
return input.FlutterFormInputMultiLine( return input.FlutterFormInputMultiLine(
enabled: enabled, 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]. /// Mainly used by [FlutterFormInputPlainText].
class FlutterFormInputPlainTextController class FlutterFormInputPlainTextController
@ -167,8 +163,10 @@ class FlutterFormInputPlainTextController
} }
@override @override
String? onValidate(String? value, String? onValidate(
String Function(String, {List<String>? params}) translator) { String? value,
String Function(String, {List<String>? params}) translator,
) {
if (mandatory) { if (mandatory) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return translator('Field can not be empty'); return translator('Field can not be empty');

View file

@ -3,46 +3,42 @@
// 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 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]. /// Standard controller is [FlutterFormInputSliderController].
class FlutterFormInputSlider extends FlutterFormInputWidget<double> { class FlutterFormInputSlider extends FlutterFormInputWidget<double> {
const FlutterFormInputSlider({ const FlutterFormInputSlider({
Key? key, required super.controller,
required FlutterFormInputController<double> controller, super.key,
FocusNode? focusNode, super.focusNode,
Widget? label, super.label,
this.minValue = 0, this.minValue = 0,
this.maxValue = 100, this.maxValue = 100,
}) : assert(minValue < maxValue), }) : assert(minValue < maxValue, 'minValue must be less than maxValue');
super(
key: key,
controller: controller,
focusNode: focusNode,
label: label);
final int minValue; final int minValue;
final int maxValue; final int maxValue;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputSlider( return input.FlutterFormInputSlider(
focusNode: focusNode, focusNode: focusNode,
onSaved: (value) => controller.onSaved(value), onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, _), 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]. /// Mainly used by [FlutterFormInputSlider].
class FlutterFormInputSliderController class FlutterFormInputSliderController
@ -83,8 +79,10 @@ class FlutterFormInputSliderController
} }
@override @override
String? onValidate(double? value, String? onValidate(
String Function(String, {List<String>? params}) translator) { double? value,
String Function(String, {List<String>? params}) translator,
) {
if (mandatory) {} if (mandatory) {}
return null; return null;

View file

@ -2,6 +2,8 @@
// //
// 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;
@ -11,25 +13,21 @@ 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({
Key? key, required super.controller,
required FlutterFormInputController<bool> controller, super.key,
FocusNode? focusNode, super.focusNode,
Widget? label, super.label,
}) : super( });
key: key,
controller: controller,
focusNode: focusNode,
label: label);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String Function(String, {List<String>? params}) _ = getTranslator(context); var _ = getTranslator(context);
super.registerController(context); super.registerController(context);
return input.FlutterFormInputBool( return input.FlutterFormInputBool(
focusNode: focusNode, focusNode: focusNode,
onSaved: (value) => controller.onSaved(value), onSaved: controller.onSaved,
onChanged: controller.onChanged, onChanged: controller.onChanged,
validator: (value) => controller.onValidate(value, _), validator: (value) => controller.onValidate(value, _),
initialValue: controller.value ?? false, 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]. /// Mainly used by [FlutterFormInputSwitch].
class FlutterFormInputSwitchController class FlutterFormInputSwitchController
@ -80,7 +79,8 @@ class FlutterFormInputSwitchController
@override @override
String? onValidate( String? onValidate(
bool? value, String Function(String, {List<String>? params}) translator) { bool? value,
return null; String Function(String, {List<String>? params}) translator,
} ) =>
null;
} }

View file

@ -3,10 +3,10 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
export 'input_carousel/input_carousel.dart'; export 'input_carousel/input_carousel.dart';
export 'input_date_picker/input_date_picker.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_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 'input_date_picker/input_date_picker.dart';

View file

@ -2,27 +2,45 @@
// //
// 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 [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. /// 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 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. /// 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.
/// [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 { 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 List<FlutterFormPage> pages;
final CheckPage? checkPage; final CheckPage? checkPage;
@ -33,30 +51,19 @@ class FlutterFormOptions {
final void Function(int pageNumber, Map<String, dynamic>) onNext; final void Function(int pageNumber, Map<String, dynamic>) onNext;
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 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. /// [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. /// [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 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. /// [onPressed] can be set so that when the user triggers it the user will be
/// Here the user can modify the input and save it. Afterwards the user will be sent back to the check page. /// 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 { 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

@ -23,14 +23,11 @@ typedef Translator = String Function(
class ShellTranslationService implements TranslationService { class ShellTranslationService implements TranslationService {
@override @override
String number(double value) { String number(double value) => value.toStringAsFixed(2);
return value.toStringAsFixed(2);
}
@override @override
String translate(BuildContext context, String key, {List<String>? params}) { String translate(BuildContext context, String key, {List<String>? params}) =>
return key; key;
}
} }
Translator getTranslator(BuildContext context) { Translator getTranslator(BuildContext context) {
@ -39,15 +36,13 @@ Translator getTranslator(BuildContext context) {
return ( return (
String key, { String key, {
List<String>? params, List<String>? params,
}) { }) =>
return translator(context, key, params: params); translator(context, key, params: params);
}; } on Exception catch (_) {
} catch (e) {
return ( return (
String key, { String key, {
List<String>? params, List<String>? params,
}) { }) =>
return key; key;
};
} }
} }

View file

@ -1,6 +1,6 @@
name: flutter_form_wizard name: flutter_form_wizard
description: A new Flutter package project. description: A new Flutter package project.
version: 6.2.2 version: 6.2.3
homepage: https://github.com/Iconica-Development/flutter_form_wizard homepage: https://github.com/Iconica-Development/flutter_form_wizard
publish_to: none publish_to: none
@ -23,7 +23,10 @@ dependencies:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter 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: flutter:

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 {
FlutterFormController formController = FlutterFormController(); var 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) { nextButton: (pageNumber, checkingPages) => Align(
return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
await formController.autoNextStep(); 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;
}, },
@ -76,7 +76,9 @@ void main() {
); );
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input'); find.widgetWithText(TextFormField, 'Field1Label'),
'Field1Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next1')); await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -84,21 +86,26 @@ void main() {
expect({'Field1': 'Field1Input'}, onNextResults); expect({'Field1': 'Field1Input'}, onNextResults);
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field2Label'), 'Field2Input'); find.widgetWithText(TextFormField, 'Field2Label'),
'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 {
FlutterFormController formController = FlutterFormController(); var formController = FlutterFormController();
var testField1Controller = FlutterFormInputPlainTextController( var testField1Controller = FlutterFormInputPlainTextController(
id: 'Field1', id: 'Field1',
@ -119,21 +126,21 @@ void main() {
child: FlutterForm( child: FlutterForm(
options: FlutterFormOptions( options: FlutterFormOptions(
checkPage: const CheckPage(), checkPage: const CheckPage(),
nextButton: (pageNumber, checkingPages) { nextButton: (pageNumber, checkingPages) => Align(
return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
await formController.autoNextStep(); 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;
}, },
@ -167,7 +174,9 @@ void main() {
); );
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input'); find.widgetWithText(TextFormField, 'Field1Label'),
'Field1Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next1')); await tester.tap(find.widgetWithText(ElevatedButton, 'next1'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -175,7 +184,9 @@ void main() {
expect({'Field1': 'Field1Input'}, onNextResults); expect({'Field1': 'Field1Input'}, onNextResults);
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field2Label'), 'Field2Input'); find.widgetWithText(TextFormField, 'Field2Label'),
'Field2Input',
);
await tester.tap(find.widgetWithText(ElevatedButton, 'next2')); await tester.tap(find.widgetWithText(ElevatedButton, 'next2'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -186,24 +197,29 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input2'); find.widgetWithText(TextFormField, 'Field1Label'),
'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 {
FlutterFormController formController = FlutterFormController(); var formController = FlutterFormController();
var testField1Controller = FlutterFormInputPlainTextController( var testField1Controller = FlutterFormInputPlainTextController(
id: 'Field1', id: 'Field1',
@ -220,8 +236,7 @@ void main() {
home: Material( home: Material(
child: FlutterForm( child: FlutterForm(
options: FlutterFormOptions( options: FlutterFormOptions(
nextButton: (pageNumber, checkingPages) { nextButton: (pageNumber, checkingPages) => Align(
return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
@ -229,8 +244,7 @@ void main() {
}, },
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;
@ -263,20 +277,25 @@ void main() {
expect(null, onNextPageNumber); expect(null, onNextPageNumber);
expect(null, onNextResults); expect(null, onNextResults);
final errorMessageFinder = find.text('Field can not be empty'); var errorMessageFinder = find.text('Field can not be empty');
expect(errorMessageFinder, findsOneWidget); expect(errorMessageFinder, findsOneWidget);
await tester.enterText( await tester.enterText(
find.widgetWithText(TextFormField, 'Field1Label'), 'Field1Input'); find.widgetWithText(TextFormField, 'Field1Label'),
'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,
);
}); });
} }