diff --git a/lib/src/auth_screen.dart b/lib/src/auth_screen.dart index 851befe..eac1746 100644 --- a/lib/src/auth_screen.dart +++ b/lib/src/auth_screen.dart @@ -35,9 +35,8 @@ class AuthScreen extends StatefulWidget { final String previousBtnTitle; final AppBar? customAppBar; final Color? customBackgroundColor; - final Widget Function( - Future Function() onPressed, String label, int step)? - nextButtonBuilder; + final Widget Function(Future 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 { 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 { ); void onPrevious() { + _validate(_pageController.page!.toInt() - 1); _pageController.previousPage( duration: _animationDuration, curve: _animationCurve, @@ -95,6 +96,7 @@ class _AuthScreenState extends State { return; } else { + _validate(_pageController.page!.toInt() + 1); _pageController.nextPage( duration: _animationDuration, curve: _animationCurve, @@ -102,6 +104,29 @@ class _AuthScreenState extends State { } } + 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 { if (field.title != null) ...[ field.title!, ], - field.build(), + field.build(context, () { + _validate(i); + }), ], ), ) @@ -197,18 +224,23 @@ class _AuthScreenState extends State { .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( diff --git a/lib/src/config/registration_options.dart b/lib/src/config/registration_options.dart index 2575df6..1d3e9e3 100644 --- a/lib/src/config/registration_options.dart +++ b/lib/src/config/registration_options.dart @@ -28,9 +28,8 @@ class RegistrationOptions { final VoidCallback afterRegistration; final RegistrationRepository registrationRepository; final AppBar Function(String title)? customAppbarBuilder; - final Widget Function( - Future Function() onPressed, String label, int step)? - nextButtonBuilder; + final Widget Function(Future Function()? onPressed, String label, + int step, bool enabled)? nextButtonBuilder; final Widget? Function(VoidCallback onPressed, String label, int step)? previousButtonBuilder; final Color? backgroundColor; diff --git a/lib/src/model/auth_bool_field.dart b/lib/src/model/auth_bool_field.dart index d5ae36c..3fc243b 100644 --- a/lib/src/model/auth_bool_field.dart +++ b/lib/src/model/auth_bool_field.dart @@ -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) { diff --git a/lib/src/model/auth_drop_down.dart b/lib/src/model/auth_drop_down.dart index 80c87da..9a2acba 100644 --- a/lib/src/model/auth_drop_down.dart +++ b/lib/src/model/auth_drop_down.dart @@ -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( @@ -41,6 +41,7 @@ class AuthDropdownField extends AuthField { onChanged: (newValue) { selectedValue = newValue; onChanged(newValue); + onValueChanged(); }, validator: (value) { if (validators.isNotEmpty) { diff --git a/lib/src/model/auth_field.dart b/lib/src/model/auth_field.dart index 3690139..1e219a5 100644 --- a/lib/src/model/auth_field.dart +++ b/lib/src/model/auth_field.dart @@ -7,9 +7,10 @@ import 'package:flutter/material.dart'; abstract class AuthField { 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 { List validators; T value; - Widget build(); + final Function(T)? onValueChanged; // Callback for value changes + + Widget build(BuildContext context, Function onValueChanged); } diff --git a/lib/src/model/auth_pass_field.dart b/lib/src/model/auth_pass_field.dart index be6bacc..6cb978c 100644 --- a/lib/src/model/auth_pass_field.dart +++ b/lib/src/model/auth_pass_field.dart @@ -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) { diff --git a/lib/src/model/auth_text_field.dart b/lib/src/model/auth_text_field.dart index cac464b..3c7b7c0 100644 --- a/lib/src/model/auth_text_field.dart +++ b/lib/src/model/auth_text_field.dart @@ -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) {