Browse Source
Merge pull request 'feature/gift' (#52) from feature/gift into develop
Merge pull request 'feature/gift' (#52) from feature/gift into develop
Reviewed-on: https://git.nwhco.ir/amirreza.chegini/hade_hoda_flutter/pulls/52pull/53/head
46 changed files with 1176 additions and 173 deletions
-
BINassets/images/gift.png
-
BINassets/images/gift_background.png
-
BINassets/images/gift_disable.png
-
10assets/svg/icon_play_video.svg
-
7lib/common_ui/resources/my_assets.dart
-
2lib/core/constants/my_api.dart
-
8lib/core/routers/my_routes.dart
-
381lib/core/widgets/dialog/reward_dialog.dart
-
76lib/core/widgets/video/my_video_player.dart
-
12lib/features/download/data/datasource/download_datasource.dart
-
2lib/features/guider/data/datasource/guider_datasource.dart
-
2lib/features/home/presentation/bloc/home_bloc.dart
-
8lib/features/level/data/datasource/level_datasource.dart
-
25lib/features/level/data/model/node_model.dart
-
21lib/features/level/data/model/prize_model.dart
-
6lib/features/level/data/repository_impl/level_repository_impl.dart
-
30lib/features/level/domain/entity/node_entity.dart
-
86lib/features/level/domain/entity/node_entity.g.dart
-
25lib/features/level/domain/entity/prize_entity.dart
-
53lib/features/level/domain/entity/prize_entity.g.dart
-
6lib/features/level/domain/entity/total_data_entity.dart
-
4lib/features/level/domain/entity/total_data_entity.g.dart
-
6lib/features/level/domain/repository/level_repository.dart
-
6lib/features/level/domain/usecases/get_levels_usecase.dart
-
29lib/features/level/presentation/bloc/level_bloc.dart
-
2lib/features/level/presentation/bloc/level_event.dart
-
17lib/features/level/presentation/ui/level_page.dart
-
121lib/features/level/presentation/ui/widgets/level_widget.dart
-
161lib/features/level/presentation/ui/widgets/node_widget.dart
-
19lib/features/question/data/datasource/question_datasource.dart
-
5lib/init_bindings.dart
-
3lib/l10n/app_ar.arb
-
3lib/l10n/app_de.arb
-
3lib/l10n/app_en.arb
-
3lib/l10n/app_fr.arb
-
6lib/l10n/app_localizations.dart
-
3lib/l10n/app_localizations_ar.dart
-
3lib/l10n/app_localizations_de.dart
-
3lib/l10n/app_localizations_en.dart
-
3lib/l10n/app_localizations_fr.dart
-
3lib/l10n/app_localizations_ru.dart
-
3lib/l10n/app_localizations_tr.dart
-
3lib/l10n/app_ru.arb
-
3lib/l10n/app_tr.arb
-
176pubspec.lock
-
1pubspec.yaml
|
After Width: 71 | Height: 75 | Size: 4.3 KiB |
|
After Width: 101 | Height: 105 | Size: 12 KiB |
|
After Width: 95 | Height: 100 | Size: 5.3 KiB |
@ -0,0 +1,10 @@ |
|||||
|
<svg width="62" height="62" viewBox="0 0 62 62" fill="none" xmlns="http://www.w3.org/2000/svg"> |
||||
|
<rect x="22.1758" y="19.1177" width="22.1765" height="24.4706" fill="white"/> |
||||
|
<path d="M30.5879 6.61768C36.9451 6.61771 43.0418 9.14309 47.5371 13.6382C52.0325 18.1335 54.5586 24.231 54.5586 30.5884C54.5586 36.9457 52.0324 43.0423 47.5371 47.5376C43.0418 52.0329 36.9452 54.5591 30.5879 54.5591C24.2305 54.5591 18.1331 52.033 13.6377 47.5376C9.1426 43.0423 6.61722 36.9456 6.61719 30.5884C6.61719 24.231 9.14234 18.1335 13.6377 13.6382C18.1331 9.14283 24.2305 6.61768 30.5879 6.61768ZM27.7012 20.9155C27.0578 20.8844 26.4176 21.0286 25.8496 21.3325C25.2817 21.6365 24.8066 22.0886 24.4756 22.6411C24.1446 23.1937 23.9697 23.8261 23.9697 24.4702V36.7056C23.9696 37.3497 24.1447 37.9821 24.4756 38.5347C24.8066 39.0873 25.2817 39.5403 25.8496 39.8442C26.4176 40.1481 27.0578 40.2924 27.7012 40.2612C28.3447 40.23 28.9679 40.0241 29.5039 39.6665L38.6807 33.5493C39.168 33.2243 39.5674 32.7836 39.8438 32.2671C40.1201 31.7506 40.2646 31.1741 40.2646 30.5884C40.2646 30.0026 40.1202 29.4252 39.8438 28.9087C39.5674 28.3924 39.1679 27.9523 38.6807 27.6274L29.5039 21.5093C28.968 21.1518 28.3446 20.9468 27.7012 20.9155Z" fill="#EB511A" stroke="url(#paint0_linear_42_2463)"/> |
||||
|
<defs> |
||||
|
<linearGradient id="paint0_linear_42_2463" x1="30.5878" y1="6.11768" x2="30.5878" y2="55.0589" gradientUnits="userSpaceOnUse"> |
||||
|
<stop stop-color="#FFCB32"/> |
||||
|
<stop offset="1" stop-color="#FFA105"/> |
||||
|
</linearGradient> |
||||
|
</defs> |
||||
|
</svg> |
||||
@ -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<void> 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<Path> { |
||||
|
@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<Path> oldClipper) { |
||||
|
return this != oldClipper; |
||||
|
} |
||||
|
} |
||||
@ -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<MyVideoPlayer> createState() => _MyVideoPlayerState(); |
||||
|
} |
||||
|
|
||||
|
class _MyVideoPlayerState extends State<MyVideoPlayer> { |
||||
|
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(); |
||||
|
} |
||||
|
}, |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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<String, dynamic> 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, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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<String, dynamic> json) { |
||||
|
return PrizeModel( |
||||
|
id: json['id'], |
||||
|
afterLevel: json['after_level'], |
||||
|
title: json['title'], |
||||
|
imageURL: json['image_url'], |
||||
|
animationURL: json['animation_url'], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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<String, NodeType> 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}); |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
|
||||
|
part of 'node_entity.dart'; |
||||
|
|
||||
|
// ************************************************************************** |
||||
|
// TypeAdapterGenerator |
||||
|
// ************************************************************************** |
||||
|
|
||||
|
class NodeEntityAdapter extends TypeAdapter<NodeEntity> { |
||||
|
@override |
||||
|
final int typeId = 7; |
||||
|
|
||||
|
@override |
||||
|
NodeEntity read(BinaryReader reader) { |
||||
|
final numOfFields = reader.readByte(); |
||||
|
final fields = <int, dynamic>{ |
||||
|
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<NodeType> { |
||||
|
@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; |
||||
|
} |
||||
@ -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, |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
|
||||
|
part of 'prize_entity.dart'; |
||||
|
|
||||
|
// ************************************************************************** |
||||
|
// TypeAdapterGenerator |
||||
|
// ************************************************************************** |
||||
|
|
||||
|
class PrizeEntityAdapter extends TypeAdapter<PrizeEntity> { |
||||
|
@override |
||||
|
final int typeId = 6; |
||||
|
|
||||
|
@override |
||||
|
PrizeEntity read(BinaryReader reader) { |
||||
|
final numOfFields = reader.readByte(); |
||||
|
final fields = <int, dynamic>{ |
||||
|
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; |
||||
|
} |
||||
@ -1,8 +1,10 @@ |
|||||
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.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/params/level_params.dart'; |
||||
import 'package:hadi_hoda_flutter/core/utils/data_state.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 { |
abstract class ILevelRepository { |
||||
Future<DataState<List<LevelEntity>, MyException>> getLevels({required LevelParams params}); |
|
||||
|
Future<DataState<List<NodeEntity>, MyException>> getLevels({ |
||||
|
required LevelParams params, |
||||
|
}); |
||||
} |
} |
||||
@ -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<LevelType, String> get image => { |
|
||||
LevelType.unFinished: MyAssets.level, |
|
||||
LevelType.finished: MyAssets.finishedLevel, |
|
||||
LevelType.current: MyAssets.currentLevel, |
|
||||
}; |
|
||||
|
|
||||
static Map<LevelType, Color> get textShadowColor => { |
|
||||
LevelType.unFinished: Color(0XFF5B5B5B), |
|
||||
LevelType.finished: Color(0XFF096D7B), |
|
||||
LevelType.current: Color(0XFF91500D), |
|
||||
}; |
|
||||
|
|
||||
static Map<LevelType, Color> 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), |
|
||||
), |
|
||||
), |
|
||||
], |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
@ -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<LevelType, String> get image => { |
||||
|
LevelType.unFinished: MyAssets.level, |
||||
|
LevelType.finished: MyAssets.finishedLevel, |
||||
|
LevelType.current: MyAssets.currentLevel, |
||||
|
}; |
||||
|
|
||||
|
static Map<LevelType, Color> get textShadowColor => { |
||||
|
LevelType.unFinished: Color(0XFF5B5B5B), |
||||
|
LevelType.finished: Color(0XFF096D7B), |
||||
|
LevelType.current: Color(0XFF91500D), |
||||
|
}; |
||||
|
|
||||
|
static Map<LevelType, Color> 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), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue