mirror of
https://github.com/Iconica-Development/flutter_login_widget.git
synced 2025-05-19 13:43:44 +02:00
feat: two step login
This commit is contained in:
parent
f1b11ae79a
commit
54afe8c4bf
3 changed files with 193 additions and 37 deletions
|
@ -68,7 +68,11 @@ packages:
|
||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
|
<<<<<<< HEAD
|
||||||
version: "6.0.0"
|
version: "6.0.0"
|
||||||
|
=======
|
||||||
|
version: "5.2.0"
|
||||||
|
>>>>>>> 60112c8 (feat: two step login)
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -79,30 +83,6 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
leak_tracker:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker
|
|
||||||
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "10.0.0"
|
|
||||||
leak_tracker_flutter_testing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker_flutter_testing
|
|
||||||
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
leak_tracker_testing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker_testing
|
|
||||||
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -115,34 +95,34 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16+1"
|
version: "0.12.16"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.0"
|
version: "0.5.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.10.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.8.3"
|
||||||
pinput:
|
pinput:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -228,14 +208,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
vm_service:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: web
|
||||||
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "13.0.0"
|
version: "0.3.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0-0 <4.0.0"
|
dart: ">=3.2.0-194.0.dev <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.7.0"
|
||||||
|
|
|
@ -9,3 +9,4 @@ export 'src/service/validation.dart';
|
||||||
export 'src/widgets/email_password_login.dart';
|
export 'src/widgets/email_password_login.dart';
|
||||||
export 'src/widgets/forgot_password_form.dart';
|
export 'src/widgets/forgot_password_form.dart';
|
||||||
export 'src/widgets/mfa_widget.dart';
|
export 'src/widgets/mfa_widget.dart';
|
||||||
|
export 'src/widgets/two_step_login.dart';
|
||||||
|
|
175
lib/src/widgets/two_step_login.dart
Normal file
175
lib/src/widgets/two_step_login.dart
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_login/flutter_login.dart';
|
||||||
|
|
||||||
|
class TwoStepLoginForm extends StatefulWidget {
|
||||||
|
/// Constructs an [TwoStepLoginForm] widget.
|
||||||
|
///
|
||||||
|
/// [onCheckEmail]: Callback function for when a user has filled in its email
|
||||||
|
/// [options]: The options for configuring the login form.
|
||||||
|
const TwoStepLoginForm({
|
||||||
|
required this.onCheckEmail,
|
||||||
|
super.key,
|
||||||
|
this.options = const LoginOptions(),
|
||||||
|
});
|
||||||
|
|
||||||
|
final LoginOptions options;
|
||||||
|
final FutureOr<void> Function(String email) onCheckEmail;
|
||||||
|
@override
|
||||||
|
State<TwoStepLoginForm> createState() => _TwoStepLoginFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TwoStepLoginFormState extends State<TwoStepLoginForm> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
final ValueNotifier<bool> _formValid = ValueNotifier(false);
|
||||||
|
bool _obscurePassword = true;
|
||||||
|
|
||||||
|
String _currentEmail = '';
|
||||||
|
|
||||||
|
void _updateCurrentEmail(String email) {
|
||||||
|
_currentEmail = email;
|
||||||
|
_validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _validate() {
|
||||||
|
late var isValid =
|
||||||
|
widget.options.validations.validateEmail(_currentEmail) == null;
|
||||||
|
if (isValid != _formValid.value) {
|
||||||
|
_formValid.value = isValid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleLogin() async {
|
||||||
|
if (mounted) {
|
||||||
|
var form = _formKey.currentState!;
|
||||||
|
if (form.validate()) {
|
||||||
|
await widget.onCheckEmail(
|
||||||
|
_currentEmail,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_currentEmail = widget.options.initialEmail;
|
||||||
|
_validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var theme = Theme.of(context);
|
||||||
|
var options = widget.options;
|
||||||
|
return CustomScrollView(
|
||||||
|
physics: const ScrollPhysics(),
|
||||||
|
slivers: [
|
||||||
|
SliverFillRemaining(
|
||||||
|
hasScrollBody: false,
|
||||||
|
fillOverscroll: true,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: options.spacers.titleSpacer,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (options.spacers.spacerBeforeTitle != null) ...[
|
||||||
|
Spacer(flex: options.spacers.spacerBeforeTitle!),
|
||||||
|
],
|
||||||
|
if (options.title != null) ...[
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: _wrapWithDefaultStyle(
|
||||||
|
options.title,
|
||||||
|
theme.textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
if (options.spacers.spacerAfterTitle != null) ...[
|
||||||
|
Spacer(flex: options.spacers.spacerAfterTitle!),
|
||||||
|
],
|
||||||
|
if (options.subtitle != null) ...[
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: _wrapWithDefaultStyle(
|
||||||
|
options.subtitle,
|
||||||
|
theme.textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
if (options.spacers.spacerAfterSubtitle != null) ...[
|
||||||
|
Spacer(flex: options.spacers.spacerAfterSubtitle!),
|
||||||
|
],
|
||||||
|
if (options.image != null) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: options.image,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
if (options.spacers.spacerAfterImage != null) ...[
|
||||||
|
Spacer(flex: options.spacers.spacerAfterImage!),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: options.spacers.formFlexValue,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: options.maxFormWidth ?? 300,
|
||||||
|
),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
options.emailInputContainerBuilder(
|
||||||
|
TextFormField(
|
||||||
|
onChanged: _updateCurrentEmail,
|
||||||
|
validator: widget.options.validations.validateEmail,
|
||||||
|
initialValue: options.initialEmail,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
style: options.emailTextStyle,
|
||||||
|
decoration: options.emailDecoration,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (options.spacers.spacerAfterForm != null) ...[
|
||||||
|
Spacer(flex: options.spacers.spacerAfterForm!),
|
||||||
|
],
|
||||||
|
AnimatedBuilder(
|
||||||
|
animation: _formValid,
|
||||||
|
builder: (context, _) => options.loginButtonBuilder(
|
||||||
|
context,
|
||||||
|
_handleLogin,
|
||||||
|
!_formValid.value,
|
||||||
|
() {
|
||||||
|
_formKey.currentState?.validate();
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (options.spacers.spacerAfterButton != null) ...[
|
||||||
|
Spacer(flex: options.spacers.spacerAfterButton!),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget? _wrapWithDefaultStyle(Widget? widget, TextStyle? style) {
|
||||||
|
if (style == null || widget == null) {
|
||||||
|
return widget;
|
||||||
|
} else {
|
||||||
|
return DefaultTextStyle(style: style, child: widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue