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/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/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/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!';