diff --git a/assets/images/behind_diamond.png b/assets/images/behind_diamond.png new file mode 100644 index 0000000..96f2091 Binary files /dev/null and b/assets/images/behind_diamond.png differ diff --git a/assets/svg/icon_notif.svg b/assets/svg/icon_notif.svg new file mode 100644 index 0000000..4dd9648 --- /dev/null +++ b/assets/svg/icon_notif.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/common_ui/resources/my_animations.dart b/lib/common_ui/resources/my_animations.dart new file mode 100644 index 0000000..5739d3d --- /dev/null +++ b/lib/common_ui/resources/my_animations.dart @@ -0,0 +1,8 @@ +class MyAnimations { + static const MyAnimations _i = MyAnimations._internal(); + const MyAnimations._internal(); + factory MyAnimations() => _i; + + static const String confetti = 'assets/animations/confetti.json'; + static const String lightPurple = 'assets/animations/lights_purple.json'; +} \ No newline at end of file diff --git a/lib/common_ui/resources/my_assets.dart b/lib/common_ui/resources/my_assets.dart index cc9809d..d13ae82 100644 --- a/lib/common_ui/resources/my_assets.dart +++ b/lib/common_ui/resources/my_assets.dart @@ -38,6 +38,7 @@ class MyAssets { static const String planet10 = 'assets/images/planet_10.png'; 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'; /// SVG static const String closeBtn = 'assets/svg/close_btn.svg'; @@ -72,6 +73,7 @@ class MyAssets { static const String homeButton = 'assets/svg/home_button.svg'; 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 final List images = [ diff --git a/lib/common_ui/resources/my_audios.dart b/lib/common_ui/resources/my_audios.dart index 854205d..5fbe749 100644 --- a/lib/common_ui/resources/my_audios.dart +++ b/lib/common_ui/resources/my_audios.dart @@ -3,7 +3,12 @@ class MyAudios { const MyAudios._internal(); factory MyAudios() => _i; - static const String homeMusic = 'assets/audios/home.mp3'; - static const String clickButton = 'assets/audios/click_button.mp3'; static const String back = 'assets/audios/back.mp3'; + static const String clickButton = 'assets/audios/click_button.mp3'; + static const String diamondEnd = 'assets/audios/diamond_end.mp3'; + static const String diamondIncrease = 'assets/audios/diamond_increase.mp3'; + static const String home = 'assets/audios/home.mp3'; + static const String incorrectAnswer = 'assets/audios/incorrect_answer.mp3'; + static const String question = 'assets/audios/question.mp3'; + static const String rightAnswer = 'assets/audios/right_answer.mp3'; } \ No newline at end of file diff --git a/lib/core/routers/hero_dialog_route.dart b/lib/core/routers/hero_dialog_route.dart index 0431187..883cb25 100644 --- a/lib/core/routers/hero_dialog_route.dart +++ b/lib/core/routers/hero_dialog_route.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; class HeroDialogRoute extends PageRoute { HeroDialogRoute({ @@ -17,16 +16,16 @@ class HeroDialogRoute extends PageRoute { bool get fullscreenDialog => false; @override - bool get barrierDismissible => false; + bool get barrierDismissible => true; @override - Duration get transitionDuration => const Duration(milliseconds: 300); // Adjust as needed + Duration get transitionDuration => const Duration(seconds: 1); // Adjust as needed @override bool get maintainState => true; @override - Color get barrierColor => MyColors.transparent; // Or your desired barrier color + Color get barrierColor => Color(0XFF322386).withValues(alpha: 0.3); // Or your desired barrier color @override Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index a33b00f..bec75cf 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -120,8 +120,12 @@ GoRouter get appPages => GoRouter( path: '${Routes.questionPage}/:id', builder: (context, state) => BlocProvider( create: (context) => - QuestionBloc(locator(), locator(), locator()) - ..add(GetLevelEvent(state.pathParameters['id'], context)), + QuestionBloc( + locator(), + locator(), + locator(instanceName: MyConstants.mainAudioService), + locator(instanceName: MyConstants.effectAudioService), + )..add(GetLevelEvent(state.pathParameters['id'], context)), child: const QuestionPage(), ), ), diff --git a/lib/core/widgets/animations/fade_anim.dart b/lib/core/widgets/animations/fade_anim.dart new file mode 100644 index 0000000..0a5e40b --- /dev/null +++ b/lib/core/widgets/animations/fade_anim.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class FadeAnim extends StatefulWidget { + const FadeAnim({super.key, required this.child}); + + final Widget child; + + @override + State createState() => _FadeAnimState(); +} + +class _FadeAnimState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: Duration(milliseconds: 500), + reverseDuration: Duration(seconds: 500), + ); + _animation = Tween( + begin: 0, + end: 1, + ).animate(CurvedAnimation(parent: _controller, curve: Curves.linear)); + + _controller.forward(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + child: widget.child, + builder: (context, child) => FadeTransition( + opacity: _animation, + child: child, + ), + ); + } +} diff --git a/lib/core/widgets/animations/scale_anim.dart b/lib/core/widgets/animations/scale_anim.dart new file mode 100644 index 0000000..e76c247 --- /dev/null +++ b/lib/core/widgets/animations/scale_anim.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class ScaleAnim extends StatefulWidget { + const ScaleAnim({super.key, required this.child, this.state = false}); + + final Widget child; + final bool state; + + @override + State createState() => _ScaleAnimState(); +} + +class _ScaleAnimState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: Duration(milliseconds: 200), + reverseDuration: Duration(milliseconds: 200), + ); + _animation = Tween( + begin: 0, + end: 1, + ).animate(CurvedAnimation(parent: _controller, curve: Curves.linear)); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + widget.state ? _controller.forward() : _controller.reverse(); + return AnimatedBuilder( + animation: _controller, + child: widget.child, + builder: (context, child) => ScaleTransition( + scale: _animation, + alignment: Alignment.center, + child: child, + ), + ); + } +} diff --git a/lib/core/widgets/animations/ship_anim.dart b/lib/core/widgets/animations/ship_anim.dart new file mode 100644 index 0000000..d439aba --- /dev/null +++ b/lib/core/widgets/animations/ship_anim.dart @@ -0,0 +1,56 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; + +class ShipAnim extends StatefulWidget { + const ShipAnim({super.key, required this.child}); + + final Widget child; + + @override + State createState() => _ShipAnimState(); +} + +class _ShipAnimState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: Duration(seconds: 15), + reverseDuration: Duration(seconds: 15), + )..repeat(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + // The angle of the ship in its circular path + final angle = _controller.value * 2 * math.pi; + // The radius of the circular path + final radius = context.widthScreen * 0.05; + // Calculate the x and y coordinates for the ship + final x = radius * math.cos(angle) + 60; + final y = radius * math.sin(angle) - 70; // -80 to lift it up + + return Transform.translate( + offset: Offset(x, y), + child: child, + ); + }, + child: widget.child, + ); + } +} diff --git a/lib/core/widgets/animations/slide_anim.dart b/lib/core/widgets/animations/slide_anim.dart new file mode 100644 index 0000000..4e5fe3c --- /dev/null +++ b/lib/core/widgets/animations/slide_anim.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +class SlideAnim extends StatefulWidget { + const SlideAnim({ + super.key, + required this.child, + required this.index, + }); + + final Widget child; + final int index; + + @override + State createState() => _SlideAnimState(); +} + +class _SlideAnimState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + final List offsetList = [ + Offset(-2, -2), + Offset(2, -2), + Offset(-2, 2), + Offset(2, 2), + ]; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: Duration(milliseconds: 500), + reverseDuration: Duration(milliseconds: 500), + ); + _animation = Tween( + begin: offsetList[widget.index], + end: Offset.zero, + ).animate(CurvedAnimation(parent: _controller, curve: Curves.linear)); + + _controller.forward(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + child: widget.child, + builder: (context, child) => SlideTransition( + position: _animation, + child: child, + ), + ); + } +} diff --git a/lib/core/widgets/animations/slide_down_fade.dart b/lib/core/widgets/animations/slide_down_fade.dart new file mode 100644 index 0000000..e035c65 --- /dev/null +++ b/lib/core/widgets/animations/slide_down_fade.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; + +class SlideDownFade extends StatefulWidget { + const SlideDownFade({ + super.key, + required this.child, + this.delay = Duration.zero, + }); + + final Widget child; + final Duration delay; + + @override + State createState() => _SlideDownFadeState(); +} + +class _SlideDownFadeState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _fadeAnim; + late Animation _slideAnim; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: Duration(milliseconds: 500), + reverseDuration: Duration(milliseconds: 500), + ); + + _fadeAnim = Tween( + begin: 0, + end: 1, + ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn)); + + _slideAnim = Tween( + begin: Offset(0, -0.1), + end: Offset.zero, + ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn)); + startAnim(); + } + + Future startAnim() async { + await Future.delayed(widget.delay, () { + _controller.forward(); + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + child: widget.child, + builder: (context, child) => FadeTransition( + opacity: _fadeAnim, + child: SlideTransition(position: _slideAnim, child: child), + ), + ); + } +} diff --git a/lib/core/widgets/answer_box/answer_box.dart b/lib/core/widgets/answer_box/answer_box.dart index bb6f470..49004a3 100644 --- a/lib/core/widgets/answer_box/answer_box.dart +++ b/lib/core/widgets/answer_box/answer_box.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/core/widgets/answer_box/styles/picture_box.dart'; import 'package:hadi_hoda_flutter/core/widgets/answer_box/styles/text_box.dart'; +import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; class AnswerBox extends StatefulWidget { @@ -11,49 +13,72 @@ class AnswerBox extends StatefulWidget { required this.correctAnswer, required this.index, this.onTap, + this.onNotifTap, }); final AnswerEntity answer; final int correctAnswer; final void Function(bool isCorrect, int correctAnswer)? onTap; final int index; + final Function(AnswerEntity answer)? onNotifTap; @override State createState() => _AnswerBoxState(); } class _AnswerBoxState extends State { - bool selected = false; @override Widget build(BuildContext context) { - return GestureDetector( - onTap: !selected ? () { - setState(() { - selected = true; - }); - widget.onTap?.call(widget.index == widget.correctAnswer, widget.correctAnswer); - } : null, - child: Stack( - alignment: Alignment.bottomCenter, - clipBehavior: Clip.none, - children: [ - AnswerPictureBox( - selected: selected, - index: widget.index, - image: widget.answer.image ?? '', - correctAnswer: widget.correctAnswer, - ), - Positioned( - left: 0, - right: 0, - bottom: -MySpaces.s26, - child: AnswerTextBox( - text: widget.answer.title ?? '', - ), + return Hero( + tag: 'Hero_answer_${widget.answer.id}', + child: Material( + type: MaterialType.transparency, + child: GestureDetector( + onTap: !selected + ? () { + setState(() { + selected = true; + }); + widget.onTap?.call( + widget.index == widget.correctAnswer, + widget.correctAnswer, + ); + } + : null, + child: Stack( + alignment: Alignment.center, + clipBehavior: Clip.none, + children: [ + AnswerPictureBox( + selected: selected, + index: widget.index, + image: widget.answer.image ?? '', + correctAnswer: widget.correctAnswer, + onTap: () { + widget.onNotifTap?.call(widget.answer); + }, + ), + Positioned( + left: 0, + right: 0, + bottom: -60, + child: AnswerTextBox(text: widget.answer.title ?? ''), + ), + PositionedDirectional( + top: MySpaces.s12, + end: MySpaces.s8, + child: GestureDetector( + onTap: () { + widget.onNotifTap?.call(widget.answer); + }, + child: MyImage(image: MyAssets.iconNotif), + ), + ), + ], ), - ], + ), ), ); } diff --git a/lib/core/widgets/answer_box/answer_box_show.dart b/lib/core/widgets/answer_box/answer_box_show.dart index 5811b2b..ccc5ed9 100644 --- a/lib/core/widgets/answer_box/answer_box_show.dart +++ b/lib/core/widgets/answer_box/answer_box_show.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/core/widgets/answer_box/styles/picture_box.dart'; import 'package:hadi_hoda_flutter/core/widgets/answer_box/styles/text_box.dart'; +import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; class AnswerBoxShow extends StatelessWidget { @@ -9,34 +11,48 @@ class AnswerBoxShow extends StatelessWidget { super.key, required this.answer, required this.index, - this.correct, + this.onNotifTap, }); final AnswerEntity answer; final int index; - final bool? correct; + final Function(AnswerEntity answer)? onNotifTap; @override Widget build(BuildContext context) { - return Stack( - alignment: Alignment.bottomCenter, - clipBehavior: Clip.none, - children: [ - AnswerPictureBox( - selected: correct ?? false, - index: index, - image: answer.image ?? '', - correctAnswer: index, + return Hero( + tag: 'Hero_answer_${answer.id}', + child: Material( + type: MaterialType.transparency, + child: Stack( + alignment: Alignment.center, + clipBehavior: Clip.none, + children: [ + AnswerPictureBox( + selected: false, + index: index, + image: answer.image ?? '', + correctAnswer: 0, + ), + Positioned( + left: 0, + right: 0, + bottom: -MySpaces.s40, + child: AnswerTextBox(text: answer.title ?? ''), + ), + PositionedDirectional( + top: MySpaces.s30, + end: MySpaces.s20, + child: GestureDetector( + onTap: () { + onNotifTap?.call(answer); + }, + child: MyImage(image: MyAssets.iconNotif, size: MySpaces.s40), + ), + ), + ], ), - Positioned( - left: 0, - right: 0, - bottom: -MySpaces.s26, - child: AnswerTextBox( - text: answer.title ?? '', - ), - ), - ], + ), ); } } diff --git a/lib/core/widgets/answer_box/styles/picture_box.dart b/lib/core/widgets/answer_box/styles/picture_box.dart index b452bbe..5e8141a 100644 --- a/lib/core/widgets/answer_box/styles/picture_box.dart +++ b/lib/core/widgets/answer_box/styles/picture_box.dart @@ -2,9 +2,10 @@ import 'dart:io'; 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_spaces.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; -import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/black_white_effect.dart'; class AnswerPictureBox extends StatelessWidget { const AnswerPictureBox({ @@ -13,77 +14,74 @@ class AnswerPictureBox extends StatelessWidget { required this.image, required this.index, required this.correctAnswer, + this.onTap, }); final bool selected; final String image; final int index; final int correctAnswer; + final VoidCallback? onTap; @override Widget build(BuildContext context) { return CustomPaint( - size: Size(170, 170), - foregroundPainter: _SvgCustomPainter(false), + painter: _CustomShapePainter(), child: ClipPath( - clipper: _SvgCustomClipper(), + clipper: _CustomShapeClipper(), child: Stack( + alignment: Alignment.center, children: [ - Builder( - builder: (context) { - if (selected && - (index != correctAnswer)) { - return BlackWhiteEffect( - child: Image.file( - File(image), - fit: BoxFit.cover, - height: 170, - width: 170, - ), - ); - } else { - return Image.file( - File(image), - fit: BoxFit.cover, - height: 170, - width: 170, - ); - } - }, + AnimatedSwitcher( + duration: Duration(milliseconds: 150), + reverseDuration: Duration(milliseconds: 150), + switchInCurve: Curves.linear, + switchOutCurve: Curves.linear, + child: selected && (index != correctAnswer) ? + Image.file( + key: Key('1'), + File(image), + fit: BoxFit.cover, + color: MyColors.black, + colorBlendMode: BlendMode.color, + ) : + Image.file( + key: Key('2'), + File(image), + fit: BoxFit.cover, + ), + transitionBuilder: (child, animation) => + FadeTransition( + opacity: animation, + child: child, + ), ), PositionedDirectional( - top: MySpaces.s12, - start: MySpaces.s12, - child: ClipPath( - clipper: _CountClipper(), - child: Container( - height: MySpaces.s32, - width: MySpaces.s32, - alignment: Alignment.center, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0XFF5732CB), - Color(0XFF322386), - ], - ), + top: 0, + child: Container( + width: MySpaces.s34, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFFF2F7FF), + borderRadius: BorderRadius.vertical( + bottom: Radius.circular(10), ), - child: Text( - '$index', + ), + child: Text( + '$index', + style: MYTextStyle.titr1.copyWith( + color: Color(0XFF9B85D8), ), ), ), ), if(selected) PositionedDirectional( - top: MySpaces.s14, - end: MySpaces.s12, + top: MySpaces.s8, + start: MySpaces.s8, child: MyImage( image: index == correctAnswer ? MyAssets.correct : MyAssets .wrong, - size: MySpaces.s40, ), ), ], @@ -93,141 +91,72 @@ class AnswerPictureBox extends StatelessWidget { } } -class _SvgCustomClipper extends CustomClipper { - @override - Path getClip(Size size) { - double scaleFactor = 170.0 / 480.0; - - Path path = Path() - ..moveTo(242.081 * scaleFactor, 4.12988 * scaleFactor) - ..cubicTo(189.733 * scaleFactor, 1.72935 * scaleFactor, 137.532 * scaleFactor, 3.16507 * scaleFactor, 96.9766 * scaleFactor, 8.33887 * scaleFactor) - ..cubicTo(76.6855 * scaleFactor, 10.9275 * scaleFactor, 59.4247 * scaleFactor, 14.4382 * scaleFactor, 46.5547 * scaleFactor, 18.8203 * scaleFactor) - ..cubicTo(40.1188 * scaleFactor, 21.0117 * scaleFactor, 34.878 * scaleFactor, 23.3892 * scaleFactor, 30.9326 * scaleFactor, 25.916 * scaleFactor) - ..cubicTo(26.9611 * scaleFactor, 28.4595 * scaleFactor, 24.5168 * scaleFactor, 31.0171 * scaleFactor, 23.3438 * scaleFactor, 33.4795 * scaleFactor) - ..cubicTo(20.5038 * scaleFactor, 39.4409 * scaleFactor, 17.8387 * scaleFactor, 49.1133 * scaleFactor, 15.4463 * scaleFactor, 61.8105 * scaleFactor) - ..cubicTo(13.066 * scaleFactor, 74.4434 * scaleFactor, 10.9937 * scaleFactor, 89.8529 * scaleFactor, 9.25879 * scaleFactor, 107.15 * scaleFactor) - ..cubicTo(5.78933 * scaleFactor, 141.742 * scaleFactor, 3.68374 * scaleFactor, 183.74 * scaleFactor, 3.14062 * scaleFactor, 225.896 * scaleFactor) - ..cubicTo(2.5975 * scaleFactor, 268.052 * scaleFactor, 3.61795 * scaleFactor, 310.308 * scaleFactor, 6.3877 * scaleFactor, 345.416 * scaleFactor) - ..cubicTo(7.77271 * scaleFactor, 362.972 * scaleFactor, 9.59224 * scaleFactor, 378.701 * scaleFactor, 11.8633 * scaleFactor, 391.718 * scaleFactor) - ..cubicTo(14.1445 * scaleFactor, 404.793 * scaleFactor, 16.8465 * scaleFactor, 414.918 * scaleFactor, 19.9121 * scaleFactor, 421.396 * scaleFactor) - ..cubicTo(21.2125 * scaleFactor, 424.143 * scaleFactor, 23.8655 * scaleFactor, 426.967 * scaleFactor, 28.083 * scaleFactor, 429.773 * scaleFactor) - ..cubicTo(32.2774 * scaleFactor, 432.565 * scaleFactor, 37.8229 * scaleFactor, 435.209 * scaleFactor, 44.6045 * scaleFactor, 437.676 * scaleFactor) - ..cubicTo(58.1675 * scaleFactor, 442.609 * scaleFactor, 76.2991 * scaleFactor, 446.701 * scaleFactor, 97.542 * scaleFactor, 449.934 * scaleFactor) - ..cubicTo(140.002 * scaleFactor, 456.395 * scaleFactor, 194.428 * scaleFactor, 459.359 * scaleFactor, 248.533 * scaleFactor, 458.966 * scaleFactor) - ..cubicTo(302.639 * scaleFactor, 458.572 * scaleFactor, 356.282 * scaleFactor, 454.822 * scaleFactor, 397.177 * scaleFactor, 447.904 * scaleFactor) - ..cubicTo(417.642 * scaleFactor, 444.443 * scaleFactor, 434.779 * scaleFactor, 440.209 * scaleFactor, 447.149 * scaleFactor, 435.27 * scaleFactor) - ..cubicTo(453.338 * scaleFactor, 432.798 * scaleFactor, 458.209 * scaleFactor, 430.199 * scaleFactor, 461.686 * scaleFactor, 427.518 * scaleFactor) - ..cubicTo(465.181 * scaleFactor, 424.821 * scaleFactor, 467.024 * scaleFactor, 422.232 * scaleFactor, 467.636 * scaleFactor, 419.835 * scaleFactor) - ..cubicTo(471.161 * scaleFactor, 405.976 * scaleFactor, 473.704 * scaleFactor, 379.536 * scaleFactor, 475.24 * scaleFactor, 346.71 * scaleFactor) - ..cubicTo(476.772 * scaleFactor, 313.978 * scaleFactor, 477.293 * scaleFactor, 275.164 * scaleFactor, 476.847 * scaleFactor, 236.729 * scaleFactor) - ..cubicTo(476.401 * scaleFactor, 198.293 * scaleFactor, 474.989 * scaleFactor, 160.274 * scaleFactor, 472.661 * scaleFactor, 129.129 * scaleFactor) - ..cubicTo(471.497 * scaleFactor, 113.555 * scaleFactor, 470.106 * scaleFactor, 99.729 * scaleFactor, 468.498 * scaleFactor, 88.4443 * scaleFactor) - ..cubicTo(466.881 * scaleFactor, 77.0977 * scaleFactor, 465.07 * scaleFactor, 68.5213 * scaleFactor, 463.128 * scaleFactor, 63.3262 * scaleFactor) - ..cubicTo(460.15 * scaleFactor, 55.3421 * scaleFactor, 451.863 * scaleFactor, 47.7494 * scaleFactor, 438.653 * scaleFactor, 40.8027 * scaleFactor) - ..cubicTo(425.546 * scaleFactor, 33.9095 * scaleFactor, 408.099 * scaleFactor, 27.9176 * scaleFactor, 387.654 * scaleFactor, 22.8643 * scaleFactor) - ..cubicTo(346.784 * scaleFactor, 12.7625 * scaleFactor, 294.436 * scaleFactor, 6.53075 * scaleFactor, 242.081 * scaleFactor, 4.12988 * scaleFactor) - ..close(); - - return path; - } - - @override - bool shouldReclip(CustomClipper oldClipper) { - return false; - } -} - -class _SvgCustomPainter extends CustomPainter { - _SvgCustomPainter(this.selected); - - final bool selected; - +class _CustomShapePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { - double scaleFactor = 170.0 / 480.0; - - Path path = Path() - ..moveTo(242.081 * scaleFactor, 4.12988 * scaleFactor) - ..cubicTo(189.733 * scaleFactor, 1.72935 * scaleFactor, 137.532 * scaleFactor, 3.16507 * scaleFactor, 96.9766 * scaleFactor, 8.33887 * scaleFactor) - ..cubicTo(76.6855 * scaleFactor, 10.9275 * scaleFactor, 59.4247 * scaleFactor, 14.4382 * scaleFactor, 46.5547 * scaleFactor, 18.8203 * scaleFactor) - ..cubicTo(40.1188 * scaleFactor, 21.0117 * scaleFactor, 34.878 * scaleFactor, 23.3892 * scaleFactor, 30.9326 * scaleFactor, 25.916 * scaleFactor) - ..cubicTo(26.9611 * scaleFactor, 28.4595 * scaleFactor, 24.5168 * scaleFactor, 31.0171 * scaleFactor, 23.3438 * scaleFactor, 33.4795 * scaleFactor) - ..cubicTo(20.5038 * scaleFactor, 39.4409 * scaleFactor, 17.8387 * scaleFactor, 49.1133 * scaleFactor, 15.4463 * scaleFactor, 61.8105 * scaleFactor) - ..cubicTo(13.066 * scaleFactor, 74.4434 * scaleFactor, 10.9937 * scaleFactor, 89.8529 * scaleFactor, 9.25879 * scaleFactor, 107.15 * scaleFactor) - ..cubicTo(5.78933 * scaleFactor, 141.742 * scaleFactor, 3.68374 * scaleFactor, 183.74 * scaleFactor, 3.14062 * scaleFactor, 225.896 * scaleFactor) - ..cubicTo(2.5975 * scaleFactor, 268.052 * scaleFactor, 3.61795 * scaleFactor, 310.308 * scaleFactor, 6.3877 * scaleFactor, 345.416 * scaleFactor) - ..cubicTo(7.77271 * scaleFactor, 362.972 * scaleFactor, 9.59224 * scaleFactor, 378.701 * scaleFactor, 11.8633 * scaleFactor, 391.718 * scaleFactor) - ..cubicTo(14.1445 * scaleFactor, 404.793 * scaleFactor, 16.8465 * scaleFactor, 414.918 * scaleFactor, 19.9121 * scaleFactor, 421.396 * scaleFactor) - ..cubicTo(21.2125 * scaleFactor, 424.143 * scaleFactor, 23.8655 * scaleFactor, 426.967 * scaleFactor, 28.083 * scaleFactor, 429.773 * scaleFactor) - ..cubicTo(32.2774 * scaleFactor, 432.565 * scaleFactor, 37.8229 * scaleFactor, 435.209 * scaleFactor, 44.6045 * scaleFactor, 437.676 * scaleFactor) - ..cubicTo(58.1675 * scaleFactor, 442.609 * scaleFactor, 76.2991 * scaleFactor, 446.701 * scaleFactor, 97.542 * scaleFactor, 449.934 * scaleFactor) - ..cubicTo(140.002 * scaleFactor, 456.395 * scaleFactor, 194.428 * scaleFactor, 459.359 * scaleFactor, 248.533 * scaleFactor, 458.966 * scaleFactor) - ..cubicTo(302.639 * scaleFactor, 458.572 * scaleFactor, 356.282 * scaleFactor, 454.822 * scaleFactor, 397.177 * scaleFactor, 447.904 * scaleFactor) - ..cubicTo(417.642 * scaleFactor, 444.443 * scaleFactor, 434.779 * scaleFactor, 440.209 * scaleFactor, 447.149 * scaleFactor, 435.27 * scaleFactor) - ..cubicTo(453.338 * scaleFactor, 432.798 * scaleFactor, 458.209 * scaleFactor, 430.199 * scaleFactor, 461.686 * scaleFactor, 427.518 * scaleFactor) - ..cubicTo(465.181 * scaleFactor, 424.821 * scaleFactor, 467.024 * scaleFactor, 422.232 * scaleFactor, 467.636 * scaleFactor, 419.835 * scaleFactor) - ..cubicTo(471.161 * scaleFactor, 405.976 * scaleFactor, 473.704 * scaleFactor, 379.536 * scaleFactor, 475.24 * scaleFactor, 346.71 * scaleFactor) - ..cubicTo(476.772 * scaleFactor, 313.978 * scaleFactor, 477.293 * scaleFactor, 275.164 * scaleFactor, 476.847 * scaleFactor, 236.729 * scaleFactor) - ..cubicTo(476.401 * scaleFactor, 198.293 * scaleFactor, 474.989 * scaleFactor, 160.274 * scaleFactor, 472.661 * scaleFactor, 129.129 * scaleFactor) - ..cubicTo(471.497 * scaleFactor, 113.555 * scaleFactor, 470.106 * scaleFactor, 99.729 * scaleFactor, 468.498 * scaleFactor, 88.4443 * scaleFactor) - ..cubicTo(466.881 * scaleFactor, 77.0977 * scaleFactor, 465.07 * scaleFactor, 68.5213 * scaleFactor, 463.128 * scaleFactor, 63.3262 * scaleFactor) - ..cubicTo(460.15 * scaleFactor, 55.3421 * scaleFactor, 451.863 * scaleFactor, 47.7494 * scaleFactor, 438.653 * scaleFactor, 40.8027 * scaleFactor) - ..cubicTo(425.546 * scaleFactor, 33.9095 * scaleFactor, 408.099 * scaleFactor, 27.9176 * scaleFactor, 387.654 * scaleFactor, 22.8643 * scaleFactor) - ..cubicTo(346.784 * scaleFactor, 12.7625 * scaleFactor, 294.436 * scaleFactor, 6.53075 * scaleFactor, 242.081 * scaleFactor, 4.12988 * scaleFactor) - ..close(); - - Paint shadowPaint = Paint() - ..color = selected ? Colors.green.withValues(alpha: 0.5) : Colors - .transparent - ..style = PaintingStyle.fill - ..maskFilter = MaskFilter.blur(BlurStyle.outer, 10); - - canvas.drawPath(path, shadowPaint); - canvas.drawPath(path, shadowPaint); - - canvas.clipPath(path); - - Paint strokePaint = Paint() - ..color = selected ? Colors.green : Colors.white + final Paint strokePaint = Paint() + ..color = Color(0XFFF2F7FF) ..style = PaintingStyle.stroke - ..strokeWidth = 5; + ..strokeWidth = 4; + + final Path path = _CustomShapeClipper().getClip(size); canvas.drawPath(path, strokePaint); } @override - bool shouldRepaint(CustomPainter oldDelegate) => true; + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return this != oldDelegate; + } } -class _CountClipper extends CustomClipper { +class _CustomShapeClipper extends CustomClipper { @override Path getClip(Size size) { - // Original SVG viewBox: width=34, height=33 - final sx = size.width / 34.0; - final sy = size.height / 33.0; + // 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. - final p = Path() - ..moveTo(33.3479 * sx, 14.8127 * sy) - ..cubicTo( - 33.3479 * sx, 23.7042 * sy, - 27.2015 * sx, 32.9501 * sy, - 17.8599 * sx, 32.9501 * sy, - )..cubicTo( - 8.51818 * sx, 32.9501 * sy, - 0.945251 * sx, 25.7421 * sy, - 0.945251 * sx, 16.8507 * sy, - )..cubicTo( - 0.945251 * sx, 7.95917 * sy, - 8.51818 * sx, 0.751205 * sy, - 17.8599 * sx, 0.751205 * sy, - )..cubicTo( - 27.2015 * sx, 0.751205 * sy, - 33.3479 * sx, 5.92127 * sy, - 33.3479 * sx, 14.8127 * sy, - )..close(); - - return p; + return path; } @override - bool shouldReclip(covariant CustomClipper oldClipper) => false; + bool shouldReclip(covariant CustomClipper oldClipper) { + return this != oldClipper; + } } \ No newline at end of file diff --git a/lib/core/widgets/answer_box/styles/text_box.dart b/lib/core/widgets/answer_box/styles/text_box.dart index 82087fc..343e1c6 100644 --- a/lib/core/widgets/answer_box/styles/text_box.dart +++ b/lib/core/widgets/answer_box/styles/text_box.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; class AnswerTextBox extends StatelessWidget { const AnswerTextBox({super.key, required this.text}); @@ -11,7 +12,9 @@ class AnswerTextBox extends StatelessWidget { return ClipPath( clipper: WavyBannerClipper(), child: Container( - padding: EdgeInsets.all(MySpaces.s10), + height: 90, + padding: EdgeInsets.symmetric(horizontal: MySpaces.s10), + alignment: Alignment.center, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, @@ -25,6 +28,11 @@ class AnswerTextBox extends StatelessWidget { child: Text( text, textAlign: TextAlign.center, + style: MYTextStyle.matn2.copyWith( + color: Color(0XFF322386), + height: 1.2, + ), + maxLines: 5, ), ), ); diff --git a/lib/core/widgets/button/enum/button_type.dart b/lib/core/widgets/button/enum/button_type.dart deleted file mode 100644 index c347d64..0000000 --- a/lib/core/widgets/button/enum/button_type.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'dart:ui'; - -import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; - -enum ButtonType { - type1, - type2; - - static Map get image => { - type1: MyAssets.button, - type2: MyAssets.button2, - }; - - static Map get textColor => { - type1: Color(0XFF1D6EFF), - type2: Color(0XFFD93D16), - }; -} \ No newline at end of file diff --git a/lib/core/widgets/button/my_button.dart b/lib/core/widgets/button/my_button.dart deleted file mode 100644 index cadc2d7..0000000 --- a/lib/core/widgets/button/my_button.dart +++ /dev/null @@ -1,50 +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_spaces.dart'; -import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; -import 'package:hadi_hoda_flutter/core/widgets/button/enum/button_type.dart'; -import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; - -class MyButton extends StatelessWidget { - const MyButton({ - super.key, - this.onTap, - this.type = ButtonType.type1, - this.title, - }); - - final VoidCallback? onTap; - final ButtonType? type; - final String? title; - - @override - Widget build(BuildContext context) { - return SizedBox( - height: 84, - width: 194, - child: InkWell( - onTap: onTap, - highlightColor: MyColors.transparent, - splashColor: MyColors.transparent, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage( - image: ButtonType.image[type] ?? MyAssets.button, - ), - PositionedDirectional( - top: MySpaces.s2, - child: Text( - title ?? '', - style: MYTextStyle.button1.copyWith( - color: ButtonType.textColor[type], - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/core/widgets/button/my_white_button.dart b/lib/core/widgets/button/my_white_button.dart new file mode 100644 index 0000000..76d606e --- /dev/null +++ b/lib/core/widgets/button/my_white_button.dart @@ -0,0 +1,52 @@ +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_spaces.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'; + +class MyWhiteButton extends StatelessWidget { + const MyWhiteButton({ + super.key, + this.onTap, + this.title, + this.top, + }); + + final VoidCallback? onTap; + final String? title; + final double? top; + + @override + Widget build(BuildContext context) { + return MyInkwell( + onTap: onTap, + highlightColor: MyColors.transparent, + splashColor: MyColors.transparent, + child: Stack( + alignment: Alignment.center, + children: [ + MyImage( + image: setSize( + context: context, + mobile: MyAssets.button3, + tablet: MyAssets.button2Tablet, + ) ?? '', + ), + PositionedDirectional( + top: top ?? setSize(context: context, mobile: MySpaces.s6, tablet: MySpaces.s22), + child: Text( + title ?? '', + style: MYTextStyle.button1.copyWith( + color: Color(0XFFD93D16), + fontSize: setSize(context: context, tablet: 60), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/features/home/presentation/bloc/home_bloc.dart b/lib/features/home/presentation/bloc/home_bloc.dart index 8b2daeb..2ae4457 100644 --- a/lib/features/home/presentation/bloc/home_bloc.dart +++ b/lib/features/home/presentation/bloc/home_bloc.dart @@ -45,7 +45,7 @@ class HomeBloc extends Bloc { orElse: () => TotalDataEntity(), ); if (findData.levels?.isNotEmpty ?? false) { - context.pushNamed(Routes.introPage); + context.goNamed(Routes.introPage); } else { context.goNamed(Routes.downloadPage); } @@ -67,8 +67,8 @@ class HomeBloc extends Bloc { } Future playMusic() async { - Future.wait([ - _mainAudioService.setAudio(assetPath: MyAudios.homeMusic), + await Future.wait([ + _mainAudioService.setAudio(assetPath: MyAudios.home), _mainAudioService.setLoopMode(isLoop: true), ]); await _mainAudioService.play(); diff --git a/lib/features/home/presentation/ui/home_page.dart b/lib/features/home/presentation/ui/home_page.dart index 9a2a1b5..3cdab7e 100644 --- a/lib/features/home/presentation/ui/home_page.dart +++ b/lib/features/home/presentation/ui/home_page.dart @@ -5,6 +5,8 @@ import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.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/animations/slide_down_fade.dart'; +import 'package:hadi_hoda_flutter/core/widgets/animations/slide_up_fade.dart'; import 'package:hadi_hoda_flutter/core/widgets/button/my_yellow_button.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; @@ -47,14 +49,17 @@ class HomePage extends StatelessWidget { return PositionedDirectional( top: MySpaces.s36, end: MySpaces.s16, - child: StreamBuilder( - initialData: 1, - stream: context.read().volumeStream, - builder: (context, snapshot) => MyInkwell( - onTap: () => context.read().changeMute(), - child: MyImage( - image: snapshot.data == 0 ? MyAssets.musicOff : MyAssets.musicOn, - size: setSize(context: context, tablet: 100), + child: SlideDownFade( + delay: Duration(milliseconds: 200), + child: StreamBuilder( + initialData: 1, + stream: context.read().volumeStream, + builder: (context, snapshot) => MyInkwell( + onTap: () => context.read().changeMute(), + child: MyImage( + image: snapshot.data == 0 ? MyAssets.musicOff : MyAssets.musicOn, + size: setSize(context: context, tablet: 100), + ), ), ), ), @@ -87,29 +92,32 @@ class HomePage extends StatelessWidget { bottom: MySpaces.s40, left: MySpaces.s16, right: MySpaces.s16, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - MyInkwell( - onTap: () => context.read().goToLanguagePage(context), - child: MyImage( - image: MyAssets.language, - size: setSize(context: context, tablet: 100), + child: SlideUpFade( + delay: Duration(milliseconds: 200), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + MyInkwell( + onTap: () => context.read().goToLanguagePage(context), + child: MyImage( + image: MyAssets.language, + size: setSize(context: context, tablet: 100), + ), ), - ), - MyYellowButton( - onTap: () => context.read().goToLevelPage(context), - title: context.translate.start, - ), - MyInkwell( - onTap: () => context.read().showAboutUs(context), - child: MyImage( - image: MyAssets.theme, - size: setSize(context: context, tablet: 100), + MyYellowButton( + onTap: () => context.read().goToLevelPage(context), + title: context.translate.start, ), - ), - ], + MyInkwell( + onTap: () => context.read().showAboutUs(context), + child: MyImage( + image: MyAssets.theme, + size: setSize(context: context, tablet: 100), + ), + ), + ], + ), ), ); } diff --git a/lib/features/intro/presentation/bloc/intro_bloc.dart b/lib/features/intro/presentation/bloc/intro_bloc.dart index 8f446c0..e976396 100644 --- a/lib/features/intro/presentation/bloc/intro_bloc.dart +++ b/lib/features/intro/presentation/bloc/intro_bloc.dart @@ -38,7 +38,7 @@ class IntroBloc extends Bloc { Future goToLevelPage() async { await LocalStorage.saveData(key: MyConstants.firstIntro, value: 'true'); if (ContextProvider.context.mounted) { - ContextProvider.context.replaceNamed(Routes.levelPage); + ContextProvider.context.goNamed(Routes.levelPage); } } diff --git a/lib/features/level/presentation/bloc/level_bloc.dart b/lib/features/level/presentation/bloc/level_bloc.dart index ac39a9b..4511ed7 100644 --- a/lib/features/level/presentation/bloc/level_bloc.dart +++ b/lib/features/level/presentation/bloc/level_bloc.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_audios.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/params/level_params.dart'; import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; @@ -25,6 +26,7 @@ class LevelBloc extends Bloc { this._effectAudioService, ) : super(const LevelState()) { volumeStream = _mainAudioService.volumeStream(); + playMusic(); on(_getLevelListEvent); on(_setCurrentLevelEvent); on(_startScrollEvent); @@ -81,6 +83,14 @@ class LevelBloc extends Bloc { final AudioService _effectAudioService; /// ------------Functions------------ + Future playMusic() async { + await Future.wait([ + _mainAudioService.setAudio(assetPath: MyAudios.question), + _mainAudioService.setLoopMode(isLoop: true), + ]); + await _mainAudioService.play(); + } + void goToQuestionPage(BuildContext context, LevelEntity level){ context.pushReplacementNamed( Routes.questionPage, @@ -90,8 +100,8 @@ class LevelBloc extends Bloc { ); } - void goToHomePage(BuildContext context){ - context.pop(); + void goToHomePage(BuildContext context) { + context.goNamed(Routes.homePage); } LevelType getLevelType(int index) { @@ -115,6 +125,13 @@ class LevelBloc extends Bloc { ]); } + int get diamonds { + int currentLevel = int.parse( + LocalStorage.readData(key: MyConstants.currentLevel) ?? '1', + ); + return currentLevel - 1; + } + /// ------------Api Calls------------ FutureOr _getLevelListEvent(GetLevelListEvent event, Emitter emit) async { @@ -185,4 +202,5 @@ class LevelBloc extends Bloc { emit(state.copyWith(chooseLevel: event.level)); } } + } diff --git a/lib/features/level/presentation/ui/level_page.dart b/lib/features/level/presentation/ui/level_page.dart index a1d89ed..1605b43 100644 --- a/lib/features/level/presentation/ui/level_page.dart +++ b/lib/features/level/presentation/ui/level_page.dart @@ -196,7 +196,9 @@ class LevelPage extends StatelessWidget { ), ), Spacer(), - DiamondLevel(), + DiamondLevel( + diamonds: context.read().diamonds, + ), StreamBuilder( initialData: 1, stream: context.read().volumeStream, diff --git a/lib/features/level/presentation/ui/widgets/diamond_level.dart b/lib/features/level/presentation/ui/widgets/diamond_level.dart index 28cb1b6..83143f0 100644 --- a/lib/features/level/presentation/ui/widgets/diamond_level.dart +++ b/lib/features/level/presentation/ui/widgets/diamond_level.dart @@ -7,7 +7,9 @@ import 'package:hadi_hoda_flutter/core/utils/gap.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; class DiamondLevel extends StatelessWidget { - const DiamondLevel({super.key}); + const DiamondLevel({super.key, this.diamonds}); + + final int? diamonds; @override Widget build(BuildContext context) { @@ -29,7 +31,7 @@ class DiamondLevel extends StatelessWidget { colors: [Color(0XFF4BA5EA), Color(0XFF0C4EE9)], ).createShader(bounds), child: Text( - '0', + '$diamonds', maxLines: 1, style: MYTextStyle.button1.copyWith( shadows: [ diff --git a/lib/features/question/data/model/answer_model.dart b/lib/features/question/data/model/answer_model.dart index 21536b3..3cab02a 100644 --- a/lib/features/question/data/model/answer_model.dart +++ b/lib/features/question/data/model/answer_model.dart @@ -9,6 +9,8 @@ class AnswerModel extends AnswerEntity { super.imageInfo, super.order, super.isActive, + super.audioID, + super.audioInfo, }); factory AnswerModel.fromJson(Map json) { @@ -21,6 +23,10 @@ class AnswerModel extends AnswerEntity { : FileModel.fromJson(json['image_info']), order: json['order'], isActive: json['is_active'], + audioID: json['audio_id'], + audioInfo: json['audio_info'] == null + ? null + : FileModel.fromJson(json['audio_info']), ); } } diff --git a/lib/features/question/domain/entity/answer_entity.dart b/lib/features/question/domain/entity/answer_entity.dart index 82d0269..0e0e647 100644 --- a/lib/features/question/domain/entity/answer_entity.dart +++ b/lib/features/question/domain/entity/answer_entity.dart @@ -1,3 +1,5 @@ +import 'package:hadi_hoda_flutter/core/constants/my_constants.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/question/domain/entity/file_entity.dart'; import 'package:hive/hive.dart'; @@ -20,6 +22,12 @@ class AnswerEntity extends HiveObject { bool? isActive; @HiveField(6) String? image; + @HiveField(7) + String? audioID; + @HiveField(8) + FileEntity? audioInfo; + @HiveField(9) + String? audio; AnswerEntity({ this.id, @@ -28,8 +36,10 @@ class AnswerEntity extends HiveObject { this.imageInfo, this.order, this.isActive, - this.image, + this.audioID, + this.audioInfo, }){ image = '${StoragePath.documentDir.path}/images/${imageInfo?.filename}'; + audio = '${StoragePath.documentDir.path}/${LocalStorage.readData(key: MyConstants.selectLanguage)}/answer_audio/${audioInfo?.filename}'; } } diff --git a/lib/features/question/domain/entity/answer_entity.g.dart b/lib/features/question/domain/entity/answer_entity.g.dart index e8a7616..bcc224b 100644 --- a/lib/features/question/domain/entity/answer_entity.g.dart +++ b/lib/features/question/domain/entity/answer_entity.g.dart @@ -23,14 +23,17 @@ class AnswerEntityAdapter extends TypeAdapter { imageInfo: fields[3] as FileEntity?, order: fields[4] as int?, isActive: fields[5] as bool?, - image: fields[6] as String?, - ); + audioID: fields[7] as String?, + audioInfo: fields[8] as FileEntity?, + ) + ..image = fields[6] as String? + ..audio = fields[9] as String?; } @override void write(BinaryWriter writer, AnswerEntity obj) { writer - ..writeByte(7) + ..writeByte(10) ..writeByte(0) ..write(obj.id) ..writeByte(1) @@ -44,7 +47,13 @@ class AnswerEntityAdapter extends TypeAdapter { ..writeByte(5) ..write(obj.isActive) ..writeByte(6) - ..write(obj.image); + ..write(obj.image) + ..writeByte(7) + ..write(obj.audioID) + ..writeByte(8) + ..write(obj.audioInfo) + ..writeByte(9) + ..write(obj.audio); } @override diff --git a/lib/features/question/domain/entity/question_entity.dart b/lib/features/question/domain/entity/question_entity.dart index beec745..e9ec445 100644 --- a/lib/features/question/domain/entity/question_entity.dart +++ b/lib/features/question/domain/entity/question_entity.dart @@ -38,7 +38,6 @@ class QuestionEntity extends HiveObject { this.isActive, this.answers, }){ - audio = - '${StoragePath.documentDir.path}/${LocalStorage.readData(key: MyConstants.selectLanguage)}/audio/${audioInfo?.filename}'; + audio = '${StoragePath.documentDir.path}/${LocalStorage.readData(key: MyConstants.selectLanguage)}/question_audio/${audioInfo?.filename}'; } } diff --git a/lib/features/question/presentation/bloc/question_bloc.dart b/lib/features/question/presentation/bloc/question_bloc.dart index 446802b..b609394 100644 --- a/lib/features/question/presentation/bloc/question_bloc.dart +++ b/lib/features/question/presentation/bloc/question_bloc.dart @@ -1,9 +1,9 @@ import 'dart:async'; -import 'package:confetti/confetti.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_audios.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/params/question_params.dart'; import 'package:hadi_hoda_flutter/core/routers/hero_dialog_route.dart'; @@ -28,18 +28,13 @@ class QuestionBloc extends Bloc { QuestionBloc( this._getLevelUseCase, this._getNextLevelUseCase, - this._audioService, + this._mainAudioService, + this._effectAudioService, ) : super(QuestionState()) { - volumeStream = _audioService.volumeStream(); + volumeStream = _mainAudioService.volumeStream(); + stopMusic(); on(_getLevelEvent); on(_chooseAnswerEvent); - on(_getNextLevelEvent); - } - - @override - Future close() { - confettiController.dispose(); - return super.close(); } /// ------------UseCases------------ @@ -57,10 +52,8 @@ class QuestionBloc extends Bloc { bool isPlaying = false; /// ------------Controllers------------ - final AudioService _audioService; - final ConfettiController confettiController = ConfettiController( - duration: Duration(seconds: 1), - ); + final AudioService _mainAudioService; + final AudioService _effectAudioService; /// ------------Functions------------ void startShowCase({required BuildContext context}) { @@ -75,46 +68,84 @@ class QuestionBloc extends Bloc { ); } + void goToHomePage({required BuildContext context}) { + context.goNamed(Routes.homePage); + } + void goToLevelPage({required BuildContext context}) { - context.pushReplacement(Routes.levelPage); + context.goNamed(Routes.levelPage); } - Future playVoice() async { - await _audioService.setAudio(filePath: state.currentQuestion?.audio); - await _audioService.play(); + Future playDiamondAudio() async { + await _effectAudioService.setAudio(assetPath: MyAudios.diamondEnd); + await _effectAudioService.play(); + } + + Future stopMusic() async { + await _mainAudioService.stop(); + await _mainAudioService.setLoopMode(isLoop: false); + } + + Future playCorrectAudio() async { + await _effectAudioService.setAudio(assetPath: MyAudios.rightAnswer); + await _effectAudioService.play(); + } + + Future playWrongAudio() async { + await _effectAudioService.setAudio(assetPath: MyAudios.incorrectAnswer); + await _effectAudioService.play(); + } + + Future playAnswerAudio({String? audio}) async { + await _mainAudioService.setAudio(filePath: audio); + await _mainAudioService.play(); + } + + Future playQuestionAudio() async { + await _mainAudioService.setAudio(filePath: state.currentQuestion?.audio); + await _mainAudioService.play(); } Future changeMute() async { - await _audioService.changeMute(); + await Future.wait([ + _mainAudioService.changeMute(), + _effectAudioService.changeMute(), + ]); } Future showAnswerDialog({ required BuildContext context, required AnswerEntity answerEntity, - bool? correct, }) async { - await Navigator.of(context).push( + Navigator.of(context).push( HeroDialogRoute( builder: (dialogContext) { - return AnswerScreen(answerEntity: answerEntity, correct: correct); + return AnswerScreen( + answerEntity: answerEntity, + onNotifTap: (answer) => playAnswerAudio(audio: answer.audio), + ); }, ), ); + playAnswerAudio(audio: answerEntity.audio); } - Future playback(BuildContext context) async { - if (isPlaying) return; - for (int i = 0; i < 4; i++) { - await Future.delayed(Duration(seconds: 1)); - if (context.mounted) { - await showAnswerDialog( - context: context, - answerEntity: state.currentQuestion?.answers?[i] ?? AnswerEntity(), - ); - isPlaying = true; - } - } - isPlaying = false; + Future getNextLevelEvent() async { + await _getNextLevelUseCase(QuestionParams()).then((value) => + value.fold( + (data) { + ContextProvider.context.pushReplacementNamed( + Routes.questionPage, + pathParameters: { + 'id': '${data.id}' + }, + ); + }, + (error) { + goToLevelPage(context: ContextProvider.context); + }, + ), + ); } /// ------------Event Calls------------ @@ -138,10 +169,7 @@ class QuestionBloc extends Bloc { levelEntity: level, currentQuestion: data.questions?.first, )); - await playVoice(); - if(event.context.mounted){ - playback(event.context); - } + await playQuestionAudio(); }, (error) { emit(state.copyWith(getQuestionStatus: BaseError(error.errorMessage))); @@ -156,14 +184,19 @@ class QuestionBloc extends Bloc { emit(state.copyWith(correctAnswer: event.chooseCorrectAnswer)); if (event.chooseCorrectAnswer) { - confettiController.play(); - await showAnswerDialog( - answerEntity: state.currentQuestion?.answers?.singleWhere((e) => - e.order == event.correctAnswer) ?? AnswerEntity(), - context: ContextProvider.context, - correct: true, + playCorrectAudio(); + await Navigator.of(ContextProvider.context).push( + HeroDialogRoute( + builder: (dialogContext) { + return AnswerScreen( + answerEntity: state.currentQuestion?.answers?.singleWhere((e) => + e.order == event.correctAnswer) ?? AnswerEntity(), + showConfetti: true, + ); + }, + ), ); - await Future.delayed(Duration(seconds: 2), () async { + await Future.delayed(Duration(seconds: 1), () async { final QuestionEntity? findPreQuestion = state.currentQuestion; final int findIndex = (findPreQuestion?.order ?? 1); emit( @@ -173,6 +206,7 @@ class QuestionBloc extends Bloc { ); if (state.currentQuestion?.order == state.levelEntity?.questions?.length) { + playDiamondAudio(); int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1'); if (state.levelEntity?.order == currentLevel) { @@ -183,31 +217,11 @@ class QuestionBloc extends Bloc { ); } } else { - await playVoice(); - if(event.context.mounted){ - playback(event.context); - } + playQuestionAudio(); } }); + } else { + playWrongAudio(); } } - - FutureOr _getNextLevelEvent(GetNextLevelEvent event, - Emitter emit) async { - await _getNextLevelUseCase(QuestionParams()).then((value) => - value.fold( - (data) { - ContextProvider.context.pushReplacementNamed( - Routes.questionPage, - pathParameters: { - 'id': '${data.id}' - }, - ); - }, - (error) { - goToLevelPage(context: ContextProvider.context); - }, - ), - ); - } } diff --git a/lib/features/question/presentation/bloc/question_event.dart b/lib/features/question/presentation/bloc/question_event.dart index 6f716d2..428a4f4 100644 --- a/lib/features/question/presentation/bloc/question_event.dart +++ b/lib/features/question/presentation/bloc/question_event.dart @@ -17,6 +17,3 @@ class ChooseAnswerEvent extends QuestionEvent { const ChooseAnswerEvent(this.chooseCorrectAnswer, this.correctAnswer, this.context); } -class GetNextLevelEvent extends QuestionEvent { - const GetNextLevelEvent(); -} diff --git a/lib/features/question/presentation/ui/question_page.dart b/lib/features/question/presentation/ui/question_page.dart index 85685f3..9556eef 100644 --- a/lib/features/question/presentation/ui/question_page.dart +++ b/lib/features/question/presentation/ui/question_page.dart @@ -1,17 +1,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_audios.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/core/utils/gap.dart'; -import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; -import 'package:hadi_hoda_flutter/core/widgets/confetti/my_confetti.dart'; +import 'package:hadi_hoda_flutter/core/widgets/animations/slide_down_fade.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_bloc.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_state.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/ui/screens/diamond_screen.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/ui/screens/question_screen.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/glassy_button.dart'; -import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/question_stepper.dart'; +import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/question_title.dart'; import 'package:showcaseview/showcaseview.dart'; class QuestionPage extends StatelessWidget { @@ -41,36 +41,31 @@ class QuestionPage extends StatelessWidget { ), ), ), - child: SafeArea( - bottom: false, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: MySpaces.s16), - child: Column( - children: [ - MyConfetti( - controller: context.read().confettiController, - ), - MySpaces.s4.gapHeight, - _topButtons(context), - MySpaces.s10.gapHeight, - _stepper(), - Expanded( - child: BlocBuilder( - buildWhen: (previous, current) => - (previous.currentQuestion?.order != - current.currentQuestion?.order), - builder: (context, state) { - if (state.currentQuestion?.order == - state.levelEntity?.questions?.length) { - return DiamondScreen(); - } else { - return QuestionScreen(); - } - }, - ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: MySpaces.s16, + vertical: MySpaces.s22, + ), + child: Column( + children: [ + _topButtons(context), + MySpaces.s10.gapHeight, + Expanded( + child: BlocBuilder( + buildWhen: (previous, current) => + (previous.currentQuestion?.order != + current.currentQuestion?.order), + builder: (context, state) { + if (state.currentQuestion?.order == + state.levelEntity?.questions?.length) { + return DiamondScreen(); + } else { + return QuestionScreen(); + } + }, ), - ], - ), + ), + ], ), ), ), @@ -79,49 +74,36 @@ class QuestionPage extends StatelessWidget { ); } - Widget _topButtons(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - GlassyButton( - image: MyAssets.home, - onTap: () => context.read().goToLevelPage(context: context), - ), - Spacer(), - BlocBuilder( - buildWhen: (previous, current) => - previous.levelEntity?.id != current.levelEntity?.id, - builder: (context, state) => Text( - '${context.translate.step} ${state.levelEntity?.order ?? 1}', + return SlideDownFade( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + GlassyButton( + image: MyAssets.home, + audio: MyAudios.back, + onTap: () => + context.read().goToHomePage(context: context), + ), + BlocBuilder( + buildWhen: (previous, current) => + previous.currentQuestion?.id != current.currentQuestion?.id, + builder: (context, state) => QuestionTitle( + step: state.levelEntity?.order, + currentQuestion: state.currentQuestion?.order, + questionLength: state.levelEntity?.questions?.length, + ), ), - ), - Spacer(), - GlassyButton( - image: MyAssets.leaf, - onTap: () => context.read().showHadith(context: context), - ), - MySpaces.s10.gapWidth, - StreamBuilder( - initialData: 1, - stream: context.read().volumeStream, - builder: (context, snapshot) => GlassyButton( - image: snapshot.data == 1 ? MyAssets.music : MyAssets.unMusic, + StreamBuilder( + initialData: 1, + stream: context.read().volumeStream, + builder: (context, snapshot) => GlassyButton( + image: snapshot.data == 0 ? MyAssets.unMusic : MyAssets.music, onTap: () => context.read().changeMute(), + ), ), - ), - ], - ); - } - - Widget _stepper() { - return BlocBuilder( - buildWhen: (previous, current) => - previous.currentQuestion?.id != current.currentQuestion?.id, - builder: (context, state) => QuestionStepper( - length: state.levelEntity?.questions?.length ?? 0, - currentStep: state.currentQuestion?.order ?? 1, + ], ), ); } diff --git a/lib/features/question/presentation/ui/screens/answer_screen.dart b/lib/features/question/presentation/ui/screens/answer_screen.dart index b14cd3c..ecbb58a 100644 --- a/lib/features/question/presentation/ui/screens/answer_screen.dart +++ b/lib/features/question/presentation/ui/screens/answer_screen.dart @@ -1,13 +1,24 @@ 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_spaces.dart'; import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; +import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; import 'package:hadi_hoda_flutter/core/widgets/answer_box/answer_box_show.dart'; import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; +import 'package:lottie/lottie.dart'; class AnswerScreen extends StatefulWidget { - const AnswerScreen({super.key, required this.answerEntity, this.correct}); + const AnswerScreen({ + super.key, + required this.answerEntity, + this.onNotifTap, + this.showConfetti = false, + }); final AnswerEntity answerEntity; - final bool? correct; + final Function(AnswerEntity answer)? onNotifTap; + final bool showConfetti; @override State createState() => _AnswerScreenState(); @@ -21,33 +32,37 @@ class _AnswerScreenState extends State { } Future back() async { - await Future.delayed(Duration(seconds: 2), () { - if (context.mounted) { - Navigator.pop(ContextProvider.context); - } - }); + if (widget.showConfetti) { + await Future.delayed(Duration(seconds: 3), () { + if (ContextProvider.context.mounted) { + ContextProvider.context.pop(); + } + }); + } } @override Widget build(BuildContext context) { - return Center( - child: Hero( - tag: 'Hero_answer_${widget.answerEntity.id}', - createRectTween: (begin, end) => MaterialRectArcTween(begin: begin, end: end), - flightShuttleBuilder: (flightContext, animation, flightDirection, - fromHeroContext, toHeroContext) => toHeroContext.widget, - child: Transform.scale( - scale: 2, - child: Material( - type: MaterialType.transparency, + return Stack( + children: [ + Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: MySpaces.s16), child: AnswerBoxShow( answer: widget.answerEntity, index: widget.answerEntity.order ?? 0, - correct: widget.correct, + onNotifTap: widget.onNotifTap, ), ), ), - ), + if (widget.showConfetti) ...{ + Lottie.asset( + MyAnimations.confetti, + height: context.heightScreen, + fit: BoxFit.cover, + ), + }, + ], ); } } diff --git a/lib/features/question/presentation/ui/screens/diamond_screen.dart b/lib/features/question/presentation/ui/screens/diamond_screen.dart index f4dbe48..606051a 100644 --- a/lib/features/question/presentation/ui/screens/diamond_screen.dart +++ b/lib/features/question/presentation/ui/screens/diamond_screen.dart @@ -2,17 +2,19 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.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_spaces.dart'; -import 'package:hadi_hoda_flutter/core/utils/gap.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; -import 'package:hadi_hoda_flutter/core/widgets/button/enum/button_type.dart'; -import 'package:hadi_hoda_flutter/core/widgets/button/my_button.dart'; +import 'package:hadi_hoda_flutter/core/widgets/animations/ship_anim.dart'; +import 'package:hadi_hoda_flutter/core/widgets/button/my_white_button.dart'; +import 'package:hadi_hoda_flutter/core/widgets/button/my_yellow_button.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_bloc.dart'; -import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_event.dart'; +import 'package:lottie/lottie.dart'; class DiamondScreen extends StatelessWidget { const DiamondScreen({super.key}); @@ -20,144 +22,146 @@ class DiamondScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _title(context), - 80.0.gapHeight, - Column( - children: [ - _diamonds(context), - _mainText(context), - ], - ), - Spacer(), Stack( alignment: Alignment.center, - clipBehavior: Clip.none, children: [ - _ship(context), - _btns(context), - ], - ), - ], - ); - } - - Text _title(BuildContext context) { - return Text( - context.translate.you_win, - ); - } - - SizedBox _diamonds(BuildContext context) { - return SizedBox( - width: context.widthScreen, - height: context.heightScreen / 3, - child: Stack( - alignment: Alignment.center, - children: [ - PositionedDirectional( - start: 20, - top: 0, - child: SizedBox( - height: 50, - width: 50, - child: Transform.rotate( - angle: -0.5, - child: Stack( - children: [ - MyImage(image: MyAssets.diamondBig), - ClipRRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 4, sigmaY: 4), - child: SizedBox(width: 50, height: 50), + Stack( + alignment: Alignment.center, + children: [ + MyImage( + image: MyAssets.behindDiamond, + size: context.widthScreen * 1.5, + fit: BoxFit.cover, + ), + Lottie.asset( + MyAnimations.lightPurple, + ), + Transform.rotate( + angle: 0.2, + child: MyImage( + image: MyAssets.diamondBig, + size: 200, + ), + ), + Padding( + padding: EdgeInsets.only( + top: 250, + ), + child: Column( + children: [ + Text( + context.translate.you_win, + style: MYTextStyle.titr0, ), - ), - ], + ShaderMask( + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + MyColors.white, + Color(0XFF63D4F9), + ], + ).createShader(bounds), + child: Text( + context.translate.you_got_diamond, + style: MYTextStyle.titr1.copyWith( + shadows: [ + BoxShadow( + color: MyColors.black.withValues(alpha: 0.25), + offset: Offset(0, 1.22), + blurRadius: 0.82, + ), + ], + ), + ), + ), + ], + ), ), - ), + ], ), - ), - PositionedDirectional( - end: 0, - top: 30, - child: Transform.rotate( - angle: 0.5, + Positioned( + top: 120, + right: MySpaces.s16, child: Stack( children: [ - MyImage(image: MyAssets.diamondBig, size: 60), + Transform.rotate( + angle: 0.4, + child: MyImage( + image: MyAssets.diamondBig, + size: 80, + ), + ), ClipRRect( child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 3, sigmaY: 3), - child: SizedBox(width: 100, height: 100), + child: SizedBox(width: 80, height: 80,), ), ), ], ), ), - ), - Positioned(top: 100, child: MyImage(image: MyAssets.diamondBig)), - ], - ), + Positioned( + top: 100, + left: MySpaces.s16, + child: Stack( + children: [ + Transform.rotate( + angle: -0.6, + child: MyImage( + image: MyAssets.diamondBig, + size: 60, + ), + ), + ClipRRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: SizedBox(width: 80, height: 80,), + ), + ), + ], + ), + ), + ], + ), + Stack( + alignment: Alignment.center, + clipBehavior: Clip.none, + children: [ + _ship(context), + _buttons(context), + ], + ), + ], ); } - Widget _mainText(BuildContext context){ - return ShaderMask( - blendMode: BlendMode.srcIn, - shaderCallback: (bounds) => LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [MyColors.white, Color(0XFF63D4F9)], - ).createShader(bounds), - child: Text( - context.translate.you_got_diamond, - ), - ); - } - PositionedDirectional _ship(BuildContext context) { - return PositionedDirectional( - end: context.widthScreen / 10, - top: -80, + Widget _ship(BuildContext context) { + return ShipAnim( child: MyImage(image: MyAssets.ship), ); } - Widget _btns(BuildContext context) { - return Padding( - padding: EdgeInsets.only( - bottom: MediaQuery.viewPaddingOf(context).bottom + MySpaces.s16, - ), - child: Row( - children: [ - Expanded( - child: InkWell( - onTap: () => context.read().goToLevelPage(context: context), - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.button3, size: 84), - Positioned( - top: 10, - child: Text( - context.translate.view_map, - ), - ), - ], - ), - ), + Widget _buttons(BuildContext context) { + return Row( + spacing: MySpaces.s12, + children: [ + Expanded( + child: MyWhiteButton( + onTap: () => context.read().getNextLevelEvent(), + title: context.translate.map, ), - Expanded( - child: MyButton( - onTap: () => context.read().add(GetNextLevelEvent()), - title: context.translate.go_next, - type: ButtonType.type2, - ), + ), + Expanded( + child: MyYellowButton( + onTap: () => context.read().getNextLevelEvent(), + title: context.translate.next, ), - ], - ), + ), + ], ); } } diff --git a/lib/features/question/presentation/ui/screens/question_screen.dart b/lib/features/question/presentation/ui/screens/question_screen.dart index abb6a76..1827676 100644 --- a/lib/features/question/presentation/ui/screens/question_screen.dart +++ b/lib/features/question/presentation/ui/screens/question_screen.dart @@ -1,19 +1,22 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/core/utils/gap.dart'; -import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; +import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; +import 'package:hadi_hoda_flutter/core/widgets/animations/fade_anim.dart'; +import 'package:hadi_hoda_flutter/core/widgets/animations/slide_anim.dart'; +import 'package:hadi_hoda_flutter/core/widgets/animations/slide_up_fade.dart'; import 'package:hadi_hoda_flutter/core/widgets/answer_box/answer_box.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; -import 'package:hadi_hoda_flutter/core/widgets/showcase/question_showcase.dart'; import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_bloc.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_event.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_state.dart'; -import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/left_blob.dart'; -import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/refresh_button.dart'; -import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/right_blob.dart'; +import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/glassy_button.dart'; +import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/question_stepper.dart'; class QuestionScreen extends StatelessWidget { const QuestionScreen({super.key}); @@ -22,122 +25,130 @@ class QuestionScreen extends StatelessWidget { Widget build(BuildContext context) { return Column( children: [ + _stepper(), _titles(), - MySpaces.s14.gapHeight, + MySpaces.s20.gapHeight, _answers(), - _bottomDetail(context), + _bottom(context), ], ); } - Column _titles() { - return Column( - spacing: MySpaces.s4, - children: [ - BlocBuilder( - buildWhen: (previous, current) => - previous.currentQuestion?.id != current.currentQuestion?.id, - builder: (context, state) => Text( - '${context.translate.question} ${state.currentQuestion?.order ?? 1} / ${(state.levelEntity?.questions?.length ?? 0) - 1}', - ), + Widget _stepper() { + return BlocBuilder( + buildWhen: (previous, current) => + previous.currentQuestion?.id != current.currentQuestion?.id, + builder: (context, state) => FadeAnim( + child: QuestionStepper( + length: state.levelEntity?.questions?.length ?? 0, + currentStep: state.currentQuestion?.order ?? 1, ), - BlocBuilder( - buildWhen: (previous, current) => - previous.currentQuestion?.id != current.currentQuestion?.id, - builder: (context, state) => Text( - state.currentQuestion?.title ?? '', - textAlign: TextAlign.center, - ), - ), - ], + ), ); } - Expanded _answers() { + Widget _titles() { return Expanded( - child: GridView.builder( - itemCount: 4, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: MySpaces.s20, - mainAxisSpacing: 50, - ), - itemBuilder: (context, index) => QuestionShowcase( - globalKey: context.read().keys[index], - description: context.translate.tap_to_select, - child: BlocBuilder( - buildWhen: (previous, current) => - previous.currentQuestion?.id != current.currentQuestion?.id, - builder: (context, state) => Hero( - key: Key('${state.currentQuestion?.id}'), - tag: 'Hero_answer_${state.currentQuestion?.answers?[index].id}', - child: AnswerBox( - index: state.currentQuestion?.answers?[index].order ?? 1, - answer: state.currentQuestion?.answers?[index] ?? AnswerEntity(), - correctAnswer: state.currentQuestion?.correctAnswer ?? 0, - onTap: (isCorrect, correctAnswer) => - context.read().add( - ChooseAnswerEvent(isCorrect, correctAnswer, context), + flex: 15, + child: BlocBuilder( + buildWhen: (previous, current) => + previous.currentQuestion?.id != current.currentQuestion?.id, + builder: (context, state) => + FadeAnim( + child: Text( + state.currentQuestion?.title ?? '', + textAlign: TextAlign.center, + maxLines: 3, + style: MYTextStyle.titr1.copyWith( + shadows: [ + BoxShadow( + offset: Offset(0, 2), + color: MyColors.black.withValues(alpha: 0.25), ), + ], + ), ), ), + ), + ); + } + + Expanded _answers() { + return Expanded( + flex: 85, + child: BlocBuilder( + buildWhen: (previous, current) => + previous.currentQuestion?.id != current.currentQuestion?.id, + builder: (context, state) => GridView.builder( + itemCount: state.currentQuestion?.answers?.length ?? 0, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: MySpaces.s20, + mainAxisSpacing: 80, ), + itemBuilder: (context, index) => + state.currentQuestion?.answers?[index].imageId == null + ? SizedBox.shrink() + : SlideAnim( + key: Key('${state.currentQuestion?.id}'), + index: index, + child: AnswerBox( + index: state.currentQuestion?.answers?[index].order ?? 1, + answer: + state.currentQuestion?.answers?[index] ?? + AnswerEntity(), + correctAnswer: state.currentQuestion?.correctAnswer ?? 0, + onNotifTap: (AnswerEntity answer) { + context.read().showAnswerDialog( + context: context, + answerEntity: answer, + ); + }, + onTap: (isCorrect, correctAnswer) => + context.read().add( + ChooseAnswerEvent(isCorrect, correctAnswer, context), + ), + ), + ), ), ), ); } - Widget _bottomDetail(BuildContext context) { - return Row( - children: [ - Spacer(), - BlocBuilder( - buildWhen: (previous, current) => - previous.correctAnswer != current.correctAnswer, - builder: (context, state) => Stack( - clipBehavior: Clip.none, - children: [ - PositionedDirectional( - start: -100, - top: -10, - child: AnimatedOpacity( - opacity: state.correctAnswer == false ? 1 : 0, - duration: Duration(milliseconds: 200), - child: LeftBlob(), + Widget _bottom(BuildContext context) { + return SlideUpFade( + child: SizedBox( + width: context.widthScreen, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + padding: EdgeInsets.all(MySpaces.s4), + decoration: BoxDecoration( + gradient: RadialGradient( + colors: [ + Color(0XFFDFCD00), + Color(0XFFDFCD00).withValues(alpha: 0.35), + Color(0XFFDFCD00).withValues(alpha: 0), + ], + center: Alignment.center, ), ), - AnimatedCrossFade( - duration: Duration(milliseconds: 200), - reverseDuration: Duration(milliseconds: 200), - crossFadeState: state.correctAnswer == true ? CrossFadeState - .showSecond : CrossFadeState.showFirst, - firstChild: MyImage( - image: MyAssets.persons, - fit: BoxFit.contain, - ), - secondChild: MyImage( - image: MyAssets.happyPersons, - fit: BoxFit.contain, - size: 110, - ), + child: MyImage( + image: MyAssets.globe, ), - PositionedDirectional( - top: -30, - end: -90, - child: AnimatedOpacity( - opacity: state.correctAnswer == false ? 1 : 0, - duration: Duration(milliseconds: 200), - child: RightBlob(), - ), + ), + PositionedDirectional( + end: 0, + child: GlassyButton( + image: MyAssets.leaf, + onTap: () => + context.read().showHadith(context: context), ), - ], - ), - ), - Spacer(), - RefreshButton( - onTap: () => context.read().playback(context), + ), + ], ), - ], + ), ); } } diff --git a/lib/features/question/presentation/ui/widgets/black_white_effect.dart b/lib/features/question/presentation/ui/widgets/black_white_effect.dart deleted file mode 100644 index 317ab60..0000000 --- a/lib/features/question/presentation/ui/widgets/black_white_effect.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/material.dart'; - -class BlackWhiteEffect extends StatelessWidget { - const BlackWhiteEffect({super.key, required this.child}); - - final Widget child; - - @override - Widget build(BuildContext context) { - return ColorFiltered( - colorFilter: ColorFilter.matrix( - [ - 0.2126, 0.7152, 0.0722, 0, 0, - 0.2126, 0.7152, 0.0722, 0, 0, - 0.2126, 0.7152, 0.0722, 0, 0, - 0, 0, 0, 1, 0, - ], - ), - child: child, - ); - } -} diff --git a/lib/features/question/presentation/ui/widgets/glassy_button.dart b/lib/features/question/presentation/ui/widgets/glassy_button.dart index 211b00b..59d260a 100644 --- a/lib/features/question/presentation/ui/widgets/glassy_button.dart +++ b/lib/features/question/presentation/ui/widgets/glassy_button.dart @@ -1,12 +1,14 @@ import 'package:flutter/material.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; +import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; class GlassyButton extends StatelessWidget { - const GlassyButton({super.key, required this.image, this.onTap}); + const GlassyButton({super.key, required this.image, this.onTap, this.audio}); final String image; final VoidCallback? onTap; + final String? audio; @override Widget build(BuildContext context) { @@ -27,8 +29,9 @@ class GlassyButton extends StatelessWidget { ), border: Border.all(color: Colors.white.withValues(alpha: 0.3)), ), - child: InkWell( + child: MyInkwell( onTap: onTap, + audio: audio, borderRadius: BorderRadius.all(Radius.circular(100)), child: Padding( padding: const EdgeInsets.all(MySpaces.s12), diff --git a/lib/features/question/presentation/ui/widgets/left_blob.dart b/lib/features/question/presentation/ui/widgets/left_blob.dart deleted file mode 100644 index 59b17fa..0000000 --- a/lib/features/question/presentation/ui/widgets/left_blob.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; -import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; -import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; - -class LeftBlob extends StatelessWidget { - const LeftBlob({super.key}); - - @override - Widget build(BuildContext context) { - return Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.bubbleChatLeft), - Text( - context.translate.wrong_answer, - textAlign: TextAlign.center, - ), - ], - ); - } -} diff --git a/lib/features/question/presentation/ui/widgets/question_title.dart b/lib/features/question/presentation/ui/widgets/question_title.dart new file mode 100644 index 0000000..4d4305e --- /dev/null +++ b/lib/features/question/presentation/ui/widgets/question_title.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.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/my_localization.dart'; + +class QuestionTitle extends StatelessWidget { + const QuestionTitle({ + super.key, + this.step, + this.currentQuestion, + this.questionLength, + }); + + final int? step; + final int? currentQuestion; + final int? questionLength; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text( + '${context.translate.step} ${step ?? 0}', + style: MYTextStyle.titr3, + ), + Text( + '${context.translate.question} ${currentQuestion ?? 0}/${(questionLength ?? 0) - 1}', + style: MYTextStyle.matn3.copyWith( + color: MyColors.white.withValues(alpha: 0.5), + shadows: [ + BoxShadow( + color: MyColors.black.withValues(alpha: 0.25), + blurRadius: 0.82, + offset: Offset(0, 1.22), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/features/question/presentation/ui/widgets/refresh_button.dart b/lib/features/question/presentation/ui/widgets/refresh_button.dart deleted file mode 100644 index 2f4a8bf..0000000 --- a/lib/features/question/presentation/ui/widgets/refresh_button.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; - -class RefreshButton extends StatelessWidget { - const RefreshButton({super.key, this.onTap,}); - - final VoidCallback? onTap; - - @override - Widget build(BuildContext context) { - return Material( - color: MyColors.transparent, - child: Ink( - height: 48, - width: 48, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [Color(0XFFA393FF), Color(0XFFC6BCFB)], - ), - ), - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.all(Radius.circular(100)), - child: Icon(Icons.refresh, size: 40, color: Color(0XFF263AA1)), - ), - ), - ); - } -} diff --git a/lib/features/question/presentation/ui/widgets/right_blob.dart b/lib/features/question/presentation/ui/widgets/right_blob.dart deleted file mode 100644 index 6d96a00..0000000 --- a/lib/features/question/presentation/ui/widgets/right_blob.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; -import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; -import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; - -class RightBlob extends StatelessWidget { - const RightBlob({super.key}); - - @override - Widget build(BuildContext context) { - return Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.bubbleChatRight), - Text( - context.translate.be_cureful, - textAlign: TextAlign.center, - ), - ], - ); - } -} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 4bad7ff..82b4f68 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -15,8 +15,8 @@ "be_cureful": "Be more\ncareful.", "wrong_answer": "Your answer\nwas not correct.", "you_got_diamond": "You got the diamond", - "view_map": "View Map", - "go_next": "Go Next", + "map": "Map", + "next": "Next", "you_win": "You Win!", "skip": "Skip", "intro_1_1": "Dinner is ready! Come quickly and wash your beautiful hands!", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index f4ec348..1e1258b 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -190,17 +190,17 @@ abstract class AppLocalizations { /// **'You got the diamond'** String get you_got_diamond; - /// No description provided for @view_map. + /// No description provided for @map. /// /// In en, this message translates to: - /// **'View Map'** - String get view_map; + /// **'Map'** + String get map; - /// No description provided for @go_next. + /// No description provided for @next. /// /// In en, this message translates to: - /// **'Go Next'** - String get go_next; + /// **'Next'** + String get next; /// No description provided for @you_win. /// diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 319b54d..95c2a37 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -59,10 +59,10 @@ class AppLocalizationsEn extends AppLocalizations { String get you_got_diamond => 'You got the diamond'; @override - String get view_map => 'View Map'; + String get map => 'Map'; @override - String get go_next => 'Go Next'; + String get next => 'Next'; @override String get you_win => 'You Win!';