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

Add mock data source to app #232

Merged
merged 2 commits into from
Jul 20, 2024
Merged
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
12 changes: 10 additions & 2 deletions app/lib/app/data/data.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
export 'repository/app_repositoty_impl.dart';
export 'repository/theme_repository_impl.dart';
export 'repository/auth_repositoty_impl.dart';
export 'source/app_local_data_source.dart';
export 'source/theme_local_data_source.dart';
export 'source/auth_local_data_source.dart';
export 'source/auth_remote_data_source.dart';
export 'source/theme_local_data_source.dart';
export 'source/app_local_data_source.dart';
export 'source/local/app_local_data_source_impl.dart';
export 'source/local/theme_local_data_source_impl.dart';
export 'source/local/auth_local_data_source_impl.dart';
export 'source/remote/auth_remote_data_source_impl.dart';
export 'source/mock/auth_local_data_source_mock.dart';
export 'source/mock/auth_remote_data_source_mock.dart';
export 'source/mock/theme_local_data_source_mock.dart';
export 'source/mock/app_local_data_source_mock.dart';
export 'models/user_model.dart';
export 'models/token_response.dart';
export 'models/user_data_response.dart';
60 changes: 23 additions & 37 deletions app/lib/app/data/repository/auth_repositoty_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ final class AuthRepositoryImpl implements AuthRepository {
final AuthRemoteDataSource remoteDataSource;

@override
UserEntity? get init {
return localDataSource.init;
}
UserEntity? get init => localDataSource.init;

@override
Future<void> setUserData(UserEntity userEntity) async {
Expand All @@ -35,49 +33,37 @@ final class AuthRepositoryImpl implements AuthRepository {
String languageCode,
Gender gender,
) async {
try {
final res = await remoteDataSource.signInWithGoogle(languageCode, gender);
return res.fold(
Left.new,
(r) => Right(
UserEntity(
accessToken: r.accessToken,
username: r.username,
gender: r.gender,
localeCode: r.localeCode,
),
final res = await remoteDataSource.signInWithGoogle(languageCode, gender);
return res.fold(
Left.new,
(r) => Right(
UserEntity(
accessToken: r.accessToken,
username: r.username,
gender: r.gender,
localeCode: r.localeCode,
),
);
} catch (e, s) {
log('signWithGoogle: error: $e\n$s');
MqCrashlytics.report(e, s);
return Left(AuthenticationExc(message: e.toString()));
}
),
);
}

@override
Future<Either<UserEntity, Exception>> signWithApple(
String languageCode,
Gender gender,
) async {
try {
final res = await remoteDataSource.signInWithApple(languageCode, gender);
return res.fold(
Left.new,
(r) => Right(
UserEntity(
accessToken: r.accessToken,
username: r.username,
gender: r.gender,
localeCode: r.localeCode,
),
final res = await remoteDataSource.signInWithApple(languageCode, gender);
return res.fold(
Left.new,
(r) => Right(
UserEntity(
accessToken: r.accessToken,
username: r.username,
gender: r.gender,
localeCode: r.localeCode,
),
);
} catch (e, s) {
MqCrashlytics.report(e, s);
log('signWithGoogle: error: $e\n$s');
return Left(AuthenticationExc(message: e.toString()));
}
),
);
}

@override
Expand Down
4 changes: 1 addition & 3 deletions app/lib/app/data/repository/theme_repository_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ final class ThemeRepositoryImpl implements ThemeRepository {
final ThemeLocalDataSource themeLocalDataSource;

@override
CustomTheme get getInitialThemeState {
return themeLocalDataSource.initialTheme;
}
CustomTheme get getInitialThemeState => themeLocalDataSource.initialTheme;

@override
Future<void> saveThemePrimaryColor(int index) async {
Expand Down
14 changes: 2 additions & 12 deletions app/lib/app/data/source/app_local_data_source.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';

@immutable
final class AppLocalDataSource {
const AppLocalDataSource({
required this.packageInfo,
});

final PackageInfo packageInfo;

String get appVersion => packageInfo.version;
abstract class AppLocalDataSource {
String get appVersion;
}
57 changes: 7 additions & 50 deletions app/lib/app/data/source/auth_local_data_source.dart
Original file line number Diff line number Diff line change
@@ -1,53 +1,10 @@
import 'package:meta/meta.dart';
import 'package:mq_storage/mq_storage.dart';
import 'package:my_quran/app/app.dart';
import 'package:my_quran/constants/contants.dart';

@immutable
final class AuthLocalDataSource {
const AuthLocalDataSource(this.storage);

final PreferencesStorage storage;

UserEntity? get init {
final userToken = storage.readString(key: StorageKeys.tokenKey);
final userGender = storage.readString(key: StorageKeys.genderKey);
final username = storage.readString(key: StorageKeys.usernameKey);
final localeCode = storage.readString(key: StorageKeys.localeKey);
if (userToken == null && userGender == null && username == null) return null;
return UserEntity(
accessToken: userToken!,
username: username!,
gender: userGender == Gender.male.name ? Gender.male : Gender.female,
localeCode: localeCode ?? 'en',
);
}

String? getToken() => storage.readString(key: StorageKeys.tokenKey);

Future<void> saveUserData(UserEntity userEntity) async {
await Future.wait([
storage.writeString(key: StorageKeys.localeKey, value: userEntity.localeCode),
storage.writeString(key: StorageKeys.genderKey, value: userEntity.gender.name),
storage.writeString(key: StorageKeys.usernameKey, value: userEntity.username),
]);
}

Future<void> saveGender(Gender gender) {
return storage.writeString(
key: StorageKeys.genderKey,
value: gender.name,
);
}

Future<void> saveLocaleCode(String localeCode) {
return storage.writeString(
key: StorageKeys.localeKey,
value: localeCode,
);
}

Future<void> logoutLocal() async {
await storage.clear();
}
abstract class AuthLocalDataSource {
UserEntity? get init;
String? getToken();
Future<void> saveUserData(UserEntity userEntity);
Future<void> saveGender(Gender gender);
Future<void> saveLocaleCode(String localeCode);
Future<void> logoutLocal();
}
143 changes: 12 additions & 131 deletions app/lib/app/data/source/auth_remote_data_source.dart
Original file line number Diff line number Diff line change
@@ -1,155 +1,36 @@
import 'package:meta/meta.dart';
import 'package:mq_storage/mq_storage.dart';
import 'package:my_quran/app/app.dart';
import 'package:my_quran/config/config.dart';
import 'package:my_quran/constants/contants.dart';
import 'package:my_quran/core/core.dart';

@immutable
final class AuthRemoteDataSource {
const AuthRemoteDataSource({
required this.client,
required this.storage,
required this.soccialAuth,
required this.isIntegrationTest,
});
abstract class AuthRemoteDataSource {
Future<void> loginWithEmail(String email);

final MqDio client;
final PreferencesStorage storage;
final SoccialAuth soccialAuth;
final bool isIntegrationTest;
Future<Either<UserModelResponse, Exception>> fetchSmsCode({
required String code,
required String languageCode,
required Gender gender,
});

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

final token = await client.postType(
apiConst.loginWithGoogle,
fromJson: TokenResponse.fromJson,
body: {'access_token': googleAuth.accessToken},
);

return token.fold(Left.new, (r) async {
final user = UserModelResponse(
accessToken: r.key,
username: googleAuth.name,
gender: gender,
localeCode: languageCode,
);

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

return Right(user);
});
}

Future<_UserReqParam> _getGoogleAuth() async {
if (isIntegrationTest) {
return const _UserReqParam(
name: 'Test User',
accessToken: r'myquran_te$t_t0ken',
);
} else {
final googleAuth = await soccialAuth.signInWithGoogle();
final accessToken = googleAuth.credential?.accessToken ?? '';
final username = googleAuth.user?.displayName ?? '';
return _UserReqParam(
name: username,
accessToken: accessToken,
);
}
}
);

Future<Either<UserModelResponse, Exception>> signInWithApple(
String languageCode,
Gender gender,
) async {
final appleAuth = await _getAppleAuth();

final token = await client.postType(
apiConst.loginWithApple,
fromJson: TokenResponse.fromJson,
body: {'access_token': appleAuth.accessToken},
);
);

return token.fold(Left.new, (r) async {
final user = UserModelResponse(
accessToken: r.key,
username: appleAuth.name,
gender: gender,
localeCode: languageCode,
);

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

return Right(user);
});
}

Future<_UserReqParam> _getAppleAuth() async {
if (isIntegrationTest) {
return const _UserReqParam(
name: 'Test User',
accessToken: r'myquran_te$t_t0ken',
);
} else {
final appleAuth = await soccialAuth.signInWithApple();
final accessToken = appleAuth.credential?.accessToken ?? '';
final username = appleAuth.user?.displayName ?? '';
return _UserReqParam(
name: username,
accessToken: accessToken,
);
}
}

Future<Either<UserDataResponse, Exception>> saveUserData(UserEntity userEntity) {
return client.putType(
apiConst.putProfile(userEntity.accessToken),
fromJson: UserDataResponse.fromJson,
body: {
'gender': userEntity.gender.name.toUpperCase(),
'language': userEntity.localeCode.toUpperCase(),
},
);
}
Future<Either<UserDataResponse, Exception>> saveUserData(UserEntity userEntity);

Future<Either<UserDataResponse, Exception>> pathGender({
required String userId,
required Gender gender,
}) {
return client.patchType(
apiConst.putProfile(userId),
fromJson: UserDataResponse.fromJson,
body: {'gender': gender.name.toUpperCase()},
);
}
});

Future<Either<UserDataResponse, Exception>> pathLocaleCode({
required String userId,
required String localeCode,
}) {
return client.patchType(
apiConst.putProfile(userId),
fromJson: UserDataResponse.fromJson,
body: {'language': localeCode.toUpperCase()},
);
}

Future<void> logoutRemote() async {
await soccialAuth.logOut();
}
}

@immutable
final class _UserReqParam {
const _UserReqParam({
required this.name,
required this.accessToken,
});

final String name;
final String accessToken;
Future<void> logoutRemote();
}
15 changes: 15 additions & 0 deletions app/lib/app/data/source/local/app_local_data_source_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
import 'package:my_quran/app/app.dart';
import 'package:package_info_plus/package_info_plus.dart';

@immutable
final class AppLocalDataSourceImpl implements AppLocalDataSource {
const AppLocalDataSourceImpl({
required this.packageInfo,
});

final PackageInfo packageInfo;

@override
String get appVersion => packageInfo.version;
}
Loading
Loading