Skip to content

Commit c27e16e

Browse files
feat: add the use of exceptions for UserService and implement translations for these exceptions
1 parent a74281c commit c27e16e

24 files changed

Lines changed: 423 additions & 237 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 6.4.0
2+
3+
- Added proper use of execptions for all auth methods.
4+
- Added tthe ability to add translations for all auth exceptions including two standard provided languages (nl, en)
5+
16
## 6.3.1
27

38
- Fixed a bug where the keyboard for the login username and password fields was closing because of a different LoginOptions.hashCode with the same LoginOptions values.

packages/firebase_user_repository/lib/src/firebase_user_repository.dart

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class FirebaseUserRepository implements UserRepositoryInterface {
1212
final String userCollecton;
1313

1414
@override
15-
Future<LoginResponse> loginWithEmailAndPassword({
15+
Future<AuthResponse> loginWithEmailAndPassword({
1616
required String email,
1717
required String password,
1818
}) async {
@@ -22,24 +22,16 @@ class FirebaseUserRepository implements UserRepositoryInterface {
2222
password: password,
2323
);
2424

25-
return LoginResponse(
26-
loginSuccessful: true,
25+
return AuthResponse(
2726
userObject: userCredential.user,
2827
);
2928
} on FirebaseAuthException catch (e) {
30-
return LoginResponse(
31-
loginSuccessful: false,
32-
userObject: null,
33-
loginError: UserError(
34-
title: e.code,
35-
message: e.message ?? "An error occurred",
36-
),
37-
);
29+
throw _mapFirebaseAuthException(e);
3830
}
3931
}
4032

4133
@override
42-
Future<RegistrationResponse> register({
34+
Future<AuthResponse> register({
4335
required Map<String, dynamic> values,
4436
}) async {
4537
try {
@@ -54,19 +46,11 @@ class FirebaseUserRepository implements UserRepositoryInterface {
5446
.doc(userCredential.user!.uid)
5547
.set(values);
5648

57-
return RegistrationResponse(
58-
registrationSuccessful: true,
49+
return AuthResponse(
5950
userObject: userCredential.user,
6051
);
6152
} on FirebaseAuthException catch (e) {
62-
return RegistrationResponse(
63-
registrationSuccessful: false,
64-
userObject: null,
65-
registrationError: UserError(
66-
title: e.code,
67-
message: e.message ?? "An error occurred",
68-
),
69-
);
53+
throw _mapFirebaseAuthException(e);
7054
}
7155
}
7256

@@ -80,13 +64,7 @@ class FirebaseUserRepository implements UserRepositoryInterface {
8064
requestSuccesfull: true,
8165
);
8266
} on FirebaseAuthException catch (e) {
83-
return RequestPasswordResponse(
84-
requestSuccesfull: false,
85-
requestPasswordError: UserError(
86-
title: e.code,
87-
message: e.message ?? "An error occurred",
88-
),
89-
);
67+
throw _mapFirebaseAuthException(e);
9068
}
9169
}
9270

@@ -101,4 +79,42 @@ class FirebaseUserRepository implements UserRepositoryInterface {
10179

10280
@override
10381
Future<bool> isLoggedIn() async => _firebaseAuth.currentUser != null;
82+
83+
AuthException _mapFirebaseAuthException(FirebaseAuthException e) {
84+
switch (e.code) {
85+
case "invalid-email":
86+
return InvalidEmailError(code: e.code, message: e.message);
87+
case "user-disabled":
88+
return UserDisabledError(code: e.code, message: e.message);
89+
case "user-not-found":
90+
return UserNotFoundError(code: e.code, message: e.message);
91+
case "wrong-password":
92+
return WrongPasswordError(code: e.code, message: e.message);
93+
case "email-already-in-use":
94+
return EmailAlreadyInUseError(code: e.code, message: e.message);
95+
case "operation-not-allowed":
96+
return OperationNotAllowedError(code: e.code, message: e.message);
97+
case "weak-password":
98+
return WeakPasswordError(code: e.code, message: e.message);
99+
case "too-many-requests":
100+
return TooManyRequestsError(code: e.code, message: e.message);
101+
case "network-request-failed":
102+
return NetworkError(code: e.code, message: e.message);
103+
case "invalid-credential":
104+
return InvalidCredentialError(code: e.code, message: e.message);
105+
case "account-exists-with-different-credential":
106+
return AccountExistsWithDifferentCredentialError(
107+
code: e.code,
108+
message: e.message,
109+
);
110+
case "invalid-verification-code":
111+
return InvalidVerificationCodeError(code: e.code, message: e.message);
112+
case "invalid-verification-id":
113+
return InvalidVerificationIdError(code: e.code, message: e.message);
114+
case "requires-recent-login":
115+
return RequiresRecentLoginError(code: e.code, message: e.message);
116+
default:
117+
return GenericAuthError(code: e.code, message: e.message);
118+
}
119+
}
104120
}

packages/firebase_user_repository/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: firebase_user_repository
22
description: "firebase_user_repository for flutter_user package"
3-
version: 6.3.1
3+
version: 6.4.0
44
repository: https://github.com/Iconica-Development/flutter_user
55

66
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
@@ -14,7 +14,7 @@ dependencies:
1414
sdk: flutter
1515
user_repository_interface:
1616
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub/
17-
version: ^6.3.1
17+
version: ^6.4.0
1818
cloud_firestore: ^5.4.2
1919
firebase_auth: ^5.3.0
2020

packages/flutter_user/lib/flutter_user.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ library flutter_user;
66
export "package:user_repository_interface/user_repository_interface.dart";
77

88
export "src/flutter_user_navigator_userstory.dart";
9+
export "src/models/auth_exception_formatter.dart";
910
export "src/models/flutter_user_options.dart";
1011
export "src/models/forgot_password/forgot_password_options.dart";
1112
export "src/models/forgot_password/forgot_password_spacer_options.dart";
@@ -18,7 +19,6 @@ export "src/models/login/login_translations.dart";
1819
export "src/models/registration/auth_action.dart";
1920
export "src/models/registration/auth_bool_field.dart";
2021
export "src/models/registration/auth_drop_down.dart";
21-
export "src/models/registration/auth_exception.dart";
2222
export "src/models/registration/auth_field.dart";
2323
export "src/models/registration/auth_pass_field.dart";
2424
export "src/models/registration/auth_step.dart";

packages/flutter_user/lib/src/flutter_user_navigator_userstory.dart

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import "dart:async";
22

33
import "package:flutter/material.dart";
44
import "package:flutter_user/flutter_user.dart";
5+
import "package:flutter_user/src/models/auth_error_details.dart";
56

67
class FlutterUserNavigatorUserstory extends StatefulWidget {
78
const FlutterUserNavigatorUserstory({
@@ -94,41 +95,41 @@ class _FlutterUserNavigatorUserstoryState
9495
await options!.beforeLogin?.call(email, password);
9596
if (!mounted) return;
9697
unawaited(showLoadingIndicator(context));
97-
var loginResponse = await userService!.loginWithEmailAndPassword(
98-
email: email,
99-
password: password,
100-
);
101-
102-
if (!loginResponse.loginSuccessful) {
98+
try {
99+
await userService!.loginWithEmailAndPassword(
100+
email: email,
101+
password: password,
102+
);
103+
} on AuthException catch (e) {
103104
if (!mounted) return;
104105
Navigator.of(context, rootNavigator: true).pop();
105106
if (!context.mounted) return;
106-
await errorScaffoldMessenger(context, loginResponse);
107+
var authErrorDetails = options!.authExceptionFormatter.format(e);
108+
await errorScaffoldMessenger(context, authErrorDetails);
107109
return;
108110
}
111+
109112
await options!.afterLogin?.call();
110113

111-
if (loginResponse.loginSuccessful) {
112-
var onboardingUser = await options!.onBoardedUser?.call();
113-
if (!mounted) return;
114-
Navigator.of(context, rootNavigator: true).pop();
115-
if (options!.useOnboarding && onboardingUser?.onboarded == false) {
116-
await push(
117-
Onboarding(
118-
onboardingFinished: (results) async {
119-
await options!.onOnboardingComplete?.call(results);
120-
if (!mounted || !context.mounted) return;
121-
Navigator.of(context).pop();
122-
await pushReplacement(widget.afterLoginScreen);
123-
},
124-
),
125-
);
126-
} else {
127-
if (!context.mounted) {
128-
return;
129-
}
130-
await pushReplacement(widget.afterLoginScreen);
114+
var onboardingUser = await options!.onBoardedUser?.call();
115+
if (!mounted) return;
116+
Navigator.of(context, rootNavigator: true).pop();
117+
if (options!.useOnboarding && onboardingUser?.onboarded == false) {
118+
await push(
119+
Onboarding(
120+
onboardingFinished: (results) async {
121+
await options!.onOnboardingComplete?.call(results);
122+
if (!mounted || !context.mounted) return;
123+
Navigator.of(context).pop();
124+
await pushReplacement(widget.afterLoginScreen);
125+
},
126+
),
127+
);
128+
} else {
129+
if (!context.mounted) {
130+
return;
131131
}
132+
await pushReplacement(widget.afterLoginScreen);
132133
}
133134
}
134135

@@ -170,17 +171,17 @@ class _FlutterUserNavigatorUserstoryState
170171
}
171172
unawaited(showLoadingIndicator(context));
172173

173-
var requestPasswordReponse =
174-
await userService!.requestChangePassword(email: email);
175-
176-
if (requestPasswordReponse.requestSuccesfull) {
177-
if (context.mounted) {
178-
await pushReplacement(_forgotPasswordSuccessScreen());
179-
}
180-
} else {
174+
try {
175+
await userService!.requestChangePassword(email: email);
176+
} on AuthException catch (_) {
181177
if (context.mounted) {
182178
await push(_forgotPasswordUnsuccessfullScreen());
183179
}
180+
return;
181+
}
182+
183+
if (context.mounted) {
184+
await pushReplacement(_forgotPasswordSuccessScreen());
184185
}
185186
}
186187

@@ -215,23 +216,20 @@ class _FlutterUserNavigatorUserstoryState
215216
registrationOptions: registrationOptions!,
216217
userService: userService!,
217218
onError: (error) async {
219+
var errorDetails = options!.authExceptionFormatter.format(error);
220+
218221
if (options!.onRegistrationError != null) {
219-
return options!
220-
.onRegistrationError!(error ?? "Something went wrong");
222+
return options!.onRegistrationError!(error, errorDetails);
221223
}
222224
await push(
223225
_registrationUnsuccessfullScreen(
224-
error ?? "Something went wrong",
226+
errorDetails,
225227
),
226228
);
227-
var isPasswordError = error?.contains("weak-password") ?? false;
228-
var isEmailError = error?.contains("email-already-in-use") ?? false;
229-
if (isPasswordError) {
230-
return 1;
231-
}
232-
if (isEmailError) {
233-
return 0;
234-
}
229+
230+
if (error is WeakPasswordError) return 1;
231+
232+
if (error is EmailAlreadyInUseError) return 0;
235233

236234
return null;
237235
},
@@ -250,15 +248,15 @@ class _FlutterUserNavigatorUserstoryState
250248
},
251249
);
252250

253-
Widget _registrationUnsuccessfullScreen(String error) =>
251+
Widget _registrationUnsuccessfullScreen(AuthErrorDetails errorDetails) =>
254252
RegistrationUnsuccessfull(
255253
registrationOptions: registrationOptions!,
256254
onPressed: () async {
257255
await options!.afterRegistrationUnsuccessful?.call() ??
258256
// ignore: use_build_context_synchronously
259257
Navigator.of(context).pop();
260258
},
261-
error: error,
259+
errorDetails: errorDetails,
262260
);
263261

264262
Future<void> push(Widget screen) async {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class AuthErrorDetails {
2+
const AuthErrorDetails({required this.title, required this.message});
3+
4+
final String title;
5+
final String message;
6+
}

0 commit comments

Comments
 (0)