diff --git a/lib/src/domain/auth/auth_failure.dart b/lib/src/domain/auth/auth_failure.dart index 5b08fc6..235c7a1 100644 --- a/lib/src/domain/auth/auth_failure.dart +++ b/lib/src/domain/auth/auth_failure.dart @@ -1,3 +1,4 @@ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'auth_failure.freezed.dart'; @@ -14,4 +15,5 @@ abstract class AuthFailure with _$AuthFailure { const factory AuthFailure.malformed() = EmailMalformed; const factory AuthFailure.userDisabled() = UserDisabled; const factory AuthFailure.tooManyRequests() = TooManyRequests; + const factory AuthFailure.linkMergeConflict(AuthCredential credentialForLinking) = LinkMergeConflict; } diff --git a/lib/src/domain/auth/auth_failure.freezed.dart b/lib/src/domain/auth/auth_failure.freezed.dart index 91e0211..356ffc6 100644 --- a/lib/src/domain/auth/auth_failure.freezed.dart +++ b/lib/src/domain/auth/auth_failure.freezed.dart @@ -46,6 +46,13 @@ class _$AuthFailureTearOff { TooManyRequests tooManyRequests() { return const TooManyRequests(); } + +// ignore: unused_element + LinkMergeConflict linkMergeConflict(AuthCredential credentialForLinking) { + return LinkMergeConflict( + credentialForLinking, + ); + } } // ignore: unused_element @@ -61,6 +68,7 @@ mixin _$AuthFailure { @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }); @optionalTypeArgs Result maybeWhen({ @@ -71,6 +79,7 @@ mixin _$AuthFailure { Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }); @optionalTypeArgs @@ -84,6 +93,7 @@ mixin _$AuthFailure { @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }); @optionalTypeArgs Result maybeMap({ @@ -95,6 +105,7 @@ mixin _$AuthFailure { Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }); } @@ -156,6 +167,7 @@ class _$CancelledByUser implements CancelledByUser { @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -164,6 +176,7 @@ class _$CancelledByUser implements CancelledByUser { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return cancelledByUser(); } @@ -177,6 +190,7 @@ class _$CancelledByUser implements CancelledByUser { Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }) { assert(orElse != null); @@ -198,6 +212,7 @@ class _$CancelledByUser implements CancelledByUser { @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -206,6 +221,7 @@ class _$CancelledByUser implements CancelledByUser { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return cancelledByUser(this); } @@ -220,6 +236,7 @@ class _$CancelledByUser implements CancelledByUser { Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }) { assert(orElse != null); @@ -276,6 +293,7 @@ class _$ServerError implements ServerError { @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -284,6 +302,7 @@ class _$ServerError implements ServerError { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return serverError(); } @@ -297,6 +316,7 @@ class _$ServerError implements ServerError { Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }) { assert(orElse != null); @@ -318,6 +338,7 @@ class _$ServerError implements ServerError { @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -326,6 +347,7 @@ class _$ServerError implements ServerError { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return serverError(this); } @@ -340,6 +362,7 @@ class _$ServerError implements ServerError { Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }) { assert(orElse != null); @@ -397,6 +420,7 @@ class _$EmailAlreadyInUse implements EmailAlreadyInUse { @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -405,6 +429,7 @@ class _$EmailAlreadyInUse implements EmailAlreadyInUse { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return emailAlreadyInUse(); } @@ -418,6 +443,7 @@ class _$EmailAlreadyInUse implements EmailAlreadyInUse { Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }) { assert(orElse != null); @@ -439,6 +465,7 @@ class _$EmailAlreadyInUse implements EmailAlreadyInUse { @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -447,6 +474,7 @@ class _$EmailAlreadyInUse implements EmailAlreadyInUse { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return emailAlreadyInUse(this); } @@ -461,6 +489,7 @@ class _$EmailAlreadyInUse implements EmailAlreadyInUse { Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }) { assert(orElse != null); @@ -523,6 +552,7 @@ class _$InvalidEmailAndPasswordCombination @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -531,6 +561,7 @@ class _$InvalidEmailAndPasswordCombination assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return invalidEmailAndPasswordCombination(); } @@ -544,6 +575,7 @@ class _$InvalidEmailAndPasswordCombination Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }) { assert(orElse != null); @@ -565,6 +597,7 @@ class _$InvalidEmailAndPasswordCombination @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -573,6 +606,7 @@ class _$InvalidEmailAndPasswordCombination assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return invalidEmailAndPasswordCombination(this); } @@ -587,6 +621,7 @@ class _$InvalidEmailAndPasswordCombination Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }) { assert(orElse != null); @@ -644,6 +679,7 @@ class _$EmailMalformed implements EmailMalformed { @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -652,6 +688,7 @@ class _$EmailMalformed implements EmailMalformed { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return malformed(); } @@ -665,6 +702,7 @@ class _$EmailMalformed implements EmailMalformed { Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }) { assert(orElse != null); @@ -686,6 +724,7 @@ class _$EmailMalformed implements EmailMalformed { @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -694,6 +733,7 @@ class _$EmailMalformed implements EmailMalformed { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return malformed(this); } @@ -708,6 +748,7 @@ class _$EmailMalformed implements EmailMalformed { Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }) { assert(orElse != null); @@ -764,6 +805,7 @@ class _$UserDisabled implements UserDisabled { @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -772,6 +814,7 @@ class _$UserDisabled implements UserDisabled { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return userDisabled(); } @@ -785,6 +828,7 @@ class _$UserDisabled implements UserDisabled { Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }) { assert(orElse != null); @@ -806,6 +850,7 @@ class _$UserDisabled implements UserDisabled { @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -814,6 +859,7 @@ class _$UserDisabled implements UserDisabled { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return userDisabled(this); } @@ -828,6 +874,7 @@ class _$UserDisabled implements UserDisabled { Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }) { assert(orElse != null); @@ -885,6 +932,7 @@ class _$TooManyRequests implements TooManyRequests { @required Result malformed(), @required Result userDisabled(), @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -893,6 +941,7 @@ class _$TooManyRequests implements TooManyRequests { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return tooManyRequests(); } @@ -906,6 +955,7 @@ class _$TooManyRequests implements TooManyRequests { Result malformed(), Result userDisabled(), Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), @required Result orElse(), }) { assert(orElse != null); @@ -927,6 +977,7 @@ class _$TooManyRequests implements TooManyRequests { @required Result malformed(EmailMalformed value), @required Result userDisabled(UserDisabled value), @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), }) { assert(cancelledByUser != null); assert(serverError != null); @@ -935,6 +986,7 @@ class _$TooManyRequests implements TooManyRequests { assert(malformed != null); assert(userDisabled != null); assert(tooManyRequests != null); + assert(linkMergeConflict != null); return tooManyRequests(this); } @@ -949,6 +1001,7 @@ class _$TooManyRequests implements TooManyRequests { Result malformed(EmailMalformed value), Result userDisabled(UserDisabled value), Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), @required Result orElse(), }) { assert(orElse != null); @@ -962,3 +1015,160 @@ class _$TooManyRequests implements TooManyRequests { abstract class TooManyRequests implements AuthFailure { const factory TooManyRequests() = _$TooManyRequests; } + +abstract class $LinkMergeConflictCopyWith<$Res> { + factory $LinkMergeConflictCopyWith( + LinkMergeConflict value, $Res Function(LinkMergeConflict) then) = + _$LinkMergeConflictCopyWithImpl<$Res>; + $Res call({AuthCredential credentialForLinking}); +} + +class _$LinkMergeConflictCopyWithImpl<$Res> + extends _$AuthFailureCopyWithImpl<$Res> + implements $LinkMergeConflictCopyWith<$Res> { + _$LinkMergeConflictCopyWithImpl( + LinkMergeConflict _value, $Res Function(LinkMergeConflict) _then) + : super(_value, (v) => _then(v as LinkMergeConflict)); + + @override + LinkMergeConflict get _value => super._value as LinkMergeConflict; + + @override + $Res call({ + Object credentialForLinking = freezed, + }) { + return _then(LinkMergeConflict( + credentialForLinking == freezed + ? _value.credentialForLinking + : credentialForLinking as AuthCredential, + )); + } +} + +class _$LinkMergeConflict implements LinkMergeConflict { + const _$LinkMergeConflict(this.credentialForLinking) + : assert(credentialForLinking != null); + + @override + final AuthCredential credentialForLinking; + + @override + String toString() { + return 'AuthFailure.linkMergeConflict(credentialForLinking: $credentialForLinking)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is LinkMergeConflict && + (identical(other.credentialForLinking, credentialForLinking) || + const DeepCollectionEquality() + .equals(other.credentialForLinking, credentialForLinking))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(credentialForLinking); + + @override + $LinkMergeConflictCopyWith get copyWith => + _$LinkMergeConflictCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + Result when({ + @required Result cancelledByUser(), + @required Result serverError(), + @required Result emailAlreadyInUse(), + @required Result invalidEmailAndPasswordCombination(), + @required Result malformed(), + @required Result userDisabled(), + @required Result tooManyRequests(), + @required Result linkMergeConflict(AuthCredential credentialForLinking), + }) { + assert(cancelledByUser != null); + assert(serverError != null); + assert(emailAlreadyInUse != null); + assert(invalidEmailAndPasswordCombination != null); + assert(malformed != null); + assert(userDisabled != null); + assert(tooManyRequests != null); + assert(linkMergeConflict != null); + return linkMergeConflict(credentialForLinking); + } + + @override + @optionalTypeArgs + Result maybeWhen({ + Result cancelledByUser(), + Result serverError(), + Result emailAlreadyInUse(), + Result invalidEmailAndPasswordCombination(), + Result malformed(), + Result userDisabled(), + Result tooManyRequests(), + Result linkMergeConflict(AuthCredential credentialForLinking), + @required Result orElse(), + }) { + assert(orElse != null); + if (linkMergeConflict != null) { + return linkMergeConflict(credentialForLinking); + } + return orElse(); + } + + @override + @optionalTypeArgs + Result map({ + @required Result cancelledByUser(CancelledByUser value), + @required Result serverError(ServerError value), + @required Result emailAlreadyInUse(EmailAlreadyInUse value), + @required + Result invalidEmailAndPasswordCombination( + InvalidEmailAndPasswordCombination value), + @required Result malformed(EmailMalformed value), + @required Result userDisabled(UserDisabled value), + @required Result tooManyRequests(TooManyRequests value), + @required Result linkMergeConflict(LinkMergeConflict value), + }) { + assert(cancelledByUser != null); + assert(serverError != null); + assert(emailAlreadyInUse != null); + assert(invalidEmailAndPasswordCombination != null); + assert(malformed != null); + assert(userDisabled != null); + assert(tooManyRequests != null); + assert(linkMergeConflict != null); + return linkMergeConflict(this); + } + + @override + @optionalTypeArgs + Result maybeMap({ + Result cancelledByUser(CancelledByUser value), + Result serverError(ServerError value), + Result emailAlreadyInUse(EmailAlreadyInUse value), + Result invalidEmailAndPasswordCombination( + InvalidEmailAndPasswordCombination value), + Result malformed(EmailMalformed value), + Result userDisabled(UserDisabled value), + Result tooManyRequests(TooManyRequests value), + Result linkMergeConflict(LinkMergeConflict value), + @required Result orElse(), + }) { + assert(orElse != null); + if (linkMergeConflict != null) { + return linkMergeConflict(this); + } + return orElse(); + } +} + +abstract class LinkMergeConflict implements AuthFailure { + const factory LinkMergeConflict(AuthCredential credentialForLinking) = + _$LinkMergeConflict; + + AuthCredential get credentialForLinking; + $LinkMergeConflictCopyWith get copyWith; +} diff --git a/lib/src/infrastructure/firebase_auth_facade.dart b/lib/src/infrastructure/firebase_auth_facade.dart index f195957..7c72857 100644 --- a/lib/src/infrastructure/firebase_auth_facade.dart +++ b/lib/src/infrastructure/firebase_auth_facade.dart @@ -175,8 +175,7 @@ class FirebaseAuthFacade implements AuthFacade { accessToken: googleAuthentication.accessToken, ); - await _firebaseAuth.signInWithCredential(authCredential); - return const Auth.success(); + return signInWithCredential(authCredential); } catch (e) { debugPrint(e); return const Auth.failure(AuthFailure.serverError()); @@ -197,8 +196,7 @@ class FirebaseAuthFacade implements AuthFacade { accessToken: googleAuthentication.accessToken, ); - await _firebaseAuth.signInWithCredential(authCredential); - return const Auth.success(); + return signInWithCredential(authCredential); } on FirebaseAuthException catch (e) { debugPrint(e.toString()); return const Auth.failure(AuthFailure.serverError()); @@ -219,10 +217,19 @@ class FirebaseAuthFacade implements AuthFacade { @override Future signInWithCredential(AuthCredential credential) async { try { - await _firebaseAuth.signInWithCredential(credential); - return const Auth.success(); + if (_firebaseAuth.currentUser == null) { + await _firebaseAuth.signInWithCredential(credential); + return const Auth.success(); + } else { + debugPrint("Already signed in, attempting to link current user with credential."); + await _firebaseAuth.currentUser.linkWithCredential(credential); + return const Auth.success(); + } } on FirebaseAuthException catch (e) { debugPrint(e.toString()); + if (e.code == "credential-already-in-use") { + return Auth.failure(AuthFailure.linkMergeConflict(e.credential)); + } return const Auth.failure(AuthFailure.serverError()); } catch (e) { debugPrint(e.toString()); @@ -234,10 +241,17 @@ class FirebaseAuthFacade implements AuthFacade { Future signInWithOAuth(String provider, List scopes, Map parameters) async { try { - await FirebaseAuthOAuth(app: _app) - .openSignInFlow(provider, scopes, parameters); - return const Auth.success(); + final firebaseAuthOAuth = FirebaseAuthOAuth(app: _app); + if (_firebaseAuth.currentUser == null) { + await firebaseAuthOAuth.openSignInFlow(provider, scopes, parameters); + return const Auth.success(); + } else { + debugPrint("Already signed in, attempting to link current user with credential."); + await firebaseAuthOAuth.linkExistingUserWithCredentials(provider, scopes, parameters); + return const Auth.success(); + } } on PlatformException catch (e) { + // TODO Merge accounts on link failure /** * The plugin has the following error codes: * 1. FirebaseAuthError: FirebaseAuth related error diff --git a/lib/src/presentation/lit_auth_ui.dart b/lib/src/presentation/lit_auth_ui.dart index e3858c0..fed6daf 100644 --- a/lib/src/presentation/lit_auth_ui.dart +++ b/lib/src/presentation/lit_auth_ui.dart @@ -68,6 +68,9 @@ class LitAuthState extends StatelessWidget { /// TypeDef callback for authentication failure typedef AuthFailureCallback = void Function(AuthFailure failure); +/// TypeDef callback for link merge conflicts +typedef LinkMergeConflictCallback = void Function(LinkMergeConflict conflict); + class LitAuth extends StatelessWidget { /// Configure the sign-in UI and provide custom decoration/configuration for /// the sign-in elements. Leaving this empty will show the standard sign-in @@ -89,6 +92,9 @@ class LitAuth extends StatelessWidget { /// Callback to be called if authentication fails final AuthFailureCallback onAuthFailure; + + /// Callback to be called to handle link merge conflicts + final LinkMergeConflictCallback onLinkMergeConflict; /// Configuration for custom error notifications final NotificationConfig errorNotification; @@ -145,6 +151,7 @@ class LitAuth extends StatelessWidget { this.config, this.onAuthSuccess, this.onAuthFailure, + this.onLinkMergeConflict, this.errorNotification = const NotificationConfig(), this.successNotification = const NotificationConfig(), }) : super(key: key); @@ -183,6 +190,7 @@ class LitAuth extends StatelessWidget { return _SignInBuilder( onAuthFailure: onAuthFailure, onAuthSuccess: onAuthSuccess, + onLinkMergeConflict: onLinkMergeConflict, errorNotification: errorNotification, successNotification: successNotification, child: StandardSignInWidget( @@ -197,6 +205,7 @@ class _SignInBuilder extends StatelessWidget { Key key, @required this.onAuthFailure, @required this.onAuthSuccess, + @required this.onLinkMergeConflict, this.builder, @required this.errorNotification, @required this.successNotification, @@ -205,6 +214,7 @@ class _SignInBuilder extends StatelessWidget { final VoidCallback onAuthSuccess; final AuthFailureCallback onAuthFailure; + final LinkMergeConflictCallback onLinkMergeConflict; final TransitionBuilder builder; final NotificationConfig errorNotification; final NotificationConfig successNotification; @@ -236,29 +246,44 @@ class _SignInBuilder extends StatelessWidget { WidgetsBinding.instance .addPostFrameCallback((_) => onAuthFailure(f.failure)); } - WidgetsBinding.instance.addPostFrameCallback( - (_) => NotificationHelper.error( - context: context, - config: errorNotification, - message: f.failure.map( - cancelledByUser: (_) => 'Cancelled', - serverError: (_) => 'Server error', - emailAlreadyInUse: (_) => 'Email already in use', - invalidEmailAndPasswordCombination: (_) => - 'Invalid email and password combination', - malformed: (_) => 'Not a valid email address', - userDisabled: (_) => - 'User disabled. Contact customer care for assistance', - tooManyRequests: (_) => - 'Too many unsuccessful login attempts. Please try again later'), - ).show(context), - ); + if (onLinkMergeConflict != null) { + // Skip showing error if link merge conflicts are handled + f.failure.maybeWhen( + linkMergeConflict: (credential) => WidgetsBinding.instance + .addPostFrameCallback((_) => onLinkMergeConflict(f.failure)), + orElse: () { showError(context, f.failure); } + ); + } else { + showError(context, f.failure); + } }, ); }, ); } + void showError(BuildContext context, AuthFailure failure) { + WidgetsBinding.instance.addPostFrameCallback( + (_) => + NotificationHelper.error( + context: context, + config: errorNotification, + message: failure.map( + cancelledByUser: (_) => 'Cancelled', + serverError: (_) => 'Server error', + emailAlreadyInUse: (_) => 'Email already in use', + invalidEmailAndPasswordCombination: (_) => + 'Invalid email and password combination', + malformed: (_) => 'Not a valid email address', + userDisabled: (_) => + 'User disabled. Contact customer care for assistance', + tooManyRequests: (_) => + 'Too many unsuccessful login attempts. Please try again later', + linkMergeConflict: (_) => 'Account already exists for sign in method',), + ).show(context), + ); + } + @override Widget build(BuildContext context) { return StateNotifierProvider