diff --git a/assets/images/map_background.png b/assets/images/map_background.png index e033ac9..3bb3c65 100644 Binary files a/assets/images/map_background.png and b/assets/images/map_background.png differ diff --git a/assets/images/planet_1.png b/assets/images/planet_1.png new file mode 100644 index 0000000..640194f Binary files /dev/null and b/assets/images/planet_1.png differ diff --git a/assets/images/planet_10.png b/assets/images/planet_10.png new file mode 100644 index 0000000..1fa1a68 Binary files /dev/null and b/assets/images/planet_10.png differ diff --git a/assets/images/planet_2.png b/assets/images/planet_2.png new file mode 100644 index 0000000..8081d99 Binary files /dev/null and b/assets/images/planet_2.png differ diff --git a/assets/images/planet_3.png b/assets/images/planet_3.png new file mode 100644 index 0000000..6a01dd5 Binary files /dev/null and b/assets/images/planet_3.png differ diff --git a/assets/images/planet_4.png b/assets/images/planet_4.png new file mode 100644 index 0000000..b5dfb04 Binary files /dev/null and b/assets/images/planet_4.png differ diff --git a/assets/images/planet_5.png b/assets/images/planet_5.png new file mode 100644 index 0000000..6dbb435 Binary files /dev/null and b/assets/images/planet_5.png differ diff --git a/assets/images/planet_6.png b/assets/images/planet_6.png new file mode 100644 index 0000000..c6c6130 Binary files /dev/null and b/assets/images/planet_6.png differ diff --git a/assets/images/planet_7.png b/assets/images/planet_7.png new file mode 100644 index 0000000..dfca92e Binary files /dev/null and b/assets/images/planet_7.png differ diff --git a/assets/images/planet_8.png b/assets/images/planet_8.png new file mode 100644 index 0000000..ba311cd Binary files /dev/null and b/assets/images/planet_8.png differ diff --git a/assets/images/planet_9.png b/assets/images/planet_9.png new file mode 100644 index 0000000..42f2e35 Binary files /dev/null and b/assets/images/planet_9.png differ diff --git a/assets/images/planet_final.png b/assets/images/planet_final.png new file mode 100644 index 0000000..4a71f0b Binary files /dev/null and b/assets/images/planet_final.png differ diff --git a/assets/images/satellite.png b/assets/images/satellite.png new file mode 100644 index 0000000..25bd9e4 Binary files /dev/null and b/assets/images/satellite.png differ diff --git a/assets/svg/diamond_container.svg b/assets/svg/diamond_container.svg new file mode 100644 index 0000000..ef874cf --- /dev/null +++ b/assets/svg/diamond_container.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/home_button.svg b/assets/svg/home_button.svg new file mode 100644 index 0000000..5b293a6 --- /dev/null +++ b/assets/svg/home_button.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/icon_play.svg b/assets/svg/icon_play.svg new file mode 100644 index 0000000..8058889 --- /dev/null +++ b/assets/svg/icon_play.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/common_ui/resources/my_assets.dart b/lib/common_ui/resources/my_assets.dart index 3e88f68..cc9809d 100644 --- a/lib/common_ui/resources/my_assets.dart +++ b/lib/common_ui/resources/my_assets.dart @@ -14,7 +14,6 @@ class MyAssets { static const String level = 'assets/images/level.png'; static const String finishedLevel = 'assets/images/finished_level.png'; static const String currentLevel = 'assets/images/current_level.png'; - static const String homeButton = 'assets/images/home_button.png'; static const String error = 'assets/images/error.png'; static const String leaf = 'assets/images/leaf.png'; static const String happyPersons = 'assets/images/happy_persons.png'; @@ -27,6 +26,18 @@ class MyAssets { static const String intro_3 = 'assets/images/intro_3.jpg'; static const String intro_4 = 'assets/images/intro_4.jpg'; static const String intro_5 = 'assets/images/intro_5.jpg'; + static const String planet1 = 'assets/images/planet_1.png'; + static const String planet2 = 'assets/images/planet_2.png'; + static const String planet3 = 'assets/images/planet_3.png'; + static const String planet4 = 'assets/images/planet_4.png'; + static const String planet5 = 'assets/images/planet_5.png'; + static const String planet6 = 'assets/images/planet_6.png'; + static const String planet7 = 'assets/images/planet_7.png'; + static const String planet8 = 'assets/images/planet_8.png'; + static const String planet9 = 'assets/images/planet_9.png'; + 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'; /// SVG static const String closeBtn = 'assets/svg/close_btn.svg'; @@ -58,6 +69,9 @@ class MyAssets { static const String lang = 'assets/svg/lang.svg'; static const String unMusic = 'assets/svg/unmusic.svg'; static const String globe = 'assets/svg/globe.svg'; + 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 final List images = [ @@ -71,7 +85,6 @@ class MyAssets { level, finishedLevel, currentLevel, - homeButton, error, leaf, happyPersons, diff --git a/lib/common_ui/resources/my_audios.dart b/lib/common_ui/resources/my_audios.dart index e499c25..854205d 100644 --- a/lib/common_ui/resources/my_audios.dart +++ b/lib/common_ui/resources/my_audios.dart @@ -5,4 +5,5 @@ class MyAudios { 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'; } \ No newline at end of file diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index 900366f..a33b00f 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -110,6 +110,7 @@ GoRouter get appPages => GoRouter( LevelBloc( locator(), locator(instanceName: MyConstants.mainAudioService), + locator(instanceName: MyConstants.effectAudioService), )..add(SetCurrentLevelEvent()), child: const LevelPage(), ), diff --git a/lib/core/widgets/inkwell/my_inkwell.dart b/lib/core/widgets/inkwell/my_inkwell.dart index 2967c7d..9901be7 100644 --- a/lib/core/widgets/inkwell/my_inkwell.dart +++ b/lib/core/widgets/inkwell/my_inkwell.dart @@ -12,6 +12,7 @@ class MyInkwell extends StatefulWidget { this.borderRadius, this.highlightColor, this.splashColor, + this.audio, }); final VoidCallback? onTap; @@ -19,6 +20,7 @@ class MyInkwell extends StatefulWidget { final BorderRadius? borderRadius; final Color? highlightColor; final Color? splashColor; + final String? audio; @override State createState() => _MyInkwellState(); @@ -35,7 +37,7 @@ class _MyInkwellState extends State { } void playAudio() { - audioService.setAudio(assetPath: MyAudios.clickButton); + audioService.setAudio(assetPath: widget.audio ?? MyAudios.clickButton); audioService.play(); } diff --git a/lib/features/level/presentation/bloc/level_bloc.dart b/lib/features/level/presentation/bloc/level_bloc.dart index b72a7f6..ac39a9b 100644 --- a/lib/features/level/presentation/bloc/level_bloc.dart +++ b/lib/features/level/presentation/bloc/level_bloc.dart @@ -9,6 +9,7 @@ import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; import 'package:hadi_hoda_flutter/core/services/audio_service.dart'; import 'package:hadi_hoda_flutter/core/status/base_status.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; +import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_location.dart'; import 'package:hadi_hoda_flutter/features/level/domain/usecases/get_levels_usecase.dart'; @@ -20,9 +21,10 @@ class LevelBloc extends Bloc { /// ------------constructor------------ LevelBloc( this._getLeveslUseCase, - this._audioService, + this._mainAudioService, + this._effectAudioService, ) : super(const LevelState()) { - volumeStream = _audioService.volumeStream(); + volumeStream = _mainAudioService.volumeStream(); on(_getLevelListEvent); on(_setCurrentLevelEvent); on(_startScrollEvent); @@ -39,34 +41,35 @@ class LevelBloc extends Bloc { final GetLevelsUseCase _getLeveslUseCase; /// ------------Variables------------ - final List bottomLocationList = [ - LevelLocation(bottom: -20, left: 30, index: 1), - LevelLocation(bottom: 50, left: 100, index: 2), - LevelLocation(bottom: 150, left: 60, index: 3), - LevelLocation(bottom: 210, left: 110, index: 4), - LevelLocation(bottom: 260, right: 70, index: 5), - LevelLocation(top: 170, right: 40, index: 6), - LevelLocation(top: 70, right: 70, index: 7), - LevelLocation(top: -20, right: 70, index: 8), + final List locationList = [ + LevelLocation(bottom: 0.13.h, left: 0.2.w, index: 0), + LevelLocation(bottom: 0.25.h, left: 0.43.w, index: 1), + LevelLocation(bottom: 0.35.h, left: 0.22.w, index: 2), + LevelLocation(bottom: 0.5.h, left: 0.35.w, index: 3), + LevelLocation(bottom: 0.57.h, left: 0.6.w, index: 4), + LevelLocation(bottom: 0.65.h, left: 0.8.w, index: 5), + LevelLocation(bottom: 0.8.h, left: 0.82.w, index: 6), + LevelLocation(bottom: 1.0.h, left: 0.76.w, index: 7), + LevelLocation(bottom: 1.15.h, left: 0.6.w, index: 8), + LevelLocation(bottom: 1.2.h, left: 0.3.w, index: 9), + LevelLocation(bottom: 1.3.h, left: 0.07.w, index: 10), + LevelLocation(bottom: 1.38.h, left: 0.3.w, index: 11), + LevelLocation(bottom: 1.44.h, left: 0.55.w, index: 12), + LevelLocation(bottom: 1.54.h, left: 0.68.w, index: 13), + LevelLocation(bottom: 1.63.h, left: 0.6.w, index: 14), + LevelLocation(bottom: 1.75.h, left: 0.63.w, index: 15), + LevelLocation(bottom: 1.84.h, left: 0.43.w, index: 16), + LevelLocation(bottom: 1.82.h, left: 0.17.w, index: 17), + LevelLocation(bottom: 1.96.h, left: 0.05.w, index: 18), + LevelLocation(bottom: 2.08.h, left: 0.1.w, index: 19), + LevelLocation(bottom: 2.14.h, left: 0.3.w, index: 20), + LevelLocation(bottom: 2.24.h, left: 0.35.w, index: 21), + LevelLocation(bottom: 2.35.h, left: 0.2.w, index: 22), + LevelLocation(bottom: 2.44.h, left: 0.14.w, index: 23), + LevelLocation(bottom: 2.55.h, left: 0.28.w, index: 24), ]; - final List topLocationList = [ - LevelLocation(bottom: 30, right: 80, index: 9), - LevelLocation(bottom: 70, left: 20, index: 10), - LevelLocation(bottom: 150, left: 50, index: 11), - LevelLocation(bottom: 180, left: 140, index: 12), - LevelLocation(bottom: 260, right: 20, index: 13), - LevelLocation(bottom: 370, right: 30, index: 14), - LevelLocation(bottom: 420, left: 40, index: 15), - LevelLocation(top: 410, left: 0, index: 16), - LevelLocation(top: 320, left: 60, index: 17), - LevelLocation(top: 220, left: 80, index: 18), - LevelLocation(top: 130, left: 20, index: 19), - LevelLocation(top: 50, left: 70, index: 20), - ]; - - final List bottom8LevelList = []; - final List top12LevelList = []; + final List levelList = []; late final Stream volumeStream; @@ -74,7 +77,8 @@ class LevelBloc extends Bloc { /// ------------Controllers------------ final ScrollController scrollController = ScrollController(); - final AudioService _audioService; + final AudioService _mainAudioService; + final AudioService _effectAudioService; /// ------------Functions------------ void goToQuestionPage(BuildContext context, LevelEntity level){ @@ -105,7 +109,10 @@ class LevelBloc extends Bloc { } Future changeMute() async { - await _audioService.changeMute(); + await Future.wait([ + _mainAudioService.changeMute(), + _effectAudioService.changeMute(), + ]); } /// ------------Api Calls------------ @@ -117,10 +124,7 @@ class LevelBloc extends Bloc { await _getLeveslUseCase(LevelParams()).then((value) { value.fold( (data) async { - bottom8LevelList.addAll(data.take(8)); - if(data.length > 8){ - top12LevelList.addAll(data.sublist(8, data.length)); - } + levelList.addAll(data); try { emit(state.copyWith( getLevelStatus: const BaseComplete(''), diff --git a/lib/features/level/presentation/ui/level_page.dart b/lib/features/level/presentation/ui/level_page.dart index f0500ed..a1d89ed 100644 --- a/lib/features/level/presentation/ui/level_page.dart +++ b/lib/features/level/presentation/ui/level_page.dart @@ -1,25 +1,31 @@ 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/screen_size.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'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_bloc.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_event.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/bloc/level_state.dart'; -import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/bottom_path.dart'; -import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/hint_level_widget.dart'; +import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/diamond_level.dart'; +import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_path.dart'; import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/level_widget.dart'; -import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/top_path.dart'; +import 'package:hadi_hoda_flutter/features/level/presentation/ui/widgets/play_button.dart'; class LevelPage extends StatelessWidget { - const LevelPage({super.key}); + const LevelPage({super.key}); + + @override Widget build(BuildContext context) { return Scaffold( body: Stack( + alignment: Alignment.center, children: [ SingleChildScrollView( controller: context.read().scrollController, @@ -28,62 +34,176 @@ class LevelPage extends StatelessWidget { alignment: Alignment.center, children: [ _background(), - _topPath(context), - _bottomPath(context), + _path(context), + _levelLocation(context), + _planets(context), ], ), ), _topButtons(context), - _hintMission(context) + _playButton(context) ], ), ); } - Widget _hintMission(BuildContext context) { - return BlocBuilder( - buildWhen: (previous, current) => - previous.chooseLevel?.id != current.chooseLevel?.id, - builder: (context, state) { - if (state.chooseLevel?.id != null) { - return Positioned( - bottom: MediaQuery.viewPaddingOf(context).bottom + MySpaces.s10, - right: MySpaces.s16, - left: MySpaces.s16, - child: HintLevelWidget( - level: state.chooseLevel ?? LevelEntity(), - onTap: (level) => - context.read().goToQuestionPage(context, level), - ), - ); - } else { - return SizedBox.shrink(); - } - } + Positioned _planets(BuildContext context) { + return Positioned.fill( + child: Stack( + alignment: Alignment.center, + children: [ + Positioned( + bottom: 0.3.h, + right: setSize(context: context, mobile: -40, tablet: -80), + child: MyImage( + image: MyAssets.planet1, + size: setSize(context: context, mobile: 180), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 0.65.h, tablet: 0.9.h), + child: MyImage( + image: MyAssets.planet2, + size: setSize(context: context, mobile: 110), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 0.8.h, tablet: 1.15.h), + left: setSize(context: context, mobile: -120, tablet: -200), + child: MyImage( + image: MyAssets.planet3, + size: setSize(context: context, mobile: 300), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 1.3.h, tablet: 1.75.h), + right: 40, + child: MyImage( + image: MyAssets.planet4, + size: setSize(context: context, mobile: 120), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 1.5.h, tablet: 2.0.h), + left: setSize(context: context, mobile: -130, tablet: -220), + child: MyImage( + image: MyAssets.planet5, + size: setSize(context: context, mobile: 300), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 1.85.h, tablet: 2.55.h), + right: setSize(context: context, mobile: 20, tablet: 20), + child: MyImage( + image: MyAssets.planet6, + size: setSize(context: context, mobile: 80), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 1.95.h, tablet: 2.6.h), + child: MyImage( + image: MyAssets.planet7, + size: setSize(context: context, mobile: 120), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 2.1.h, tablet: 2.8.h), + right: setSize(context: context, mobile: -50, tablet: -120), + child: MyImage( + image: MyAssets.planet8, + size: setSize(context: context, mobile: 250), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 2.3.h, tablet: 3.1.h), + left: -20, + child: MyImage( + image: MyAssets.planet9, + size: setSize(context: context, mobile: 100), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 2.5.h, tablet: 3.4.h), + child: MyImage( + image: MyAssets.planet10, + size: setSize(context: context, mobile: 60), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 2.55.h, tablet: 3.45.h), + right: 20, + child: MyImage( + image: MyAssets.satellite, + size: setSize(context: context, mobile: 80), + ), + ), + Positioned( + bottom: setSize(context: context, mobile: 2.6.h, tablet: 3.5.h), + left: setSize(context: context, mobile: 40), + child: MyImage( + image: MyAssets.planetFinal, + size: setSize(context: context, mobile: 300), + ), + ), + ], + ), + ); + } + + Positioned _path(BuildContext context) { + return Positioned.fill( + top: setSize(context: context, mobile: 0.3.h, tablet: 0.37.h), + bottom: setSize(context: context, mobile: 0.15.h, tablet: 200), + left: MySpaces.s30, + right: MySpaces.s30, + child: LevelPath( + width: setSize(context: context, tablet: 0.45.w, mobile: 0.9.w) ?? 0, + height: setSize(context: context, tablet: 1.75.h, mobile: 2.55.h) ?? 0, + ), ); } + Widget _playButton(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => + previous.chooseLevel?.id != current.chooseLevel?.id, + builder: (context, state) { + return Positioned( + bottom: MySpaces.s20, + child: PlayButton( + level: state.chooseLevel ?? LevelEntity(), + onTap: (level) => + context.read().goToQuestionPage(context, level), + ), + ); + } + ); + } + Positioned _topButtons(BuildContext context) { return Positioned( left: MySpaces.s16, right: MySpaces.s16, - top: MediaQuery.viewPaddingOf(context).top + MySpaces.s16, + top: MySpaces.s20, child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: MySpaces.s16, children: [ - InkWell( + MyInkwell( onTap: () => context.read().goToHomePage(context), + audio: MyAudios.back, child: MyImage( image: MyAssets.homeButton, ), ), + Spacer(), + DiamondLevel(), StreamBuilder( initialData: 1, stream: context.read().volumeStream, - builder: (context, snapshot) => InkWell( + builder: (context, snapshot) => MyInkwell( onTap: () => context.read().changeMute(), child: MyImage( - image: snapshot.data == 1 ? MyAssets.musicOn : MyAssets.musicOff, + image: snapshot.data == 0 ? MyAssets.musicOff : MyAssets.musicOn, ), ), ), @@ -92,75 +212,44 @@ class LevelPage extends StatelessWidget { ); } - MyImage _background() { - return MyImage(image: MyAssets.mapBackground, fit: BoxFit.cover); - } - - Positioned _topPath(BuildContext context) { - return Positioned( - top: context.heightScreen * 0.16, - left: context.widthScreen * 0.15, - child: BlocBuilder( - builder: (context, state) => Stack( - children: [ - TopPath( - height: 950, - width: context.widthScreen * 0.6, - ), - ...List.generate( - context.read().top12LevelList.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: BlocBuilder( - builder: (context, state) => LevelWidget( - chooseLevel: state.chooseLevel, - level: context.read().top12LevelList[index], - type: context.read().getLevelType(index + 9), - onTap: (LevelEntity level, LevelType type) { - context.read().add(ChooseLevelEvent(level, type)); - }, - ), - ), - ), - ), - ], + Widget _background() { + return Stack( + children: [ + MyImage( + image: MyAssets.mapBackground, + fit: BoxFit.cover, ), - ), + ], ); } - Positioned _bottomPath(BuildContext context) { - return Positioned( - bottom: context.heightScreen * 0.18, - left: context.widthScreen * 0.2, - child: BlocBuilder( - builder: (context, state) => Stack( - clipBehavior: Clip.none, + Widget _levelLocation(BuildContext context) { + return BlocBuilder( + builder: (context, state) => Positioned.fill( + child: Stack( children: [ - BottomPath(), ...List.generate( - context.read().bottom8LevelList.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: BlocBuilder( - buildWhen: (previous, current) => + context.read().levelList.length, + (index) => Positioned( + top: context.read().locationList[index].top, + bottom: context.read().locationList[index].bottom, + right: context.read().locationList[index].right, + left: context.read().locationList[index].left, + child: BlocBuilder( + buildWhen: (previous, current) => previous.chooseLevel?.id != current.chooseLevel?.id, - builder: (context, state) => LevelWidget( - chooseLevel: state.chooseLevel, - level: context.read().bottom8LevelList[index], - type: context.read().getLevelType(index + 1), - onTap: (LevelEntity level, LevelType type) { - context.read().add(ChooseLevelEvent(level, type)); - }, - ), - ), + builder: (context, state) => LevelWidget( + chooseLevel: state.chooseLevel, + level: context.read().levelList[index], + type: context.read().getLevelType(index + 1), + onTap: (LevelEntity level, LevelType type) { + context.read().add( + ChooseLevelEvent(level, type), + ); + }, ), + ), + ), ), ], ), diff --git a/lib/features/level/presentation/ui/widgets/diamond_level.dart b/lib/features/level/presentation/ui/widgets/diamond_level.dart new file mode 100644 index 0000000..28cb1b6 --- /dev/null +++ b/lib/features/level/presentation/ui/widgets/diamond_level.dart @@ -0,0 +1,50 @@ +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/gap.dart'; +import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; + +class DiamondLevel extends StatelessWidget { + const DiamondLevel({super.key}); + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + MyImage(image: MyAssets.diamondContainer), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + MyImage(image: MyAssets.diamondBig, size: 42), + MySpaces.s16.gapWidth, + ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFF4BA5EA), Color(0XFF0C4EE9)], + ).createShader(bounds), + child: Text( + '0', + maxLines: 1, + style: MYTextStyle.button1.copyWith( + shadows: [ + BoxShadow( + color: MyColors.black.withValues(alpha: 0.25), + offset: Offset(0, 1.43), + blurRadius: 1.43, + ), + ], + ), + ), + ), + ], + ), + ], + ); + } +} diff --git a/lib/features/level/presentation/ui/widgets/hint_level_widget.dart b/lib/features/level/presentation/ui/widgets/hint_level_widget.dart deleted file mode 100644 index d32c310..0000000 --- a/lib/features/level/presentation/ui/widgets/hint_level_widget.dart +++ /dev/null @@ -1,61 +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_spaces.dart'; -import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; -import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; -import 'package:hadi_hoda_flutter/core/widgets/answer_box/styles/text_box.dart'; -import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; -import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; - -class HintLevelWidget extends StatelessWidget { - const HintLevelWidget({ - super.key, - required this.level, - this.onTap, - }); - - final LevelEntity level; - final Function(LevelEntity level)? onTap; - - @override - Widget build(BuildContext context) { - return ClipPath( - clipper: WavyBannerClipper(), - child: Container( - width: context.widthScreen, - padding: EdgeInsets.symmetric(horizontal: 14, vertical: 16), - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [Color(0XFFCADCFF), Color(0XFFFFFFFF)], - ), - ), - child: Row( - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - spacing: MySpaces.s8, - children: [ - Text( - '${context.translate.step} ${level.order ?? 0}', - ), - Text( - level.title ?? '', - maxLines: 3, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - InkWell( - onTap: () => onTap?.call(level), - child: MyImage(image: MyAssets.play, size: 70),), - ], - ), - ), - ); - } -} diff --git a/lib/features/level/presentation/ui/widgets/level_path.dart b/lib/features/level/presentation/ui/widgets/level_path.dart index 8e327e2..f814cba 100644 --- a/lib/features/level/presentation/ui/widgets/level_path.dart +++ b/lib/features/level/presentation/ui/widgets/level_path.dart @@ -2,20 +2,38 @@ import 'package:flutter/material.dart'; import 'package:path_drawing/path_drawing.dart'; class LevelPath extends StatelessWidget { - const LevelPath({super.key}); + const LevelPath({ + super.key, + required this.width, + required this.height + }); + + final double width; + final double height; @override Widget build(BuildContext context) { - return CustomPaint(size: Size(361, 2233), painter: CurvedPathPainter()); + return CustomPaint( + size: Size(width, height), + painter: CurvedPathPainter(width: width, height: height), + ); } } class CurvedPathPainter extends CustomPainter { + const CurvedPathPainter({ + required this.width, + required this.height + }); + + final double width; + final double height; + @override void paint(Canvas canvas, Size size) { // Scale factor to fit the design - final scaleX = size.width / 361; - final scaleY = size.height / 2233; + final scaleX = size.width / width; + final scaleY = size.height / height; final paint = Paint() ..color = Colors.white diff --git a/lib/features/level/presentation/ui/widgets/level_widget.dart b/lib/features/level/presentation/ui/widgets/level_widget.dart index 70d049d..c2d2968 100644 --- a/lib/features/level/presentation/ui/widgets/level_widget.dart +++ b/lib/features/level/presentation/ui/widgets/level_widget.dart @@ -1,5 +1,7 @@ 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_text_style.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; @@ -13,6 +15,18 @@ enum LevelType { LevelType.finished: MyAssets.finishedLevel, LevelType.current: MyAssets.currentLevel, }; + + static Map get textShadowColor => { + LevelType.unFinished: Color(0XFF5B5B5B), + LevelType.finished: Color(0XFF096D7B), + LevelType.current: Color(0XFF91500D), + }; + + static Map get textColor => { + LevelType.unFinished: Color(0XFFEDEDED), + LevelType.finished: Color(0XFFFFF2D0), + LevelType.current: Color(0XFFFFF2D0), + }; } class LevelWidget extends StatelessWidget { @@ -38,8 +52,29 @@ class LevelWidget extends StatelessWidget { clipBehavior: Clip.none, children: [ MyImage(image: LevelType.image[type] ?? MyAssets.level, size: 46), - Text( - '${level.order}', + ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0XFFFFFFFF), + LevelType.textColor[type] ?? MyColors.white, + ], + ).createShader(bounds), + child: Text( + '${level.order ?? 0}', + maxLines: 1, + style: MYTextStyle.button1.copyWith( + fontSize: 24, + shadows: [ + BoxShadow( + color: LevelType.textShadowColor[type] ?? MyColors.white, + offset: Offset(0, 2.97), + ) + ], + ), + ), ), if(level.id == chooseLevel?.id) Positioned( diff --git a/lib/features/level/presentation/ui/widgets/play_button.dart b/lib/features/level/presentation/ui/widgets/play_button.dart new file mode 100644 index 0000000..bd41792 --- /dev/null +++ b/lib/features/level/presentation/ui/widgets/play_button.dart @@ -0,0 +1,64 @@ +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/common_ui/resources/my_text_style.dart'; +import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; +import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; +import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; +import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; + +class PlayButton extends StatelessWidget { + const PlayButton({super.key, required this.level, this.onTap}); + + final LevelEntity level; + final Function(LevelEntity level)? onTap; + + @override + Widget build(BuildContext context) { + return MyInkwell( + onTap: () => onTap?.call(level), + child: Stack( + alignment: Alignment.center, + children: [ + MyImage(image: MyAssets.button2), + Positioned( + top: MySpaces.s2, + child: Row( + spacing: MySpaces.s4, + children: [ + MyImage(image: MyAssets.iconPlay), + ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFFF9601F), Color(0XFFD93D16)], + ).createShader(bounds), + child: Text( + context.translate.play, + maxLines: 1, + style: MYTextStyle.button1.copyWith( + shadows: [ + BoxShadow( + color: Color(0XFFFFFFAB).withValues(alpha: 0.40), + offset: Offset(0, 2.61), + ), + ], + ), + ), + ), + ], + ), + ), + Positioned( + bottom: MySpaces.s20, + child: Text( + '${context.translate.step} ${level.order ?? 0}', + style: MYTextStyle.matn3.copyWith(color: Color(0XFFD8490B)), + ), + ), + ], + ), + ); + } +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 07c32b4..4bad7ff 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -28,5 +28,6 @@ "want_to_exit": "Want To Exit?", "exit_dialog_desc": "Come back, hero!\nThe adventure isn’t over yet", "cancel": "Cancel", - "exit": "Exit" + "exit": "Exit", + "play": "PLAY" } \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 205ea03..f4ec348 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -273,6 +273,12 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Exit'** String get exit; + + /// No description provided for @play. + /// + /// In en, this message translates to: + /// **'PLAY'** + String get play; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index fbc64fa..319b54d 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -103,4 +103,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get exit => 'Exit'; + + @override + String get play => 'PLAY'; }