From fe2ba3874313d997969882b1d0537eaea5d4c169 Mon Sep 17 00:00:00 2001 From: AmirrezaChegini Date: Mon, 29 Sep 2025 23:00:55 +0330 Subject: [PATCH] add: refactor path and mission code --- assets/fonts/dinokids.ttf | Bin 0 -> 46436 bytes lib/common_ui/resources/my_text_style.dart | 17 +- lib/core/routers/my_routes.dart | 13 +- .../home/domain/entity/mission_location.dart | 15 + .../home/presentation/bloc/home_bloc.dart | 26 + .../home/presentation/ui/home_page.dart | 633 ++---------------- .../presentation/ui/widgets/bottom_path.dart | 87 +++ .../ui/widgets/mission_widget.dart | 38 ++ .../presentation/ui/widgets/top_path.dart | 99 +++ pubspec.yaml | 7 + 10 files changed, 356 insertions(+), 579 deletions(-) create mode 100644 assets/fonts/dinokids.ttf create mode 100644 lib/features/home/domain/entity/mission_location.dart create mode 100644 lib/features/home/presentation/ui/widgets/bottom_path.dart create mode 100644 lib/features/home/presentation/ui/widgets/mission_widget.dart create mode 100644 lib/features/home/presentation/ui/widgets/top_path.dart diff --git a/assets/fonts/dinokids.ttf b/assets/fonts/dinokids.ttf new file mode 100644 index 0000000000000000000000000000000000000000..968f36d4a4a6ac0f646599f07e682f2461e7726d GIT binary patch literal 46436 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 _i; - static const String fontFamily = ''; + static const String fontFamily = 'dinokids'; - static const TextStyle lightXS = TextStyle( - fontFamily: fontFamily, - fontSize: 10, - fontWeight: FontWeight.w400, + static const TextStyle normal = TextStyle( + fontFamily: fontFamily, + fontSize: 28, + fontWeight: FontWeight.w400, + shadows: [ + Shadow( + color: Color(0XFF5B5B5B), + blurRadius: 2.86, + offset: Offset(0, 2), + ), + ] ); } diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index 55f4ca7..5a91e0a 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -1,6 +1,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; +import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_bloc.dart'; +import 'package:hadi_hoda_flutter/features/home/presentation/ui/home_page.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'; @@ -14,10 +16,11 @@ class Routes { static const String introPage = '/intro_page'; static const String questionPage = '/question_page'; + static const String homePage = '/home_page'; } GoRouter get appPages => GoRouter( - initialLocation: Routes.introPage, + initialLocation: Routes.homePage, navigatorKey: ContextProvider.navigatorKey, routes: [ GoRoute( @@ -28,6 +31,14 @@ GoRouter get appPages => GoRouter( child: const IntroPage(), ), ), + GoRoute( + name: Routes.homePage, + path: Routes.homePage, + builder: (context, state) => BlocProvider( + create: (context) => HomeBloc(locator()), + child: const HomePage(), + ), + ), GoRoute( name: Routes.questionPage, path: Routes.questionPage, diff --git a/lib/features/home/domain/entity/mission_location.dart b/lib/features/home/domain/entity/mission_location.dart new file mode 100644 index 0000000..330e984 --- /dev/null +++ b/lib/features/home/domain/entity/mission_location.dart @@ -0,0 +1,15 @@ +class MissionLocation { + final int? index; + final double? top; + final double? bottom; + final double? right; + final double? left; + + const MissionLocation({ + this.index, + this.top, + this.bottom, + this.right, + this.left, + }); +} diff --git a/lib/features/home/presentation/bloc/home_bloc.dart b/lib/features/home/presentation/bloc/home_bloc.dart index ae5f8ec..c52801b 100644 --- a/lib/features/home/presentation/bloc/home_bloc.dart +++ b/lib/features/home/presentation/bloc/home_bloc.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:hadi_hoda_flutter/core/status/base_status.dart'; import 'package:hadi_hoda_flutter/features/home/domain/entity/home_entity.dart'; +import 'package:hadi_hoda_flutter/features/home/domain/entity/mission_location.dart'; import 'package:hadi_hoda_flutter/features/home/domain/usecases/get_home_usecase.dart'; import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_event.dart'; import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_state.dart'; @@ -18,6 +19,31 @@ class HomeBloc extends Bloc { final GetHomeUseCase _getHomeUseCase; /// ------------Variables------------ + final List bottomLocationList = [ + MissionLocation(bottom: -30, left: 30, index: 1), + MissionLocation(bottom: 50, left: 100, index: 2), + MissionLocation(bottom: 150, left: 50, index: 3), + MissionLocation(bottom: 250, left: 130, index: 4), + MissionLocation(bottom: 300, right: 50, index: 5), + MissionLocation(top: 170, right: 40, index: 6), + MissionLocation(top: 70, right: 70, index: 7), + MissionLocation(top: -20, right: 60, index: 8), + ]; + + final List topLocationList = [ + MissionLocation(bottom: 30, right: 80, index: 9), + MissionLocation(bottom: 70, left: 20, index: 10), + MissionLocation(bottom: 150, left: 50, index: 11), + MissionLocation(bottom: 180, left: 140, index: 12), + MissionLocation(bottom: 260, right: 20, index: 13), + MissionLocation(bottom: 370, right: 30, index: 14), + MissionLocation(bottom: 420, left: 40, index: 15), + MissionLocation(top: 410, left: 0, index: 16), + MissionLocation(top: 320, left: 60, index: 17), + MissionLocation(top: 220, left: 80, index: 18), + MissionLocation(top: 130, left: 20, index: 19), + MissionLocation(top: 50, left: 70, index: 20), + ]; /// ------------Controllers------------ diff --git a/lib/features/home/presentation/ui/home_page.dart b/lib/features/home/presentation/ui/home_page.dart index 82f7ef8..9b068c4 100644 --- a/lib/features/home/presentation/ui/home_page.dart +++ b/lib/features/home/presentation/ui/home_page.dart @@ -1,601 +1,88 @@ import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; import 'package:hadi_hoda_flutter/core/utils/my_image.dart'; import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; -import 'package:path_drawing/path_drawing.dart'; +import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_bloc.dart'; +import 'package:hadi_hoda_flutter/features/home/presentation/ui/widgets/bottom_path.dart'; +import 'package:hadi_hoda_flutter/features/home/presentation/ui/widgets/mission_widget.dart'; +import 'package:hadi_hoda_flutter/features/home/presentation/ui/widgets/top_path.dart'; -class HomePage extends StatefulWidget { +class HomePage extends StatelessWidget { const HomePage({super.key}); - @override - State createState() => _HomePageState(); -} - -class _HomePageState extends State { - final ScrollController scrollController = ScrollController(); - @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( - controller: scrollController, child: Stack( alignment: Alignment.center, children: [ - MyImage(image: MyAssets.mapBackground, fit: BoxFit.cover), - Positioned( - top: context.heightScreen * 0.16, - left: context.widthScreen * 0.15, - child: Stack( - children: [ - CurvyDashedPathPD( - height: 950, - width: context.widthScreen * 0.6, - ), - Positioned( - bottom: 30, - right: 80, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '9', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 70, - left: 20, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '10', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 150, - left: 50, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '11', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 180, - left: 140, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '12', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 260, - right: 20, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '13', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 370, - right: 30, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '14', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 420, - left: 40, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '15', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: 410, - left: 0, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '16', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: 320, - left: 60, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '17', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: 220, - left: 80, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '18', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: 130, - left: 20, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '19', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: 50, - left: 70, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '20', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - ], - ), - ), - Positioned( - bottom: context.heightScreen * 0.12, - left: context.widthScreen * 0.2, - child: Stack( - clipBehavior: Clip.none, - children: [ - DottedRoute( - width: context.widthScreen * 0.75, - height: context.heightScreen * 0.65, - ), - Positioned( - bottom: -30, - left: 30, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '1', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 50, - left: 100, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '2', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 150, - left: 50, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '3', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 250, - left: 130, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '4', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - bottom: 300, - right: 50, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '5', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: 170, - right: 40, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '6', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: 70, - right: 70, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '7', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - Positioned( - top: -20, - right: 60, - child: Stack( - alignment: Alignment.center, - children: [ - MyImage(image: MyAssets.mission, size: 43), - Text( - '8', - style: GoogleFonts.marhey( - fontSize: 28, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - ), - ], - ), - ), - ], - ), - ), + _background(), + _topPath(context), + _bottomPath(context), ], ), ), ); } -} -class DottedRoute extends StatelessWidget { - const DottedRoute({ - super.key, - this.width = 500, - this.height = 1523, - this.color = Colors.white, - }); - - final double width; - final double height; - final Color color; - - @override - Widget build(BuildContext context) { - return CustomPaint( - painter: _DottedRoutePainter(color), - size: Size( - width, - height, - ), // or Size.infinite inside a parent with constraints - ); + MyImage _background() { + return MyImage(image: MyAssets.mapBackground, fit: BoxFit.cover); } -} - -class _DottedRoutePainter extends CustomPainter { - _DottedRoutePainter(this.color); - - final Color color; - - // SVG viewBox - static const double _vbW = 500; - static const double _vbH = 1523; - // Your SVG path data (unchanged) - static const String _svgPath = - 'M1.95892 1520.75C1.95892 1520.75 199.206 1423.63 169.156 1328.9C143.058 1246.63 30.8103 1281.9 15.4421 1225.27C-11.9488 1124.33 48.5736 1164.01 42.795 1033.8C38.5466 938.07 154.913 925.725 219.623 855.048C286.233 782.296 385.022 821.209 446.532 744.097C516.262 656.681 493.917 461.712 493.917 461.712C493.917 461.712 440.122 333.473 428.04 246.36C414.846 151.222 436.901 0.572754 436.901 0.572754'; - - @override - void paint(Canvas canvas, Size size) { - // Scale SVG viewBox -> current canvas while preserving aspect - final scale = _scaleToFit( - srcW: _vbW, - srcH: _vbH, - dstW: size.width, - dstH: size.height, - ); - canvas.translate( - (size.width - _vbW * scale) / 2, - (size.height - _vbH * scale) / 2, - ); - canvas.scale(scale); - - // Parse and dash the path - final path = parseSvgPathData(_svgPath); - final dashed = dashPath( - path, - dashArray: CircularIntervalList(const [3.08, 13.1]), - ); - - // Stroke paint - final paint = Paint() - ..style = PaintingStyle.stroke - ..strokeWidth = 4.62295 - ..color = color - ..strokeCap = StrokeCap.butt - ..strokeJoin = StrokeJoin.miter; - - canvas.drawPath(dashed, paint); - } - - double _scaleToFit({ - required double srcW, - required double srcH, - required double dstW, - required double dstH, - }) { - final sx = dstW / srcW; - final sy = dstH / srcH; - return sx < sy ? sx : sy; // contain - } - - @override - bool shouldRepaint(covariant _DottedRoutePainter oldDelegate) => - oldDelegate.color != color; -} - -class CurvyDashedPathPD extends StatelessWidget { - const CurvyDashedPathPD({ - super.key, - this.width = 604, - this.height = 2651, - this.color = Colors.white, - }); - - final double width; - final double height; - final Color color; - - @override - Widget build(BuildContext context) { - return CustomPaint( - size: Size(width, height), - painter: _CurvyDashedPathPDPainter(color: color), - isComplex: true, - willChange: false, + Positioned _topPath(BuildContext context) { + return Positioned( + top: context.heightScreen * 0.16, + left: context.widthScreen * 0.15, + child: Stack( + children: [ + TopPath( + height: 950, + width: context.widthScreen * 0.6, + ), + ...List.generate( + context.read().topLocationList.length, + (index) => Positioned( + top: context.read().topLocationList[index].top, + bottom: context.read().topLocationList[index].bottom, + right: context.read().topLocationList[index].right, + left: context.read().topLocationList[index].left, + child: MissionWidget( + index: context.read().topLocationList[index].index ?? 0, + ), + ), + ), + ], + ), ); } -} - -class _CurvyDashedPathPDPainter extends CustomPainter { - _CurvyDashedPathPDPainter({required this.color}); - - final Color color; - // SVG viewBox - static const double _vbW = 604.0; - static const double _vbH = 2651.0; - - // SVG stroke styling - static const double _strokeWidth = 4.62295; - static const List _dashPattern = [3.08, 13.1]; - - // The original SVG "d" attribute: - static const String _d = ''' -M323.844 1.5163 -C323.844 1.5163 254.064 132.635 209.041 216.483 -C167.229 294.353 105.588 327.363 101.557 415.655 -C96.6703 522.7 235.238 655.278 235.238 655.278 -C235.238 655.278 284.393 748.372 277.229 810.918 -C270.331 871.151 205.959 948.836 205.959 948.836 -C205.959 948.836 31.3055 963.687 11.4099 1046.3 -C-1.94798 1101.77 54.9427 1185.76 54.9427 1185.76 -C54.9427 1185.76 -32.6228 1326.5 19.8853 1386.09 -C63.1414 1435.18 185.541 1411.13 185.541 1411.13 -C185.541 1411.13 427.654 1354.52 472.164 1458.9 -C492.877 1507.48 472.164 1594.12 472.164 1594.12 -C472.164 1594.12 454.029 1680.13 464.844 1733.58 -C476.306 1790.23 531.492 1865.72 531.492 1865.72 -C531.492 1865.72 515.799 1970.22 472.164 2015.58 -C437.994 2051.1 361.598 2076.45 361.598 2076.45 -C361.598 2076.45 304.217 2117.23 262.59 2133.08 -C221.475 2148.74 152.41 2156.58 152.41 2156.58 -C152.41 2156.58 60.2151 2199.32 47.623 2253.66 -C34.196 2311.61 108.877 2393.12 108.877 2393.12 -C108.877 2393.12 201.293 2437.1 262.59 2460.15 -C315.761 2480.15 400.893 2505.23 400.893 2505.23 -C400.893 2505.23 509.508 2505.09 553.451 2548.76 -C584.574 2579.7 601.221 2650.47 601.221 2650.47 -'''; - - @override - void paint(Canvas canvas, Size size) { - // Scale to widget size - final sx = size.width / _vbW; - final sy = size.height / _vbH; - canvas.save(); - canvas.scale(sx, sy); - - // Parse SVG path data to a Path - final Path original = parseSvgPathData(_d); - - // Apply dash pattern - final Path dashed = dashPath( - original, - dashArray: CircularIntervalList(_dashPattern), + Positioned _bottomPath(BuildContext context) { + return Positioned( + bottom: context.heightScreen * 0.12, + left: context.widthScreen * 0.2, + child: Stack( + clipBehavior: Clip.none, + children: [ + BottomPath( + width: context.widthScreen * 0.75, + height: context.heightScreen * 0.65, + ), + ...List.generate( + context.read().bottomLocationList.length, + (index) => Positioned( + top: context.read().bottomLocationList[index].top, + bottom: context.read().bottomLocationList[index].bottom, + right: context.read().bottomLocationList[index].right, + left: context.read().bottomLocationList[index].left, + child: MissionWidget( + index: context.read().bottomLocationList[index].index ?? 0, + ), + ), + ), + ], + ), ); - - // Stroke paint - final paint = Paint() - ..style = PaintingStyle.stroke - ..strokeWidth = _strokeWidth - ..strokeCap = StrokeCap.butt - ..strokeJoin = StrokeJoin.miter - ..color = color; - - canvas.drawPath(dashed, paint); - canvas.restore(); } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) => false; } - diff --git a/lib/features/home/presentation/ui/widgets/bottom_path.dart b/lib/features/home/presentation/ui/widgets/bottom_path.dart new file mode 100644 index 0000000..cb2d5a5 --- /dev/null +++ b/lib/features/home/presentation/ui/widgets/bottom_path.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:path_drawing/path_drawing.dart'; + +class BottomPath extends StatelessWidget { + const BottomPath({ + super.key, + this.width = 500, + this.height = 1523, + this.color = Colors.white, + }); + + final double width; + final double height; + final Color color; + + @override + Widget build(BuildContext context) { + return CustomPaint( + painter: _Path(color), + size: Size( + width, + height, + ), // or Size.infinite inside a parent with constraints + ); + } +} + +class _Path extends CustomPainter { + _Path(this.color); + + final Color color; + + // SVG viewBox + static const double _vbW = 500; + static const double _vbH = 1523; + + // Your SVG path data (unchanged) + static const String _svgPath = + 'M1.95892 1520.75C1.95892 1520.75 199.206 1423.63 169.156 1328.9C143.058 1246.63 30.8103 1281.9 15.4421 1225.27C-11.9488 1124.33 48.5736 1164.01 42.795 1033.8C38.5466 938.07 154.913 925.725 219.623 855.048C286.233 782.296 385.022 821.209 446.532 744.097C516.262 656.681 493.917 461.712 493.917 461.712C493.917 461.712 440.122 333.473 428.04 246.36C414.846 151.222 436.901 0.572754 436.901 0.572754'; + + @override + void paint(Canvas canvas, Size size) { + // Scale SVG viewBox -> current canvas while preserving aspect + final scale = _scaleToFit( + srcW: _vbW, + srcH: _vbH, + dstW: size.width, + dstH: size.height, + ); + canvas.translate( + (size.width - _vbW * scale) / 2, + (size.height - _vbH * scale) / 2, + ); + canvas.scale(scale); + + // Parse and dash the path + final path = parseSvgPathData(_svgPath); + final dashed = dashPath( + path, + dashArray: CircularIntervalList(const [3.08, 13.1]), + ); + + // Stroke paint + final paint = Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 4.62295 + ..color = color + ..strokeCap = StrokeCap.butt + ..strokeJoin = StrokeJoin.miter; + + canvas.drawPath(dashed, paint); + } + + double _scaleToFit({ + required double srcW, + required double srcH, + required double dstW, + required double dstH, + }) { + final sx = dstW / srcW; + final sy = dstH / srcH; + return sx < sy ? sx : sy; // contain + } + + @override + bool shouldRepaint(covariant _Path oldDelegate) => oldDelegate.color != color; +} diff --git a/lib/features/home/presentation/ui/widgets/mission_widget.dart b/lib/features/home/presentation/ui/widgets/mission_widget.dart new file mode 100644 index 0000000..f25a665 --- /dev/null +++ b/lib/features/home/presentation/ui/widgets/mission_widget.dart @@ -0,0 +1,38 @@ +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_text_style.dart'; +import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart'; +import 'package:hadi_hoda_flutter/core/utils/my_image.dart'; + +enum MissionType { + unFinished, + finished, + current; + + static Map get image => { + MissionType.unFinished: MyAssets.mission, + MissionType.finished: MyAssets.finishedMission, + MissionType.current: MyAssets.currentMission, + }; +} + +class MissionWidget extends StatelessWidget { + const MissionWidget({super.key, required this.index, this.type}); + + final int index; + final MissionType? type; + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.topCenter, + children: [ + MyImage(image: MissionType.image[type] ?? MyAssets.mission, size: 48), + Text( + '$index', + style: MyTextStyle.normal.copyWith(color: context.primaryColor), + ), + ], + ); + } +} diff --git a/lib/features/home/presentation/ui/widgets/top_path.dart b/lib/features/home/presentation/ui/widgets/top_path.dart new file mode 100644 index 0000000..c6a24bc --- /dev/null +++ b/lib/features/home/presentation/ui/widgets/top_path.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:path_drawing/path_drawing.dart'; + +class TopPath extends StatelessWidget { + const TopPath({ + super.key, + this.width = 604, + this.height = 2651, + this.color = Colors.white, + }); + + final double width; + final double height; + final Color color; + + @override + Widget build(BuildContext context) { + return CustomPaint( + size: Size(width, height), + painter: _Path(color: color), + isComplex: true, + willChange: false, + ); + } +} + +class _Path extends CustomPainter { + _Path({required this.color}); + + final Color color; + + // SVG viewBox + static const double _vbW = 604.0; + static const double _vbH = 2651.0; + + // SVG stroke styling + static const double _strokeWidth = 4.62295; + static const List _dashPattern = [3.08, 13.1]; + + // The original SVG "d" attribute: + static const String _d = ''' +M323.844 1.5163 +C323.844 1.5163 254.064 132.635 209.041 216.483 +C167.229 294.353 105.588 327.363 101.557 415.655 +C96.6703 522.7 235.238 655.278 235.238 655.278 +C235.238 655.278 284.393 748.372 277.229 810.918 +C270.331 871.151 205.959 948.836 205.959 948.836 +C205.959 948.836 31.3055 963.687 11.4099 1046.3 +C-1.94798 1101.77 54.9427 1185.76 54.9427 1185.76 +C54.9427 1185.76 -32.6228 1326.5 19.8853 1386.09 +C63.1414 1435.18 185.541 1411.13 185.541 1411.13 +C185.541 1411.13 427.654 1354.52 472.164 1458.9 +C492.877 1507.48 472.164 1594.12 472.164 1594.12 +C472.164 1594.12 454.029 1680.13 464.844 1733.58 +C476.306 1790.23 531.492 1865.72 531.492 1865.72 +C531.492 1865.72 515.799 1970.22 472.164 2015.58 +C437.994 2051.1 361.598 2076.45 361.598 2076.45 +C361.598 2076.45 304.217 2117.23 262.59 2133.08 +C221.475 2148.74 152.41 2156.58 152.41 2156.58 +C152.41 2156.58 60.2151 2199.32 47.623 2253.66 +C34.196 2311.61 108.877 2393.12 108.877 2393.12 +C108.877 2393.12 201.293 2437.1 262.59 2460.15 +C315.761 2480.15 400.893 2505.23 400.893 2505.23 +C400.893 2505.23 509.508 2505.09 553.451 2548.76 +C584.574 2579.7 601.221 2650.47 601.221 2650.47 +'''; + + @override + void paint(Canvas canvas, Size size) { + // Scale to widgets size + final sx = size.width / _vbW; + final sy = size.height / _vbH; + canvas.save(); + canvas.scale(sx, sy); + + // Parse SVG path data to a Path + final Path original = parseSvgPathData(_d); + + // Apply dash pattern + final Path dashed = dashPath( + original, + dashArray: CircularIntervalList(_dashPattern), + ); + + // Stroke paint + final paint = Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = _strokeWidth + ..strokeCap = StrokeCap.butt + ..strokeJoin = StrokeJoin.miter + ..color = color; + + canvas.drawPath(dashed, paint); + canvas.restore(); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} diff --git a/pubspec.yaml b/pubspec.yaml index 4cd4cfc..aaef526 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,3 +37,10 @@ flutter: assets: - assets/images/ + - assets/fonts/ + + + fonts: + - family: dinokids + fonts: + - asset: assets/fonts/dinokids.ttf \ No newline at end of file