mirror of
https://github.com/Iconica-Development/flutter_registration.git
synced 2025-05-19 05:23:43 +02:00
fix(auth-field): save state in stateful widget; retrieve from there on rebuild
This commit is contained in:
parent
7a4bcd8b3f
commit
98ac73ee66
6 changed files with 198 additions and 160 deletions
|
@ -64,6 +64,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
||||||
final _animationDuration = const Duration(milliseconds: 300);
|
final _animationDuration = const Duration(milliseconds: 300);
|
||||||
final _animationCurve = Curves.ease;
|
final _animationCurve = Curves.ease;
|
||||||
bool _formValid = false;
|
bool _formValid = false;
|
||||||
|
final _values = HashMap();
|
||||||
|
|
||||||
AppBar get _appBar =>
|
AppBar get _appBar =>
|
||||||
widget.customAppBar ??
|
widget.customAppBar ??
|
||||||
|
@ -89,6 +90,14 @@ class _AuthScreenState extends State<AuthScreen> {
|
||||||
|
|
||||||
FocusScope.of(context).unfocus();
|
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) {
|
if (widget.steps.last == step) {
|
||||||
var values = HashMap<String, dynamic>();
|
var values = HashMap<String, dynamic>();
|
||||||
|
|
||||||
|
@ -142,151 +151,180 @@ class _AuthScreenState extends State<AuthScreen> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return widget.isLoading
|
if (widget.isLoading) {
|
||||||
? const Center(
|
return const Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 120,
|
height: 120,
|
||||||
width: 120,
|
width: 120,
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
)
|
);
|
||||||
: Scaffold(
|
}
|
||||||
backgroundColor: widget.customBackgroundColor ?? Colors.white,
|
|
||||||
appBar: _appBar,
|
return Scaffold(
|
||||||
body: Form(
|
backgroundColor: widget.customBackgroundColor ?? Colors.white,
|
||||||
key: _formKey,
|
appBar: _appBar,
|
||||||
child: PageView(
|
body: Form(
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
key: _formKey,
|
||||||
controller: _pageController,
|
child: PageView(
|
||||||
children: <Widget>[
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
for (var i = 0; i < widget.steps.length; i++)
|
controller: _pageController,
|
||||||
Column(
|
children: <Widget>[
|
||||||
mainAxisSize: MainAxisSize.min,
|
for (var i = 0; i < widget.steps.length; i++)
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
if (widget.titleWidget != null) ...[
|
||||||
|
Expanded(
|
||||||
|
flex: widget.titleFlex ?? 1,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Spacer(
|
||||||
|
flex: widget.beforeTitleFlex ?? 3,
|
||||||
|
),
|
||||||
|
widget.titleWidget!,
|
||||||
|
Spacer(
|
||||||
|
flex: widget.afterTitleFlex ?? 2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
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(
|
||||||
|
onPrevious,
|
||||||
|
widget.previousBtnTitle,
|
||||||
|
i,
|
||||||
|
) ==
|
||||||
|
null)
|
||||||
|
? MainAxisAlignment.start
|
||||||
|
: widget.steps.first != widget.steps[i]
|
||||||
|
? MainAxisAlignment.center
|
||||||
|
: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
if (widget.titleWidget != null) ...[
|
if (widget.previousButtonBuilder == null) ...[
|
||||||
Expanded(
|
if (widget.steps.first != widget.steps[i])
|
||||||
flex: widget.titleFlex ?? 1,
|
ElevatedButton(
|
||||||
child: Column(
|
onPressed: onPrevious,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: widget.beforeTitleFlex ?? 3,
|
|
||||||
child: Container(),
|
|
||||||
),
|
|
||||||
widget.titleWidget!,
|
|
||||||
Expanded(
|
|
||||||
flex: widget.afterTitleFlex ?? 2,
|
|
||||||
child: Container(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
widget.buttonMainAxisAlignment != null
|
|
||||||
? widget.buttonMainAxisAlignment!
|
|
||||||
: (widget.previousButtonBuilder !=
|
|
||||||
null &&
|
|
||||||
widget.previousButtonBuilder
|
|
||||||
?.call(
|
|
||||||
onPrevious,
|
|
||||||
widget
|
|
||||||
.previousBtnTitle,
|
|
||||||
i,
|
|
||||||
) ==
|
|
||||||
null)
|
|
||||||
? MainAxisAlignment.start
|
|
||||||
: widget.steps.first !=
|
|
||||||
widget.steps[i]
|
|
||||||
? MainAxisAlignment.center
|
|
||||||
: MainAxisAlignment.end,
|
|
||||||
children: [
|
children: [
|
||||||
if (widget.previousButtonBuilder ==
|
const Icon(
|
||||||
null) ...[
|
Icons.arrow_back,
|
||||||
if (widget.steps.first !=
|
size: 18,
|
||||||
widget.steps[i])
|
),
|
||||||
ElevatedButton(
|
Padding(
|
||||||
onPressed: onPrevious,
|
padding:
|
||||||
child: Row(
|
const EdgeInsets.only(left: 4.0),
|
||||||
children: [
|
child: Text(widget.previousBtnTitle),
|
||||||
const Icon(
|
),
|
||||||
Icons.arrow_back,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(
|
|
||||||
left: 4.0),
|
|
||||||
child: Text(
|
|
||||||
widget.previousBtnTitle),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
] else if (widget.previousButtonBuilder
|
|
||||||
?.call(onPrevious,
|
|
||||||
widget.previousBtnTitle, i) !=
|
|
||||||
null) ...[
|
|
||||||
widget.previousButtonBuilder!.call(
|
|
||||||
onPrevious,
|
|
||||||
widget.previousBtnTitle,
|
|
||||||
i)!
|
|
||||||
],
|
|
||||||
widget.nextButtonBuilder?.call(
|
|
||||||
!_formValid
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
await onNext(
|
|
||||||
widget.steps[i]);
|
|
||||||
},
|
|
||||||
widget.steps.last == widget.steps[i]
|
|
||||||
? widget.submitBtnTitle
|
|
||||||
: widget.nextBtnTitle,
|
|
||||||
i,
|
|
||||||
_formValid,
|
|
||||||
) ??
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: !_formValid
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
await onNext(
|
|
||||||
widget.steps[i]);
|
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
widget.steps.last ==
|
|
||||||
widget.steps[i]
|
|
||||||
? widget.submitBtnTitle
|
|
||||||
: widget.nextBtnTitle,
|
|
||||||
),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
left: 4.0),
|
|
||||||
child: Icon(
|
|
||||||
Icons.arrow_forward,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (widget.loginButton != null)
|
),
|
||||||
Padding(
|
] else if (widget.previousButtonBuilder?.call(
|
||||||
padding: const EdgeInsets.only(top: 20.0),
|
onPrevious, widget.previousBtnTitle, i) !=
|
||||||
child: widget.loginButton!,
|
null) ...[
|
||||||
),
|
widget.previousButtonBuilder!
|
||||||
],
|
.call(onPrevious, widget.previousBtnTitle, i)!
|
||||||
),
|
|
||||||
],
|
],
|
||||||
]),
|
widget.nextButtonBuilder?.call(
|
||||||
]),
|
!_formValid
|
||||||
));
|
? null
|
||||||
|
: () async {
|
||||||
|
await onNext(widget.steps[i]);
|
||||||
|
},
|
||||||
|
widget.steps.last == widget.steps[i]
|
||||||
|
? widget.submitBtnTitle
|
||||||
|
: widget.nextBtnTitle,
|
||||||
|
i,
|
||||||
|
_formValid,
|
||||||
|
) ??
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: !_formValid
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
await onNext(widget.steps[i]);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.steps.last == widget.steps[i]
|
||||||
|
? widget.submitBtnTitle
|
||||||
|
: widget.nextBtnTitle,
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(left: 4.0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.arrow_forward,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (widget.loginButton != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 20.0),
|
||||||
|
child: widget.loginButton!,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_registration/flutter_registration.dart';
|
import 'package:flutter_registration/flutter_registration.dart';
|
||||||
|
|
||||||
class RegistrationOptions {
|
class RegistrationOptions {
|
||||||
RegistrationOptions({
|
const RegistrationOptions({
|
||||||
required this.registrationRepository,
|
required this.registrationRepository,
|
||||||
required this.registrationSteps,
|
required this.registrationSteps,
|
||||||
required this.afterRegistration,
|
required this.afterRegistration,
|
||||||
|
@ -35,8 +35,8 @@ class RegistrationOptions {
|
||||||
previousButtonBuilder;
|
previousButtonBuilder;
|
||||||
final MainAxisAlignment? buttonMainAxisAlignment;
|
final MainAxisAlignment? buttonMainAxisAlignment;
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
Widget? titleWidget;
|
final Widget? titleWidget;
|
||||||
Widget? loginButton;
|
final Widget? loginButton;
|
||||||
|
|
||||||
static List<AuthStep> getDefaultSteps({
|
static List<AuthStep> getDefaultSteps({
|
||||||
TextEditingController? emailController,
|
TextEditingController? emailController,
|
||||||
|
|
|
@ -30,8 +30,9 @@ class AuthBoolField extends AuthField {
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
value = v;
|
value = v;
|
||||||
onChange?.call(value);
|
onChange?.call(value);
|
||||||
onValueChanged();
|
onValueChanged(v);
|
||||||
},
|
},
|
||||||
|
initialValue: value,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
for (var validator in validators) {
|
for (var validator in validators) {
|
||||||
var output = validator(value);
|
var output = validator(value);
|
||||||
|
|
|
@ -11,9 +11,7 @@ class AuthDropdownField extends AuthField {
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.icon = const Icon(Icons.keyboard_arrow_down),
|
this.icon = const Icon(Icons.keyboard_arrow_down),
|
||||||
required super.value,
|
required super.value,
|
||||||
}) {
|
});
|
||||||
selectedValue = value ?? items.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> items;
|
final List<String> items;
|
||||||
final Function(String?) onChanged;
|
final Function(String?) onChanged;
|
||||||
|
@ -30,7 +28,7 @@ class AuthDropdownField extends AuthField {
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
icon: icon,
|
icon: icon,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
value: selectedValue,
|
value: value,
|
||||||
decoration: dropdownDecoration,
|
decoration: dropdownDecoration,
|
||||||
items: items.map((String value) {
|
items: items.map((String value) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
|
@ -41,7 +39,7 @@ class AuthDropdownField extends AuthField {
|
||||||
onChanged: (newValue) {
|
onChanged: (newValue) {
|
||||||
selectedValue = newValue;
|
selectedValue = newValue;
|
||||||
onChanged(newValue);
|
onChanged(newValue);
|
||||||
onValueChanged();
|
onValueChanged(newValue);
|
||||||
},
|
},
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (validators.isNotEmpty) {
|
if (validators.isNotEmpty) {
|
||||||
|
|
|
@ -9,10 +9,10 @@ import 'package:flutter_registration/flutter_registration.dart';
|
||||||
class AuthPassField extends AuthField {
|
class AuthPassField extends AuthField {
|
||||||
AuthPassField({
|
AuthPassField({
|
||||||
required super.name,
|
required super.name,
|
||||||
TextEditingController? textEditingController,
|
|
||||||
super.title,
|
super.title,
|
||||||
super.validators = const [],
|
super.validators = const [],
|
||||||
super.value = '',
|
super.value = '',
|
||||||
|
this.textEditingController,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.onChange,
|
this.onChange,
|
||||||
this.iconSize,
|
this.iconSize,
|
||||||
|
@ -24,6 +24,7 @@ class AuthPassField extends AuthField {
|
||||||
final double? iconSize;
|
final double? iconSize;
|
||||||
final Function(String value)? onChange;
|
final Function(String value)? onChange;
|
||||||
final InputDecoration? textFieldDecoration;
|
final InputDecoration? textFieldDecoration;
|
||||||
|
final TextEditingController? textEditingController;
|
||||||
final EdgeInsets padding;
|
final EdgeInsets padding;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -33,11 +34,13 @@ class AuthPassField extends AuthField {
|
||||||
child: FlutterFormInputPassword(
|
child: FlutterFormInputPassword(
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
iconSize: iconSize ?? 24.0,
|
iconSize: iconSize ?? 24.0,
|
||||||
|
initialValue: textEditingController == null ? value : null,
|
||||||
decoration: textFieldDecoration,
|
decoration: textFieldDecoration,
|
||||||
|
controller: textEditingController,
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
value = v;
|
value = v;
|
||||||
onChange?.call(value);
|
onChange?.call(value);
|
||||||
onValueChanged();
|
onValueChanged(v);
|
||||||
},
|
},
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
for (var validator in validators) {
|
for (var validator in validators) {
|
||||||
|
|
|
@ -8,20 +8,17 @@ import 'package:flutter_registration/flutter_registration.dart';
|
||||||
class AuthTextField extends AuthField {
|
class AuthTextField extends AuthField {
|
||||||
AuthTextField({
|
AuthTextField({
|
||||||
required super.name,
|
required super.name,
|
||||||
TextEditingController? textEditingController,
|
|
||||||
super.title,
|
super.title,
|
||||||
super.validators = const [],
|
super.validators = const [],
|
||||||
super.value = '',
|
super.value = '',
|
||||||
|
this.textEditingController,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.onChange,
|
this.onChange,
|
||||||
this.textFieldDecoration,
|
this.textFieldDecoration,
|
||||||
this.padding = const EdgeInsets.all(8.0),
|
this.padding = const EdgeInsets.all(8.0),
|
||||||
}) {
|
});
|
||||||
textController =
|
|
||||||
textEditingController ?? TextEditingController(text: value);
|
|
||||||
}
|
|
||||||
|
|
||||||
late TextEditingController textController;
|
final TextEditingController? textEditingController;
|
||||||
final TextStyle? textStyle;
|
final TextStyle? textStyle;
|
||||||
final Function(String value)? onChange;
|
final Function(String value)? onChange;
|
||||||
final InputDecoration? textFieldDecoration;
|
final InputDecoration? textFieldDecoration;
|
||||||
|
@ -34,11 +31,12 @@ class AuthTextField extends AuthField {
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
decoration: textFieldDecoration,
|
decoration: textFieldDecoration,
|
||||||
controller: textController,
|
controller: textEditingController,
|
||||||
|
initialValue: textEditingController == null ? value : null,
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
value = v;
|
value = v;
|
||||||
onChange?.call(value);
|
onChange?.call(value);
|
||||||
onValueChanged();
|
onValueChanged(v);
|
||||||
},
|
},
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
for (var validator in validators) {
|
for (var validator in validators) {
|
||||||
|
|
Loading…
Reference in a new issue