fix(auth-field): save state in stateful widget; retrieve from there on rebuild

This commit is contained in:
Kiril Tijsma 2024-04-03 11:23:48 +02:00
parent 7a4bcd8b3f
commit 98ac73ee66
6 changed files with 198 additions and 160 deletions

View file

@ -64,6 +64,7 @@ class _AuthScreenState extends State<AuthScreen> {
final _animationDuration = const Duration(milliseconds: 300);
final _animationCurve = Curves.ease;
bool _formValid = false;
final _values = HashMap();
AppBar get _appBar =>
widget.customAppBar ??
@ -89,6 +90,14 @@ class _AuthScreenState extends State<AuthScreen> {
FocusScope.of(context).unfocus();
for (var step in widget.steps) {
for (var field in step.fields) {
setState(() {
_values[field.name] = field.value;
});
}
}
if (widget.steps.last == step) {
var values = HashMap<String, dynamic>();
@ -142,15 +151,17 @@ class _AuthScreenState extends State<AuthScreen> {
@override
Widget build(BuildContext context) {
return widget.isLoading
? const Center(
if (widget.isLoading) {
return const Center(
child: SizedBox(
height: 120,
width: 120,
child: CircularProgressIndicator(),
),
)
: Scaffold(
);
}
return Scaffold(
backgroundColor: widget.customBackgroundColor ?? Colors.white,
appBar: _appBar,
body: Form(
@ -171,44 +182,77 @@ class _AuthScreenState extends State<AuthScreen> {
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
Spacer(
flex: widget.beforeTitleFlex ?? 3,
child: Container(),
),
widget.titleWidget!,
Expanded(
Spacer(
flex: widget.afterTitleFlex ?? 2,
child: Container(),
),
],
),
),
Column(
],
Expanded(
flex: widget.formFlex ?? 3,
child: Column(
children: [
for (AuthField field
in widget.steps[i].fields.map((field) {
if (!_values.containsKey(field.name)) return field;
field.value = _values[field.name]!;
return field;
}))
Align(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (field.title != null) ...[
field.title!,
],
field.build(context, (v) {
_values[field.name] = v;
_validate(i);
}),
],
),
),
],
),
),
Padding(
padding: EdgeInsets.only(
top: 15.0,
bottom: 30.0,
left: widget.previousButtonBuilder == null &&
widget.steps.first != widget.steps[i]
? 30.0
: 0.0,
right: widget.nextButtonBuilder == null &&
widget.previousButtonBuilder == null
? 30.0
: 0.0,
),
child: Column(
children: [
Row(
mainAxisAlignment:
widget.buttonMainAxisAlignment != null
? widget.buttonMainAxisAlignment!
: (widget.previousButtonBuilder !=
null &&
widget.previousButtonBuilder
?.call(
: (widget.previousButtonBuilder != null &&
widget.previousButtonBuilder?.call(
onPrevious,
widget
.previousBtnTitle,
widget.previousBtnTitle,
i,
) ==
null)
? MainAxisAlignment.start
: widget.steps.first !=
widget.steps[i]
: widget.steps.first != widget.steps[i]
? MainAxisAlignment.center
: MainAxisAlignment.end,
children: [
if (widget.previousButtonBuilder ==
null) ...[
if (widget.steps.first !=
widget.steps[i])
if (widget.previousButtonBuilder == null) ...[
if (widget.steps.first != widget.steps[i])
ElevatedButton(
onPressed: onPrevious,
child: Row(
@ -219,29 +263,23 @@ class _AuthScreenState extends State<AuthScreen> {
),
Padding(
padding:
const EdgeInsets.only(
left: 4.0),
child: Text(
widget.previousBtnTitle),
const EdgeInsets.only(left: 4.0),
child: Text(widget.previousBtnTitle),
),
],
),
),
] else if (widget.previousButtonBuilder
?.call(onPrevious,
widget.previousBtnTitle, i) !=
] else if (widget.previousButtonBuilder?.call(
onPrevious, widget.previousBtnTitle, i) !=
null) ...[
widget.previousButtonBuilder!.call(
onPrevious,
widget.previousBtnTitle,
i)!
widget.previousButtonBuilder!
.call(onPrevious, widget.previousBtnTitle, i)!
],
widget.nextButtonBuilder?.call(
!_formValid
? null
: () async {
await onNext(
widget.steps[i]);
await onNext(widget.steps[i]);
},
widget.steps.last == widget.steps[i]
? widget.submitBtnTitle
@ -253,20 +291,17 @@ class _AuthScreenState extends State<AuthScreen> {
onPressed: !_formValid
? null
: () async {
await onNext(
widget.steps[i]);
await onNext(widget.steps[i]);
},
child: Row(
children: [
Text(
widget.steps.last ==
widget.steps[i]
widget.steps.last == widget.steps[i]
? widget.submitBtnTitle
: widget.nextBtnTitle,
),
const Padding(
padding: EdgeInsets.only(
left: 4.0),
padding: EdgeInsets.only(left: 4.0),
child: Icon(
Icons.arrow_forward,
size: 18,
@ -284,9 +319,12 @@ class _AuthScreenState extends State<AuthScreen> {
),
],
),
)
],
]),
]),
));
)
],
),
),
);
}
}

View file

@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_registration/flutter_registration.dart';
class RegistrationOptions {
RegistrationOptions({
const RegistrationOptions({
required this.registrationRepository,
required this.registrationSteps,
required this.afterRegistration,
@ -35,8 +35,8 @@ class RegistrationOptions {
previousButtonBuilder;
final MainAxisAlignment? buttonMainAxisAlignment;
final Color? backgroundColor;
Widget? titleWidget;
Widget? loginButton;
final Widget? titleWidget;
final Widget? loginButton;
static List<AuthStep> getDefaultSteps({
TextEditingController? emailController,

View file

@ -30,8 +30,9 @@ class AuthBoolField extends AuthField {
onChanged: (v) {
value = v;
onChange?.call(value);
onValueChanged();
onValueChanged(v);
},
initialValue: value,
validator: (value) {
for (var validator in validators) {
var output = validator(value);

View file

@ -11,9 +11,7 @@ class AuthDropdownField extends AuthField {
this.textStyle,
this.icon = const Icon(Icons.keyboard_arrow_down),
required super.value,
}) {
selectedValue = value ?? items.first;
}
});
final List<String> items;
final Function(String?) onChanged;
@ -30,7 +28,7 @@ class AuthDropdownField extends AuthField {
child: DropdownButtonFormField<String>(
icon: icon,
style: textStyle,
value: selectedValue,
value: value,
decoration: dropdownDecoration,
items: items.map((String value) {
return DropdownMenuItem<String>(
@ -41,7 +39,7 @@ class AuthDropdownField extends AuthField {
onChanged: (newValue) {
selectedValue = newValue;
onChanged(newValue);
onValueChanged();
onValueChanged(newValue);
},
validator: (value) {
if (validators.isNotEmpty) {

View file

@ -9,10 +9,10 @@ import 'package:flutter_registration/flutter_registration.dart';
class AuthPassField extends AuthField {
AuthPassField({
required super.name,
TextEditingController? textEditingController,
super.title,
super.validators = const [],
super.value = '',
this.textEditingController,
this.textStyle,
this.onChange,
this.iconSize,
@ -24,6 +24,7 @@ class AuthPassField extends AuthField {
final double? iconSize;
final Function(String value)? onChange;
final InputDecoration? textFieldDecoration;
final TextEditingController? textEditingController;
final EdgeInsets padding;
@override
@ -33,11 +34,13 @@ class AuthPassField extends AuthField {
child: FlutterFormInputPassword(
style: textStyle,
iconSize: iconSize ?? 24.0,
initialValue: textEditingController == null ? value : null,
decoration: textFieldDecoration,
controller: textEditingController,
onChanged: (v) {
value = v;
onChange?.call(value);
onValueChanged();
onValueChanged(v);
},
validator: (value) {
for (var validator in validators) {

View file

@ -8,20 +8,17 @@ import 'package:flutter_registration/flutter_registration.dart';
class AuthTextField extends AuthField {
AuthTextField({
required super.name,
TextEditingController? textEditingController,
super.title,
super.validators = const [],
super.value = '',
this.textEditingController,
this.textStyle,
this.onChange,
this.textFieldDecoration,
this.padding = const EdgeInsets.all(8.0),
}) {
textController =
textEditingController ?? TextEditingController(text: value);
}
});
late TextEditingController textController;
final TextEditingController? textEditingController;
final TextStyle? textStyle;
final Function(String value)? onChange;
final InputDecoration? textFieldDecoration;
@ -34,11 +31,12 @@ class AuthTextField extends AuthField {
child: TextFormField(
style: textStyle,
decoration: textFieldDecoration,
controller: textController,
controller: textEditingController,
initialValue: textEditingController == null ? value : null,
onChanged: (v) {
value = v;
onChange?.call(value);
onValueChanged();
onValueChanged(v);
},
validator: (value) {
for (var validator in validators) {