Browse Source

add: question page ui

pull/7/head
AmirrezaChegini 1 week ago
parent
commit
827e8358e7
  1. BIN
      assets/images/diamond.png
  2. 4
      assets/images/done.svg
  3. 2
      lib/common_ui/resources/my_assets.dart
  4. 152
      lib/features/question/presentation/ui/question_page.dart
  5. 41
      lib/features/question/presentation/ui/widgets/glassy_button.dart
  6. 27
      lib/features/question/presentation/ui/widgets/left_blob.dart
  7. 102
      lib/features/question/presentation/ui/widgets/question_stepper.dart
  8. 32
      lib/features/question/presentation/ui/widgets/refresh_button.dart
  9. 27
      lib/features/question/presentation/ui/widgets/right_blob.dart
  10. 34
      pubspec.lock
  11. 1
      pubspec.yaml

BIN
assets/images/diamond.png

After

Width: 46  |  Height: 38  |  Size: 2.6 KiB

4
assets/images/done.svg

@ -0,0 +1,4 @@
<svg width="13" height="11" viewBox="0 0 13 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.558 0.348633L12.7359 1.73042C12.7359 1.73042 10.3562 7.14247 5.62103 10.07L4.30176 8.70894C6.51804 5.29707 8.49556 3.42465 11.558 0.348633Z" fill="white"/>
<path d="M0.594727 5.23829L2.01443 3.89746C2.01443 3.89746 4.17176 5.14167 6.90451 9.1387L5.59316 10.1301C2.25105 7.7622 2.64541 7.99882 0.594727 5.23829Z" fill="white"/>
</svg>

2
lib/common_ui/resources/my_assets.dart

@ -23,4 +23,6 @@ class MyAssets {
static const String persons = 'assets/images/persons.png'; static const String persons = 'assets/images/persons.png';
static const String bubbleChatLeft = 'assets/images/bubble_chat_left.svg'; static const String bubbleChatLeft = 'assets/images/bubble_chat_left.svg';
static const String bubbleChatRight = 'assets/images/bubble_chat_right.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';
} }

152
lib/features/question/presentation/ui/question_page.dart

@ -1,9 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.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_assets.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_image.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/utils/screen_size.dart';
import 'package:hadi_hoda_flutter/core/widgets/answer_box/answer_box.dart'; import 'package:hadi_hoda_flutter/core/widgets/answer_box/answer_box.dart';
import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/glassy_button.dart';
import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/left_blob.dart';
import 'package:hadi_hoda_flutter/features/question/presentation/ui/widgets/question_stepper.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';
class QuestionPage extends StatelessWidget { class QuestionPage extends StatelessWidget {
const QuestionPage({super.key}); const QuestionPage({super.key});
@ -31,32 +38,32 @@ class QuestionPage extends StatelessWidget {
), ),
), ),
child: SafeArea( child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: MySpaces.s16),
child: Column( child: Column(
children: [ children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 48,
height: 48,
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.white.withValues(alpha: 0.3),
Color(0XFF6930DA).withValues(alpha: 0.1),
MySpaces.s4.gapHeight,
_topButtons(),
MySpaces.s10.gapHeight,
QuestionStepper(),
_titles(),
MySpaces.s14.gapHeight,
_questions(),
_bottomDetail(context),
], ],
), ),
border: Border.all(
color: Colors.white.withValues(alpha: 0.3),
), ),
), ),
child: MyImage(image: MyAssets.home),
), ),
);
}
Widget _topButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GlassyButton(image: MyAssets.home, onTap: () {}),
Text( Text(
'Toothbrushing etiquette', 'Toothbrushing etiquette',
style: GoogleFonts.marhey( style: GoogleFonts.marhey(
@ -65,29 +72,14 @@ class QuestionPage extends StatelessWidget {
color: Colors.white, color: Colors.white,
), ),
), ),
Container(
width: 48,
height: 48,
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.white.withValues(alpha: 0.3),
Color(0XFF6930DA).withValues(alpha: 0.1),
],
),
border: Border.all(
color: Colors.white.withValues(alpha: 0.3),
),
),
child: MyImage(image: MyAssets.music),
),
GlassyButton(image: MyAssets.music, onTap: () {}),
], ],
),
Column(
);
}
Column _titles() {
return Column(
spacing: MySpaces.s4,
children: [ children: [
Text( Text(
'Question 1 / 5', 'Question 1 / 5',
@ -106,6 +98,7 @@ class QuestionPage extends StatelessWidget {
), ),
Text( Text(
'Heda wants her teeth to be clean. Which of her actions do you think is correct?', 'Heda wants her teeth to be clean. Which of her actions do you think is correct?',
textAlign: TextAlign.center,
style: GoogleFonts.marhey( style: GoogleFonts.marhey(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -120,19 +113,25 @@ class QuestionPage extends StatelessWidget {
), ),
), ),
], ],
),
Expanded(
);
}
Expanded _questions() {
return Expanded(
child: GridView.builder( child: GridView.builder(
itemCount: 4, itemCount: 4,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisCount: 2,
crossAxisSpacing: 20,
mainAxisSpacing: 30,
crossAxisSpacing: MySpaces.s20,
mainAxisSpacing: 50,
), ),
itemBuilder: (context, index) => AnswerBox(), itemBuilder: (context, index) => AnswerBox(),
), ),
),
SizedBox(
);
}
Widget _bottomDetail(BuildContext context) {
return SizedBox(
width: context.widthScreen, width: context.widthScreen,
child: Stack( child: Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
@ -142,75 +141,28 @@ class QuestionPage extends StatelessWidget {
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
start: 0, start: 0,
top: -10, top: -10,
child: Stack(
alignment: Alignment.center,
children: [
MyImage(image: MyAssets.bubbleChatLeft),
Text(
'Your answer\nwas not correct.',
textAlign: TextAlign.center,
style: GoogleFonts.marhey(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0XFFB5AEEE),
),
),
],
),
child: LeftBlob(),
), ),
Padding( Padding(
padding: const EdgeInsetsDirectional.only(end: 90),
padding: const EdgeInsetsDirectional.only(end: 60),
child: MyImage(image: MyAssets.persons), child: MyImage(image: MyAssets.persons),
), ),
Positioned.directional( Positioned.directional(
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
start: 220,
start: 210,
top: -20, top: -20,
child: Stack(
alignment: Alignment.center,
children: [
MyImage(image: MyAssets.bubbleChatRight),
Text(
'Be more\ncareful.',
textAlign: TextAlign.center,
style: GoogleFonts.marhey(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0XFFB5AEEE),
),
),
],
),
child: RightBlob(),
), ),
Positioned.directional( Positioned.directional(
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
end: 0, end: 0,
bottom: 10, bottom: 10,
child: Container(
height: 48,
width: 48,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0XFFA393FF), Color(0XFFC6BCFB)],
),
),
child: Icon(
Icons.refresh,
size: 40,
color: Color(0XFF263AA1),
),
),
),
],
child: RefreshButton(
onTap: () {},
), ),
), ),
], ],
), ),
),
),
); );
} }
} }

41
lib/features/question/presentation/ui/widgets/glassy_button.dart

@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart';
import 'package:hadi_hoda_flutter/core/utils/my_image.dart';
class GlassyButton extends StatelessWidget {
const GlassyButton({super.key, required this.image, this.onTap});
final String image;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: Ink(
width: 48,
height: 48,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.white.withValues(alpha: 0.3),
Color(0XFF6930DA).withValues(alpha: 0.1),
],
),
border: Border.all(color: Colors.white.withValues(alpha: 0.3)),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.all(Radius.circular(100)),
child: Padding(
padding: const EdgeInsets.all(MySpaces.s12),
child: MyImage(image: image),
),
),
),
);
}
}

27
lib/features/question/presentation/ui/widgets/left_blob.dart

@ -0,0 +1,27 @@
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/core/utils/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(
'Your answer\nwas not correct.',
textAlign: TextAlign.center,
style: GoogleFonts.marhey(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0XFFB5AEEE),
),
),
],
);
}
}

102
lib/features/question/presentation/ui/widgets/question_stepper.dart

@ -0,0 +1,102 @@
import 'package:easy_stepper/easy_stepper.dart';
import 'package:flutter/material.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart';
import 'package:hadi_hoda_flutter/core/utils/my_image.dart';
class QuestionStepper extends StatelessWidget {
const QuestionStepper({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 80,
child: EasyStepper(
activeStep: 1,
lineStyle: LineStyle(
lineLength: 20,
lineType: LineType.normal,
defaultLineColor: Color(0XFFDFDDF6),
lineThickness: 5,
finishedLineColor: Color(0XFF21B738),
),
activeStepBackgroundColor: Colors.transparent,
finishedStepBackgroundColor: Colors.transparent,
unreachedStepBackgroundColor: Colors.transparent,
internalPadding: 0,
showLoadingAnimation: false,
stepRadius: 18,
showStepBorder: false,
padding: EdgeInsets.all(0),
enableStepTapping: false,
steps: List.generate(
6,
(index) => EasyStep(
customStep: index == 5
? MyImage(image: MyAssets.diamond, size: 50)
: ClipPath(
clipper: _StepperClipper(),
child: Container(
height: 32,
width: 32,
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Color(0XFFDFDDF6),
shape: BoxShape.circle,
),
child: ClipPath(
clipper: _StepperClipper(),
child: Container(
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: index < 1
? Color(0XFF21B738)
: index == 1
? Color(0XFF847AC4)
: Colors.transparent,
),
child: index < 1 ? MyImage(image: MyAssets.done) : null,
),
),
),
),
),
),
),
);
}
}
class _StepperClipper extends CustomClipper<Path> {
@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<Path> oldClipper) => false;
}

32
lib/features/question/presentation/ui/widgets/refresh_button.dart

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart';
class RefreshButton extends StatelessWidget {
const RefreshButton({super.key, this.onTap,});
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
return Material(
color: context.noColor,
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)),
),
),
);
}
}

27
lib/features/question/presentation/ui/widgets/right_blob.dart

@ -0,0 +1,27 @@
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/core/utils/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(
'Be more\ncareful.',
textAlign: TextAlign.center,
style: GoogleFonts.marhey(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0XFFB5AEEE),
),
),
],
);
}
}

34
pubspec.lock

@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
archive:
dependency: transitive
description:
name: archive
sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
url: "https://pub.dev"
source: hosted
version: "4.0.7"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -81,6 +89,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
easy_stepper:
dependency: "direct main"
description:
name: easy_stepper
sha256: "63f66314a509ec690c8152a41288961fd96ba9e92ef184299f068a5e78bd16ad"
url: "https://pub.dev"
source: hosted
version: "0.8.5+1"
equatable: equatable:
dependency: "direct main" dependency: "direct main"
description: description:
@ -245,6 +261,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
lottie:
dependency: transitive
description:
name: lottie
sha256: "8ae0be46dbd9e19641791dc12ee480d34e1fd3f84c749adc05f3ad9342b71b95"
url: "https://pub.dev"
source: hosted
version: "3.3.2"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -373,6 +397,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
posix:
dependency: transitive
description:
name: posix
sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61"
url: "https://pub.dev"
source: hosted
version: "6.0.3"
pretty_dio_logger: pretty_dio_logger:
dependency: "direct main" dependency: "direct main"
description: description:
@ -572,4 +604,4 @@ packages:
version: "6.6.1" version: "6.6.1"
sdks: sdks:
dart: ">=3.9.2 <4.0.0" dart: ">=3.9.2 <4.0.0"
flutter: ">=3.29.0"
flutter: ">=3.35.0"

1
pubspec.yaml

@ -9,6 +9,7 @@ environment:
dependencies: dependencies:
bloc: ^9.0.0 bloc: ^9.0.0
dio: ^5.9.0 dio: ^5.9.0
easy_stepper: ^0.8.5+1
equatable: ^2.0.7 equatable: ^2.0.7
flutter: flutter:
sdk: flutter sdk: flutter

Loading…
Cancel
Save