diff --git a/app/lib/app/services/app_service.dart b/app/lib/app/services/app_service.dart index 02314588..77556394 100644 --- a/app/lib/app/services/app_service.dart +++ b/app/lib/app/services/app_service.dart @@ -13,15 +13,15 @@ final class AppService { final PreferencesStorage storage; Locale get init { - final code = storage.readString(key: AppConst.localeKey); + final code = storage.readString(key: StorageKeys.localeKey); if (code != null) return Locale(code); // ignore: deprecated_member_use final deviceLocal = window.locale.languageCode; - return AppLocalizations.delegate.isSupported(Locale(deviceLocal)) ? Locale(deviceLocal) : const Locale('en'); + return AppLocalizationHelper.getSupportedLocale(deviceLocal); } Future setLocale(String langKey) async { - await storage.writeString(key: AppConst.localeKey, value: langKey); + await storage.writeString(key: StorageKeys.localeKey, value: langKey); return Locale(langKey); } } diff --git a/app/lib/app/services/auth_service.dart b/app/lib/app/services/auth_service.dart index e024ce59..74eb66ca 100644 --- a/app/lib/app/services/auth_service.dart +++ b/app/lib/app/services/auth_service.dart @@ -14,9 +14,9 @@ final class AuthService { final RemoteClient client; User? get init { - final userToken = storage.readString(key: AppConst.tokenKey); - final userGender = storage.readString(key: AppConst.genderKey); - final username = storage.readString(key: AppConst.usernameKey); + final userToken = storage.readString(key: StorageKeys.tokenKey); + final userGender = storage.readString(key: StorageKeys.genderKey); + final username = storage.readString(key: StorageKeys.usernameKey); if (userToken == null && userGender == null && username == null) return null; return User( accessToken: userToken!, @@ -25,7 +25,7 @@ final class AuthService { ); } - String? getToken() => storage.readString(key: AppConst.tokenKey); + String? getToken() => storage.readString(key: StorageKeys.tokenKey); Future> login(String languageCode, Gender gender) async { final user = await client.post( @@ -41,15 +41,18 @@ final class AuthService { Left.new, (r) async { final user = r.copyWith(gender: gender); - await storage.writeString(key: AppConst.tokenKey, value: user.accessToken); - await storage.writeString(key: AppConst.genderKey, value: user.gender!.name); - await storage.writeString(key: AppConst.usernameKey, value: user.username); + await Future.wait([ + storage.writeString(key: StorageKeys.tokenKey, value: user.accessToken), + storage.writeString(key: StorageKeys.genderKey, value: user.gender!.name), + storage.writeString(key: StorageKeys.usernameKey, value: user.username), + ]); + return Right(user); }, ); } Future changeGender(Gender gender) async { - await storage.writeString(key: AppConst.genderKey, value: gender.name); + await storage.writeString(key: StorageKeys.genderKey, value: gender.name); } } diff --git a/app/lib/app/services/theme_service.dart b/app/lib/app/services/theme_service.dart index 451fcfad..295cd61f 100644 --- a/app/lib/app/services/theme_service.dart +++ b/app/lib/app/services/theme_service.dart @@ -1,17 +1,17 @@ import 'package:flutter/material.dart'; import 'package:mq_storage/mq_storage.dart'; import 'package:my_quran/constants/contants.dart'; - import 'package:my_quran/theme/theme.dart'; -class ThemeService { +@immutable +final class ThemeService { const ThemeService(this.storage); final PreferencesStorage storage; CustomTheme get init { - final isDark = storage.readBool(key: AppConst.modeKey); - final cachedColorIndex = storage.readInt(key: AppConst.colorKey); + final isDark = storage.readBool(key: StorageKeys.modeKey); + final cachedColorIndex = storage.readInt(key: StorageKeys.colorKey); return switch (isDark) { true => CustomTheme(Brightness.dark, _getColor(cachedColorIndex)), _ => CustomTheme(Brightness.light, _getColor(cachedColorIndex)), @@ -23,10 +23,10 @@ class ThemeService { } Future setColor(int index) async { - await storage.writeInt(key: AppConst.colorKey, value: index); + await storage.writeInt(key: StorageKeys.colorKey, value: index); } Future setMode({required bool isDark}) async { - await storage.writeBool(key: AppConst.modeKey, value: isDark); + await storage.writeBool(key: StorageKeys.modeKey, value: isDark); } } diff --git a/app/lib/app_observer.dart b/app/lib/app_observer.dart index 5fd8fbe7..d8ae21a2 100644 --- a/app/lib/app_observer.dart +++ b/app/lib/app_observer.dart @@ -1,29 +1,31 @@ -import 'dart:developer'; - import 'package:flutter_bloc/flutter_bloc.dart'; class AppBlocObserver extends BlocObserver { + const AppBlocObserver({this.onLog}); + + final void Function(String log)? onLog; + @override void onCreate(BlocBase bloc) { super.onCreate(bloc); - log('onCreate(${bloc.state})'); + onLog?.call('onCreate(${bloc.state})'); } @override void onChange(BlocBase bloc, Change change) { super.onChange(bloc, change); - log('onChange(${bloc.runtimeType}, $change)'); + onLog?.call('onChange(${bloc.runtimeType}, $change)'); } @override void onError(BlocBase bloc, Object error, StackTrace stackTrace) { - log('onError(${bloc.runtimeType}, $error, $stackTrace)'); + onLog?.call('onError(${bloc.runtimeType}, $error, $stackTrace)'); super.onError(bloc, error, stackTrace); } @override void onClose(BlocBase bloc) { super.onClose(bloc); - log('onClose(${bloc.runtimeType})'); + onLog?.call('onClose(${bloc.runtimeType})'); } } diff --git a/app/lib/components/card/select_lang_list.dart b/app/lib/components/card/select_lang_list.dart index 6cc49740..4c8dd1ed 100644 --- a/app/lib/components/card/select_lang_list.dart +++ b/app/lib/components/card/select_lang_list.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:mq_ci_keys/mq_ci_keys.dart'; - import 'package:my_quran/app/app.dart'; -import 'package:my_quran/constants/contants.dart'; +import 'package:my_quran/l10n/l10.dart'; class SelectLangFromListViewBuilder extends StatelessWidget { const SelectLangFromListViewBuilder({super.key}); @@ -13,10 +12,10 @@ class SelectLangFromListViewBuilder extends StatelessWidget { final appCubit = context.watch(); final colorScheme = Theme.of(context).colorScheme; return ListView.builder( - itemCount: AppConst.locales.length, + itemCount: AppLocalizationHelper.locales.length, itemBuilder: (BuildContext context, int index) { - final locale = AppConst.locales[index]; - final langName = AppConst.getName(locale.toLanguageTag()); + final locale = AppLocalizationHelper.locales[index]; + final langName = AppLocalizationHelper.getName(locale.toLanguageTag()); return Card( child: ListTile( key: Key(MqKeys.languageCode(locale.languageCode)), diff --git a/app/lib/constants/app/app_const.dart b/app/lib/constants/app/app_const.dart deleted file mode 100644 index 64b6b41a..00000000 --- a/app/lib/constants/app/app_const.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:my_quran/config/app_config.dart'; - -class AppConst { - const AppConst._(); - - static const bismallah = 'بِسْمِ ٱللَّهِ ٱلرَّحْمَـٰنِ ٱلرَّحِيمِ'; - static const sajdaSymbol = '۩'; - static const sajdaAyats = [1160, 1722, 1951, 2138, 2308, 2613, 2672, 2915, 3185, 3518, 3994, 4256, 4846, 5905, 6125]; - - /* - yes - https://api.quran.com/api/v4/quran/verses/uthmanit?page_number=1 has sajda symbol ۩ - correct - check from mushaf - 1. 1160(ayat id) - 176 page - аль-Араф:206 (yes) (correct) - 2. 1722(ayat id) - 251 page - ар-Рад:15 (yes) (correct) - 3. 1951(ayat id) - 272 page - ан-Нахль:50 (yes) (correct) - 4. 2138(ayat id) - 293 page - аль-Исра:109 (yes) (correct) - 5. 2308(ayat id) - 309 page - Марьям:58 (yes) (correct) - 6. 2613(ayat id) - 334 page - аль-Хадж:18 (yes) (correct) - 7. 2672(ayat id) - 341 page - аль-Хадж:77 (yes) (correct) - 8. 2915(ayat id) - 365 page - аль-Фуркан:60 (yes) (correct) - 9. 3185(ayat id) - 379 page - ан-Намль:26 (yes) (correct) - 10. 3518(ayat id) - 416 page - ас-Сажда:15 (yes) (correct) - 11. 3994(ayat id) - 454 page - Сад:24 (yes) (correct) - 12. 4256(ayat id) - 480 page - Фуссилят:38 (yes) (correct) - 13. 4846(ayat id) - 528 page - ан-Наджм:62 (yes) (correct) - 14. 5905(ayat id) - 589 page - аль-Иншикак:21 (yes) (correct) - 16. 6125(ayat id) - 597 page - аль-Аляк:19 (yes) (correct) - */ - - static String get localeKey => apiConst.isDevmode ? _localeKeyDev : _localeKey; - static String get tokenKey => apiConst.isDevmode ? _tokenKeyDev : _tokenKey; - static String get genderKey => apiConst.isDevmode ? _genderKeyDev : _genderKey; - static String get usernameKey => apiConst.isDevmode ? _usernameKeyDev : _usernameKey; - static String get modeKey => apiConst.isDevmode ? _modeKeyDev : _modeKey; - static String get readThemeKey => apiConst.isDevmode ? _readThemeKeyDev : _readThemeKey; - static String get colorKey => apiConst.isDevmode ? _colorKeyDev : _colorKey; - - static const _localeKey = 'locale'; - static const _tokenKey = 'token'; - static const _genderKey = 'gender'; - static const _usernameKey = 'username'; - static const _modeKey = 'mode'; - static const _readThemeKey = 'readThemeKey'; - static const _colorKey = 'color'; - - static const _localeKeyDev = 'locale-dev'; - static const _tokenKeyDev = 'token-dev'; - static const _genderKeyDev = 'gender-dev'; - static const _usernameKeyDev = 'username-dev'; - static const _modeKeyDev = 'mode-dev'; - static const _readThemeKeyDev = 'readThemeKey-dev'; - static const _colorKeyDev = 'color-dev'; - - static const locales = [ - Locale('en'), - Locale('ky'), - Locale('kk'), - Locale('tr'), - Locale('ar'), - Locale('id'), - Locale('ru'), - ]; - - static String getName(String code) { - return switch (code) { - 'en' => 'English', - 'ky' => 'Кыргызча', - 'tr' => 'Türkçe', - 'kk' => 'Қазақша', - 'ru' => 'Русский', - 'id' => 'Indonesia', - 'ar' => 'العربية', - _ => 'English', - }; - } - - static bool isLocalSupport(String deviceLocal) { - return switch (deviceLocal) { - 'en' || 'ky' || 'tr' || 'kk' || 'ru' || 'id' || 'ar' => true, - _ => false, - }; - } -} diff --git a/app/lib/constants/contants.dart b/app/lib/constants/contants.dart index 20b35255..bfb1ec36 100644 --- a/app/lib/constants/contants.dart +++ b/app/lib/constants/contants.dart @@ -1,4 +1,5 @@ export 'api/api_const.dart'; -export 'app/app_const.dart'; export 'assets/assets.gen.dart'; export 'assets/fonts.gen.dart'; +export 'keys/storage_keys.dart'; +export 'static/app_static.dart'; diff --git a/app/lib/constants/keys/storage_keys.dart b/app/lib/constants/keys/storage_keys.dart new file mode 100644 index 00000000..1e2d63f1 --- /dev/null +++ b/app/lib/constants/keys/storage_keys.dart @@ -0,0 +1,31 @@ +import 'package:meta/meta.dart'; +import 'package:my_quran/config/config.dart'; + +@immutable +final class StorageKeys { + const StorageKeys._(); + + static String get localeKey => apiConst.isDevmode ? _localeKeyDev : _localeKey; + static String get tokenKey => apiConst.isDevmode ? _tokenKeyDev : _tokenKey; + static String get genderKey => apiConst.isDevmode ? _genderKeyDev : _genderKey; + static String get usernameKey => apiConst.isDevmode ? _usernameKeyDev : _usernameKey; + static String get modeKey => apiConst.isDevmode ? _modeKeyDev : _modeKey; + static String get readThemeKey => apiConst.isDevmode ? _readThemeKeyDev : _readThemeKey; + static String get colorKey => apiConst.isDevmode ? _colorKeyDev : _colorKey; + + static const _localeKey = 'locale'; + static const _tokenKey = 'token'; + static const _genderKey = 'gender'; + static const _usernameKey = 'username'; + static const _modeKey = 'mode'; + static const _readThemeKey = 'readThemeKey'; + static const _colorKey = 'color'; + + static const _localeKeyDev = 'locale-dev'; + static const _tokenKeyDev = 'token-dev'; + static const _genderKeyDev = 'gender-dev'; + static const _usernameKeyDev = 'username-dev'; + static const _modeKeyDev = 'mode-dev'; + static const _readThemeKeyDev = 'readThemeKey-dev'; + static const _colorKeyDev = 'color-dev'; +} diff --git a/app/lib/constants/static/app_static.dart b/app/lib/constants/static/app_static.dart new file mode 100644 index 00000000..5ec33aec --- /dev/null +++ b/app/lib/constants/static/app_static.dart @@ -0,0 +1,46 @@ +import 'package:meta/meta.dart'; + +@immutable +final class AppStatic { + const AppStatic._(); + + static const bismallah = 'بِسْمِ ٱللَّهِ ٱلرَّحْمَـٰنِ ٱلرَّحِيمِ'; + static const sajdaSymbol = '۩'; + static const sajdaAyats = [ + 1160, + 1722, + 1951, + 2138, + 2308, + 2613, + 2672, + 2915, + 3185, + 3518, + 3994, + 4256, + 4846, + 5905, + 6125, + ]; + + /* + yes - https://api.quran.com/api/v4/quran/verses/uthmanit?page_number=1 has sajda symbol ۩ + correct - check from mushaf + 1. 1160(ayat id) - 176 page - аль-Араф:206 (yes) (correct) + 2. 1722(ayat id) - 251 page - ар-Рад:15 (yes) (correct) + 3. 1951(ayat id) - 272 page - ан-Нахль:50 (yes) (correct) + 4. 2138(ayat id) - 293 page - аль-Исра:109 (yes) (correct) + 5. 2308(ayat id) - 309 page - Марьям:58 (yes) (correct) + 6. 2613(ayat id) - 334 page - аль-Хадж:18 (yes) (correct) + 7. 2672(ayat id) - 341 page - аль-Хадж:77 (yes) (correct) + 8. 2915(ayat id) - 365 page - аль-Фуркан:60 (yes) (correct) + 9. 3185(ayat id) - 379 page - ан-Намль:26 (yes) (correct) + 10. 3518(ayat id) - 416 page - ас-Сажда:15 (yes) (correct) + 11. 3994(ayat id) - 454 page - Сад:24 (yes) (correct) + 12. 4256(ayat id) - 480 page - Фуссилят:38 (yes) (correct) + 13. 4846(ayat id) - 528 page - ан-Наджм:62 (yes) (correct) + 14. 5905(ayat id) - 589 page - аль-Иншикак:21 (yes) (correct) + 16. 6125(ayat id) - 597 page - аль-Аляк:19 (yes) (correct) + */ +} diff --git a/app/lib/core/client/remote_client.dart b/app/lib/core/client/remote_client.dart index 37514c2c..846c12a4 100644 --- a/app/lib/core/client/remote_client.dart +++ b/app/lib/core/client/remote_client.dart @@ -40,7 +40,7 @@ class RemoteClient { /// if an Unauthorized return Authentication Exception } else if (response.statusCode == 401) { - return const Left(AuthenticationException()); + return const Left(AuthenticationExc()); } else { /// if the response is not successful and unauthorized, it will return a server exception return const Left(ServerExc('server exception')); diff --git a/app/lib/core/core.dart b/app/lib/core/core.dart index 33878be5..4a43d4f9 100644 --- a/app/lib/core/core.dart +++ b/app/lib/core/core.dart @@ -1,9 +1,9 @@ export 'client/network_client.dart'; export 'client/remote_client.dart'; +export 'either/either.dart'; export 'exceptions/network_exception.dart'; export 'exceptions/server_exception.dart'; export 'exceptions/auth_exception.dart'; export 'exceptions/convert_exception.dart'; export 'launch/app_launch.dart'; -export 'interface/either.dart'; export 'enums/fetch_status.dart'; diff --git a/app/lib/core/interface/either.dart b/app/lib/core/either/either.dart similarity index 97% rename from app/lib/core/interface/either.dart rename to app/lib/core/either/either.dart index c9f7c401..e46f4281 100644 --- a/app/lib/core/interface/either.dart +++ b/app/lib/core/either/either.dart @@ -49,7 +49,7 @@ abstract class Either { /// } /// ``` @immutable -class Right extends Either { +final class Right extends Either { const Right(this.r); /// A field is defined to hold the right value. @@ -62,6 +62,7 @@ class Right extends Either { /// Equality check is defined for operator == and hashCode is computed for hashing. @override bool operator ==(Object other) => other is Right && other.r == r; + @override int get hashCode => r.hashCode; } @@ -81,7 +82,7 @@ class Right extends Either { /// } /// ``` @immutable -class Left extends Either { +final class Left extends Either { const Left(this.l); /// A field is defined to hold the left value. @@ -94,6 +95,7 @@ class Left extends Either { /// Equality check is defined for operator == and hashCode is computed for hashing. @override bool operator ==(Object other) => other is Left && other.l == l; + @override int get hashCode => l.hashCode; } diff --git a/app/lib/core/exceptions/auth_exception.dart b/app/lib/core/exceptions/auth_exception.dart index 2cf96f58..9b56b976 100644 --- a/app/lib/core/exceptions/auth_exception.dart +++ b/app/lib/core/exceptions/auth_exception.dart @@ -1,6 +1,8 @@ -/// Auhtentication Exception -class AuthenticationException implements Exception { - const AuthenticationException({this.message}); +import 'package:meta/meta.dart'; + +@immutable +final class AuthenticationExc implements Exception { + const AuthenticationExc({this.message}); final String? message; diff --git a/app/lib/core/exceptions/convert_exception.dart b/app/lib/core/exceptions/convert_exception.dart index d41b8494..c60570c1 100644 --- a/app/lib/core/exceptions/convert_exception.dart +++ b/app/lib/core/exceptions/convert_exception.dart @@ -1,5 +1,7 @@ -/// Convert Exception -class ConvertExc implements Exception { +import 'package:meta/meta.dart'; + +@immutable +final class ConvertExc implements Exception { const ConvertExc({this.message}); final String? message; diff --git a/app/lib/core/exceptions/network_exception.dart b/app/lib/core/exceptions/network_exception.dart index 4d064139..f201ddb4 100644 --- a/app/lib/core/exceptions/network_exception.dart +++ b/app/lib/core/exceptions/network_exception.dart @@ -1,4 +1,7 @@ -class NetworkExc implements Exception { +import 'package:meta/meta.dart'; + +@immutable +final class NetworkExc implements Exception { const NetworkExc([this.massage]); final String? massage; diff --git a/app/lib/core/exceptions/server_exception.dart b/app/lib/core/exceptions/server_exception.dart index 9a0858c4..bfb07228 100644 --- a/app/lib/core/exceptions/server_exception.dart +++ b/app/lib/core/exceptions/server_exception.dart @@ -1,4 +1,7 @@ -class ServerExc implements Exception { +import 'package:meta/meta.dart'; + +@immutable +final class ServerExc implements Exception { const ServerExc(this.massage); final String? massage; diff --git a/app/lib/core/launch/app_launch.dart b/app/lib/core/launch/app_launch.dart index 5b8371fe..43e99609 100644 --- a/app/lib/core/launch/app_launch.dart +++ b/app/lib/core/launch/app_launch.dart @@ -5,7 +5,13 @@ import 'package:url_launcher/url_launcher.dart'; @immutable final class AppLaunch { - static Future sendEmail(String email, {String? snackBarText, BuildContext? context}) async { + const AppLaunch._(); + + static Future sendEmail( + String email, { + String? snackBarText, + BuildContext? context, + }) async { try { final isSuccess = await launchUrl(Uri(scheme: 'mailto', path: email)); if (!isSuccess && snackBarText != null && context != null && context.mounted) { @@ -16,7 +22,11 @@ final class AppLaunch { } } - static Future sendTelegram(String username, {String? snackBarText, BuildContext? context}) async { + static Future sendTelegram( + String username, { + String? snackBarText, + BuildContext? context, + }) async { try { final isSuccess = await launchUrl( Uri.parse('https://telegram.me/$username'), @@ -30,7 +40,11 @@ final class AppLaunch { } } - static Future sendWhatsApp(String whatsapp, {String? snackBarText, BuildContext? context}) async { + static Future sendWhatsApp( + String whatsapp, { + String? snackBarText, + BuildContext? context, + }) async { try { final isSuccess = await launchUrl( Uri.parse('whatsapp://send?phone=$whatsapp'), @@ -44,7 +58,11 @@ final class AppLaunch { } } - static Future launchURL(String url, {String? snackBarText, BuildContext? context}) async { + static Future launchURL( + String url, { + String? snackBarText, + BuildContext? context, + }) async { try { final isSuccess = await launchUrl(Uri.parse(url)); if (!isSuccess && snackBarText != null && context != null && context.mounted) { diff --git a/app/lib/l10n/l10.dart b/app/lib/l10n/l10.dart index 17c891b5..9a24d132 100644 --- a/app/lib/l10n/l10.dart +++ b/app/lib/l10n/l10.dart @@ -6,3 +6,42 @@ export 'package:flutter_gen/gen_l10n/app_localizations.dart'; extension AppLocalizationsX on BuildContext { AppLocalizations get l10n => AppLocalizations.of(this); } + +final class AppLocalizationHelper { + const AppLocalizationHelper._(); + + static const locales = [ + Locale('en'), + Locale('ky'), + Locale('kk'), + Locale('tr'), + Locale('ar'), + Locale('id'), + Locale('ru'), + ]; + + static String getName(String code) { + return switch (code) { + 'en' => 'English', + 'ky' => 'Кыргызча', + 'tr' => 'Türkçe', + 'kk' => 'Қазақша', + 'ru' => 'Русский', + 'id' => 'Indonesia', + 'ar' => 'العربية', + _ => 'English', + }; + } + + static bool isSupported(String locale) { + return switch (locale) { + 'en' || 'ky' || 'tr' || 'kk' || 'ru' || 'id' || 'ar' => true, + _ => false, + }; + } + + static Locale getSupportedLocale(String locale) { + if (isSupported(locale)) return Locale(locale); + return const Locale('en'); + } +} diff --git a/app/lib/main.dart b/app/lib/main.dart index 53f970ff..58f03a2b 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -25,7 +25,7 @@ Future main({AppConfig? appConfig}) async { androidNotificationIcon: 'mipmap/launcher_icon', ); - Bloc.observer = AppBlocObserver(); + Bloc.observer = const AppBlocObserver(onLog: log); final storage = await PreferencesStorage.getInstance(); appConfig ??= AppConfig(storage: storage); diff --git a/app/lib/modules/home/data/model/home_model_response.dart b/app/lib/modules/home/data/model/home_model_response.dart index dc4fe334..45d636bf 100644 --- a/app/lib/modules/home/data/model/home_model_response.dart +++ b/app/lib/modules/home/data/model/home_model_response.dart @@ -1,9 +1,11 @@ +import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; part 'home_model_response.g.dart'; @JsonSerializable() -class HomeModelResponse { +@immutable +final class HomeModelResponse { const HomeModelResponse({ required this.allDoneHatims, required this.allDonePages, diff --git a/app/lib/modules/home/data/repository/home_repository_impl.dart b/app/lib/modules/home/data/repository/home_repository_impl.dart index 462e85ed..89c76800 100644 --- a/app/lib/modules/home/data/repository/home_repository_impl.dart +++ b/app/lib/modules/home/data/repository/home_repository_impl.dart @@ -1,8 +1,10 @@ import 'dart:developer'; +import 'package:flutter/material.dart'; import 'package:my_quran/modules/modules.dart'; -class HomeRepositoryImpl implements HomeRepository { +@immutable +final class HomeRepositoryImpl implements HomeRepository { const HomeRepositoryImpl( this.localDataSource, this.remoteDataSource, diff --git a/app/lib/modules/home/data/source/home_local_data_source.dart b/app/lib/modules/home/data/source/home_local_data_source.dart index 8806c20e..059097d5 100644 --- a/app/lib/modules/home/data/source/home_local_data_source.dart +++ b/app/lib/modules/home/data/source/home_local_data_source.dart @@ -1,8 +1,10 @@ import 'dart:convert'; +import 'package:flutter/material.dart'; import 'package:mq_storage/mq_storage.dart'; import 'package:my_quran/modules/modules.dart'; -class HomeLocalDataSource { +@immutable +final class HomeLocalDataSource { const HomeLocalDataSource(this.storage); final PreferencesStorage storage; diff --git a/app/lib/modules/home/data/source/home_remote_data_source.dart b/app/lib/modules/home/data/source/home_remote_data_source.dart index 64b7ef84..a0f752e7 100644 --- a/app/lib/modules/home/data/source/home_remote_data_source.dart +++ b/app/lib/modules/home/data/source/home_remote_data_source.dart @@ -1,8 +1,10 @@ +import 'package:flutter/material.dart'; import 'package:my_quran/config/config.dart'; import 'package:my_quran/core/core.dart'; import 'package:my_quran/modules/modules.dart'; -class HomeRemoteDataSource { +@immutable +final class HomeRemoteDataSource { const HomeRemoteDataSource(this.remoteClient); final RemoteClient remoteClient; diff --git a/app/lib/modules/home/domain/entity/home_entity.dart b/app/lib/modules/home/domain/entity/home_entity.dart index 1082155f..f281db42 100644 --- a/app/lib/modules/home/domain/entity/home_entity.dart +++ b/app/lib/modules/home/domain/entity/home_entity.dart @@ -1,4 +1,7 @@ -class HomeEntity { +import 'package:flutter/material.dart'; + +@immutable +final class HomeEntity { const HomeEntity({ required this.allDoneHatims, required this.allDonePages, diff --git a/app/lib/modules/home/domain/usecase/get_data_usecase.dart b/app/lib/modules/home/domain/usecase/get_data_usecase.dart index b12bb4d8..7aed328f 100644 --- a/app/lib/modules/home/domain/usecase/get_data_usecase.dart +++ b/app/lib/modules/home/domain/usecase/get_data_usecase.dart @@ -1,6 +1,8 @@ +import 'package:flutter/material.dart'; import 'package:my_quran/modules/modules.dart'; -class GetHomeDataUseCase { +@immutable +final class GetHomeDataUseCase { const GetHomeDataUseCase(this.repository); final HomeRepository repository; diff --git a/app/lib/modules/home/presentation/cubit/home_cubit.dart b/app/lib/modules/home/presentation/cubit/home_cubit.dart index 7752b898..63e45802 100644 --- a/app/lib/modules/home/presentation/cubit/home_cubit.dart +++ b/app/lib/modules/home/presentation/cubit/home_cubit.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:my_quran/core/core.dart'; import 'package:my_quran/modules/modules.dart'; diff --git a/app/lib/modules/home/presentation/cubit/home_state.dart b/app/lib/modules/home/presentation/cubit/home_state.dart index 5da04e45..975cddf9 100644 --- a/app/lib/modules/home/presentation/cubit/home_state.dart +++ b/app/lib/modules/home/presentation/cubit/home_state.dart @@ -1,6 +1,7 @@ part of 'home_cubit.dart'; -class HomeState extends Equatable { +@immutable +final class HomeState extends Equatable { const HomeState({ this.status = FetchStatus.loading, this.homeModel, diff --git a/app/lib/modules/read/data/source/local_theme_data_source.dart b/app/lib/modules/read/data/source/local_theme_data_source.dart index ea1c80b7..26019c2c 100644 --- a/app/lib/modules/read/data/source/local_theme_data_source.dart +++ b/app/lib/modules/read/data/source/local_theme_data_source.dart @@ -11,12 +11,12 @@ final class LocalThemeDataSource { final PreferencesStorage storage; ReadThemeState get initialTheme { - final value = storage.readString(key: AppConst.readThemeKey); + final value = storage.readString(key: StorageKeys.readThemeKey); return value != null ? ReadThemeState.fromJson(json.decode(value) as Map) : const ReadThemeState(); } Future saveThemeState(ReadThemeState themeState) async { final value = json.encode(themeState.toJson()); - await storage.writeString(key: AppConst.readThemeKey, value: value); + await storage.writeString(key: StorageKeys.readThemeKey, value: value); } } diff --git a/app/lib/modules/read/domain/entity/quran_page_entity.dart b/app/lib/modules/read/domain/entity/quran_page_entity.dart index 4719fdd7..793bb89a 100644 --- a/app/lib/modules/read/domain/entity/quran_page_entity.dart +++ b/app/lib/modules/read/domain/entity/quran_page_entity.dart @@ -17,7 +17,7 @@ final class QuranPageEntity { ..writeAll( verses.map( (e) => - '${e.isFirst ? '\n\n${AppConst.bismallah.padLeft(50).padRight(50)}\n' : ''} ${e.textUthmani} ${e.hasSajda ? AppConst.sajdaSymbol : ''} \uFD3F${e.ayatNumber.toArabicDigits}\uFD3E', + '${e.isFirst ? '\n\n${AppStatic.bismallah.padLeft(50).padRight(50)}\n' : ''} ${e.textUthmani} ${e.hasSajda ? AppStatic.sajdaSymbol : ''} \uFD3F${e.ayatNumber.toArabicDigits}\uFD3E', ), ' ', ); diff --git a/app/lib/modules/read/domain/entity/verse_entity.dart b/app/lib/modules/read/domain/entity/verse_entity.dart index 47e5641d..b8b92d3b 100644 --- a/app/lib/modules/read/domain/entity/verse_entity.dart +++ b/app/lib/modules/read/domain/entity/verse_entity.dart @@ -16,5 +16,5 @@ final class VerseEnity { int get juzNumber => int.parse(verseKey.split(':').first); int get ayatNumber => int.parse(verseKey.split(':').last); bool get isFirst => ayatNumber == 1; - bool get hasSajda => AppConst.sajdaAyats.contains(id); + bool get hasSajda => AppStatic.sajdaAyats.contains(id); } diff --git a/app/lib/modules/read/presentation/view/read_view.dart b/app/lib/modules/read/presentation/view/read_view.dart index 0753b8da..7b40c817 100644 --- a/app/lib/modules/read/presentation/view/read_view.dart +++ b/app/lib/modules/read/presentation/view/read_view.dart @@ -84,7 +84,7 @@ class ReadUI extends StatelessWidget { centerTitle: true, title: FittedBox( child: Text( - AppConst.bismallah, + AppStatic.bismallah, maxLines: 2, textAlign: TextAlign.center, style: TextStyle( diff --git a/app/lib/modules/settings/view/settings_view.dart b/app/lib/modules/settings/view/settings_view.dart index 9b0f80bb..e486cce9 100644 --- a/app/lib/modules/settings/view/settings_view.dart +++ b/app/lib/modules/settings/view/settings_view.dart @@ -4,7 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:mq_ci_keys/mq_ci_keys.dart'; import 'package:my_quran/app/app.dart'; -import 'package:my_quran/constants/contants.dart'; import 'package:my_quran/l10n/l10.dart'; import 'package:my_quran/models/models.dart'; @@ -45,7 +44,11 @@ class SettingsView extends StatelessWidget { trailing: Row( mainAxisSize: MainAxisSize.min, children: [ - Text(AppConst.getName(appCubit.state.currentLocale.toLanguageTag())), + Text( + AppLocalizationHelper.getName( + appCubit.state.currentLocale.toLanguageTag(), + ), + ), const SizedBox(width: 17), const Icon(Icons.arrow_forward_ios), ], diff --git a/app/lib/theme/custom/color/app_colors.dart b/app/lib/theme/custom/color/app_colors.dart index 63c58feb..beca906a 100644 --- a/app/lib/theme/custom/color/app_colors.dart +++ b/app/lib/theme/custom/color/app_colors.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; @immutable final class AppColors { + const AppColors._(); + static const Color white = Colors.white; static const Color black = Colors.black; static const Color red = Colors.red; diff --git a/app/lib/theme/custom/component/componet_theme.dart b/app/lib/theme/custom/component/componet_theme.dart index e48bf0d8..910f6fa6 100644 --- a/app/lib/theme/custom/component/componet_theme.dart +++ b/app/lib/theme/custom/component/componet_theme.dart @@ -3,55 +3,57 @@ import 'package:flutter/material.dart'; mixin CompomnentTheme { ShapeBorder get shapeMedium => const RoundedRectangleBorder(); - CardTheme cardTheme() { + ColorScheme get scheme; + + CardTheme get cardTheme { return const CardTheme(); } - ButtonThemeData buttonTheme(ColorScheme colors) { + ButtonThemeData get buttonTheme { return const ButtonThemeData(); } - ElevatedButtonThemeData elevatedButtonThemeData(ColorScheme colors) { + ElevatedButtonThemeData get elevatedButtonThemeData { return ElevatedButtonThemeData( style: ElevatedButton.styleFrom(), ); } - InputDecorationTheme inputDecorationTheme(ColorScheme colors) { + InputDecorationTheme get inputDecorationTheme { return const InputDecorationTheme( border: OutlineInputBorder(), ); } - ListTileThemeData listTileTheme(ColorScheme colors) { + ListTileThemeData get listTileTheme { return const ListTileThemeData(); } - AppBarTheme appBarTheme(ColorScheme colors) { - return AppBarTheme(backgroundColor: colors.surfaceVariant); + AppBarTheme get appBarTheme { + return AppBarTheme(backgroundColor: scheme.surfaceVariant); } - TabBarTheme tabBarTheme(ColorScheme colors) { + TabBarTheme get tabBarTheme { return const TabBarTheme(); } - BottomAppBarTheme bottomAppBarTheme(ColorScheme colors) { + BottomAppBarTheme get bottomAppBarTheme { return const BottomAppBarTheme(); } - BottomNavigationBarThemeData bottomNavigationBarTheme(ColorScheme colors) { + BottomNavigationBarThemeData get bottomNavigationBarTheme { return const BottomNavigationBarThemeData(); } - NavigationRailThemeData navigationRailTheme(ColorScheme colors) { + NavigationRailThemeData get navigationRailTheme { return const NavigationRailThemeData(); } - DrawerThemeData drawerTheme(ColorScheme colors) { + DrawerThemeData get drawerTheme { return const DrawerThemeData(); } - ScrollbarThemeData scrollbarThemeData(ColorScheme colors) { + ScrollbarThemeData get scrollbarThemeData { return const ScrollbarThemeData(); } } diff --git a/app/lib/theme/custom/custom_theme.dart b/app/lib/theme/custom/custom_theme.dart index 01fd61e0..56759a3a 100644 --- a/app/lib/theme/custom/custom_theme.dart +++ b/app/lib/theme/custom/custom_theme.dart @@ -1,54 +1,42 @@ import 'package:flutter/material.dart'; import 'package:my_quran/theme/theme.dart'; -class CustomTheme with CompomnentTheme { +@immutable +final class CustomTheme with CompomnentTheme { const CustomTheme(this.brightness, this.targetColor); final Brightness brightness; final Color targetColor; - ColorScheme colors() { - return ColorScheme.fromSeed( - seedColor: targetColor, - brightness: brightness, - ); - } + @override + ColorScheme get scheme => ColorScheme.fromSeed( + seedColor: targetColor, + brightness: brightness, + ); - ThemeData light() { - final scheme = colors(); - return ThemeData.light().copyWith( + ThemeData get _base { + return ThemeData( colorScheme: scheme, - appBarTheme: appBarTheme(scheme), - cardTheme: cardTheme(), - listTileTheme: listTileTheme(scheme), - bottomAppBarTheme: bottomAppBarTheme(scheme), - bottomNavigationBarTheme: bottomNavigationBarTheme(scheme), - navigationRailTheme: navigationRailTheme(scheme), - tabBarTheme: tabBarTheme(scheme), - drawerTheme: drawerTheme(scheme), - buttonTheme: buttonTheme(scheme), - inputDecorationTheme: inputDecorationTheme(scheme), - elevatedButtonTheme: elevatedButtonThemeData(scheme), - scrollbarTheme: scrollbarThemeData(scheme), + appBarTheme: appBarTheme, + cardTheme: cardTheme, + listTileTheme: listTileTheme, + bottomAppBarTheme: bottomAppBarTheme, + bottomNavigationBarTheme: bottomNavigationBarTheme, + navigationRailTheme: navigationRailTheme, + tabBarTheme: tabBarTheme, + drawerTheme: drawerTheme, + buttonTheme: buttonTheme, + inputDecorationTheme: inputDecorationTheme, + elevatedButtonTheme: elevatedButtonThemeData, + scrollbarTheme: scrollbarThemeData, ); } - ThemeData dark() { - final scheme = colors(); - return ThemeData.dark().copyWith( - colorScheme: scheme, - appBarTheme: appBarTheme(scheme), - cardTheme: cardTheme(), - listTileTheme: listTileTheme(scheme), - bottomAppBarTheme: bottomAppBarTheme(scheme), - bottomNavigationBarTheme: bottomNavigationBarTheme(scheme), - navigationRailTheme: navigationRailTheme(scheme), - tabBarTheme: tabBarTheme(scheme), - drawerTheme: drawerTheme(scheme), - ); - } + ThemeData get light => _base.copyWith(brightness: Brightness.light); + + ThemeData get dark => _base.copyWith(brightness: Brightness.dark); - ThemeData get themeData => brightness == Brightness.dark ? dark() : light(); + ThemeData get themeData => brightness == Brightness.dark ? dark : light; CustomTheme copyWith({Brightness? brightness, Color? targetColor}) { return CustomTheme(brightness ?? this.brightness, targetColor ?? this.targetColor); diff --git a/app/test/widget_test.dart b/app/test/widget_test.dart index a1226d32..71543bd5 100644 --- a/app/test/widget_test.dart +++ b/app/test/widget_test.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:mq_storage/mq_storage.dart'; - import 'package:my_quran/app/app.dart'; import 'package:my_quran/constants/contants.dart'; import 'package:my_quran/core/core.dart'; @@ -32,11 +31,11 @@ void main() { final homeRepo = MockHomeRepositoryImpl(); final themeService = ThemeService(storage); - when(() => storage.readString(key: AppConst.tokenKey)).thenReturn(null); - when(() => storage.readString(key: AppConst.genderKey)).thenReturn(null); - when(() => storage.readString(key: AppConst.localeKey)).thenReturn('en'); - when(() => storage.readString(key: AppConst.modeKey)).thenReturn(null); - when(() => storage.readString(key: AppConst.colorKey)).thenReturn(null); + when(() => storage.readString(key: StorageKeys.tokenKey)).thenReturn(null); + when(() => storage.readString(key: StorageKeys.genderKey)).thenReturn(null); + when(() => storage.readString(key: StorageKeys.localeKey)).thenReturn('en'); + when(() => storage.readString(key: StorageKeys.modeKey)).thenReturn(null); + when(() => storage.readString(key: StorageKeys.colorKey)).thenReturn(null); await tester.pumpApp(appService, themeService, authStorage, homeRepo); await tester.pumpAndSettle();