Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email authentification #236

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions app/lib/app/data/repository/auth_repositoty_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,50 @@ final class AuthRepositoryImpl implements AuthRepository {
}
}

@override
Future<void> loginWithEmail(String email) async {
try {
await remoteDataSource.loginWithEmail(email);
} catch (e, s) {
MqCrashlytics.report(e, s);
log('signWithEmail: error: $e\n$s');
}
}

@override
Future<Either<UserEntity, Exception>> verifyOtp({
required String email,
required String otp,
required String languageCode,
required Gender gender,
}) async {
try {
final res = await remoteDataSource.verifyOtp(
email: email,
otp: otp,
languageCode: languageCode,
gender: gender,
);

return res.fold(
Left.new,
(r) {
final userEntity = UserEntity(
accessToken: r.accessToken,
username: r.username,
gender: r.gender,
localeCode: r.localeCode,
);
return Right(userEntity);
},
);
} catch (e, s) {
log('signWithemail: error: $e\n$s');
MqCrashlytics.report(e, s);
return Left(AuthenticationExc(message: e.toString()));
}
}

@override
Future<Either<UserEntity, Exception>> signWithGoogle(
String languageCode,
Expand Down
5 changes: 3 additions & 2 deletions app/lib/app/data/source/auth_remote_data_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import 'package:my_quran/app/app.dart';
abstract class AuthRemoteDataSource {
Future<void> loginWithEmail(String email);

Future<Either<UserModelResponse, Exception>> fetchSmsCode({
required String code,
Future<Either<UserModelResponse, Exception>> verifyOtp({
required String email,
required String otp,
required String languageCode,
required Gender gender,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ final class AuthRemoteDataSourceMock implements AuthRemoteDataSource {
Future<void> loginWithEmail(String email) async {}

@override
Future<Either<UserModelResponse, Exception>> fetchSmsCode({
required String code,
Future<Either<UserModelResponse, Exception>> verifyOtp({
required String email,
required String otp,
required String languageCode,
required Gender gender,
}) async {
Expand Down
105 changes: 52 additions & 53 deletions app/lib/app/data/source/remote/auth_remote_data_source_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,61 @@ final class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
final PreferencesStorage storage;
final SoccialAuth soccialAuth;
final bool isIntegrationTest;
@override
Future<Either<UserModelResponse, Exception>> verifyOtp({
required String otp,
required String email,
required String languageCode,
required Gender gender,
}) async {
try {
final token = await client.postType(
apiConst.loginWithEmailVerify,
fromJson: TokenResponse.fromJson,
body: {'email': email, 'opt': otp},
);

return token.fold(
(error) {
return Left(error);
},
(r) async {
final user = UserModelResponse(
accessToken: r.key,
username: email,
gender: gender,
localeCode: languageCode,
);

await storage.writeString(key: StorageKeys.tokenKey, value: user.accessToken);

return Right(user);
},
);
} catch (e) {
return Left(Exception('Error fetching SMS code: $e'));
}
}

@override
Future<void> loginWithEmail(String email) async {
try {
await client.post<TokenResponse>(
apiConst.loginWithEmailSend,
fromJson: TokenResponse.fromJson,
body: {'email': email},
);
} catch (e) {
throw Exception('Error during login: $e');
}
}

@override
Future<Either<UserModelResponse, Exception>> signInWithGoogle(
String languageCode,
Gender gender,
) async {
final googleAuth = await _getGoogleAuth();

final token = await client.postType(
apiConst.loginWithGoogle,
fromJson: TokenResponse.fromJson,
Expand All @@ -40,7 +87,6 @@ final class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
gender: gender,
localeCode: languageCode,
);

await storage.writeString(key: StorageKeys.tokenKey, value: user.accessToken);

return Right(user);
Expand All @@ -55,11 +101,11 @@ final class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
);
} else {
final googleAuth = await soccialAuth.signInWithGoogle();
final accessToken = googleAuth.credential?.accessToken ?? '';
final username = googleAuth.user?.displayName ?? '';
final accessToken = googleAuth?['accessToken'] ?? '';
final username = googleAuth?['name'] ?? '';
return _UserReqParam(
name: username,
accessToken: accessToken,
name: username.toString(),
accessToken: accessToken.toString(),
);
}
}
Expand Down Expand Up @@ -148,53 +194,6 @@ final class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
Future<void> logoutRemote() async {
await soccialAuth.logOut();
}

@override
Future<Either<UserModelResponse, Exception>> fetchSmsCode({
required String code,
required String languageCode,
required Gender gender,
}) async {
try {
final token = await client.post(
'apiConst.fetchSmsCode',
fromJson: TokenResponse.fromJson,
body: {'code': code},
);
return token.fold(
(error) {
return Left(error);
},
(r) async {
final user = UserModelResponse(
accessToken: r.key,
username: '',
gender: gender,
localeCode: languageCode,
);

await storage.writeString(key: StorageKeys.tokenKey, value: user.accessToken);

return Right(user);
},
);
} catch (e) {
return Left(Exception('Error fetching SMS code: $e'));
}
}

@override
Future<void> loginWithEmail(String email) async {
try {
await client.post(
'apiConst.loginWithEmail',
fromJson: TokenResponse.fromJson,
body: {'email': email},
);
} catch (e) {
throw Exception('Error during login: $e');
}
}
}

@immutable
Expand Down
2 changes: 2 additions & 0 deletions app/lib/app/domain/domain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ export 'usecase/ser_user_data_user_case.dart';
export 'usecase/patch_gender_user_case.dart';
export 'usecase/patch_locale_code_use_case.dart';
export 'usecase/logout_use_case.dart';
export 'usecase/email_login_usecase.dart';
export 'usecase/verify_otp_use_case.dart';
export 'entity/user_entity.dart';
export 'entity/user_data_entity.dart';
9 changes: 9 additions & 0 deletions app/lib/app/domain/repository/auth_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import 'package:my_quran/app/app.dart';
abstract class AuthRepository {
UserEntity? get init;

Future<void> loginWithEmail(String email);

Future<Either<UserEntity, Exception>> verifyOtp({
required String email,
required String otp,
required String languageCode,
required Gender gender,
});

Future<Either<UserEntity, Exception>> signWithGoogle(
String languageCode,
Gender gender,
Expand Down
13 changes: 13 additions & 0 deletions app/lib/app/domain/usecase/email_login_usecase.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:meta/meta.dart';
import 'package:my_quran/app/app.dart';

@immutable
final class EmailLoginUseCase {
const EmailLoginUseCase(this.repository);

final AuthRepository repository;

Future<void> call(String email) {
return repository.loginWithEmail(email);
}
}
24 changes: 24 additions & 0 deletions app/lib/app/domain/usecase/verify_otp_use_case.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:meta/meta.dart';
import 'package:my_quran/app/app.dart';
import 'package:my_quran/core/core.dart';

@immutable
final class VerifyOtpUseCase {
const VerifyOtpUseCase(this.repository);

final AuthRepository repository;

Future<Either<UserEntity, Exception>> call({
required String email,
required String otp,
required String languageCode,
required Gender gender,
}) {
return repository.verifyOtp(
email: email,
otp: otp,
languageCode: languageCode,
gender: gender,
);
}
}
26 changes: 26 additions & 0 deletions app/lib/app/presentation/cubit/auth_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class AuthCubit extends Cubit<AuthState> {
this.patchGenderUseCase,
this.patchLocaleCodeUseCase,
this.logoutUseCase,
this.loginUsecase,
this.verifyOtpUseCase,
) : super(AuthState(user: getInitialUserUseCase.call));

final GetInitialUserUseCase getInitialUserUseCase;
Expand All @@ -26,6 +28,30 @@ class AuthCubit extends Cubit<AuthState> {
final PatchGenderUseCase patchGenderUseCase;
final PatchLocaleCodeUseCase patchLocaleCodeUseCase;
final LogoutUseCase logoutUseCase;
final EmailLoginUseCase loginUsecase;
final VerifyOtpUseCase verifyOtpUseCase;

Future<void> login(String email) async {
try {
await loginUsecase(email);
} catch (e) {
emit(state.copyWith(exception: Exception(e)));
}
}

Future<AuthState> verifyOtp(String otp, String email) async {
final user = await verifyOtpUseCase(
email: email,
otp: otp,
languageCode: state.currentLocale.languageCode,
gender: state.gender,
);
user.fold(
(l) => emit(state.copyWith(exception: l)),
(r) => emit(state.copyWith(user: r)),
);
return state;
}

Future<AuthState> signInWithGoogle() async {
final user = await googleSignIn(
Expand Down
2 changes: 2 additions & 0 deletions app/lib/app/presentation/view/app_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class MyApp extends StatelessWidget {
PatchGenderUseCase(context.read<AuthRepository>()),
PatchLocaleCodeUseCase(context.read<AuthRepository>()),
LogoutUseCase(context.read<AuthRepository>()),
EmailLoginUseCase(context.read<AuthRepository>()),
VerifyOtpUseCase(context.read<AuthRepository>()),
),
),
BlocProvider(
Expand Down
1 change: 1 addition & 0 deletions app/lib/components/components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export 'indicators/dot_indicator.dart';
export 'audio/seek_bar.dart';
export 'audio/audio_center_button.dart';
export 'alert/confirmation_dialog.dart';
export 'forms/custom_text_field.dart';
33 changes: 33 additions & 0 deletions app/lib/components/forms/custom_text_field.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';

class CustomTextFormField extends StatelessWidget {
const CustomTextFormField({
this.controller,
this.labelText,
this.obscureText = false,
this.suffixIcon,
this.validator,
super.key,
});

final bool obscureText;
final TextEditingController? controller;
final String? labelText;
final Widget? suffixIcon;
final String? Function(String?)? validator;

@override
Widget build(BuildContext context) {
return TextFormField(
controller: controller,
decoration: InputDecoration(
labelText: labelText,
border: const OutlineInputBorder(),
suffixIcon: suffixIcon,
errorMaxLines: 3,
),
obscureText: obscureText,
validator: validator,
);
}
}
Loading
Loading