diff --git a/assets/images/button.svg b/assets/images/button.svg new file mode 100644 index 0000000..bc05b38 --- /dev/null +++ b/assets/images/button.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/button_2.svg b/assets/images/button_2.svg new file mode 100644 index 0000000..c27135a --- /dev/null +++ b/assets/images/button_2.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/lang.svg b/assets/images/lang.svg new file mode 100644 index 0000000..c2452a0 --- /dev/null +++ b/assets/images/lang.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/start.svg b/assets/images/start.svg deleted file mode 100644 index 8151c85..0000000 --- a/assets/images/start.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/common_ui/resources/my_assets.dart b/lib/common_ui/resources/my_assets.dart index 041843e..063d962 100644 --- a/lib/common_ui/resources/my_assets.dart +++ b/lib/common_ui/resources/my_assets.dart @@ -8,7 +8,8 @@ class MyAssets { static const String hadiHoda = 'assets/images/hadi_hoda.png'; static const String musicOff = 'assets/images/music_off.svg'; static const String musicOn = 'assets/images/music_on.svg'; - static const String start = 'assets/images/start.svg'; + static const String button = 'assets/images/button.svg'; + static const String button2 = 'assets/images/button_2.svg'; static const String theme = 'assets/images/theme.svg'; static const String facebook = 'assets/images/facebook.svg'; static const String whatsapp = 'assets/images/whatsapp.svg'; @@ -36,4 +37,5 @@ class MyAssets { static const String play = 'assets/images/play.svg'; static const String homeButton = 'assets/images/home_button.png'; static const String doneRounded = 'assets/images/done_rounded.svg'; + static const String lang = 'assets/images/lang.svg'; } \ No newline at end of file diff --git a/lib/common_ui/resources/my_text_style.dart b/lib/common_ui/resources/my_text_style.dart index de47e8f..1d93190 100644 --- a/lib/common_ui/resources/my_text_style.dart +++ b/lib/common_ui/resources/my_text_style.dart @@ -18,6 +18,11 @@ class DinoKids { fontSize: 26, fontWeight: FontWeight.w400, ); + static const TextStyle regular45 = TextStyle( + fontFamily: fontFamily, + fontSize: 45, + fontWeight: FontWeight.w400, + ); } class Marhey { diff --git a/lib/core/constants/my_constants.dart b/lib/core/constants/my_constants.dart index 7772e42..e96b59e 100644 --- a/lib/core/constants/my_constants.dart +++ b/lib/core/constants/my_constants.dart @@ -8,4 +8,5 @@ class MyConstants { static const String levelBox = 'LEVEL_BOX'; static const String downloadCompleted = 'DOWNLOAD_COMPLETED'; static const String extractCompleted = 'EXTRACT_COMPLETED'; + static const String selectLanguage = 'SELECT_LANGUAGE'; } \ No newline at end of file diff --git a/lib/core/middleware/auth_middleware.dart b/lib/core/middleware/auth_middleware.dart deleted file mode 100644 index a6901af..0000000 --- a/lib/core/middleware/auth_middleware.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:hadi_hoda_flutter/core/auth_storage/auth_storage.dart'; -import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; -import 'package:go_router/go_router.dart'; - -class AuthMiddleware { - static const AuthMiddleware _i = AuthMiddleware._internal(); - const AuthMiddleware._internal(); - factory AuthMiddleware() => _i; - - static FutureOr redirect(BuildContext context, GoRouterState state) async { - if (AuthStorage.isLogin()) { - return Routes.homePage; - } else { - return null; - } - } -} diff --git a/lib/core/middleware/language_middleware.dart b/lib/core/middleware/language_middleware.dart new file mode 100644 index 0000000..3d092bd --- /dev/null +++ b/lib/core/middleware/language_middleware.dart @@ -0,0 +1,21 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; +import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; + +class LanguageMiddleware { + static const LanguageMiddleware _i = LanguageMiddleware._internal(); + const LanguageMiddleware._internal(); + factory LanguageMiddleware() => _i; + + static FutureOr redirect(BuildContext context, GoRouterState state) async { + if (LocalStorage.readData(key: MyConstants.selectLanguage).isNotEmpty) { + return Routes.homePage; + } else { + return null; + } + } +} diff --git a/lib/core/params/language_params.dart b/lib/core/params/language_params.dart new file mode 100644 index 0000000..c5866ec --- /dev/null +++ b/lib/core/params/language_params.dart @@ -0,0 +1,17 @@ +class LanguageParams { + String? code; + + LanguageParams({this.code}); + + LanguageParams copyWith({ + String? code, + }) { + return LanguageParams( + code: code ?? this.code, + ); + } + + Map get toHeader => { + if (code != null) 'HTTP_X_USER_LANGUAGE': code, + }; +} diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index e7781c5..5066c81 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -1,10 +1,13 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/core/middleware/language_middleware.dart'; import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_bloc.dart'; import 'package:hadi_hoda_flutter/features/home/presentation/ui/home_page.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_bloc.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/ui/intro_page.dart'; +import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_bloc.dart'; +import 'package:hadi_hoda_flutter/features/language/presentation/ui/language_page.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_bloc.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_event.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/ui/level_page.dart'; @@ -19,6 +22,7 @@ class Routes { factory Routes() => _i; static const String introPage = '/intro_page'; + static const String languagePage = '/language_page'; static const String homePage = '/home_page'; static const String questionPage = '/question_page'; static const String levelPage = '/level_page'; @@ -36,6 +40,15 @@ GoRouter get appPages => GoRouter( child: const IntroPage(), ), ), + GoRoute( + name: Routes.languagePage, + path: Routes.languagePage, + redirect: LanguageMiddleware.redirect, + builder: (context, state) => BlocProvider( + create: (context) => LanguageBloc(locator()), + child: const LanguagePage(), + ), + ), GoRoute( name: Routes.homePage, path: Routes.homePage, diff --git a/lib/core/widgets/button/enum/button_type.dart b/lib/core/widgets/button/enum/button_type.dart new file mode 100644 index 0000000..c347d64 --- /dev/null +++ b/lib/core/widgets/button/enum/button_type.dart @@ -0,0 +1,18 @@ +import 'dart:ui'; + +import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; + +enum ButtonType { + type1, + type2; + + static Map get image => { + type1: MyAssets.button, + type2: MyAssets.button2, + }; + + static Map get textColor => { + type1: Color(0XFF1D6EFF), + type2: Color(0XFFD93D16), + }; +} \ No newline at end of file diff --git a/lib/core/widgets/button/my_button.dart b/lib/core/widgets/button/my_button.dart new file mode 100644 index 0000000..188cb3a --- /dev/null +++ b/lib/core/widgets/button/my_button.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; +import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart'; +import 'package:hadi_hoda_flutter/core/utils/my_image.dart'; +import 'package:hadi_hoda_flutter/core/widgets/button/enum/button_type.dart'; + +class MyButton extends StatelessWidget { + const MyButton({ + super.key, + this.onTap, + this.type = ButtonType.type1, + this.title, + }); + + final VoidCallback? onTap; + final ButtonType? type; + final String? title; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 84, + width: 194, + child: InkWell( + onTap: onTap, + highlightColor: context.noColor, + splashColor: context.noColor, + child: Stack( + alignment: Alignment.center, + children: [ + MyImage( + image: ButtonType.image[type] ?? MyAssets.button, + ), + PositionedDirectional( + top: MySpaces.s2, + child: Text( + title ?? '', + style: DinoKids.regular45.copyWith( + color: ButtonType.textColor[type], + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/features/home/presentation/ui/home_page.dart b/lib/features/home/presentation/ui/home_page.dart index b6665fd..82c5c85 100644 --- a/lib/features/home/presentation/ui/home_page.dart +++ b/lib/features/home/presentation/ui/home_page.dart @@ -76,7 +76,7 @@ class HomePage extends StatelessWidget { ), InkWell( child: MyImage( - image: MyAssets.start, + image: MyAssets.button, size: checkSize(context: context, mobile: 90, tablet: 160), ), onTap: () => diff --git a/lib/features/intro/presentation/bloc/intro_bloc.dart b/lib/features/intro/presentation/bloc/intro_bloc.dart index 9ec1665..26fbddd 100644 --- a/lib/features/intro/presentation/bloc/intro_bloc.dart +++ b/lib/features/intro/presentation/bloc/intro_bloc.dart @@ -40,7 +40,7 @@ class IntroBloc extends Bloc { (data) async { await Future.delayed( Duration(milliseconds: 300), () { - ContextProvider.context!.goNamed(Routes.homePage); + ContextProvider.context!.goNamed(Routes.languagePage); }, ); }, diff --git a/lib/features/language/data/datasource/language_datasource.dart b/lib/features/language/data/datasource/language_datasource.dart new file mode 100644 index 0000000..6c37a9d --- /dev/null +++ b/lib/features/language/data/datasource/language_datasource.dart @@ -0,0 +1,46 @@ +import 'package:hadi_hoda_flutter/core/constants/my_api.dart'; +import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; +import 'package:hadi_hoda_flutter/core/network/http_request.dart'; +import 'package:hadi_hoda_flutter/core/params/language_params.dart'; +import 'package:hadi_hoda_flutter/core/response/base_response.dart'; +import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; +import 'package:hadi_hoda_flutter/features/level/data/model/level_model.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart'; +import 'package:hive/hive.dart'; + +abstract class ILanguageDatasource { + Future saveLevels({required LanguageParams params}); +} + +class LanguageDatasourceImpl implements ILanguageDatasource { + final IHttpRequest httpRequest; + + const LanguageDatasourceImpl(this.httpRequest); + + @override + Future saveLevels({required LanguageParams params}) async { + await LocalStorage.saveData( + key: MyConstants.selectLanguage, + value: params.code ?? 'fa', + ); + final Box data = Hive.box(MyConstants.levelBox); + final TotalDataEntity findData = data.values.singleWhere( + (e) => e.code == params.code, + orElse: () => TotalDataEntity(), + ); + + if (findData.code != params.code) { + final response = await httpRequest.get( + path: MyApi.levels, + header: params.toHeader, + ); + final List levels = BaseResponse.getDataList( + response?['result'], + (json) => LevelModel.fromJson(json), + ); + + await data.add(TotalDataEntity(code: params.code, levels: levels)); + } + } +} diff --git a/lib/features/language/data/repository_impl/language_repository_impl.dart b/lib/features/language/data/repository_impl/language_repository_impl.dart new file mode 100644 index 0000000..7441fac --- /dev/null +++ b/lib/features/language/data/repository_impl/language_repository_impl.dart @@ -0,0 +1,29 @@ +import 'package:hadi_hoda_flutter/core/params/language_params.dart'; +import 'package:flutter/foundation.dart'; +import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; +import 'package:hadi_hoda_flutter/core/params/no_params.dart'; +import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; +import 'package:hadi_hoda_flutter/features/language/data/datasource/language_datasource.dart'; +import 'package:hadi_hoda_flutter/features/language/domain/repository/language_repository.dart'; + +class LanguageRepositoryImpl implements ILanguageRepository { + final ILanguageDatasource datasource; + + const LanguageRepositoryImpl(this.datasource); + + @override + Future> saveLevels({required LanguageParams params}) async { + try { + await datasource.saveLevels(params: params); + return DataState.success(NoParams()); + } on MyException catch (e) { + return DataState.error(e); + } catch (e) { + if (kDebugMode) { + rethrow; + } else { + return DataState.error(MyException(errorMessage: '$e')); + } + } + } +} diff --git a/lib/features/language/domain/entity/language_entity.dart b/lib/features/language/domain/entity/language_entity.dart new file mode 100644 index 0000000..2e76d7a --- /dev/null +++ b/lib/features/language/domain/entity/language_entity.dart @@ -0,0 +1,17 @@ +import 'package:equatable/equatable.dart'; + +class LanguageEntity extends Equatable { + final String? title; + final String? code; + + const LanguageEntity({ + this.title, + this.code, + }); + + @override + List get props => [ + title, + code, + ]; +} diff --git a/lib/features/language/domain/repository/language_repository.dart b/lib/features/language/domain/repository/language_repository.dart new file mode 100644 index 0000000..734c561 --- /dev/null +++ b/lib/features/language/domain/repository/language_repository.dart @@ -0,0 +1,8 @@ +import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; +import 'package:hadi_hoda_flutter/core/params/language_params.dart'; +import 'package:hadi_hoda_flutter/core/params/no_params.dart'; +import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; + +abstract class ILanguageRepository { + Future> saveLevels({required LanguageParams params}); +} diff --git a/lib/features/language/domain/usecases/save_levels_usecase.dart b/lib/features/language/domain/usecases/save_levels_usecase.dart new file mode 100644 index 0000000..61c6546 --- /dev/null +++ b/lib/features/language/domain/usecases/save_levels_usecase.dart @@ -0,0 +1,17 @@ +import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; +import 'package:hadi_hoda_flutter/core/params/language_params.dart'; +import 'package:hadi_hoda_flutter/core/params/no_params.dart'; +import 'package:hadi_hoda_flutter/core/usecase/usecase.dart'; +import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; +import 'package:hadi_hoda_flutter/features/language/domain/repository/language_repository.dart'; + +class SaveLevelsUseCase implements UseCase { + final ILanguageRepository repository; + + const SaveLevelsUseCase(this.repository); + + @override + Future> call(LanguageParams params) { + return repository.saveLevels(params: params); + } +} diff --git a/lib/features/language/presentation/bloc/language_bloc.dart b/lib/features/language/presentation/bloc/language_bloc.dart new file mode 100644 index 0000000..c339a88 --- /dev/null +++ b/lib/features/language/presentation/bloc/language_bloc.dart @@ -0,0 +1,60 @@ +import 'dart:async'; +import 'package:bloc/bloc.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/core/params/language_params.dart'; +import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; +import 'package:hadi_hoda_flutter/core/status/base_status.dart'; +import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; +import 'package:hadi_hoda_flutter/features/language/domain/entity/language_entity.dart'; +import 'package:hadi_hoda_flutter/features/language/domain/usecases/save_levels_usecase.dart'; +import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_event.dart'; +import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_state.dart'; + +class LanguageBloc extends Bloc { + /// ------------constructor------------ + LanguageBloc( + this._saveLevelsUseCase, + ) : super(const LanguageState()) { + on(_changeLanguageEvent); + on(_saveLevelsEvent); + } + + /// ------------UseCases------------ + final SaveLevelsUseCase _saveLevelsUseCase; + + /// ------------Variables------------ + final List languages = [ + LanguageEntity(title: 'Persian (فارسی)', code: 'fa'), + LanguageEntity(title: 'English (English)', code: 'en'), + LanguageEntity(title: 'Arabic (عربی)', code: 'ar'), + ]; + + /// ------------Controllers------------ + + /// ------------Functions------------ + FutureOr _changeLanguageEvent( + ChangeLanguageEvent event, + Emitter emit, + ) { + emit(state.copyWith(selectedLang: event.lang)); + } + + /// ------------Api Calls------------ + FutureOr _saveLevelsEvent( + SaveLevelsEvent event, + Emitter emit, + ) async { + emit(state.copyWith(saveLevelsStatus: const BaseLoading())); + await _saveLevelsUseCase(LanguageParams(code: state.selectedLang.code)).then( + (value) => value.fold( + (data) { + emit(state.copyWith(saveLevelsStatus: const BaseInit())); + ContextProvider.context!.goNamed(Routes.homePage); + }, + (error) { + emit(state.copyWith(saveLevelsStatus: const BaseInit())); + }, + ), + ); + } +} diff --git a/lib/features/language/presentation/bloc/language_event.dart b/lib/features/language/presentation/bloc/language_event.dart new file mode 100644 index 0000000..2531db4 --- /dev/null +++ b/lib/features/language/presentation/bloc/language_event.dart @@ -0,0 +1,16 @@ +import 'package:hadi_hoda_flutter/features/language/domain/entity/language_entity.dart'; + +sealed class LanguageEvent { + const LanguageEvent(); +} + +class ChangeLanguageEvent extends LanguageEvent { + final LanguageEntity lang; + + const ChangeLanguageEvent(this.lang); +} + +class SaveLevelsEvent extends LanguageEvent { + const SaveLevelsEvent(); +} + diff --git a/lib/features/language/presentation/bloc/language_state.dart b/lib/features/language/presentation/bloc/language_state.dart new file mode 100644 index 0000000..44d40bb --- /dev/null +++ b/lib/features/language/presentation/bloc/language_state.dart @@ -0,0 +1,22 @@ +import 'package:hadi_hoda_flutter/core/status/base_status.dart'; +import 'package:hadi_hoda_flutter/features/language/domain/entity/language_entity.dart'; + +class LanguageState { + final BaseStatus saveLevelsStatus; + final LanguageEntity selectedLang; + + const LanguageState({ + this.saveLevelsStatus = const BaseInit(), + this.selectedLang = const LanguageEntity(code: 'fa'), + }); + + LanguageState copyWith({ + BaseStatus? saveLevelsStatus, + LanguageEntity? selectedLang, + }) { + return LanguageState( + saveLevelsStatus: saveLevelsStatus ?? this.saveLevelsStatus, + selectedLang: selectedLang ?? this.selectedLang, + ); + } +} diff --git a/lib/features/language/presentation/ui/language_page.dart b/lib/features/language/presentation/ui/language_page.dart new file mode 100644 index 0000000..4c81130 --- /dev/null +++ b/lib/features/language/presentation/ui/language_page.dart @@ -0,0 +1,157 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; +import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart'; +import 'package:hadi_hoda_flutter/core/status/base_status.dart'; +import 'package:hadi_hoda_flutter/core/utils/my_image.dart'; +import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; +import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; +import 'package:hadi_hoda_flutter/core/widgets/button/my_button.dart'; +import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_bloc.dart'; +import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_event.dart'; +import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_state.dart'; + +class LanguagePage extends StatelessWidget { + const LanguagePage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + height: context.heightScreen, + width: context.widthScreen, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFF00154C), Color(0XFF150532)], + ), + image: DecorationImage( + image: AssetImage(MyAssets.pattern), + scale: 3, + repeat: ImageRepeat.repeat, + colorFilter: ColorFilter.mode( + Colors.white.withValues(alpha: 0.2), + BlendMode.srcIn, + ), + ), + ), + child: Padding( + padding: EdgeInsets.only( + left: 60, + right: 60, + bottom: MediaQuery.viewPaddingOf(context).bottom + MySpaces.s16, + top: MediaQuery.viewPaddingOf(context).bottom + 50, + ), + child: Column( + children: [_title(context), _list(context), _btn(context)], + ), + ), + ), + ); + } + + Widget _title(BuildContext context) { + return Row( + spacing: MySpaces.s10, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + MyImage(image: MyAssets.lang, size: 28), + Text( + context.translate.select_language, + style: Marhey.semiBold22.copyWith(color: Color(0XFF847AC4)), + ), + ], + ); + } + + Expanded _list(BuildContext context) { + return Expanded( + child: Material( + color: context.noColor, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate( + context.read().languages.length, + (index) => BlocBuilder( + buildWhen: (previous, current) => + previous.selectedLang.code != current.selectedLang.code, + builder: (context, state) { + final LanguageBloc languageBloc = context.read(); + return ListTile( + selected: state.selectedLang.code == + languageBloc.languages[index].code, + onTap: () { + languageBloc.add( + ChangeLanguageEvent(languageBloc.languages[index])); + }, + title: Text(context.read().languages[index].title ?? ''), + titleTextStyle: Marhey.medium16.copyWith( + color: context.primaryColor, + ), + contentPadding: EdgeInsets.symmetric( + vertical: MySpaces.s12, + horizontal: 30, + ), + minVerticalPadding: 0, + minTileHeight: 0, + minLeadingWidth: 0, + horizontalTitleGap: MySpaces.s12, + trailing: BlocBuilder( + builder: (context, state) { + if (state.saveLevelsStatus is BaseLoading && (state + .selectedLang.code == languageBloc.languages[index].code)) { + return CupertinoActivityIndicator( + color: context.primaryColor, + ); + } else { + return SizedBox.shrink(); + } + }, + ), + leading: state.selectedLang.code == + languageBloc.languages[index].code ? Container( + height: 17, + width: 17, + padding: EdgeInsets.all(3), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + width: 1, + color: Color(0XFF3CFF3C), + ), + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0XFF48D336), + Color(0XFF2D7C23), + ], + ), + ), + child: MyImage(image: MyAssets.doneRounded), + ) : SizedBox(height: 17, width: 17), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + selectedTileColor: context.primaryColor.withValues(alpha: 0.2), + selectedColor: context.primaryColor, + ); + } + ), + ), + ), + ), + ); + } + + Widget _btn(BuildContext context) { + return MyButton( + onTap: () => context.read().add(SaveLevelsEvent()), + title: context.translate.select, + ); + } +} diff --git a/lib/features/level/data/datasource/level_datasource.dart b/lib/features/level/data/datasource/level_datasource.dart index 77abd2b..1921cc1 100644 --- a/lib/features/level/data/datasource/level_datasource.dart +++ b/lib/features/level/data/datasource/level_datasource.dart @@ -1,10 +1,6 @@ -import 'package:hadi_hoda_flutter/core/constants/my_api.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; -import 'package:hadi_hoda_flutter/core/network/http_request.dart'; import 'package:hadi_hoda_flutter/core/params/level_params.dart'; -import 'package:hadi_hoda_flutter/core/response/base_response.dart'; -import 'package:hadi_hoda_flutter/features/level/data/model/level_model.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; import 'package:hive/hive.dart'; @@ -12,26 +8,6 @@ abstract class ILevelDatasource { Future> getLevels({required LevelParams params}); } -/// Remote -class RemoteLevelDatasourceImpl implements ILevelDatasource { - final IHttpRequest httpRequest; - - const RemoteLevelDatasourceImpl(this.httpRequest); - - @override - Future> getLevels({required LevelParams params}) async { - final response = await httpRequest.get( - path: MyApi.baseUrl, - ); - - return BaseResponse.getDataList( - response?['data'], - (json) => LevelModel.fromJson(json), - ); - } -} - - /// Local class LocalLevelDatasourceImpl implements ILevelDatasource { diff --git a/lib/features/level/domain/entity/level_entity.dart b/lib/features/level/domain/entity/level_entity.dart index 196bd26..cee3840 100644 --- a/lib/features/level/domain/entity/level_entity.dart +++ b/lib/features/level/domain/entity/level_entity.dart @@ -3,7 +3,7 @@ import 'package:hive/hive.dart'; part 'level_entity.g.dart'; -@HiveType(typeId: 0) +@HiveType(typeId: 1) class LevelEntity extends HiveObject { @HiveField(0) int? id; diff --git a/lib/features/level/domain/entity/level_entity.g.dart b/lib/features/level/domain/entity/level_entity.g.dart index 7c5ddd0..22ae93a 100644 --- a/lib/features/level/domain/entity/level_entity.g.dart +++ b/lib/features/level/domain/entity/level_entity.g.dart @@ -8,7 +8,7 @@ part of 'level_entity.dart'; class LevelEntityAdapter extends TypeAdapter { @override - final int typeId = 0; + final int typeId = 1; @override LevelEntity read(BinaryReader reader) { diff --git a/lib/features/level/domain/entity/total_data_entity.dart b/lib/features/level/domain/entity/total_data_entity.dart new file mode 100644 index 0000000..1428455 --- /dev/null +++ b/lib/features/level/domain/entity/total_data_entity.dart @@ -0,0 +1,17 @@ +import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hive/hive.dart'; + +part 'total_data_entity.g.dart'; + +@HiveType(typeId: 0) +class TotalDataEntity extends HiveObject{ + @HiveField(0) + String? code; + @HiveField(1) + List? levels; + + TotalDataEntity({ + this.code, + this.levels, + }); +} \ No newline at end of file diff --git a/lib/features/level/domain/entity/total_data_entity.g.dart b/lib/features/level/domain/entity/total_data_entity.g.dart new file mode 100644 index 0000000..947076d --- /dev/null +++ b/lib/features/level/domain/entity/total_data_entity.g.dart @@ -0,0 +1,44 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'total_data_entity.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class TotalDataEntityAdapter extends TypeAdapter { + @override + final int typeId = 0; + + @override + TotalDataEntity read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return TotalDataEntity( + code: fields[0] as String?, + levels: (fields[1] as List?)?.cast(), + ); + } + + @override + void write(BinaryWriter writer, TotalDataEntity obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.code) + ..writeByte(1) + ..write(obj.levels); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is TotalDataEntityAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/features/question/domain/entity/answer_entity.dart b/lib/features/question/domain/entity/answer_entity.dart index e3204e0..d2fa120 100644 --- a/lib/features/question/domain/entity/answer_entity.dart +++ b/lib/features/question/domain/entity/answer_entity.dart @@ -3,7 +3,7 @@ import 'package:hive/hive.dart'; part 'answer_entity.g.dart'; -@HiveType(typeId: 2) +@HiveType(typeId: 3) class AnswerEntity extends HiveObject { @HiveField(0) int? id; diff --git a/lib/features/question/domain/entity/answer_entity.g.dart b/lib/features/question/domain/entity/answer_entity.g.dart index 34a06de..17f432c 100644 --- a/lib/features/question/domain/entity/answer_entity.g.dart +++ b/lib/features/question/domain/entity/answer_entity.g.dart @@ -8,7 +8,7 @@ part of 'answer_entity.dart'; class AnswerEntityAdapter extends TypeAdapter { @override - final int typeId = 2; + final int typeId = 3; @override AnswerEntity read(BinaryReader reader) { diff --git a/lib/features/question/domain/entity/file_entity.dart b/lib/features/question/domain/entity/file_entity.dart index 9446384..6faaf73 100644 --- a/lib/features/question/domain/entity/file_entity.dart +++ b/lib/features/question/domain/entity/file_entity.dart @@ -2,7 +2,7 @@ import 'package:hive/hive.dart'; part 'file_entity.g.dart'; -@HiveType(typeId: 3) +@HiveType(typeId: 4) class FileEntity extends HiveObject { @HiveField(0) String? filename; diff --git a/lib/features/question/domain/entity/file_entity.g.dart b/lib/features/question/domain/entity/file_entity.g.dart index 964bef5..ef3f994 100644 --- a/lib/features/question/domain/entity/file_entity.g.dart +++ b/lib/features/question/domain/entity/file_entity.g.dart @@ -8,7 +8,7 @@ part of 'file_entity.dart'; class FileEntityAdapter extends TypeAdapter { @override - final int typeId = 3; + final int typeId = 4; @override FileEntity read(BinaryReader reader) { diff --git a/lib/features/question/domain/entity/question_entity.dart b/lib/features/question/domain/entity/question_entity.dart index 4c05d26..3407e84 100644 --- a/lib/features/question/domain/entity/question_entity.dart +++ b/lib/features/question/domain/entity/question_entity.dart @@ -4,7 +4,7 @@ import 'package:hive/hive.dart'; part 'question_entity.g.dart'; -@HiveType(typeId: 1) +@HiveType(typeId: 2) class QuestionEntity extends HiveObject { @HiveField(0) int? id; diff --git a/lib/features/question/domain/entity/question_entity.g.dart b/lib/features/question/domain/entity/question_entity.g.dart index d90e05f..db9d48a 100644 --- a/lib/features/question/domain/entity/question_entity.g.dart +++ b/lib/features/question/domain/entity/question_entity.g.dart @@ -8,7 +8,7 @@ part of 'question_entity.dart'; class QuestionEntityAdapter extends TypeAdapter { @override - final int typeId = 1; + final int typeId = 2; @override QuestionEntity read(BinaryReader reader) { diff --git a/lib/init_bindings.dart b/lib/init_bindings.dart index c8c7a8c..bad6e5e 100644 --- a/lib/init_bindings.dart +++ b/lib/init_bindings.dart @@ -12,9 +12,14 @@ import 'package:hadi_hoda_flutter/features/intro/data/repository_impl/intro_repo import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/usecases/get_files_usecase.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/usecases/loading_stream_usecase.dart'; +import 'package:hadi_hoda_flutter/features/language/data/datasource/language_datasource.dart'; +import 'package:hadi_hoda_flutter/features/language/data/repository_impl/language_repository_impl.dart'; +import 'package:hadi_hoda_flutter/features/language/domain/repository/language_repository.dart'; +import 'package:hadi_hoda_flutter/features/language/domain/usecases/save_levels_usecase.dart'; import 'package:hadi_hoda_flutter/features/level/data/datasource/level_datasource.dart'; import 'package:hadi_hoda_flutter/features/level/data/repository_impl/level_repository_impl.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/repository/level_repository.dart'; import 'package:hadi_hoda_flutter/features/level/domain/usecases/get_levels_usecase.dart'; import 'package:hadi_hoda_flutter/features/question/data/datasource/question_datasource.dart'; @@ -49,6 +54,11 @@ void initBindings() { locator.registerLazySingleton(() => GetFilesUseCase(locator())); locator.registerLazySingleton(() => LoadingStreamUseCase(locator())); + /// Language Feature + locator.registerLazySingleton(() => LanguageDatasourceImpl(locator())); + locator.registerLazySingleton(() => LanguageRepositoryImpl(locator())); + locator.registerLazySingleton(() => SaveLevelsUseCase(locator())); + /// Home Feature locator.registerLazySingleton(() => HomeDatasourceImpl(locator())); locator.registerLazySingleton(() => HomeRepositoryImpl(locator())); @@ -72,7 +82,8 @@ Future initDataBase() async { ..registerAdapter(FileEntityAdapter()) ..registerAdapter(AnswerEntityAdapter()) ..registerAdapter(QuestionEntityAdapter()) - ..registerAdapter(LevelEntityAdapter()); + ..registerAdapter(LevelEntityAdapter()) + ..registerAdapter(TotalDataEntityAdapter()); - await Hive.openBox(MyConstants.levelBox); + await Hive.openBox(MyConstants.levelBox); } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f21e3f9..fd36a8d 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1,5 +1,7 @@ { "about_us": "About us", "about_us_desc" : "Rive combines an interactive design tool, a new stateful graphics format, a lightweight multi-platform runtime, and a blazing-fast vector renderer. \nThis end-to-end pipeline brings interfaces to life with motion. It gives designers and devs the tools to build.", - "tap_to_select": "Tap the correct option to select." + "tap_to_select": "Tap the correct option to select.", + "select_language": "Select language", + "select": "Select" } \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 6e94635..8b63165 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -111,6 +111,18 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Tap the correct option to select.'** String get tap_to_select; + + /// No description provided for @select_language. + /// + /// In en, this message translates to: + /// **'Select language'** + String get select_language; + + /// No description provided for @select. + /// + /// In en, this message translates to: + /// **'Select'** + String get select; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 6b8bd59..290f727 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -17,4 +17,10 @@ class AppLocalizationsEn extends AppLocalizations { @override String get tap_to_select => 'Tap the correct option to select.'; + + @override + String get select_language => 'Select language'; + + @override + String get select => 'Select'; }