From 59df5bdce4b0ef3e24e34ac2bf9a72511ddce6e7 Mon Sep 17 00:00:00 2001 From: Aidaiym Date: Thu, 18 Jul 2024 14:13:27 +0600 Subject: [PATCH 1/2] add mock data source to app --- app/lib/app/data/data.dart | 10 +- .../data/source/auth_local_data_source.dart | 57 +---- .../data/source/auth_remote_data_source.dart | 143 +----------- .../app_local_data_source_impl.dart} | 0 .../local/auth_local_data_source_impl.dart | 59 +++++ .../local/theme_local_data_source_impl.dart | 34 +++ .../mock/auth_local_data_source_mock.dart | 33 +++ .../mock/auth_remote_data_source_mock.dart | 96 ++++++++ .../mock/theme_local_data_source_mock.dart | 19 ++ .../remote/auth_remote_data_source_impl.dart | 208 ++++++++++++++++++ .../data/source/theme_local_data_source.dart | 31 +-- app/lib/app/presentation/view/app_view.dart | 31 ++- app/lib/config/app_config.dart | 2 + app/test/widget_test.dart | 6 +- 14 files changed, 504 insertions(+), 225 deletions(-) rename app/lib/app/data/source/{app_local_data_source.dart => local/app_local_data_source_impl.dart} (100%) create mode 100644 app/lib/app/data/source/local/auth_local_data_source_impl.dart create mode 100644 app/lib/app/data/source/local/theme_local_data_source_impl.dart create mode 100644 app/lib/app/data/source/mock/auth_local_data_source_mock.dart create mode 100644 app/lib/app/data/source/mock/auth_remote_data_source_mock.dart create mode 100644 app/lib/app/data/source/mock/theme_local_data_source_mock.dart create mode 100644 app/lib/app/data/source/remote/auth_remote_data_source_impl.dart diff --git a/app/lib/app/data/data.dart b/app/lib/app/data/data.dart index 1619b9d1..797b28b2 100644 --- a/app/lib/app/data/data.dart +++ b/app/lib/app/data/data.dart @@ -1,10 +1,16 @@ 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/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/auth_local_data_source.dart'; export 'source/auth_remote_data_source.dart'; +export 'source/theme_local_data_source.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 'models/user_model.dart'; export 'models/token_response.dart'; export 'models/user_data_response.dart'; diff --git a/app/lib/app/data/source/auth_local_data_source.dart b/app/lib/app/data/source/auth_local_data_source.dart index faf8dccc..b3a4986a 100644 --- a/app/lib/app/data/source/auth_local_data_source.dart +++ b/app/lib/app/data/source/auth_local_data_source.dart @@ -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 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 saveGender(Gender gender) { - return storage.writeString( - key: StorageKeys.genderKey, - value: gender.name, - ); - } - - Future saveLocaleCode(String localeCode) { - return storage.writeString( - key: StorageKeys.localeKey, - value: localeCode, - ); - } - - Future logoutLocal() async { - await storage.clear(); - } +abstract class AuthLocalDataSource { + UserEntity? get init; + String? getToken(); + Future saveUserData(UserEntity userEntity); + Future saveGender(Gender gender); + Future saveLocaleCode(String localeCode); + Future logoutLocal(); } diff --git a/app/lib/app/data/source/auth_remote_data_source.dart b/app/lib/app/data/source/auth_remote_data_source.dart index 9ea94695..e5a57563 100644 --- a/app/lib/app/data/source/auth_remote_data_source.dart +++ b/app/lib/app/data/source/auth_remote_data_source.dart @@ -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 loginWithEmail(String email); - final MqDio client; - final PreferencesStorage storage; - final SoccialAuth soccialAuth; - final bool isIntegrationTest; + Future> fetchSmsCode({ + required String code, + required String languageCode, + required Gender gender, + }); Future> 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> 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> saveUserData(UserEntity userEntity) { - return client.putType( - apiConst.putProfile(userEntity.accessToken), - fromJson: UserDataResponse.fromJson, - body: { - 'gender': userEntity.gender.name.toUpperCase(), - 'language': userEntity.localeCode.toUpperCase(), - }, - ); - } + Future> saveUserData(UserEntity userEntity); Future> pathGender({ required String userId, required Gender gender, - }) { - return client.patchType( - apiConst.putProfile(userId), - fromJson: UserDataResponse.fromJson, - body: {'gender': gender.name.toUpperCase()}, - ); - } + }); Future> pathLocaleCode({ required String userId, required String localeCode, - }) { - return client.patchType( - apiConst.putProfile(userId), - fromJson: UserDataResponse.fromJson, - body: {'language': localeCode.toUpperCase()}, - ); - } - - Future logoutRemote() async { - await soccialAuth.logOut(); - } -} - -@immutable -final class _UserReqParam { - const _UserReqParam({ - required this.name, - required this.accessToken, }); - final String name; - final String accessToken; + Future logoutRemote(); } diff --git a/app/lib/app/data/source/app_local_data_source.dart b/app/lib/app/data/source/local/app_local_data_source_impl.dart similarity index 100% rename from app/lib/app/data/source/app_local_data_source.dart rename to app/lib/app/data/source/local/app_local_data_source_impl.dart diff --git a/app/lib/app/data/source/local/auth_local_data_source_impl.dart b/app/lib/app/data/source/local/auth_local_data_source_impl.dart new file mode 100644 index 00000000..8728965a --- /dev/null +++ b/app/lib/app/data/source/local/auth_local_data_source_impl.dart @@ -0,0 +1,59 @@ +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 AuthLocalDataSourceImpl implements AuthLocalDataSource { + const AuthLocalDataSourceImpl(this.storage); + + final PreferencesStorage storage; + + @override + 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', + ); + } + + @override + String? getToken() => storage.readString(key: StorageKeys.tokenKey); + + @override + Future 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), + ]); + } + + @override + Future saveGender(Gender gender) { + return storage.writeString( + key: StorageKeys.genderKey, + value: gender.name, + ); + } + + @override + Future saveLocaleCode(String localeCode) { + return storage.writeString( + key: StorageKeys.localeKey, + value: localeCode, + ); + } + + @override + Future logoutLocal() async { + await storage.clear(); + } +} diff --git a/app/lib/app/data/source/local/theme_local_data_source_impl.dart b/app/lib/app/data/source/local/theme_local_data_source_impl.dart new file mode 100644 index 00000000..c940617a --- /dev/null +++ b/app/lib/app/data/source/local/theme_local_data_source_impl.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:my_quran/app/app.dart'; +import 'package:my_quran/constants/contants.dart'; +import 'package:mq_storage/mq_storage.dart'; +import 'package:my_quran/theme/theme.dart'; + +@immutable +final class ThemeLocalDataSourceImpl implements ThemeLocalDataSource { + const ThemeLocalDataSourceImpl(this.storage); + final PreferencesStorage storage; + + @override + CustomTheme get initialTheme { + final isDark = storage.readBool(key: StorageKeys.modeKey); + final cachedColorIndex = storage.readInt(key: StorageKeys.colorKey); + final brightness = isDark != null ? (isDark ? Brightness.dark : Brightness.light) : Brightness.light; + final targetColor = _getColor(cachedColorIndex); + return CustomTheme(brightness, targetColor); + } + + @override + Future saveThemePrimaryColor(int index) async { + await storage.writeInt(key: StorageKeys.colorKey, value: index); + } + + @override + Future saveThemeMode({required bool isDark}) async { + await storage.writeBool(key: StorageKeys.modeKey, value: isDark); + } + + Color _getColor(int? cacheColor) { + return TargetColor.fromIndex(cacheColor ?? 0).color; + } +} diff --git a/app/lib/app/data/source/mock/auth_local_data_source_mock.dart b/app/lib/app/data/source/mock/auth_local_data_source_mock.dart new file mode 100644 index 00000000..12839ce0 --- /dev/null +++ b/app/lib/app/data/source/mock/auth_local_data_source_mock.dart @@ -0,0 +1,33 @@ +import 'package:meta/meta.dart'; +import 'package:my_quran/app/app.dart'; + +@immutable +final class AuthLocalDataSourceMock implements AuthLocalDataSource { + const AuthLocalDataSourceMock(); + + @override + UserEntity? get init { + return null; + } + + @override + String? getToken() => ''; + + @override + Future saveUserData(UserEntity userEntity) async {} + + @override + Future saveGender(Gender gender) { + return Future.value(); + } + + @override + Future saveLocaleCode(String localeCode) { + return Future.value(); + } + + @override + Future logoutLocal() async { + return Future.value(); + } +} diff --git a/app/lib/app/data/source/mock/auth_remote_data_source_mock.dart b/app/lib/app/data/source/mock/auth_remote_data_source_mock.dart new file mode 100644 index 00000000..0a9b7c45 --- /dev/null +++ b/app/lib/app/data/source/mock/auth_remote_data_source_mock.dart @@ -0,0 +1,96 @@ +import 'package:meta/meta.dart'; +import 'package:my_quran/app/app.dart'; + +import 'package:my_quran/core/core.dart'; + +@immutable +final class AuthRemoteDataSourceMock implements AuthRemoteDataSource { + const AuthRemoteDataSourceMock(); + + @override + Future loginWithEmail(String email) async { + return; + } + + @override + Future> fetchSmsCode({ + required String code, + required String languageCode, + required Gender gender, + }) async { + final user = UserModelResponse( + accessToken: r'myquran_te$t_t0ken', + username: 'Test User', + gender: gender, + localeCode: languageCode, + ); + + return Right(user); + } + + @override + Future> signInWithGoogle( + String languageCode, + Gender gender, + ) async { + final user = UserModelResponse( + accessToken: 'mock_token_google', + username: 'Mock Google User', + gender: gender, + localeCode: languageCode, + ); + return Right(user); + } + + @override + Future> signInWithApple( + String languageCode, + Gender gender, + ) async { + final user = UserModelResponse( + accessToken: 'mock_token_apple', + username: 'Mock Apple User', + gender: gender, + localeCode: languageCode, + ); + return Right(user); + } + + @override + Future> saveUserData(UserEntity userEntity) async { + final response = UserDataResponse( + gender: userEntity.gender.toString(), + language: userEntity.localeCode, + ); + return Right(response); + } + + @override + Future> pathGender({ + required String userId, + required Gender gender, + }) async { + final response = UserDataResponse( + gender: Gender.male.toString(), + language: 'en', + ); + return Right(response); + } + + @override + Future> pathLocaleCode({ + required String userId, + required String localeCode, + }) async { + final response = UserDataResponse( + gender: Gender.male.toString(), + language: 'en', + ); + return Right(response); + } + + @override + Future logoutRemote() async { + return; + } +} diff --git a/app/lib/app/data/source/mock/theme_local_data_source_mock.dart b/app/lib/app/data/source/mock/theme_local_data_source_mock.dart new file mode 100644 index 00000000..630660db --- /dev/null +++ b/app/lib/app/data/source/mock/theme_local_data_source_mock.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:my_quran/app/app.dart'; +import 'package:my_quran/theme/theme.dart'; + +@immutable +final class ThemeLocalDataSourceMock implements ThemeLocalDataSource { + const ThemeLocalDataSourceMock(); + + @override + CustomTheme get initialTheme { + return const CustomTheme(Brightness.light, Colors.red); + } + + @override + Future saveThemePrimaryColor(int index) async {} + + @override + Future saveThemeMode({required bool isDark}) async {} +} diff --git a/app/lib/app/data/source/remote/auth_remote_data_source_impl.dart b/app/lib/app/data/source/remote/auth_remote_data_source_impl.dart new file mode 100644 index 00000000..3d4615b7 --- /dev/null +++ b/app/lib/app/data/source/remote/auth_remote_data_source_impl.dart @@ -0,0 +1,208 @@ +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 AuthRemoteDataSourceImpl implements AuthRemoteDataSource { + const AuthRemoteDataSourceImpl({ + required this.client, + required this.storage, + required this.soccialAuth, + required this.isIntegrationTest, + }); + + final MqDio client; + final PreferencesStorage storage; + final SoccialAuth soccialAuth; + final bool isIntegrationTest; + + @override + Future> 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, + ); + } + } + + @override + Future> 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, + ); + } + } + + @override + Future> saveUserData(UserEntity userEntity) { + return client.putType( + apiConst.putProfile(userEntity.accessToken), + fromJson: UserDataResponse.fromJson, + body: { + 'gender': userEntity.gender.name.toUpperCase(), + 'language': userEntity.localeCode.toUpperCase(), + }, + ); + } + + @override + Future> pathGender({ + required String userId, + required Gender gender, + }) { + return client.patchType( + apiConst.putProfile(userId), + fromJson: UserDataResponse.fromJson, + body: {'gender': gender.name.toUpperCase()}, + ); + } + + @override + Future> pathLocaleCode({ + required String userId, + required String localeCode, + }) { + return client.patchType( + apiConst.putProfile(userId), + fromJson: UserDataResponse.fromJson, + body: {'language': localeCode.toUpperCase()}, + ); + } + + @override + Future logoutRemote() async { + await soccialAuth.logOut(); + } + + @override + Future> 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 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 +final class _UserReqParam { + const _UserReqParam({ + required this.name, + required this.accessToken, + }); + + final String name; + final String accessToken; +} diff --git a/app/lib/app/data/source/theme_local_data_source.dart b/app/lib/app/data/source/theme_local_data_source.dart index 3c33c02e..0ead7590 100644 --- a/app/lib/app/data/source/theme_local_data_source.dart +++ b/app/lib/app/data/source/theme_local_data_source.dart @@ -1,30 +1,7 @@ -import 'package:flutter/material.dart'; -import 'package:my_quran/constants/contants.dart'; -import 'package:mq_storage/mq_storage.dart'; import 'package:my_quran/theme/theme.dart'; -@immutable -final class ThemeLocalDataSource { - const ThemeLocalDataSource(this.storage); - final PreferencesStorage storage; - - CustomTheme get initialTheme { - final isDark = storage.readBool(key: StorageKeys.modeKey); - final cachedColorIndex = storage.readInt(key: StorageKeys.colorKey); - final brightness = isDark != null ? (isDark ? Brightness.dark : Brightness.light) : Brightness.light; - final targetColor = _getColor(cachedColorIndex); - return CustomTheme(brightness, targetColor); - } - - Future saveThemePrimaryColor(int index) async { - await storage.writeInt(key: StorageKeys.colorKey, value: index); - } - - Future saveThemeMode({required bool isDark}) async { - await storage.writeBool(key: StorageKeys.modeKey, value: isDark); - } - - Color _getColor(int? cacheColor) { - return TargetColor.fromIndex(cacheColor ?? 0).color; - } +abstract class ThemeLocalDataSource { + CustomTheme get initialTheme; + Future saveThemePrimaryColor(int index); + Future saveThemeMode({required bool isDark}); } diff --git a/app/lib/app/presentation/view/app_view.dart b/app/lib/app/presentation/view/app_view.dart index e2522852..b89ba96c 100644 --- a/app/lib/app/presentation/view/app_view.dart +++ b/app/lib/app/presentation/view/app_view.dart @@ -17,6 +17,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { + final isMockData = context.read().isMockData; return MultiBlocProvider( providers: [ RepositoryProvider( @@ -28,7 +29,9 @@ class MyApp extends StatelessWidget { ), RepositoryProvider( create: (context) => ThemeRepositoryImpl( - ThemeLocalDataSource(context.read()), + isMockData + ? const ThemeLocalDataSourceMock() + : ThemeLocalDataSourceImpl(context.read()), ), ), BlocProvider( @@ -40,17 +43,21 @@ class MyApp extends StatelessWidget { ), ), RepositoryProvider( - create: (context) => AuthRepositoryImpl( - localDataSource: AuthLocalDataSource( - context.read(), - ), - remoteDataSource: AuthRemoteDataSource( - client: context.read(), - storage: context.read(), - soccialAuth: context.read(), - isIntegrationTest: context.read().isIntegrationTest, - ), - ), + create: (context) { + return AuthRepositoryImpl( + localDataSource: isMockData + ? const AuthLocalDataSourceMock() + : AuthLocalDataSourceImpl(context.read()), + remoteDataSource: isMockData + ? const AuthRemoteDataSourceMock() + : AuthRemoteDataSourceImpl( + client: context.read(), + storage: context.read(), + soccialAuth: context.read(), + isIntegrationTest: context.read().isIntegrationTest, + ), + ); + }, ), BlocProvider( create: (context) => AuthCubit( diff --git a/app/lib/config/app_config.dart b/app/lib/config/app_config.dart index 81c66e0d..3b335e3a 100644 --- a/app/lib/config/app_config.dart +++ b/app/lib/config/app_config.dart @@ -7,9 +7,11 @@ final class AppConfig { const AppConfig({ this.storage, this.isIntegrationTest = false, + this.isMockData = false, }); final bool isIntegrationTest; + final bool isMockData; final PreferencesStorage? storage; diff --git a/app/test/widget_test.dart b/app/test/widget_test.dart index 7b154882..97ab9912 100644 --- a/app/test/widget_test.dart +++ b/app/test/widget_test.dart @@ -19,10 +19,10 @@ void main() { final homeRepo = MockHomeRepositoryImpl(); final appLocalDataSource = AppLocalDataSource(packageInfo: packageInfo); final appRepository = AppRepositoryImpl(appLocalDataSource); - final themeRepository = ThemeRepositoryImpl(ThemeLocalDataSource(storage)); + final themeRepository = ThemeRepositoryImpl(ThemeLocalDataSourceImpl(storage)); final authRepository = AuthRepositoryImpl( - localDataSource: AuthLocalDataSource(storage), - remoteDataSource: AuthRemoteDataSource( + localDataSource: AuthLocalDataSourceImpl(storage), + remoteDataSource: AuthRemoteDataSourceImpl( client: remoteClient, storage: storage, soccialAuth: MockSccialAuth(), From d1a1328798bed6f9b2bed3e531132a864b710e50 Mon Sep 17 00:00:00 2001 From: Eldar2021 Date: Sat, 20 Jul 2024 12:38:35 +0600 Subject: [PATCH 2/2] Refactored --- app/lib/app/data/data.dart | 8 ++- .../data/repository/auth_repositoty_impl.dart | 60 +++++++------------ .../repository/theme_repository_impl.dart | 4 +- .../data/source/app_local_data_source.dart | 3 + .../local/app_local_data_source_impl.dart | 6 +- .../local/theme_local_data_source_impl.dart | 2 +- .../mock/app_local_data_source_mock.dart | 10 ++++ .../mock/auth_local_data_source_mock.dart | 16 ++--- .../mock/auth_remote_data_source_mock.dart | 8 +-- .../mock/theme_local_data_source_mock.dart | 4 +- .../app/domain/entity/user_data_entity.dart | 4 +- app/lib/app/domain/entity/user_entity.dart | 13 +++- app/lib/app/presentation/view/app_view.dart | 6 +- app/test/widget_test.dart | 2 +- 14 files changed, 71 insertions(+), 75 deletions(-) create mode 100644 app/lib/app/data/source/app_local_data_source.dart create mode 100644 app/lib/app/data/source/mock/app_local_data_source_mock.dart diff --git a/app/lib/app/data/data.dart b/app/lib/app/data/data.dart index 797b28b2..81307378 100644 --- a/app/lib/app/data/data.dart +++ b/app/lib/app/data/data.dart @@ -1,16 +1,18 @@ export 'repository/app_repositoty_impl.dart'; export 'repository/theme_repository_impl.dart'; export 'repository/auth_repositoty_impl.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/auth_local_data_source.dart'; -export 'source/auth_remote_data_source.dart'; -export 'source/theme_local_data_source.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'; diff --git a/app/lib/app/data/repository/auth_repositoty_impl.dart b/app/lib/app/data/repository/auth_repositoty_impl.dart index fab4875c..7b4ac921 100644 --- a/app/lib/app/data/repository/auth_repositoty_impl.dart +++ b/app/lib/app/data/repository/auth_repositoty_impl.dart @@ -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 setUserData(UserEntity userEntity) async { @@ -35,24 +33,18 @@ 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 @@ -60,24 +52,18 @@ final class AuthRepositoryImpl implements AuthRepository { 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 diff --git a/app/lib/app/data/repository/theme_repository_impl.dart b/app/lib/app/data/repository/theme_repository_impl.dart index a24e259b..59cd2633 100644 --- a/app/lib/app/data/repository/theme_repository_impl.dart +++ b/app/lib/app/data/repository/theme_repository_impl.dart @@ -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 saveThemePrimaryColor(int index) async { diff --git a/app/lib/app/data/source/app_local_data_source.dart b/app/lib/app/data/source/app_local_data_source.dart new file mode 100644 index 00000000..5ea06698 --- /dev/null +++ b/app/lib/app/data/source/app_local_data_source.dart @@ -0,0 +1,3 @@ +abstract class AppLocalDataSource { + String get appVersion; +} diff --git a/app/lib/app/data/source/local/app_local_data_source_impl.dart b/app/lib/app/data/source/local/app_local_data_source_impl.dart index ab7d599b..8f8ad093 100644 --- a/app/lib/app/data/source/local/app_local_data_source_impl.dart +++ b/app/lib/app/data/source/local/app_local_data_source_impl.dart @@ -1,13 +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 AppLocalDataSource { - const AppLocalDataSource({ +final class AppLocalDataSourceImpl implements AppLocalDataSource { + const AppLocalDataSourceImpl({ required this.packageInfo, }); final PackageInfo packageInfo; + @override String get appVersion => packageInfo.version; } diff --git a/app/lib/app/data/source/local/theme_local_data_source_impl.dart b/app/lib/app/data/source/local/theme_local_data_source_impl.dart index c940617a..c6394e97 100644 --- a/app/lib/app/data/source/local/theme_local_data_source_impl.dart +++ b/app/lib/app/data/source/local/theme_local_data_source_impl.dart @@ -13,7 +13,7 @@ final class ThemeLocalDataSourceImpl implements ThemeLocalDataSource { CustomTheme get initialTheme { final isDark = storage.readBool(key: StorageKeys.modeKey); final cachedColorIndex = storage.readInt(key: StorageKeys.colorKey); - final brightness = isDark != null ? (isDark ? Brightness.dark : Brightness.light) : Brightness.light; + final brightness = (isDark ?? false) ? Brightness.dark : Brightness.light; final targetColor = _getColor(cachedColorIndex); return CustomTheme(brightness, targetColor); } diff --git a/app/lib/app/data/source/mock/app_local_data_source_mock.dart b/app/lib/app/data/source/mock/app_local_data_source_mock.dart new file mode 100644 index 00000000..203b9cbc --- /dev/null +++ b/app/lib/app/data/source/mock/app_local_data_source_mock.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; +import 'package:my_quran/app/app.dart'; + +@immutable +final class AppLocalDataSourceMock implements AppLocalDataSource { + const AppLocalDataSourceMock(); + + @override + String get appVersion => '1.3.1'; +} diff --git a/app/lib/app/data/source/mock/auth_local_data_source_mock.dart b/app/lib/app/data/source/mock/auth_local_data_source_mock.dart index 12839ce0..caa6d55b 100644 --- a/app/lib/app/data/source/mock/auth_local_data_source_mock.dart +++ b/app/lib/app/data/source/mock/auth_local_data_source_mock.dart @@ -6,9 +6,7 @@ final class AuthLocalDataSourceMock implements AuthLocalDataSource { const AuthLocalDataSourceMock(); @override - UserEntity? get init { - return null; - } + UserEntity? get init => null; @override String? getToken() => ''; @@ -17,17 +15,11 @@ final class AuthLocalDataSourceMock implements AuthLocalDataSource { Future saveUserData(UserEntity userEntity) async {} @override - Future saveGender(Gender gender) { - return Future.value(); - } + Future saveGender(Gender gender) => Future.value(); @override - Future saveLocaleCode(String localeCode) { - return Future.value(); - } + Future saveLocaleCode(String localeCode) => Future.value(); @override - Future logoutLocal() async { - return Future.value(); - } + Future logoutLocal() async => Future.value(); } diff --git a/app/lib/app/data/source/mock/auth_remote_data_source_mock.dart b/app/lib/app/data/source/mock/auth_remote_data_source_mock.dart index 0a9b7c45..7848cbe8 100644 --- a/app/lib/app/data/source/mock/auth_remote_data_source_mock.dart +++ b/app/lib/app/data/source/mock/auth_remote_data_source_mock.dart @@ -8,9 +8,7 @@ final class AuthRemoteDataSourceMock implements AuthRemoteDataSource { const AuthRemoteDataSourceMock(); @override - Future loginWithEmail(String email) async { - return; - } + Future loginWithEmail(String email) async {} @override Future> fetchSmsCode({ @@ -90,7 +88,5 @@ final class AuthRemoteDataSourceMock implements AuthRemoteDataSource { } @override - Future logoutRemote() async { - return; - } + Future logoutRemote() async {} } diff --git a/app/lib/app/data/source/mock/theme_local_data_source_mock.dart b/app/lib/app/data/source/mock/theme_local_data_source_mock.dart index 630660db..c21948cc 100644 --- a/app/lib/app/data/source/mock/theme_local_data_source_mock.dart +++ b/app/lib/app/data/source/mock/theme_local_data_source_mock.dart @@ -7,9 +7,7 @@ final class ThemeLocalDataSourceMock implements ThemeLocalDataSource { const ThemeLocalDataSourceMock(); @override - CustomTheme get initialTheme { - return const CustomTheme(Brightness.light, Colors.red); - } + CustomTheme get initialTheme => const CustomTheme(Brightness.light, AppColors.red); @override Future saveThemePrimaryColor(int index) async {} diff --git a/app/lib/app/domain/entity/user_data_entity.dart b/app/lib/app/domain/entity/user_data_entity.dart index aeb007ee..ea04b375 100644 --- a/app/lib/app/domain/entity/user_data_entity.dart +++ b/app/lib/app/domain/entity/user_data_entity.dart @@ -11,9 +11,7 @@ final class UserDataEntity { final String gender; final String language; - Gender get genderValue { - return gender.toLowerCase() == 'male' ? Gender.male : Gender.female; - } + Gender get genderValue => Gender.fromData(gender.toLowerCase()); String get localeValue => language.toLowerCase(); } diff --git a/app/lib/app/domain/entity/user_entity.dart b/app/lib/app/domain/entity/user_entity.dart index d4e3c168..88dd9952 100644 --- a/app/lib/app/domain/entity/user_entity.dart +++ b/app/lib/app/domain/entity/user_entity.dart @@ -29,4 +29,15 @@ final class UserEntity { } } -enum Gender { male, female } +enum Gender { + male, + female; + + factory Gender.fromData(String? src) { + return switch (src) { + 'male' => Gender.male, + 'female' => Gender.female, + _ => Gender.male, + }; + } +} diff --git a/app/lib/app/presentation/view/app_view.dart b/app/lib/app/presentation/view/app_view.dart index b89ba96c..94d38484 100644 --- a/app/lib/app/presentation/view/app_view.dart +++ b/app/lib/app/presentation/view/app_view.dart @@ -22,9 +22,9 @@ class MyApp extends StatelessWidget { providers: [ RepositoryProvider( create: (context) => AppRepositoryImpl( - AppLocalDataSource( - packageInfo: context.read(), - ), + isMockData + ? const AppLocalDataSourceMock() + : AppLocalDataSourceImpl(packageInfo: context.read()), ), ), RepositoryProvider( diff --git a/app/test/widget_test.dart b/app/test/widget_test.dart index 97ab9912..0b864e79 100644 --- a/app/test/widget_test.dart +++ b/app/test/widget_test.dart @@ -17,7 +17,7 @@ void main() { final remoteConfig = MockMqRemoteConfig(); final homeRepo = MockHomeRepositoryImpl(); - final appLocalDataSource = AppLocalDataSource(packageInfo: packageInfo); + final appLocalDataSource = AppLocalDataSourceImpl(packageInfo: packageInfo); final appRepository = AppRepositoryImpl(appLocalDataSource); final themeRepository = ThemeRepositoryImpl(ThemeLocalDataSourceImpl(storage)); final authRepository = AuthRepositoryImpl(