diff --git a/assets/images/bubble_chat_left.svg b/assets/images/bubble_chat_left.svg
new file mode 100644
index 0000000..9d64c11
--- /dev/null
+++ b/assets/images/bubble_chat_left.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/images/bubble_chat_right.svg b/assets/images/bubble_chat_right.svg
new file mode 100644
index 0000000..b8ab88d
--- /dev/null
+++ b/assets/images/bubble_chat_right.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/correct.svg b/assets/images/correct.svg
new file mode 100644
index 0000000..17b0900
--- /dev/null
+++ b/assets/images/correct.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/images/diamond.png b/assets/images/diamond.png
new file mode 100644
index 0000000..ba816b1
Binary files /dev/null and b/assets/images/diamond.png differ
diff --git a/assets/images/done.svg b/assets/images/done.svg
new file mode 100644
index 0000000..28d7f58
--- /dev/null
+++ b/assets/images/done.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/hand_point.svg b/assets/images/hand_point.svg
new file mode 100644
index 0000000..5c28ef9
--- /dev/null
+++ b/assets/images/hand_point.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/home.svg b/assets/images/home.svg
new file mode 100644
index 0000000..d9d0a2c
--- /dev/null
+++ b/assets/images/home.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/music.svg b/assets/images/music.svg
new file mode 100644
index 0000000..03eb33b
--- /dev/null
+++ b/assets/images/music.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/pattern.png b/assets/images/pattern.png
new file mode 100644
index 0000000..3cc6062
Binary files /dev/null and b/assets/images/pattern.png differ
diff --git a/assets/images/persons.png b/assets/images/persons.png
new file mode 100644
index 0000000..3438d1f
Binary files /dev/null and b/assets/images/persons.png differ
diff --git a/assets/images/wrong.svg b/assets/images/wrong.svg
new file mode 100644
index 0000000..ebf05ff
--- /dev/null
+++ b/assets/images/wrong.svg
@@ -0,0 +1,17 @@
+
diff --git a/lib/common_ui/resources/my_assets.dart b/lib/common_ui/resources/my_assets.dart
index 8fc0a00..aafeaa3 100644
--- a/lib/common_ui/resources/my_assets.dart
+++ b/lib/common_ui/resources/my_assets.dart
@@ -17,4 +17,15 @@ class MyAssets {
static const String language = 'assets/images/language.svg';
static const String newHorizon = 'assets/images/new_horizon.svg';
static const String khadijeLogo = 'assets/images/khadije_logo.png';
+ static const String home = 'assets/images/home.svg';
+ static const String music = 'assets/images/music.svg';
+ static const String pattern = 'assets/images/pattern.png';
+ static const String persons = 'assets/images/persons.png';
+ static const String bubbleChatLeft = 'assets/images/bubble_chat_left.svg';
+ static const String bubbleChatRight = 'assets/images/bubble_chat_right.svg';
+ static const String diamond = 'assets/images/diamond.png';
+ static const String done = 'assets/images/done.svg';
+ static const String correct = 'assets/images/correct.svg';
+ static const String wrong = 'assets/images/wrong.svg';
+ static const String handPoint = 'assets/images/hand_point.svg';
}
\ No newline at end of file
diff --git a/lib/core/params/question_params.dart b/lib/core/params/question_params.dart
new file mode 100644
index 0000000..0c6fff1
--- /dev/null
+++ b/lib/core/params/question_params.dart
@@ -0,0 +1,13 @@
+class QuestionParams {
+ int? id;
+
+ QuestionParams({this.id});
+
+ QuestionParams copyWith({
+ int? id,
+ }) {
+ return QuestionParams(
+ id: id ?? this.id,
+ );
+ }
+}
diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart
index f6b6730..55f4ca7 100644
--- a/lib/core/routers/my_routes.dart
+++ b/lib/core/routers/my_routes.dart
@@ -3,6 +3,8 @@ import 'package:go_router/go_router.dart';
import 'package:hadi_hoda_flutter/core/utils/context_provider.dart';
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_bloc.dart';
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/intro_page.dart';
+import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_bloc.dart';
+import 'package:hadi_hoda_flutter/features/question/presentation/ui/question_page.dart';
import 'package:hadi_hoda_flutter/init_bindings.dart';
class Routes {
@@ -11,6 +13,7 @@ class Routes {
factory Routes() => _i;
static const String introPage = '/intro_page';
+ static const String questionPage = '/question_page';
}
GoRouter get appPages => GoRouter(
@@ -25,5 +28,13 @@ GoRouter get appPages => GoRouter(
child: const IntroPage(),
),
),
+ GoRoute(
+ name: Routes.questionPage,
+ path: Routes.questionPage,
+ builder: (context, state) => BlocProvider(
+ create: (context) => QuestionBloc(locator()),
+ child: const QuestionPage(),
+ ),
+ ),
],
);
diff --git a/lib/core/widgets/answer_box/answer_box.dart b/lib/core/widgets/answer_box/answer_box.dart
index 05e4268..b22198e 100644
--- a/lib/core/widgets/answer_box/answer_box.dart
+++ b/lib/core/widgets/answer_box/answer_box.dart
@@ -22,7 +22,6 @@ class _AnswerBoxState extends State {
});
},
child: SizedBox(
- width: 170,
child: Stack(
alignment: Alignment.bottomCenter,
clipBehavior: Clip.none,
@@ -34,10 +33,7 @@ class _AnswerBoxState extends State {
left: 0,
right: 0,
bottom: -36,
- child: SizedBox(
- height: 60,
- child: AnswerTextBox(),
- ),
+ child: AnswerTextBox(),
),
],
),
diff --git a/lib/core/widgets/answer_box/styles/picture_box.dart b/lib/core/widgets/answer_box/styles/picture_box.dart
index 7263d0f..1b9ab51 100644
--- a/lib/core/widgets/answer_box/styles/picture_box.dart
+++ b/lib/core/widgets/answer_box/styles/picture_box.dart
@@ -1,5 +1,8 @@
import 'package:flutter/material.dart';
+import 'package:google_fonts/google_fonts.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart';
+import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart';
+import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart';
import 'package:hadi_hoda_flutter/core/utils/my_image.dart';
class AnswerPictureBox extends StatelessWidget {
@@ -14,8 +17,53 @@ class AnswerPictureBox extends StatelessWidget {
foregroundPainter: _SvgCustomPainter(selected),
child: ClipPath(
clipper: _SvgCustomClipper(),
- child: MyImage(
- image: MyAssets.backgroundIntro, fit: BoxFit.cover, size: 170),
+ child: Stack(
+ children: [
+ MyImage(
+ image: MyAssets.backgroundIntro,
+ fit: BoxFit.cover,
+ size: 170,
+ ),
+ 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),
+ ],
+ ),
+ ),
+ child: Text(
+ '1',
+ style: GoogleFonts.marhey(
+ fontSize: 17,
+ fontWeight: FontWeight.w600,
+ color: context.primaryColor,
+ ),
+ ),
+ ),
+ ),
+ ),
+ PositionedDirectional(
+ top: MySpaces.s14,
+ end: MySpaces.s12,
+ child: MyImage(
+ image: MyAssets.correct,
+ size: MySpaces.s40,
+ ),
+ ),
+ ],
+ ),
),
);
}
@@ -124,4 +172,38 @@ class _SvgCustomPainter extends CustomPainter {
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
+}
+
+class _CountClipper 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;
+
+ 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;
+ }
+
+ @override
+ bool shouldReclip(covariant CustomClipper oldClipper) => false;
}
\ 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 ed40b1d..c636cfa 100644
--- a/lib/core/widgets/answer_box/styles/text_box.dart
+++ b/lib/core/widgets/answer_box/styles/text_box.dart
@@ -1,39 +1,43 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
+import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart';
class AnswerTextBox extends StatelessWidget {
const AnswerTextBox({super.key});
@override
Widget build(BuildContext context) {
- return AspectRatio(
- aspectRatio: 480 / 149.0,
- child: Stack(
- alignment: Alignment.center,
- children: [
- Positioned.fill(
- child: CustomPaint(
- painter: _WavyBannerPainter(),
- ),
+ return ClipPath(
+ clipper: _WavyBannerClipper(),
+ child: Container(
+ padding: EdgeInsets.all(MySpaces.s10),
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.topCenter,
+ end: Alignment.bottomCenter,
+ colors: [
+ Color(0XFFFFFFFF),
+ Color(0XFFCADCFF),
+ ],
),
- Text(
- 'We walk in the yard with a glass of juice',
- textAlign: TextAlign.center,
- style: GoogleFonts.marhey(
- fontSize: 12,
- fontWeight: FontWeight.w600,
- color: Color(0XFF322386)
- ),
- )
- ],
+ ),
+ child: Text(
+ 'We walk in the yard with a glass of juice ',
+ textAlign: TextAlign.center,
+ style: GoogleFonts.marhey(
+ fontSize: 14,
+ fontWeight: FontWeight.w700,
+ color: Color(0XFF322386)
+ ),
+ ),
),
);
}
}
-class _WavyBannerPainter extends CustomPainter {
+class _WavyBannerClipper extends CustomClipper {
@override
- void paint(Canvas canvas, Size size) {
+ Path getClip(Size size) {
final sx = size.width / 480.0;
final sy = size.height / 149.0;
@@ -44,19 +48,9 @@ class _WavyBannerPainter extends CustomPainter {
..cubicTo(488.753 * sx, 118.634 * sy, 483.484 * sx, 26.7097 * sy, 459.365 * sx, 10.3813 * sy)
..cubicTo(435.246 * sx, -5.94701 * sy, 41.0302 * sx, -3.23423 * sy, 14.0623 * sx, 20.0845 * sy)
..close();
-
- final paint = Paint()
- ..style = PaintingStyle.fill
- ..isAntiAlias = true
- ..shader = const LinearGradient(
- begin: Alignment.bottomCenter,
- end: Alignment.topCenter,
- colors: [Color(0xFFCADCFF), Colors.white],
- ).createShader(Offset.zero & size);
-
- canvas.drawPath(path, paint);
+ return path;
}
@override
- bool shouldRepaint(covariant _WavyBannerPainter oldDelegate) => false;
-}
+ bool shouldReclip(covariant CustomClipper oldClipper) => false;
+}
\ No newline at end of file
diff --git a/lib/core/widgets/showcase/question_showcase.dart b/lib/core/widgets/showcase/question_showcase.dart
new file mode 100644
index 0000000..f6401c0
--- /dev/null
+++ b/lib/core/widgets/showcase/question_showcase.dart
@@ -0,0 +1,50 @@
+import 'package:flutter/material.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart';
+import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart';
+import 'package:hadi_hoda_flutter/core/utils/my_image.dart';
+import 'package:hadi_hoda_flutter/core/utils/screen_size.dart';
+import 'package:showcaseview/showcaseview.dart';
+
+class QuestionShowcase extends StatelessWidget {
+ const QuestionShowcase({
+ super.key,
+ required this.globalKey,
+ required this.child,
+ this.description,
+ });
+
+ final GlobalKey globalKey;
+ final String? description;
+ final Widget child;
+
+ @override
+ Widget build(BuildContext context) {
+ return Showcase(
+ key: globalKey,
+ blurValue: 10,
+ targetShapeBorder: CircleBorder(),
+ tooltipBackgroundColor: Colors.transparent,
+ disableMovingAnimation: true,
+ textColor: context.primaryColor,
+ descriptionTextAlign: TextAlign.center,
+ descTextStyle: GoogleFonts.marhey(
+ fontSize: 12,
+ fontWeight: FontWeight.w700,
+ color: context.primaryColor,
+ ),
+ disableScaleAnimation: true,
+ tooltipPadding: EdgeInsets.only(top: 60),
+ floatingActionWidget: FloatingActionWidget(
+ height: 60,
+ width: 60,
+ right: context.widthScreen * 0.17,
+ top: context.widthScreen * 1.17,
+ child: MyImage(image: MyAssets.handPoint),
+ ),
+ overlayColor: Color(0XFF0F0041),
+ description: description ?? '',
+ child: child,
+ );
+ }
+}
diff --git a/lib/features/intro/presentation/ui/intro_page.dart b/lib/features/intro/presentation/ui/intro_page.dart
index 4ef6fd6..bc2c0d5 100644
--- a/lib/features/intro/presentation/ui/intro_page.dart
+++ b/lib/features/intro/presentation/ui/intro_page.dart
@@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart';
import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart';
+import 'package:hadi_hoda_flutter/core/routers/my_routes.dart';
import 'package:hadi_hoda_flutter/core/utils/check_platform.dart';
import 'package:hadi_hoda_flutter/core/utils/my_image.dart';
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart';
-import 'package:hadi_hoda_flutter/core/widgets/about_us_dialog/about_us_dialog.dart';
class IntroPage extends StatelessWidget {
const IntroPage({super.key});
@@ -79,7 +80,7 @@ class IntroPage extends StatelessWidget {
size: checkSize(context: context, mobile: 90, tablet: 160),
),
onTap: () {
- showAboutUsDialog(context: context);
+ context.goNamed(Routes.questionPage);
},
),
MyImage(
diff --git a/lib/features/question/data/datasource/question_datasource.dart b/lib/features/question/data/datasource/question_datasource.dart
new file mode 100644
index 0000000..2142b93
--- /dev/null
+++ b/lib/features/question/data/datasource/question_datasource.dart
@@ -0,0 +1,28 @@
+import 'package:hadi_hoda_flutter/core/constants/my_api.dart';
+import 'package:hadi_hoda_flutter/core/network/http_request.dart';
+import 'package:hadi_hoda_flutter/core/params/question_params.dart';
+import 'package:hadi_hoda_flutter/core/response/base_response.dart';
+import 'package:hadi_hoda_flutter/features/question/data/model/question_model.dart';
+import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart';
+
+abstract class IQuestionDatasource {
+ Future getData({required QuestionParams params});
+}
+
+class QuestionDatasourceImpl implements IQuestionDatasource {
+ final IHttpRequest httpRequest;
+
+ const QuestionDatasourceImpl(this.httpRequest);
+
+ @override
+ Future getData({required QuestionParams params}) async {
+ final response = await httpRequest.get(
+ path: MyApi.baseUrl,
+ );
+
+ return BaseResponse.getData(
+ response?['data'],
+ (json) => QuestionModel.fromJson(json),
+ );
+ }
+}
diff --git a/lib/features/question/data/model/question_model.dart b/lib/features/question/data/model/question_model.dart
new file mode 100644
index 0000000..489b66c
--- /dev/null
+++ b/lib/features/question/data/model/question_model.dart
@@ -0,0 +1,13 @@
+import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart';
+
+class QuestionModel extends QuestionEntity {
+ const QuestionModel({
+ super.id,
+ });
+
+ factory QuestionModel.fromJson(Map json) {
+ return QuestionModel(
+ id: json['id'],
+ );
+ }
+}
diff --git a/lib/features/question/data/repository_impl/question_repository_impl.dart b/lib/features/question/data/repository_impl/question_repository_impl.dart
new file mode 100644
index 0000000..af5a1c6
--- /dev/null
+++ b/lib/features/question/data/repository_impl/question_repository_impl.dart
@@ -0,0 +1,29 @@
+import 'package:hadi_hoda_flutter/core/params/question_params.dart';
+import 'package:flutter/foundation.dart';
+import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart';
+import 'package:hadi_hoda_flutter/core/utils/data_state.dart';
+import 'package:hadi_hoda_flutter/features/question/data/datasource/question_datasource.dart';
+import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart';
+import 'package:hadi_hoda_flutter/features/question/domain/repository/question_repository.dart';
+
+class QuestionRepositoryImpl implements IQuestionRepository {
+ final IQuestionDatasource datasource;
+
+ const QuestionRepositoryImpl(this.datasource);
+
+ @override
+ Future> getData({required QuestionParams params}) async {
+ try {
+ final QuestionEntity response = await datasource.getData(params: params);
+ return DataState.success(response);
+ } on MyException catch (e) {
+ return DataState.error(e);
+ } catch (e) {
+ if (kDebugMode) {
+ rethrow;
+ } else {
+ return DataState.error(MyException(errorMessage: '$e'));
+ }
+ }
+ }
+}
diff --git a/lib/features/question/domain/entity/question_entity.dart b/lib/features/question/domain/entity/question_entity.dart
new file mode 100644
index 0000000..377f2b1
--- /dev/null
+++ b/lib/features/question/domain/entity/question_entity.dart
@@ -0,0 +1,14 @@
+import 'package:equatable/equatable.dart';
+
+class QuestionEntity extends Equatable {
+ final int? id;
+
+ const QuestionEntity({
+ this.id,
+ });
+
+ @override
+ List