Merge pull request #47 from Iconica-Development/refactor/replace-ShellTranslationService

refactor: replace shelltranslationservice with validationMessage input
This commit is contained in:
Freek van de Ven 2024-02-29 16:52:11 +01:00 committed by GitHub
commit 48534c0db1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 131 additions and 113 deletions

View file

@ -129,3 +129,8 @@
- Updated the `flutter_input_library` from 3.1.0 to 3.2.1
- Added `FlutterFormInputPhone` for phone number with dial code selection.
- Added `InputDecoration` parameter to the following inputfields: `FlutterFormInputEmail` and `FlutterFormInputPassword`
## 6.3.1 - February 29th 2024
- Removed `TranslationService` and add `validationMessage` property to fields with validation.
- Added a way to override a input field validator.
- Exposed all properties for `FlutterFormInputDateTime` provided by `flutter_input_library`.

View file

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

View file

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

View file

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

View file

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

View file

@ -189,6 +189,7 @@ class _FormExampleState extends ConsumerState<FormExample> {
child: Center(
child: FlutterFormInputPhone(
controller: phoneInputController,
validationMessage: 'Please fill in a valid phone number',
),
),
),

View file

@ -9,4 +9,3 @@ export 'src/form.dart';
export 'src/widgets/input/abstractions.dart';
export 'src/widgets/input/input_types/input_types.dart';
export 'utils/form.dart';
export 'utils/translation_service.dart';

View file

@ -122,6 +122,6 @@ abstract class FlutterFormInputController<T> {
/// [onValidate] is used to validate the given input by the user.
String? onValidate(
T? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
);
}

View file

@ -16,24 +16,27 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
class FlutterFormInputCarousel extends FlutterFormInputWidget<int> {
const FlutterFormInputCarousel({
required super.controller,
required this.validationMessage,
required this.items,
super.key,
super.label,
this.validator,
this.height = 425,
});
final List<Widget> items;
final double height;
final String validationMessage;
final String? Function(int?)? validator;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
return input.FlutterFormInputCarousel(
onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
onChanged: controller.onChanged,
initialValue: controller.value ?? 0,
items: items,
@ -86,7 +89,7 @@ class FlutterFormInputCarouselController
@override
String? onValidate(
int? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {}

View file

@ -33,36 +33,57 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
required super.controller,
required this.inputType,
required this.dateFormat,
required this.validationMessage,
this.decoration,
this.style,
super.key,
super.label,
this.label,
this.showIcon = true,
this.firstDate,
this.lastDate,
this.initialDate,
this.initialDateTimeRange,
this.initialTime,
this.icon = Icons.calendar_today,
this.initialValue,
this.onChanged,
this.onSaved,
this.validator,
this.autovalidateMode = AutovalidateMode.disabled,
this.timePickerEntryMode = TimePickerEntryMode.dial,
this.enabled = true,
this.onTapEnabled = true,
});
final TextStyle? style;
final InputDecoration? decoration;
final Widget? label;
final bool showIcon;
final input.FlutterFormDateTimeType inputType;
final DateFormat dateFormat;
final DateTime? initialDate;
final DateTimeRange? initialDateTimeRange;
final TimeOfDay? initialTime;
final DateTime? firstDate;
final DateTime? lastDate;
final IconData icon;
final String? initialValue;
final String? Function(String?)? validator;
final String validationMessage;
final void Function(String?)? onSaved;
final void Function(String?)? onChanged;
final AutovalidateMode autovalidateMode;
final TimePickerEntryMode timePickerEntryMode;
final bool enabled;
final bool onTapEnabled;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
return input.FlutterFormInputDateTime(
enabled: enabled,
showIcon: showIcon,
decoration: decoration,
onTapEnabled: onTapEnabled,
label: label,
icon: icon,
@ -71,7 +92,8 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget<String> {
inputType: inputType,
onChanged: (value) => controller.onChanged?.call(value),
onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
initialValue: controller.value,
dateFormat: dateFormat,
initialDate: initialDate,
@ -143,11 +165,11 @@ class FlutterFormInputDateTimeController
@override
String? onValidate(
String? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {
if (value == null || value.isEmpty) {
return translator('shell.form.error.empty');
return validationMessage;
}
}

View file

@ -16,21 +16,23 @@ class FlutterFormInputEmail extends FlutterFormInputWidget<String> {
/// The [key], [focusNode], [label], and [enabled] parameters are optional.
const FlutterFormInputEmail({
required super.controller,
required this.validationMessage,
super.key,
super.focusNode,
super.label,
bool? enabled,
this.validator,
this.decoration,
}) : super(
enabled: enabled ?? true,
);
final InputDecoration? decoration;
final String validationMessage;
final String? Function(String?)? validator;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
return input.FlutterFormInputPlainText(
@ -40,7 +42,8 @@ class FlutterFormInputEmail extends FlutterFormInputWidget<String> {
controller.onSaved(value);
},
focusNode: focusNode,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value),
decoration: decoration,
);
@ -98,17 +101,17 @@ class FlutterFormInputEmailController
@override
String? onValidate(
String? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {
if (value == null || value.isEmpty) {
return translator('shell.form.error.empty');
return validationMessage;
}
if (!RegExp(
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');
return validationMessage;
}
}

View file

@ -15,26 +15,29 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
class FlutterFormInputNumberPicker extends FlutterFormInputWidget<int> {
const FlutterFormInputNumberPicker({
required super.controller,
required this.validationMessage,
super.key,
super.label,
this.validator,
this.minValue = 0,
this.maxValue = 100,
}) : assert(minValue < maxValue, 'minValue must be less than maxValue');
final int minValue;
final int maxValue;
final String validationMessage;
final String? Function(int?)? validator;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
return input.FlutterFormInputNumberPicker(
minValue: minValue,
maxValue: maxValue,
onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value),
initialValue: controller.value ?? minValue,
);
@ -91,7 +94,7 @@ class FlutterFormInputNumberPickerController
@override
String? onValidate(
int? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {}

View file

@ -12,29 +12,31 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
class FlutterFormInputPassword extends FlutterFormInputWidget<String> {
const FlutterFormInputPassword({
required super.controller,
required this.validationMessage,
super.key,
super.focusNode,
super.label,
bool? enabled,
this.validator,
this.decoration,
}) : super(
enabled: enabled ?? true,
);
final InputDecoration? decoration;
final String validationMessage;
final String? Function(String?)? validator;
@override
Widget build(BuildContext context) {
super.registerController(context);
var translator = getTranslator(context);
return input.FlutterFormInputPassword(
enabled: enabled,
initialValue: controller.value,
focusNode: focusNode,
onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.call(value),
decoration: decoration,
@ -93,15 +95,15 @@ class FlutterFormInputPasswordController
@override
String? onValidate(
String? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {
if (value == null || value.isEmpty) {
return translator('Field can not be empty');
return validationMessage;
}
if (value.length < 6) {
return translator('Field should be at least 6 characters long');
return validationMessage;
}
}

View file

@ -14,12 +14,14 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
class FlutterFormInputPhone extends FlutterFormInputWidget<input.PhoneNumber?> {
const FlutterFormInputPhone({
required super.controller,
required this.validationMessage,
super.key,
super.focusNode,
super.label,
this.decoration,
this.enabled = true,
this.numberFieldStyle,
this.validator,
this.dialCodeSelectorStyle,
this.dialCodeSelectorPadding = const EdgeInsets.only(top: 6),
this.textAlignVertical = TextAlignVertical.top,
@ -32,11 +34,11 @@ class FlutterFormInputPhone extends FlutterFormInputWidget<input.PhoneNumber?> {
final TextStyle? dialCodeSelectorStyle;
final EdgeInsets dialCodeSelectorPadding;
final TextAlignVertical textAlignVertical;
final String validationMessage;
final String? Function(PhoneNumber?)? validator;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
var inputDecoration = decoration ??
@ -50,7 +52,8 @@ class FlutterFormInputPhone extends FlutterFormInputWidget<input.PhoneNumber?> {
enabled: enabled,
initialValue: controller.value,
onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.call(value),
decoration: inputDecoration,
@ -100,11 +103,11 @@ class FlutterFormInputPhoneController
@override
String? onValidate(
input.PhoneNumber? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {
if (value == null || value.number == null) {
return translator('Field can not be empty');
return validationMessage;
}
}

View file

@ -20,6 +20,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
/// [enabled], [style], and [textCapitalization] parameters are optional.
const FlutterFormInputPlainText({
required super.controller,
required this.validationMessage,
super.key,
super.focusNode,
super.label,
@ -30,6 +31,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
this.scrollPadding,
this.maxLength,
this.keyboardType,
this.validator,
this.enabled = true,
this.style,
this.textCapitalization = TextCapitalization.none,
@ -46,11 +48,11 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
final bool enabled;
final TextStyle? style;
final TextCapitalization textCapitalization;
final String validationMessage;
final String? Function(String?)? validator;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
var inputDecoration = decoration ??
@ -65,7 +67,8 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
initialValue: controller.value,
focusNode: focusNode,
onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
onChanged: (value) => controller.onChanged?.call(value),
onFieldSubmitted: (value) => controller.onSubmit?.call(value),
decoration: inputDecoration,
@ -89,10 +92,12 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget<String> {
class FlutterFormInputMultiLine extends StatelessWidget {
const FlutterFormInputMultiLine({
required this.controller,
required this.validationMessage,
super.key,
this.focusNode,
this.label,
this.hint,
this.validator,
this.maxCharacters,
this.enabled = true,
this.textCapitalization = TextCapitalization.sentences,
@ -119,11 +124,12 @@ class FlutterFormInputMultiLine extends StatelessWidget {
/// The capitalization behavior for the input field.
final TextCapitalization textCapitalization;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
final String validationMessage;
return input.FlutterFormInputMultiLine(
final String? Function(String?)? validator;
@override
Widget build(BuildContext context) => input.FlutterFormInputMultiLine(
enabled: enabled,
label: label,
hint: hint,
@ -132,11 +138,11 @@ class FlutterFormInputMultiLine extends StatelessWidget {
maxCharacters: maxCharacters,
onChanged: controller.onChanged,
onSaved: controller.onSaved,
validator: (v) => controller.onValidate(v, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
textCapitalization: textCapitalization,
);
}
}
/// Controller for plain text used by a [FlutterFormInputWidget] used in a
/// [FlutterForm].
@ -189,11 +195,11 @@ class FlutterFormInputPlainTextController
@override
String? onValidate(
String? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {
if (value == null || value.isEmpty) {
return translator('Field can not be empty');
return validationMessage;
}
}

View file

@ -19,26 +19,29 @@ class FlutterFormInputSlider extends FlutterFormInputWidget<double> {
/// The [enabled] parameter specifies whether the input field is enabled.
const FlutterFormInputSlider({
required super.controller,
required this.validationMessage,
super.key,
super.focusNode,
super.label,
this.validator,
this.minValue = 0,
this.maxValue = 100,
}) : assert(minValue < maxValue, 'minValue must be less than maxValue');
final int minValue;
final int maxValue;
final String validationMessage;
final String? Function(double?)? validator;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
return input.FlutterFormInputSlider(
focusNode: focusNode,
onSaved: controller.onSaved,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
);
}
}
@ -93,7 +96,7 @@ class FlutterFormInputSliderController
@override
String? onValidate(
double? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) {
if (mandatory) {}

View file

@ -14,22 +14,26 @@ import 'package:flutter_input_library/flutter_input_library.dart' as input;
class FlutterFormInputSwitch extends FlutterFormInputWidget<bool> {
const FlutterFormInputSwitch({
required super.controller,
required this.validationMessage,
super.key,
super.focusNode,
super.label,
this.validator,
});
final String validationMessage;
final String? Function(bool?)? validator;
@override
Widget build(BuildContext context) {
var translator = getTranslator(context);
super.registerController(context);
return input.FlutterFormInputBool(
focusNode: focusNode,
onSaved: controller.onSaved,
onChanged: controller.onChanged,
validator: (value) => controller.onValidate(value, translator),
validator: validator ??
(value) => controller.onValidate(value, validationMessage),
initialValue: controller.value ?? false,
widgetType: input.BoolWidgetType.switchWidget,
);
@ -86,7 +90,7 @@ class FlutterFormInputSwitchController
@override
String? onValidate(
bool? value,
String Function(String, {List<String>? params}) translator,
String validationMessage,
) =>
null;
}

View file

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

View file

@ -1,6 +1,6 @@
name: flutter_form_wizard
description: A new Flutter package project.
version: 6.3.0
version: 6.3.1
homepage: https://github.com/Iconica-Development/flutter_form_wizard
publish_to: none

View file

@ -56,6 +56,7 @@ void main() {
child: FlutterFormInputPlainText(
label: const Text('Field1Label'),
controller: testField1Controller,
validationMessage: 'Please fill in this field',
),
),
),
@ -64,6 +65,7 @@ void main() {
child: FlutterFormInputPlainText(
label: const Text('Field2Label'),
controller: testField2Controller,
validationMessage: 'Please fill in this field',
),
),
),
@ -154,6 +156,7 @@ void main() {
child: FlutterFormInputPlainText(
label: const Text('Field1Label'),
controller: testField1Controller,
validationMessage: 'Please fill in this field',
),
),
),
@ -162,6 +165,7 @@ void main() {
child: FlutterFormInputPlainText(
label: const Text('Field2Label'),
controller: testField2Controller,
validationMessage: 'Please fill in this field',
),
),
),
@ -260,6 +264,7 @@ void main() {
child: FlutterFormInputPlainText(
label: const Text('Field1Label'),
controller: testField1Controller,
validationMessage: 'Field can not be empty',
),
),
),