mirror of
https://github.com/Iconica-Development/flutter_registration.git
synced 2025-05-18 21:23:43 +02:00
feat: add validation to disable next button
This commit is contained in:
parent
15aa74ebda
commit
277b38f39e
7 changed files with 57 additions and 19 deletions
|
@ -35,9 +35,8 @@ class AuthScreen extends StatefulWidget {
|
|||
final String previousBtnTitle;
|
||||
final AppBar? customAppBar;
|
||||
final Color? customBackgroundColor;
|
||||
final Widget Function(
|
||||
Future<void> Function() onPressed, String label, int step)?
|
||||
nextButtonBuilder;
|
||||
final Widget Function(Future<void> Function()? onPressed, String label,
|
||||
int step, bool enabled)? nextButtonBuilder;
|
||||
final Widget? Function(VoidCallback onPressed, String label, int step)?
|
||||
previousButtonBuilder;
|
||||
final Widget? titleWidget;
|
||||
|
@ -52,6 +51,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||
final _pageController = PageController();
|
||||
final _animationDuration = const Duration(milliseconds: 300);
|
||||
final _animationCurve = Curves.ease;
|
||||
bool _formValid = false;
|
||||
|
||||
AppBar get _appBar =>
|
||||
widget.customAppBar ??
|
||||
|
@ -60,6 +60,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||
);
|
||||
|
||||
void onPrevious() {
|
||||
_validate(_pageController.page!.toInt() - 1);
|
||||
_pageController.previousPage(
|
||||
duration: _animationDuration,
|
||||
curve: _animationCurve,
|
||||
|
@ -95,6 +96,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||
|
||||
return;
|
||||
} else {
|
||||
_validate(_pageController.page!.toInt() + 1);
|
||||
_pageController.nextPage(
|
||||
duration: _animationDuration,
|
||||
curve: _animationCurve,
|
||||
|
@ -102,6 +104,29 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||
}
|
||||
}
|
||||
|
||||
void _validate(int currentPage) {
|
||||
bool isStepValid = true;
|
||||
|
||||
// Loop through each field in the current step
|
||||
for (var field in widget.steps[currentPage].fields) {
|
||||
for (var validator in field.validators) {
|
||||
String? validationResult = validator(field.value);
|
||||
if (validationResult != null) {
|
||||
// If any validator returns an error, mark step as invalid and break
|
||||
isStepValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isStepValid) {
|
||||
break; // No need to check further fields if one is already invalid
|
||||
}
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_formValid = isStepValid;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -136,7 +161,9 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||
if (field.title != null) ...[
|
||||
field.title!,
|
||||
],
|
||||
field.build(),
|
||||
field.build(context, () {
|
||||
_validate(i);
|
||||
}),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
@ -197,18 +224,23 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||
.call(onPrevious, widget.previousBtnTitle, i)!
|
||||
],
|
||||
widget.nextButtonBuilder?.call(
|
||||
() async {
|
||||
await onNext(widget.steps[i]);
|
||||
},
|
||||
!_formValid
|
||||
? null
|
||||
: () async {
|
||||
await onNext(widget.steps[i]);
|
||||
},
|
||||
widget.steps.last == widget.steps[i]
|
||||
? widget.submitBtnTitle
|
||||
: widget.nextBtnTitle,
|
||||
i,
|
||||
_formValid,
|
||||
) ??
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
await onNext(widget.steps[i]);
|
||||
},
|
||||
onPressed: !_formValid
|
||||
? null
|
||||
: () async {
|
||||
await onNext(widget.steps[i]);
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
|
|
|
@ -28,9 +28,8 @@ class RegistrationOptions {
|
|||
final VoidCallback afterRegistration;
|
||||
final RegistrationRepository registrationRepository;
|
||||
final AppBar Function(String title)? customAppbarBuilder;
|
||||
final Widget Function(
|
||||
Future<void> Function() onPressed, String label, int step)?
|
||||
nextButtonBuilder;
|
||||
final Widget Function(Future<void> Function()? onPressed, String label,
|
||||
int step, bool enabled)? nextButtonBuilder;
|
||||
final Widget? Function(VoidCallback onPressed, String label, int step)?
|
||||
previousButtonBuilder;
|
||||
final Color? backgroundColor;
|
||||
|
|
|
@ -24,12 +24,13 @@ class AuthBoolField extends AuthField {
|
|||
final Function(String value)? onChange;
|
||||
|
||||
@override
|
||||
Widget build() {
|
||||
Widget build(BuildContext context, Function onValueChanged) {
|
||||
return FlutterFormInputBool(
|
||||
widgetType: widgetType,
|
||||
onChanged: (v) {
|
||||
value = v;
|
||||
onChange?.call(value);
|
||||
onValueChanged();
|
||||
},
|
||||
validator: (value) {
|
||||
for (var validator in validators) {
|
||||
|
|
|
@ -24,7 +24,7 @@ class AuthDropdownField extends AuthField {
|
|||
final Icon icon;
|
||||
|
||||
@override
|
||||
Widget build() {
|
||||
Widget build(BuildContext context, Function onValueChanged) {
|
||||
return Padding(
|
||||
padding: padding,
|
||||
child: DropdownButtonFormField<String>(
|
||||
|
@ -41,6 +41,7 @@ class AuthDropdownField extends AuthField {
|
|||
onChanged: (newValue) {
|
||||
selectedValue = newValue;
|
||||
onChanged(newValue);
|
||||
onValueChanged();
|
||||
},
|
||||
validator: (value) {
|
||||
if (validators.isNotEmpty) {
|
||||
|
|
|
@ -7,9 +7,10 @@ import 'package:flutter/material.dart';
|
|||
abstract class AuthField<T> {
|
||||
AuthField({
|
||||
required this.name,
|
||||
required this.value,
|
||||
this.onValueChanged,
|
||||
this.title,
|
||||
this.validators = const [],
|
||||
required this.value,
|
||||
});
|
||||
|
||||
final String name;
|
||||
|
@ -17,5 +18,7 @@ abstract class AuthField<T> {
|
|||
List<String? Function(T?)> validators;
|
||||
T value;
|
||||
|
||||
Widget build();
|
||||
final Function(T)? onValueChanged; // Callback for value changes
|
||||
|
||||
Widget build(BuildContext context, Function onValueChanged);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class AuthPassField extends AuthField {
|
|||
final EdgeInsets padding;
|
||||
|
||||
@override
|
||||
Widget build() {
|
||||
Widget build(BuildContext context, Function onValueChanged) {
|
||||
return Padding(
|
||||
padding: padding,
|
||||
child: FlutterFormInputPassword(
|
||||
|
@ -37,6 +37,7 @@ class AuthPassField extends AuthField {
|
|||
onChanged: (v) {
|
||||
value = v;
|
||||
onChange?.call(value);
|
||||
onValueChanged();
|
||||
},
|
||||
validator: (value) {
|
||||
for (var validator in validators) {
|
||||
|
|
|
@ -28,7 +28,7 @@ class AuthTextField extends AuthField {
|
|||
final EdgeInsets padding;
|
||||
|
||||
@override
|
||||
Widget build() {
|
||||
Widget build(BuildContext context, Function onValueChanged) {
|
||||
return Padding(
|
||||
padding: padding,
|
||||
child: TextFormField(
|
||||
|
@ -38,6 +38,7 @@ class AuthTextField extends AuthField {
|
|||
onChanged: (v) {
|
||||
value = v;
|
||||
onChange?.call(value);
|
||||
onValueChanged();
|
||||
},
|
||||
validator: (value) {
|
||||
for (var validator in validators) {
|
||||
|
|
Loading…
Reference in a new issue