mirror of
https://github.com/Iconica-Development/flutter_login_widget.git
synced 2025-05-19 05:33:45 +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: ".."
|
||||
relative: true
|
||||
source: path
|
||||
<<<<<<< HEAD
|
||||
version: "6.0.0"
|
||||
=======
|
||||
version: "5.2.0"
|
||||
>>>>>>> 60112c8 (feat: two step login)
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -79,30 +83,6 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -115,34 +95,34 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16+1"
|
||||
version: "0.12.16"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
version: "0.5.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
version: "1.10.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.8.3"
|
||||
pinput:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -228,14 +208,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
vm_service:
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||
name: web
|
||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
version: "0.3.0"
|
||||
sdks:
|
||||
dart: ">=3.2.0-0 <4.0.0"
|
||||
dart: ">=3.2.0-194.0.dev <4.0.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
|
|
@ -9,3 +9,4 @@ export 'src/service/validation.dart';
|
|||
export 'src/widgets/email_password_login.dart';
|
||||
export 'src/widgets/forgot_password_form.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