Skip to content

Commit e32e968

Browse files
authored
Add initialEmail parameter and update onSignInComplete
Added an optional initialEmail to pass in a saved email address so that the email field is already populated. Passed in the email to the onSignInComplete() callback, so that the email can be used inside (eg. for saving to sharedPreferences) Also, added a focus node for the password field to move the focus to it if the initialEmail is non-empty.
1 parent 6a77704 commit e32e968

File tree

1 file changed

+31
-7
lines changed

1 file changed

+31
-7
lines changed

lib/src/components/supa_email_auth.dart

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class SupaEmailAuth extends StatefulWidget {
179179
final String? Function(String?)? passwordValidator;
180180

181181
/// Callback for the user to complete a sign in.
182-
final void Function(AuthResponse response) onSignInComplete;
182+
final void Function(AuthResponse response, String email) onSignInComplete;
183183

184184
/// Callback for the user to complete a signUp.
185185
///
@@ -217,12 +217,15 @@ class SupaEmailAuth extends StatefulWidget {
217217
final Widget? prefixIconEmail;
218218
final Widget? prefixIconPassword;
219219

220+
final String? initialEmail;
221+
220222
/// Whether the confirm password field should be displayed
221223
final bool showConfirmPasswordField;
222224

223225
/// {@macro supa_email_auth}
224226
const SupaEmailAuth({
225227
super.key,
228+
this.initialEmail = "",
226229
this.autofocus = true,
227230
this.redirectTo,
228231
this.resetPasswordRedirectTo,
@@ -248,7 +251,7 @@ class SupaEmailAuth extends StatefulWidget {
248251

249252
class _SupaEmailAuthState extends State<SupaEmailAuth> {
250253
final _formKey = GlobalKey<FormState>();
251-
final _emailController = TextEditingController();
254+
late final TextEditingController _emailController;
252255
final _passwordController = TextEditingController();
253256
final _confirmPasswordController = TextEditingController();
254257
late bool _isSigningIn;
@@ -261,10 +264,12 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
261264

262265
/// Focus node for email field
263266
final FocusNode _emailFocusNode = FocusNode();
267+
final FocusNode _passwordFocusNode = FocusNode();
264268

265269
@override
266270
void initState() {
267271
super.initState();
272+
_emailController = TextEditingController(text: widget.initialEmail);
268273
_isSigningIn = widget.isInitiallySigningIn;
269274
_metadataControllers = Map.fromEntries((widget.metadataFields ?? []).map(
270275
(metadataField) => MapEntry(
@@ -274,13 +279,33 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
274279
: TextEditingController(),
275280
),
276281
));
282+
283+
// Request focus on password field if email is pre-filled and not recovering password
284+
if (widget.initialEmail != null && widget.initialEmail!.isNotEmpty && !_isRecoveringPassword) {
285+
// It's important to request focus after the first frame has been built.
286+
// WidgetsBinding.instance.addPostFrameCallback ensures that.
287+
WidgetsBinding.instance.addPostFrameCallback((_) {
288+
if (mounted) {
289+
FocusScope.of(context).requestFocus(_passwordFocusNode);
290+
}
291+
});
292+
} else if (widget.autofocus && !_isRecoveringPassword) {
293+
// Default autofocus behavior if no initial email or recovering password
294+
WidgetsBinding.instance.addPostFrameCallback((_) {
295+
if (mounted) {
296+
FocusScope.of(context).requestFocus(_emailFocusNode);
297+
}
298+
});
299+
}
277300
}
278301

279302
@override
280303
void dispose() {
281304
_emailController.dispose();
282305
_passwordController.dispose();
283306
_confirmPasswordController.dispose();
307+
_emailFocusNode.dispose();
308+
_passwordFocusNode.dispose();
284309
for (final controller in _metadataControllers.values) {
285310
if (controller is TextEditingController) {
286311
controller.dispose();
@@ -333,6 +358,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
333358
? [AutofillHints.password]
334359
: [AutofillHints.newPassword],
335360
autovalidateMode: AutovalidateMode.onUserInteraction,
361+
focusNode: _passwordFocusNode,
336362
textInputAction: widget.metadataFields != null && !_isSigningIn
337363
? TextInputAction.next
338364
: TextInputAction.done,
@@ -468,7 +494,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
468494
height: 16,
469495
width: 16,
470496
child: CircularProgressIndicator(
471-
color: Theme.of(context).colorScheme.onPrimary,
497+
color: Theme.of(context).colorScheme.surface,
472498
strokeWidth: 1.5,
473499
),
474500
)
@@ -539,7 +565,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
539565
email: _emailController.text.trim(),
540566
password: _passwordController.text.trim(),
541567
);
542-
widget.onSignInComplete.call(response);
568+
widget.onSignInComplete.call(response, _emailController.text.trim());
543569
} else {
544570
final user = supabase.auth.currentUser;
545571
late final AuthResponse response;
@@ -607,9 +633,7 @@ class _SupaEmailAuthState extends State<SupaEmailAuth> {
607633
// FIX use_build_context_synchronously
608634
if (!mounted) return;
609635
context.showSnackBar(widget.localization.passwordResetSent);
610-
setState(() {
611-
_isRecoveringPassword = false;
612-
});
636+
613637
} on AuthException catch (error) {
614638
widget.onError?.call(error);
615639
} catch (error) {

0 commit comments

Comments
 (0)