From da15c875d427e1655a80d0e5ac5a2a4fdf0b1766 Mon Sep 17 00:00:00 2001 From: AmirrezaChegini Date: Fri, 12 Dec 2025 16:22:38 +0330 Subject: [PATCH 1/2] add: reward feature --- assets/images/gift.png | Bin 0 -> 4407 bytes assets/images/gift_background.png | Bin 0 -> 11854 bytes assets/images/gift_disable.png | Bin 0 -> 5455 bytes assets/svg/icon_play_video.svg | 10 + lib/common_ui/resources/my_assets.dart | 7 + lib/core/constants/my_api.dart | 2 +- lib/core/routers/my_routes.dart | 8 + lib/core/widgets/dialog/reward_dialog.dart | 381 ++++++++++++++++++ lib/core/widgets/video/my_video_player.dart | 76 ++++ .../data/datasource/download_datasource.dart | 12 +- .../data/datasource/guider_datasource.dart | 2 +- .../home/presentation/bloc/home_bloc.dart | 2 +- .../data/datasource/level_datasource.dart | 8 +- lib/features/level/data/model/node_model.dart | 25 ++ .../level/data/model/prize_model.dart | 21 + .../level_repository_impl.dart | 6 +- .../level/domain/entity/node_entity.dart | 30 ++ .../level/domain/entity/prize_entity.dart | 25 ++ .../domain/entity/total_data_entity.dart | 6 +- .../domain/entity/total_data_entity.g.dart | 4 +- .../domain/repository/level_repository.dart | 6 +- .../domain/usecases/get_levels_usecase.dart | 6 +- .../level/presentation/bloc/level_bloc.dart | 29 +- .../level/presentation/bloc/level_event.dart | 2 +- .../level/presentation/ui/level_page.dart | 17 +- .../presentation/ui/widgets/level_widget.dart | 121 ------ .../presentation/ui/widgets/node_widget.dart | 161 ++++++++ .../data/datasource/question_datasource.dart | 19 +- lib/init_bindings.dart | 5 + lib/l10n/app_ar.arb | 3 +- lib/l10n/app_de.arb | 3 +- lib/l10n/app_en.arb | 3 +- lib/l10n/app_fr.arb | 3 +- lib/l10n/app_localizations.dart | 6 + lib/l10n/app_localizations_ar.dart | 3 + lib/l10n/app_localizations_de.dart | 3 + lib/l10n/app_localizations_en.dart | 3 + lib/l10n/app_localizations_fr.dart | 3 + lib/l10n/app_localizations_ru.dart | 3 + lib/l10n/app_localizations_tr.dart | 3 + lib/l10n/app_ru.arb | 3 +- lib/l10n/app_tr.arb | 3 +- pubspec.lock | 176 ++++++++ pubspec.yaml | 1 + 44 files changed, 1037 insertions(+), 173 deletions(-) create mode 100644 assets/images/gift.png create mode 100644 assets/images/gift_background.png create mode 100644 assets/images/gift_disable.png create mode 100644 assets/svg/icon_play_video.svg create mode 100644 lib/core/widgets/dialog/reward_dialog.dart create mode 100644 lib/core/widgets/video/my_video_player.dart create mode 100644 lib/features/level/data/model/node_model.dart create mode 100644 lib/features/level/data/model/prize_model.dart create mode 100644 lib/features/level/domain/entity/node_entity.dart create mode 100644 lib/features/level/domain/entity/prize_entity.dart delete mode 100644 lib/features/level/presentation/ui/widgets/level_widget.dart create mode 100644 lib/features/level/presentation/ui/widgets/node_widget.dart diff --git a/assets/images/gift.png b/assets/images/gift.png new file mode 100644 index 0000000000000000000000000000000000000000..1dfe4c412c41607f5e5dcc80e24d443244d6c714 GIT binary patch literal 4407 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 IM6N<$f*vyX>i_@% literal 0 HcmV?d00001 diff --git a/assets/images/gift_disable.png b/assets/images/gift_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..d16110741c98134d7ff2e097e45d33dac9ef13fb GIT binary patch literal 5455 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 + + + + + + + + + diff --git a/lib/common_ui/resources/my_assets.dart b/lib/common_ui/resources/my_assets.dart index 2153575..59ccf34 100644 --- a/lib/common_ui/resources/my_assets.dart +++ b/lib/common_ui/resources/my_assets.dart @@ -36,6 +36,9 @@ class MyAssets { static const String satellite = 'assets/images/satellite.png'; static const String planetFinal = 'assets/images/planet_final.png'; static const String behindDiamond = 'assets/images/behind_diamond.png'; + static const String gift = 'assets/images/gift.png'; + static const String giftDisable = 'assets/images/gift_disable.png'; + static const String giftBackground = 'assets/images/gift_background.png'; /// SVG static const String closeBtn = 'assets/svg/close_btn.svg'; @@ -69,6 +72,7 @@ class MyAssets { static const String diamondContainer = 'assets/svg/diamond_container.svg'; static const String iconPlay = 'assets/svg/icon_play.svg'; static const String iconNotif = 'assets/svg/icon_notif.svg'; + static const String iconPlayVideo = 'assets/svg/icon_play_video.svg'; static final List images = [ backgroundHome, @@ -103,5 +107,8 @@ class MyAssets { satellite, planetFinal, behindDiamond, + gift, + giftDisable, + giftBackground, ]; } \ No newline at end of file diff --git a/lib/core/constants/my_api.dart b/lib/core/constants/my_api.dart index 0e24eaa..a8aebd5 100644 --- a/lib/core/constants/my_api.dart +++ b/lib/core/constants/my_api.dart @@ -10,7 +10,7 @@ class MyApi { static const String baseUrl = 'https://hadihoda.newhorizonco.uk/api'; - static const String levels = '/quiz/optimized/v2/levels/'; + static const String levels = '/quiz/optimized/v3/levels/'; static const String images = '/quiz/optimized/download-all-files/images/'; static const String audios = '/quiz/optimized/v2/download-all-files/audio/'; } diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index bab2866..e149e3c 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -3,6 +3,7 @@ import 'package:go_router/go_router.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/middlewares/my_middlewares.dart'; import 'package:hadi_hoda_flutter/core/utils/my_context.dart'; +import 'package:hadi_hoda_flutter/core/widgets/video/my_video_player.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_bloc.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_event.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/ui/download_page.dart'; @@ -42,6 +43,7 @@ class Routes { static const String questionPage = '/question_page'; static const String guiderPage = '/guider_page'; static const String levelPage = '/level_page'; + static const String videoPage = '/video_page'; } final GoRouter appPages = _appPages(); @@ -147,5 +149,11 @@ GoRouter _appPages() => GoRouter( child: const QuestionPage(), ), ), + GoRoute( + name: Routes.videoPage, + path: Routes.videoPage, + builder: (context, state) => + MyVideoPlayer(videoURL: state.extra as String), + ), ], ); \ No newline at end of file diff --git a/lib/core/widgets/dialog/reward_dialog.dart b/lib/core/widgets/dialog/reward_dialog.dart new file mode 100644 index 0000000..cb63843 --- /dev/null +++ b/lib/core/widgets/dialog/reward_dialog.dart @@ -0,0 +1,381 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_animations.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; +import 'package:hadi_hoda_flutter/core/routers/my_routes.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/utils/set_platform_size.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/styles/dialog_background.dart'; +import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/prize_entity.dart'; +import 'package:lottie/lottie.dart'; + +Future showRewardDialog({ + required BuildContext context, + required PrizeEntity prize, +}) async { + await showDialog( + context: context, + builder: (context) => RewardDialog(prize: prize), + barrierColor: MyColors.purple.withValues(alpha: 0.82), + useSafeArea: false, + ); +} + +class RewardDialog extends StatelessWidget { + const RewardDialog({super.key, required this.prize}); + + final PrizeEntity prize; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: MyColors.transparent, + body: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), + child: Center( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: + setSize(context: context, mobile: 18, tablet: 120) ?? 0, + ), + child: Stack( + alignment: Alignment.center, + children: [ + Lottie.asset( + MyAnimations.confetti, + height: context.heightScreen, + fit: BoxFit.cover, + ), + Stack( + clipBehavior: Clip.none, + children: [ + DialogBackground( + child: Column( + spacing: 34, + children: [ + Text( + context.translate.reward, + style: MYTextStyle.titr0.copyWith( + color: Color(0XFF322386), + fontSize: 22, + ), + ), + Text( + prize.title ?? '', + style: MYTextStyle.titr0.copyWith( + color: Color(0XFF322386), + fontSize: 22, + ), + ), + CustomPaint( + painter: _CustomShapePainter(), + child: ClipPath( + clipper: _CustomShapeClipper(), + child: GestureDetector( + onTap: () { + context.pushNamed( + Routes.videoPage, + extra: prize.animationURL as String, + ); + }, + child: Stack( + alignment: Alignment.center, + children: [ + Image.network( + prize.imageURL ?? '', + fit: BoxFit.cover, + ), + MyImage( + image: MyAssets.iconPlayVideo, + ), + ], + ), + ), + ), + ), + ], + ), + ), + PositionedDirectional( + end: setSize(context: context, mobile: 30, tablet: 40), + top: -12, + child: GestureDetector( + onTap: context.pop, + behavior: HitTestBehavior.opaque, + child: MyImage( + image: MyAssets.closeBtn, + size: setSize(context: context, mobile: 40, tablet: 60), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } +} + +class _CustomShapePainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Paint strokePaint = Paint() + ..color = Color(0XFFF2F7FF) + ..style = PaintingStyle.stroke + ..strokeWidth = 4; + + final Path path = _CustomShapeClipper().getClip(size); + canvas.drawPath(path, strokePaint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return this != oldDelegate; + } +} + +class _CustomShapeClipper extends CustomClipper { + @override + Path getClip(Size size) { + // Original SVG dimensions to calculate the scaling factors. + final double originalWidth = 193.0; + final double originalHeight = 189.0; + + // Scaling factors to make the path responsive. + final double scaleX = size.width / originalWidth; + final double scaleY = size.height / originalHeight; + + // The path is defined using the scaled coordinates from the SVG. + final Path path = Path() + ..moveTo(148.483 * scaleX, 4.10254 * scaleY) + ..cubicTo( + 131.624 * scaleX, + 1.93333 * scaleY, + 111.221 * scaleX, + 1.00169 * scaleY, + 91.2451 * scaleX, + 1.2666 * scaleY, + ) + ..cubicTo( + 71.2667 * scaleX, + 1.53156 * scaleY, + 51.7626 * scaleX, + 2.99274 * scaleY, + 36.6973 * scaleX, + 5.59668 * scaleY, + ) + ..cubicTo( + 29.1597 * scaleX, + 6.8995 * scaleY, + 22.7796 * scaleX, + 8.48114 * scaleY, + 18.0205 * scaleX, + 10.3203 * scaleY, + ) + ..cubicTo( + 15.641 * scaleX, + 11.2399 * scaleY, + 13.7026 * scaleX, + 12.2101 * scaleY, + 12.2383 * scaleX, + 13.2188 * scaleY, + ) + ..cubicTo( + 10.7653 * scaleX, + 14.2333 * scaleY, + 9.84633 * scaleX, + 15.2359 * scaleY, + 9.3916 * scaleX, + 16.1904 * scaleY, + ) + ..cubicTo( + 8.252 * scaleX, + 18.5828 * scaleY, + 7.18153 * scaleX, + 22.466 * scaleY, + 6.2207 * scaleX, + 27.5654 * scaleY, + ) + ..cubicTo( + 5.26481 * scaleX, + 32.6387 * scaleY, + 4.43215 * scaleX, + 38.8273 * scaleY, + 3.73535 * scaleX, + 45.7744 * scaleY, + ) + ..cubicTo( + 2.34189 * scaleX, + 59.6675 * scaleY, + 1.49647 * scaleX, + 76.5363 * scaleY, + 1.27832 * scaleX, + 93.4678 * scaleY, + ) + ..cubicTo( + 1.06017 * scaleX, + 110.4 * scaleY, + 1.47057 * scaleX, + 127.372 * scaleY, + 2.58301 * scaleX, + 141.473 * scaleY, + ) + ..cubicTo( + 3.13928 * scaleX, + 148.524 * scaleY, + 3.86921 * scaleX, + 154.841 * scaleY, + 4.78125 * scaleX, + 160.068 * scaleY, + ) + ..cubicTo( + 5.69748 * scaleX, + 165.32 * scaleY, + 6.78334 * scaleX, + 169.385 * scaleY, + 8.01367 * scaleX, + 171.984 * scaleY, + ) + ..cubicTo( + 8.53417 * scaleX, + 173.084 * scaleY, + 9.59654 * scaleX, + 174.216 * scaleY, + 11.2891 * scaleX, + 175.343 * scaleY, + ) + ..cubicTo( + 12.9722 * scaleX, + 176.463 * scaleY, + 15.1988 * scaleX, + 177.524 * scaleY, + 17.9219 * scaleX, + 178.515 * scaleY, + ) + ..cubicTo( + 23.3679 * scaleX, + 180.496 * scaleY, + 30.6491 * scaleX, + 182.138 * scaleY, + 39.1807 * scaleX, + 183.437 * scaleY, + ) + ..cubicTo( + 56.2336 * scaleX, + 186.032 * scaleY, + 78.0934 * scaleX, + 187.222 * scaleY, + 99.8242 * scaleX, + 187.064 * scaleY, + ) + ..cubicTo( + 121.556 * scaleX, + 186.906 * scaleY, + 143.101 * scaleX, + 185.4 * scaleY, + 159.525 * scaleX, + 182.622 * scaleY, + ) + ..cubicTo( + 167.745 * scaleX, + 181.232 * scaleY, + 174.627 * scaleX, + 179.531 * scaleY, + 179.594 * scaleX, + 177.548 * scaleY, + ) + ..cubicTo( + 182.079 * scaleX, + 176.556 * scaleY, + 184.034 * scaleX, + 175.512 * scaleY, + 185.429 * scaleX, + 174.437 * scaleY, + ) + ..cubicTo( + 186.83 * scaleX, + 173.355 * scaleY, + 187.568 * scaleX, + 172.319 * scaleY, + 187.812 * scaleX, + 171.361 * scaleY, + ) + ..lineTo( + 187.812 * scaleX, + 171.361 * scaleY, + ) // In SVG, this was H (horizontal line), equivalent to lineTo in Flutter + ..cubicTo( + 189.156 * scaleX, + 166.074 * scaleY, + 190.148 * scaleX, + 155.525 * scaleY, + 190.773 * scaleX, + 142.157 * scaleY, + ) + ..cubicTo( + 191.396 * scaleX, + 128.832 * scaleY, + 191.651 * scaleX, + 112.822 * scaleY, + 191.552 * scaleX, + 96.6875 * scaleY, + ) + ..cubicTo( + 191.453 * scaleX, + 80.5539 * scaleY, + 191.001 * scaleX, + 64.3091 * scaleY, + 190.213 * scaleX, + 50.5156 * scaleY, + ) + ..cubicTo( + 189.423 * scaleX, + 36.6928 * scaleY, + 188.299 * scaleX, + 25.4153 * scaleY, + 186.876 * scaleX, + 19.167 * scaleY, + ) + ..cubicTo( + 186.404 * scaleX, + 17.0929 * scaleY, + 185.566 * scaleX, + 15.3424 * scaleY, + 184.087 * scaleX, + 14.1582 * scaleY, + ) + ..cubicTo( + 181.343 * scaleX, + 11.9613 * scaleY, + 176.72 * scaleX, + 9.98089 * scaleY, + 170.561 * scaleX, + 8.27539 * scaleY, + ) + ..cubicTo( + 164.434 * scaleX, + 6.579 * scaleY, + 156.914 * scaleX, + 5.18731 * scaleY, + 148.483 * scaleX, + 4.10254 * scaleY, + ) + ..close(); // Closes the path to form a complete shape. + + return path; + } + + @override + bool shouldReclip(covariant CustomClipper oldClipper) { + return this != oldClipper; + } +} diff --git a/lib/core/widgets/video/my_video_player.dart b/lib/core/widgets/video/my_video_player.dart new file mode 100644 index 0000000..7e37ffb --- /dev/null +++ b/lib/core/widgets/video/my_video_player.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; +import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; +import 'package:hadi_hoda_flutter/core/services/audio_service.dart'; +import 'package:hadi_hoda_flutter/core/utils/my_device.dart'; +import 'package:hadi_hoda_flutter/init_bindings.dart'; +import 'package:pod_player/pod_player.dart'; + +class MyVideoPlayer extends StatefulWidget { + const MyVideoPlayer({super.key, required this.videoURL}); + + final String? videoURL; + + @override + State createState() => _MyVideoPlayerState(); +} + +class _MyVideoPlayerState extends State { + late final PodPlayerController _controller; + final AudioService _mainAudioService = locator( + instanceName: MyConstants.mainAudioService, + ); + final AudioService _effectAudioService = locator( + instanceName: MyConstants.effectAudioService, + ); + + @override + void initState() { + super.initState(); + _mainAudioService.stop(); + _effectAudioService.stop(); + _controller = PodPlayerController( + podPlayerConfig: PodPlayerConfig( + autoPlay: false, + isLooping: false, + wakelockEnabled: true, + ), + playVideoFrom: PlayVideoFrom.network(widget.videoURL ?? ''), + )..initialise(); + } + + @override + void dispose() { + _controller.dispose(); + _mainAudioService.play(); + _effectAudioService.play(); + MyDevice.setPortrait(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: MyColors.black, + extendBodyBehindAppBar: true, + appBar: AppBar( + backgroundColor: MyColors.transparent, + foregroundColor: MyColors.white, + ), + body: PodVideoPlayer( + controller: _controller, + matchVideoAspectRatioToFrame: true, + matchFrameAspectRatioToVideo: true, + videoAspectRatio: _controller.videoPlayerValue?.aspectRatio ?? 16 / 9, + podProgressBarConfig: PodProgressBarConfig(), + onToggleFullScreen: (isFullScreen) async { + if (isFullScreen) { + await MyDevice.setAllOrientations(); + } else { + await MyDevice.setPortrait(); + } + }, + ), + ); + } +} diff --git a/lib/features/download/data/datasource/download_datasource.dart b/lib/features/download/data/datasource/download_datasource.dart index 587574d..843d969 100644 --- a/lib/features/download/data/datasource/download_datasource.dart +++ b/lib/features/download/data/datasource/download_datasource.dart @@ -10,8 +10,8 @@ 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/core/utils/storage_path.dart'; import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.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/data/model/node_model.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart'; import 'package:hive/hive.dart'; @@ -146,11 +146,11 @@ class DownloadDatasourceImpl implements IDownloadDatasource { path: MyApi.levels, queryParameters: {'lang': selectedLanguage}, ); - final List levels = BaseResponse.getDataList( - response?['result'], - (json) => LevelModel.fromJson(json), + final List levels = BaseResponse.getDataList( + response?['path'], + (json) => NodeModel.fromJson(json), ); - await data.add(TotalDataEntity(code: selectedLanguage, levels: levels)); + await data.add(TotalDataEntity(code: selectedLanguage, nodes: levels)); } } diff --git a/lib/features/guider/data/datasource/guider_datasource.dart b/lib/features/guider/data/datasource/guider_datasource.dart index b2c2a12..6816cf5 100644 --- a/lib/features/guider/data/datasource/guider_datasource.dart +++ b/lib/features/guider/data/datasource/guider_datasource.dart @@ -24,7 +24,7 @@ class GuiderDatasourceImpl implements IGuiderDatasource { (e) => e.code == selectedLanguage, orElse: () => TotalDataEntity(), ); - final LevelEntity? findLevel = findData.levels?.first; + final LevelEntity? findLevel = findData.nodes?.first.level; return findLevel ?? LevelEntity(); } catch (e) { throw MyException(errorMessage: '$e'); diff --git a/lib/features/home/presentation/bloc/home_bloc.dart b/lib/features/home/presentation/bloc/home_bloc.dart index 706dfa9..3389b8b 100644 --- a/lib/features/home/presentation/bloc/home_bloc.dart +++ b/lib/features/home/presentation/bloc/home_bloc.dart @@ -42,7 +42,7 @@ class HomeBloc extends Bloc { (e) => e.code == selectedLanguage, orElse: () => TotalDataEntity(), ); - if (findData.levels?.isNotEmpty ?? false) { + if (findData.nodes?.isNotEmpty ?? false) { context.goNamed(Routes.levelPage); } else { context.goNamed(Routes.downloadPage); diff --git a/lib/features/level/data/datasource/level_datasource.dart b/lib/features/level/data/datasource/level_datasource.dart index 64cdcf9..77490c1 100644 --- a/lib/features/level/data/datasource/level_datasource.dart +++ b/lib/features/level/data/datasource/level_datasource.dart @@ -2,12 +2,12 @@ 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/params/level_params.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; -import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart'; import 'package:hive/hive.dart'; abstract class ILevelDatasource { - Future> getLevels({required LevelParams params}); + Future> getLevels({required LevelParams params}); } /// Local @@ -15,7 +15,7 @@ class LocalLevelDatasourceImpl implements ILevelDatasource { const LocalLevelDatasourceImpl(); @override - Future> getLevels({required LevelParams params}) async { + Future> getLevels({required LevelParams params}) async { try { final String selectedLanguage = LocalStorage.readData( key: MyConstants.selectLanguage) ?? MyConstants.defaultLanguage; @@ -24,7 +24,7 @@ class LocalLevelDatasourceImpl implements ILevelDatasource { (e) => e.code == selectedLanguage, orElse: () => TotalDataEntity(), ); - return findData.levels ?? []; + return findData.nodes ?? []; } catch (_) { throw MyException(errorMessage: 'Operation Failed'); } diff --git a/lib/features/level/data/model/node_model.dart b/lib/features/level/data/model/node_model.dart new file mode 100644 index 0000000..d476f17 --- /dev/null +++ b/lib/features/level/data/model/node_model.dart @@ -0,0 +1,25 @@ +import 'package:hadi_hoda_flutter/features/level/data/model/level_model.dart'; +import 'package:hadi_hoda_flutter/features/level/data/model/prize_model.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; + +class NodeModel extends NodeEntity { + NodeModel({super.nodeType, super.level, super.prize}); + + factory NodeModel.fromJson(Map json) { + return NodeModel( + nodeType: json['node_type'] == null + ? null + : NodeType.fromJson[json['node_type']], + level: json['node_type'] == null + ? null + : json['node_type'] == 'level' + ? LevelModel.fromJson(json['data']) + : null, + prize: json['node_type'] == null + ? null + : json['node_type'] == 'prize' + ? PrizeModel.fromJson(json['data']) + : null, + ); + } +} diff --git a/lib/features/level/data/model/prize_model.dart b/lib/features/level/data/model/prize_model.dart new file mode 100644 index 0000000..7655a37 --- /dev/null +++ b/lib/features/level/data/model/prize_model.dart @@ -0,0 +1,21 @@ +import 'package:hadi_hoda_flutter/features/level/domain/entity/prize_entity.dart'; + +class PrizeModel extends PrizeEntity { + PrizeModel({ + super.id, + super.afterLevel, + super.title, + super.imageURL, + super.animationURL, + }); + + factory PrizeModel.fromJson(Map json) { + return PrizeModel( + id: json['id'], + afterLevel: json['after_level'], + title: json['title'], + imageURL: json['image_url'], + animationURL: json['animation_url'], + ); + } +} diff --git a/lib/features/level/data/repository_impl/level_repository_impl.dart b/lib/features/level/data/repository_impl/level_repository_impl.dart index 07d9366..51fdb4f 100644 --- a/lib/features/level/data/repository_impl/level_repository_impl.dart +++ b/lib/features/level/data/repository_impl/level_repository_impl.dart @@ -3,7 +3,7 @@ import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; import 'package:hadi_hoda_flutter/core/params/level_params.dart'; import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; import 'package:hadi_hoda_flutter/features/level/data/datasource/level_datasource.dart'; -import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/repository/level_repository.dart'; class LevelRepositoryImpl implements ILevelRepository { @@ -12,11 +12,11 @@ class LevelRepositoryImpl implements ILevelRepository { const LevelRepositoryImpl(this.datasource); @override - Future, MyException>> getLevels({ + Future, MyException>> getLevels({ required LevelParams params, }) async { try { - final List response = await datasource.getLevels( + final List response = await datasource.getLevels( params: params, ); return DataState.success(response); diff --git a/lib/features/level/domain/entity/node_entity.dart b/lib/features/level/domain/entity/node_entity.dart new file mode 100644 index 0000000..6c9fa84 --- /dev/null +++ b/lib/features/level/domain/entity/node_entity.dart @@ -0,0 +1,30 @@ +import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/prize_entity.dart'; +import 'package:hive/hive.dart'; + +part 'node_entity.g.dart'; + +@HiveType(typeId: 8) +enum NodeType { + @HiveField(0) + level, + @HiveField(1) + prize; + + static Map get fromJson => { + 'level': NodeType.level, + 'prize': NodeType.prize, + }; +} + +@HiveType(typeId: 7) +class NodeEntity extends HiveObject { + @HiveField(0) + NodeType? nodeType; + @HiveField(1) + LevelEntity? level; + @HiveField(2) + PrizeEntity? prize; + + NodeEntity({this.nodeType, this.level, this.prize}); +} diff --git a/lib/features/level/domain/entity/prize_entity.dart b/lib/features/level/domain/entity/prize_entity.dart new file mode 100644 index 0000000..7af133b --- /dev/null +++ b/lib/features/level/domain/entity/prize_entity.dart @@ -0,0 +1,25 @@ +import 'package:hive/hive.dart'; + +part 'prize_entity.g.dart'; + +@HiveType(typeId: 6) +class PrizeEntity extends HiveObject { + @HiveField(0) + int? id; + @HiveField(1) + int? afterLevel; + @HiveField(2) + String? title; + @HiveField(3) + String? imageURL; + @HiveField(4) + String? animationURL; + + PrizeEntity({ + this.id, + this.afterLevel, + this.title, + this.imageURL, + this.animationURL, + }); +} diff --git a/lib/features/level/domain/entity/total_data_entity.dart b/lib/features/level/domain/entity/total_data_entity.dart index 1428455..4b0c5b8 100644 --- a/lib/features/level/domain/entity/total_data_entity.dart +++ b/lib/features/level/domain/entity/total_data_entity.dart @@ -1,4 +1,4 @@ -import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; import 'package:hive/hive.dart'; part 'total_data_entity.g.dart'; @@ -8,10 +8,10 @@ class TotalDataEntity extends HiveObject{ @HiveField(0) String? code; @HiveField(1) - List? levels; + List? nodes; TotalDataEntity({ this.code, - this.levels, + this.nodes, }); } \ 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 index 947076d..9512c61 100644 --- a/lib/features/level/domain/entity/total_data_entity.g.dart +++ b/lib/features/level/domain/entity/total_data_entity.g.dart @@ -18,7 +18,7 @@ class TotalDataEntityAdapter extends TypeAdapter { }; return TotalDataEntity( code: fields[0] as String?, - levels: (fields[1] as List?)?.cast(), + nodes: (fields[1] as List?)?.cast(), ); } @@ -29,7 +29,7 @@ class TotalDataEntityAdapter extends TypeAdapter { ..writeByte(0) ..write(obj.code) ..writeByte(1) - ..write(obj.levels); + ..write(obj.nodes); } @override diff --git a/lib/features/level/domain/repository/level_repository.dart b/lib/features/level/domain/repository/level_repository.dart index 672d6f4..fd29b6b 100644 --- a/lib/features/level/domain/repository/level_repository.dart +++ b/lib/features/level/domain/repository/level_repository.dart @@ -1,8 +1,10 @@ import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; import 'package:hadi_hoda_flutter/core/params/level_params.dart'; import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; -import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; abstract class ILevelRepository { - Future, MyException>> getLevels({required LevelParams params}); + Future, MyException>> getLevels({ + required LevelParams params, + }); } diff --git a/lib/features/level/domain/usecases/get_levels_usecase.dart b/lib/features/level/domain/usecases/get_levels_usecase.dart index 3f12106..fe555c0 100644 --- a/lib/features/level/domain/usecases/get_levels_usecase.dart +++ b/lib/features/level/domain/usecases/get_levels_usecase.dart @@ -2,16 +2,16 @@ import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; import 'package:hadi_hoda_flutter/core/params/level_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/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/repository/level_repository.dart'; -class GetLevelsUseCase implements UseCase, LevelParams> { +class GetLevelsUseCase implements UseCase, LevelParams> { final ILevelRepository repository; const GetLevelsUseCase(this.repository); @override - Future, MyException>> call(LevelParams params) { + Future, MyException>> call(LevelParams params) { return repository.getLevels(params: params); } } diff --git a/lib/features/level/presentation/bloc/level_bloc.dart b/lib/features/level/presentation/bloc/level_bloc.dart index 981cc3e..62449dc 100644 --- a/lib/features/level/presentation/bloc/level_bloc.dart +++ b/lib/features/level/presentation/bloc/level_bloc.dart @@ -13,12 +13,15 @@ import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; import 'package:hadi_hoda_flutter/core/utils/my_context.dart'; import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/reward_dialog.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_location.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/prize_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/usecases/get_levels_usecase.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_event.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_state.dart'; -import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_widget.dart'; +import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/node_widget.dart'; class LevelBloc extends Bloc { /// ------------constructor------------ @@ -174,7 +177,7 @@ class LevelBloc extends Bloc { ]; - final List levelList = []; + final List nodeList = []; late final Stream volumeStream; @@ -221,6 +224,14 @@ class LevelBloc extends Bloc { } } + bool getReward(int index) { + final int currentLevel = int.parse( + LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', + ); + + return currentLevel > index; + } + Future changeMute() async { await Future.wait([ _mainAudioService.changeMute(), @@ -235,7 +246,15 @@ class LevelBloc extends Bloc { return currentLevel - 1; } - /// ------------Api Calls------------ + + void showReward({ + required BuildContext context, + required PrizeEntity prize, + }) { + showRewardDialog(context: context, prize: prize); + } + + /// ------------Event Calls------------ FutureOr _getLevelListEvent(GetLevelListEvent event, Emitter emit) async { final int currentLevel = int.parse( @@ -244,11 +263,11 @@ class LevelBloc extends Bloc { await _getLeveslUseCase(LevelParams()).then((value) { value.fold( (data) async { - levelList.addAll(data); + nodeList.addAll(data); try { emit(state.copyWith( getLevelStatus: const BaseComplete(''), - chooseLevel: data.singleWhere((e) => e.order == currentLevel), + chooseLevel: data.singleWhere((e) => e.level?.order == currentLevel).level, )); } catch (e) { emit(state.copyWith( diff --git a/lib/features/level/presentation/bloc/level_event.dart b/lib/features/level/presentation/bloc/level_event.dart index 818ed6f..b5824a6 100644 --- a/lib/features/level/presentation/bloc/level_event.dart +++ b/lib/features/level/presentation/bloc/level_event.dart @@ -1,5 +1,5 @@ import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; -import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_widget.dart'; +import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/node_widget.dart'; sealed class LevelEvent { const LevelEvent(); diff --git a/lib/features/level/presentation/ui/level_page.dart b/lib/features/level/presentation/ui/level_page.dart index 2fb4ce7..1c8c075 100644 --- a/lib/features/level/presentation/ui/level_page.dart +++ b/lib/features/level/presentation/ui/level_page.dart @@ -16,7 +16,7 @@ import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_event.d import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_state.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/diamond_level.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_path.dart'; -import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_widget.dart'; +import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/node_widget.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/play_button.dart'; class LevelPage extends StatelessWidget { @@ -208,7 +208,7 @@ class LevelPage extends StatelessWidget { clipBehavior: Clip.none, children: [ ...List.generate( - context.read().levelList.length, + context.read().nodeList.length, (index) => Positioned( top: context.read().locationList[index].top, bottom: context.read().locationList[index].bottom, @@ -217,10 +217,17 @@ class LevelPage extends StatelessWidget { child: BlocBuilder( buildWhen: (previous, current) => previous.chooseLevel?.id != current.chooseLevel?.id, - builder: (context, state) => LevelWidget( + builder: (context, state) => NodeWidget( chooseLevel: state.chooseLevel, - level: context.read().levelList[index], - type: context.read().getLevelType(index + 1), + node: context.read().nodeList[index], + type: context.read().getLevelType, + getReward: context.read().getReward, + onRewardPressed: (prize) { + context.read().showReward( + context: context, + prize: prize, + ); + }, onTap: (LevelEntity level, LevelType type) { context.read().add( ChooseLevelEvent(level, type), diff --git a/lib/features/level/presentation/ui/widgets/level_widget.dart b/lib/features/level/presentation/ui/widgets/level_widget.dart deleted file mode 100644 index f39fc81..0000000 --- a/lib/features/level/presentation/ui/widgets/level_widget.dart +++ /dev/null @@ -1,121 +0,0 @@ -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_colors.dart'; -import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; -import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; -import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; -import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; - -enum LevelType { - unFinished, - finished, - current; - - static Map get image => { - LevelType.unFinished: MyAssets.level, - LevelType.finished: MyAssets.finishedLevel, - LevelType.current: MyAssets.currentLevel, - }; - - static Map get textShadowColor => { - LevelType.unFinished: Color(0XFF5B5B5B), - LevelType.finished: Color(0XFF096D7B), - LevelType.current: Color(0XFF91500D), - }; - - static Map get textColor => { - LevelType.unFinished: Color(0XFFEDEDED), - LevelType.finished: Color(0XFFFFF2D0), - LevelType.current: Color(0XFFFFF2D0), - }; -} - -class LevelWidget extends StatelessWidget { - const LevelWidget({ - super.key, - required this.level, - required this.type, - required this.chooseLevel, - this.onTap, - }); - - final LevelType type; - final LevelEntity level; - final LevelEntity? chooseLevel; - final Function(LevelEntity level, LevelType type)? onTap; - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: () => onTap?.call(level, type), - child: Stack( - alignment: Alignment.topCenter, - clipBehavior: Clip.none, - children: [ - MyImage( - image: LevelType.image[type] ?? MyAssets.level, - fit: BoxFit.cover, - size: setSize(context: context, tablet: 70, mobile: 44), - ), - ShaderMask( - blendMode: BlendMode.modulate, - shaderCallback: (bounds) => LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0XFFFFFFFF), - LevelType.textColor[type] ?? MyColors.white, - ], - ).createShader(bounds), - child: Text( - '${level.order ?? 0}', - maxLines: 1, - style: MYTextStyle.button1.copyWith( - fontSize: setSize(context: context, mobile: 24, tablet: 34), - shadows: [ - BoxShadow( - color: LevelType.textShadowColor[type] ?? MyColors.white, - offset: Offset(0, 2.97), - ) - ], - ), - ), - ), - if(level.id == chooseLevel?.id) - Positioned( - top: setSize(context: context, mobile: -20, tablet: -30), - child: MyImage( - image: MyAssets.location, - size: setSize(context: context,mobile: 26, tablet: 40), - ), - ), - if(type == LevelType.finished) - Positioned( - bottom: 0, - child: Container( - height: setSize(context: context, mobile: 17, tablet: 24), - width: setSize(context: context, mobile: 17, tablet: 24), - 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), - ), - ), - ], - ), - ); - } -} diff --git a/lib/features/level/presentation/ui/widgets/node_widget.dart b/lib/features/level/presentation/ui/widgets/node_widget.dart new file mode 100644 index 0000000..46af3e4 --- /dev/null +++ b/lib/features/level/presentation/ui/widgets/node_widget.dart @@ -0,0 +1,161 @@ +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_colors.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; +import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; +import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; +import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/prize_entity.dart'; + +enum LevelType { + unFinished, + finished, + current; + + static Map get image => { + LevelType.unFinished: MyAssets.level, + LevelType.finished: MyAssets.finishedLevel, + LevelType.current: MyAssets.currentLevel, + }; + + static Map get textShadowColor => { + LevelType.unFinished: Color(0XFF5B5B5B), + LevelType.finished: Color(0XFF096D7B), + LevelType.current: Color(0XFF91500D), + }; + + static Map get textColor => { + LevelType.unFinished: Color(0XFFEDEDED), + LevelType.finished: Color(0XFFFFF2D0), + LevelType.current: Color(0XFFFFF2D0), + }; +} + +class NodeWidget extends StatelessWidget { + const NodeWidget({ + super.key, + required this.node, + required this.getReward, + required this.type, + required this.chooseLevel, + this.onTap, + this.onRewardPressed, + }); + + final LevelType Function(int index) type; + final bool Function(int index) getReward; + final NodeEntity node; + final LevelEntity? chooseLevel; + final Function(LevelEntity level, LevelType type)? onTap; + final void Function(PrizeEntity prize)? onRewardPressed; + + @override + Widget build(BuildContext context) { + return Builder( + builder: (context) { + if (node.nodeType == NodeType.prize) { + return MyInkwell( + onTap: () { + if (getReward(node.prize?.afterLevel ?? 1)) { + onRewardPressed?.call(node.prize ?? PrizeEntity()); + } + }, + child: Stack( + alignment: Alignment.center, + children: [ + if (getReward(node.prize?.afterLevel ?? 1)) ...{ + MyImage(image: MyAssets.giftBackground, size: 70), + MyImage(image: MyAssets.gift, size: 50), + } else ...{ + MyImage(image: MyAssets.giftDisable, size: 50), + }, + ], + ), + ); + } else { + return InkWell( + onTap: () => onTap?.call( + node.level ?? LevelEntity(), + type(node.level?.order ?? 1), + ), + child: Stack( + alignment: Alignment.topCenter, + clipBehavior: Clip.none, + children: [ + MyImage( + image: + LevelType.image[type(node.level?.order ?? 1)] ?? + MyAssets.level, + fit: BoxFit.cover, + size: setSize(context: context, tablet: 70, mobile: 44), + ), + ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0XFFFFFFFF), + LevelType.textColor[type(node.level?.order ?? 1)] ?? + MyColors.white, + ], + ).createShader(bounds), + child: Text( + '${node.level?.order ?? 0}', + maxLines: 1, + style: MYTextStyle.button1.copyWith( + fontSize: setSize( + context: context, + mobile: 24, + tablet: 34, + ), + shadows: [ + BoxShadow( + color: + LevelType.textShadowColor[type( + node.level?.order ?? 1, + )] ?? + MyColors.white, + offset: Offset(0, 2.97), + ), + ], + ), + ), + ), + if (node.level?.id == chooseLevel?.id) + Positioned( + top: setSize(context: context, mobile: -20, tablet: -30), + child: MyImage( + image: MyAssets.location, + size: setSize(context: context, mobile: 26, tablet: 40), + ), + ), + if (type(node.level?.order ?? 1) == LevelType.finished) + Positioned( + bottom: 0, + child: Container( + height: setSize(context: context, mobile: 17, tablet: 24), + width: setSize(context: context, mobile: 17, tablet: 24), + 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), + ), + ), + ], + ), + ); + } + }, + ); + } +} diff --git a/lib/features/question/data/datasource/question_datasource.dart b/lib/features/question/data/datasource/question_datasource.dart index 831f844..a89b1f3 100644 --- a/lib/features/question/data/datasource/question_datasource.dart +++ b/lib/features/question/data/datasource/question_datasource.dart @@ -3,6 +3,7 @@ import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; import 'package:hadi_hoda_flutter/core/params/question_params.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/node_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart'; import 'package:hive/hive.dart'; @@ -25,11 +26,11 @@ class QuestionDatasourceImpl implements IQuestionDatasource { (e) => e.code == selectedLanguage, orElse: () => TotalDataEntity(), ); - final LevelEntity? findLevel = findData.levels?.singleWhere( - (e) => e.id == params.id, - orElse: () => LevelEntity(), + final NodeEntity? findLevel = findData.nodes?.singleWhere( + (e) => e.level?.id == params.id, + orElse: () => NodeEntity(), ); - return findLevel ?? LevelEntity(); + return findLevel?.level ?? LevelEntity(); } catch (e) { throw MyException(errorMessage: '$e'); } @@ -47,14 +48,14 @@ class QuestionDatasourceImpl implements IQuestionDatasource { (e) => e.code == selectedLanguage, orElse: () => TotalDataEntity(), ); - if(index > (findData.levels?.length ?? 0)){ + if(index > (findData.nodes?.length ?? 0)){ throw MyException(); } - final LevelEntity? findLevel = findData.levels?.singleWhere( - (e) => e.order == index, - orElse: () => LevelEntity(), + final NodeEntity? findLevel = findData.nodes?.singleWhere( + (e) => e.level?.order == index, + orElse: () => NodeEntity(), ); - return findLevel ?? LevelEntity(); + return findLevel?.level ?? LevelEntity(); } catch (e) { throw MyException(errorMessage: '$e'); } diff --git a/lib/init_bindings.dart b/lib/init_bindings.dart index c950e18..9a80563 100644 --- a/lib/init_bindings.dart +++ b/lib/init_bindings.dart @@ -20,6 +20,8 @@ import 'package:hadi_hoda_flutter/features/guider/domain/usecases/get_first_leve 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/node_entity.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/prize_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'; @@ -92,7 +94,10 @@ Future initDataBase() async { ..registerAdapter(AnswerEntityAdapter()) ..registerAdapter(QuestionEntityAdapter()) ..registerAdapter(HadithEntityAdapter()) + ..registerAdapter(PrizeEntityAdapter()) ..registerAdapter(LevelEntityAdapter()) + ..registerAdapter(NodeTypeAdapter()) + ..registerAdapter(NodeEntityAdapter()) ..registerAdapter(TotalDataEntityAdapter()); await Hive.openBox(MyConstants.levelBox); diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index eac3c2f..6999f41 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -35,5 +35,6 @@ "showcase_notif": "سيقوم الراوي بقراءة\nالإجابات والخيارات لك.", "showcase_stepper": "هنا سترى الأسئلة الخاصة\nبهذه المرحلة للوصول\nإلى الماسة.", "showcase_hadith": "اطّلع على المصادر والأحاديث\nلهذا السؤال", - "showcase_guide": "هذا دليل سيساعدك\nفي رحلتك." + "showcase_guide": "هذا دليل سيساعدك\nفي رحلتك.", + "reward": "جائزة" } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 5e2cf47..156cbbd 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -35,5 +35,6 @@ "showcase_notif": "Der Sprecher wird\ndir die Antwortmöglichkeiten\nvorlesen.", "showcase_stepper": "Hier siehst du die\nFragen für diese\nStufe, um den\nDiamanten zu erreichen.", "showcase_hadith": "Quellen und\nHadithe zu dieser\nFrage ansehen.", - "showcase_guide": "Dies ist eine Anleitung,\ndie dir hilft." + "showcase_guide": "Dies ist eine Anleitung,\ndie dir hilft.", + "reward": "belohnen" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cdb4691..e4b3a06 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -35,5 +35,6 @@ "showcase_notif": "The announcer will\nread the answers to\nthe options to you.", "showcase_stepper": "Here you will see the\nquestions for this\nstage to reach the\ndiamond.", "showcase_hadith": "View sources and\nhadiths for this\nquestion", - "showcase_guide": "This is a guide that will\nhelp you." + "showcase_guide": "This is a guide that will\nhelp you.", + "reward": "Reward" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 8c008a6..5ba2ce2 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -35,5 +35,6 @@ "showcase_notif": "Le narrateur lira\nles réponses des\noptions pour toi.", "showcase_stepper": "Ici, tu verras les\nquestions de cette\nétape pour atteindre\nle diamant.", "showcase_hadith": "Consulte les sources et\nles hadiths pour cette\nquestion", - "showcase_guide": "Ceci est un guide\nqui t’aidera." + "showcase_guide": "Ceci est un guide\nqui t’aidera.", + "reward": "récompense" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index dce9f70..68eec8f 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -321,6 +321,12 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'This is a guide that will\nhelp you.'** String get showcase_guide; + + /// No description provided for @reward. + /// + /// In en, this message translates to: + /// **'Reward'** + String get reward; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index fdbe46b..3c5f345 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -119,4 +119,7 @@ class AppLocalizationsAr extends AppLocalizations { @override String get showcase_guide => 'هذا دليل سيساعدك\nفي رحلتك.'; + + @override + String get reward => 'جائزة'; } diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index bc7873b..49f7a1f 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -126,4 +126,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get showcase_guide => 'Dies ist eine Anleitung,\ndie dir hilft.'; + + @override + String get reward => 'belohnen'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index baf9d51..991362a 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -123,4 +123,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get showcase_guide => 'This is a guide that will\nhelp you.'; + + @override + String get reward => 'Reward'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index f870a7e..6e6ec23 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -124,4 +124,7 @@ class AppLocalizationsFr extends AppLocalizations { @override String get showcase_guide => 'Ceci est un guide\nqui t’aidera.'; + + @override + String get reward => 'récompense'; } diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index dbd16a8..e374e4a 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -124,4 +124,7 @@ class AppLocalizationsRu extends AppLocalizations { @override String get showcase_guide => 'Это руководство,\nкоторое поможет тебе.'; + + @override + String get reward => 'награда'; } diff --git a/lib/l10n/app_localizations_tr.dart b/lib/l10n/app_localizations_tr.dart index 0ae805a..db16200 100644 --- a/lib/l10n/app_localizations_tr.dart +++ b/lib/l10n/app_localizations_tr.dart @@ -123,4 +123,7 @@ class AppLocalizationsTr extends AppLocalizations { @override String get showcase_guide => 'Bu, sana yardımcı olacak\nbir rehberdir.'; + + @override + String get reward => 'ödül'; } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index c457456..9460133 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -35,5 +35,6 @@ "showcase_notif": "Диктор прочитает\nтебе все варианты\nответов.", "showcase_stepper": "Здесь ты увидишь\nвопросы этого этапа,\nчтобы получить\nалмаз.", "showcase_hadith": "Просмотри источники и\nхадисы по этому вопросу", - "showcase_guide": "Это руководство,\nкоторое поможет тебе." + "showcase_guide": "Это руководство,\nкоторое поможет тебе.", + "reward": "награда" } diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index e8b78c8..9e4691c 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -35,5 +35,6 @@ "showcase_notif": "Anlatıcı, seçeneklerin\ncevaplarını sana\nokuyacak.", "showcase_stepper": "Burada, elmasa ulaşmak\niçin bu aşamadaki\nsoruları göreceksin.", "showcase_hadith": "Bu soruya ait\nkaynakları ve hadisleri\nincele", - "showcase_guide": "Bu, sana yardımcı olacak\nbir rehberdir." + "showcase_guide": "Bu, sana yardımcı olacak\nbir rehberdir.", + "reward": "ödül" } diff --git a/pubspec.lock b/pubspec.lock index f14a07c..b4f8cb6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -145,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" + source: hosted + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -201,6 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" dart_style: dependency: transitive description: @@ -209,6 +225,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.6" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" dio: dependency: "direct main" description: @@ -317,6 +341,14 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8" + url: "https://pub.dev" + source: hosted + version: "3.1.0" frontend_server_client: dependency: transitive description: @@ -325,6 +357,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + get: + dependency: transitive + description: + name: get + sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a" + url: "https://pub.dev" + source: hosted + version: "4.7.3" get_it: dependency: "direct main" description: @@ -381,6 +421,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" http: dependency: transitive description: @@ -557,6 +605,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d + url: "https://pub.dev" + source: hosted + version: "9.0.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" + url: "https://pub.dev" + source: hosted + version: "3.2.1" path: dependency: transitive description: @@ -653,6 +717,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pod_player: + dependency: "direct main" + description: + name: pod_player + sha256: "38564f2e0d9b06fa9e4ad5023be2f6fa4cd9f95f70ace2f517a6d899b166a502" + url: "https://pub.dev" + source: hosted + version: "0.2.2" pool: dependency: transitive description: @@ -789,6 +861,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.1" + simple_sparse_list: + dependency: transitive + description: + name: simple_sparse_list + sha256: aa648fd240fa39b49dcd11c19c266990006006de6699a412de485695910fbc1f + url: "https://pub.dev" + source: hosted + version: "0.1.4" sky_engine: dependency: transitive description: flutter @@ -898,6 +978,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0d99edbd2e74726bed2e4989713c8bec02e5581628e334d8c88c0271593fb402" + url: "https://pub.dev" + source: hosted + version: "1.1.8" + universal_html: + dependency: transitive + description: + name: universal_html + sha256: c0bcae5c733c60f26c7dfc88b10b0fd27cbcc45cb7492311cdaa6067e21c9cd4 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: f63cbc48103236abf48e345e07a03ce5757ea86285ed313a6a032596ed9301e2 + url: "https://pub.dev" + source: hosted + version: "2.3.1" uuid: dependency: transitive description: @@ -938,6 +1042,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + video_player: + dependency: transitive + description: + name: video_player + sha256: "096bc28ce10d131be80dfb00c223024eb0fba301315a406728ab43dd99c45bdf" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: d74b66f283afff135d5be0ceccca2ca74dff7df1e9b1eaca6bd4699875d3ae60 + url: "https://pub.dev" + source: hosted + version: "2.8.22" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: e4d33b79a064498c6eb3a6a492b6a5012573d4943c28d566caf1a6c0840fe78d + url: "https://pub.dev" + source: hosted + version: "2.8.8" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: "57c5d73173f76d801129d0531c2774052c5a7c11ccb962f1830630decd9f24ec" + url: "https://pub.dev" + source: hosted + version: "6.6.0" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" + url: "https://pub.dev" + source: hosted + version: "2.4.0" vm_service: dependency: transitive description: @@ -946,6 +1090,22 @@ packages: url: "https://pub.dev" source: hosted version: "15.0.2" + wakelock_plus: + dependency: transitive + description: + name: wakelock_plus + sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2" + url: "https://pub.dev" + source: hosted + version: "1.3.0" watcher: dependency: transitive description: @@ -978,6 +1138,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + win32: + dependency: transitive + description: + name: win32 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + url: "https://pub.dev" + source: hosted + version: "5.15.0" xdg_directories: dependency: transitive description: @@ -1002,6 +1170,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.3" + youtube_explode_dart: + dependency: transitive + description: + name: youtube_explode_dart + sha256: "947ba05e0c4f050743e480e7bca3575ff6427d86cc898c1a69f5e1d188cdc9e0" + url: "https://pub.dev" + source: hosted + version: "2.5.3" sdks: dart: ">=3.9.2 <4.0.0" flutter: ">=3.35.0" diff --git a/pubspec.yaml b/pubspec.yaml index 98a157d..f8ba2c6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: lottie: ^3.3.2 path_drawing: ^1.0.1 path_provider: ^2.1.5 + pod_player: ^0.2.2 pretty_dio_logger: ^1.4.0 shared_preferences: ^2.5.3 showcaseview: ^5.0.1 From 0ac3ad9a4f09013422ccf10c4e7d3a40ca073322 Mon Sep 17 00:00:00 2001 From: AmirrezaChegini Date: Fri, 12 Dec 2025 16:23:03 +0330 Subject: [PATCH 2/2] add: adapters --- .../level/domain/entity/node_entity.g.dart | 86 +++++++++++++++++++ .../level/domain/entity/prize_entity.g.dart | 53 ++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 lib/features/level/domain/entity/node_entity.g.dart create mode 100644 lib/features/level/domain/entity/prize_entity.g.dart diff --git a/lib/features/level/domain/entity/node_entity.g.dart b/lib/features/level/domain/entity/node_entity.g.dart new file mode 100644 index 0000000..41204de --- /dev/null +++ b/lib/features/level/domain/entity/node_entity.g.dart @@ -0,0 +1,86 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'node_entity.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class NodeEntityAdapter extends TypeAdapter { + @override + final int typeId = 7; + + @override + NodeEntity read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return NodeEntity( + nodeType: fields[0] as NodeType?, + level: fields[1] as LevelEntity?, + prize: fields[2] as PrizeEntity?, + ); + } + + @override + void write(BinaryWriter writer, NodeEntity obj) { + writer + ..writeByte(3) + ..writeByte(0) + ..write(obj.nodeType) + ..writeByte(1) + ..write(obj.level) + ..writeByte(2) + ..write(obj.prize); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NodeEntityAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class NodeTypeAdapter extends TypeAdapter { + @override + final int typeId = 8; + + @override + NodeType read(BinaryReader reader) { + switch (reader.readByte()) { + case 0: + return NodeType.level; + case 1: + return NodeType.prize; + default: + return NodeType.level; + } + } + + @override + void write(BinaryWriter writer, NodeType obj) { + switch (obj) { + case NodeType.level: + writer.writeByte(0); + break; + case NodeType.prize: + writer.writeByte(1); + break; + } + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NodeTypeAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/features/level/domain/entity/prize_entity.g.dart b/lib/features/level/domain/entity/prize_entity.g.dart new file mode 100644 index 0000000..5ab0f95 --- /dev/null +++ b/lib/features/level/domain/entity/prize_entity.g.dart @@ -0,0 +1,53 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'prize_entity.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class PrizeEntityAdapter extends TypeAdapter { + @override + final int typeId = 6; + + @override + PrizeEntity read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return PrizeEntity( + id: fields[0] as int?, + afterLevel: fields[1] as int?, + title: fields[2] as String?, + imageURL: fields[3] as String?, + animationURL: fields[4] as String?, + ); + } + + @override + void write(BinaryWriter writer, PrizeEntity obj) { + writer + ..writeByte(5) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.afterLevel) + ..writeByte(2) + ..write(obj.title) + ..writeByte(3) + ..write(obj.imageURL) + ..writeByte(4) + ..write(obj.animationURL); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is PrizeEntityAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +}