diff --git a/assets/audios/back.mp3 b/assets/audios/back.mp3 new file mode 100644 index 0000000..b2a877a Binary files /dev/null and b/assets/audios/back.mp3 differ diff --git a/assets/audios/click_button.mp3 b/assets/audios/click_button.mp3 new file mode 100644 index 0000000..ea977e9 Binary files /dev/null and b/assets/audios/click_button.mp3 differ diff --git a/assets/audios/diamond_end.mp3 b/assets/audios/diamond_end.mp3 new file mode 100644 index 0000000..5938bb7 Binary files /dev/null and b/assets/audios/diamond_end.mp3 differ diff --git a/assets/audios/diamond_increase.mp3 b/assets/audios/diamond_increase.mp3 new file mode 100644 index 0000000..831a8ec Binary files /dev/null and b/assets/audios/diamond_increase.mp3 differ diff --git a/assets/audios/home.mp3 b/assets/audios/home.mp3 new file mode 100644 index 0000000..637448f Binary files /dev/null and b/assets/audios/home.mp3 differ diff --git a/assets/audios/incorrect_answer.mp3 b/assets/audios/incorrect_answer.mp3 new file mode 100644 index 0000000..17eabf6 Binary files /dev/null and b/assets/audios/incorrect_answer.mp3 differ diff --git a/assets/audios/question.mp3 b/assets/audios/question.mp3 new file mode 100644 index 0000000..495f6c1 Binary files /dev/null and b/assets/audios/question.mp3 differ diff --git a/assets/audios/right_answer.mp3 b/assets/audios/right_answer.mp3 new file mode 100644 index 0000000..de51d68 Binary files /dev/null and b/assets/audios/right_answer.mp3 differ diff --git a/lib/common_ui/resources/my_audios.dart b/lib/common_ui/resources/my_audios.dart new file mode 100644 index 0000000..e499c25 --- /dev/null +++ b/lib/common_ui/resources/my_audios.dart @@ -0,0 +1,8 @@ +class MyAudios { + static const MyAudios _i = MyAudios._internal(); + const MyAudios._internal(); + factory MyAudios() => _i; + + static const String homeMusic = 'assets/audios/home.mp3'; + static const String clickButton = 'assets/audios/click_button.mp3'; +} \ No newline at end of file diff --git a/lib/core/constants/my_constants.dart b/lib/core/constants/my_constants.dart index c157bdd..f06985f 100644 --- a/lib/core/constants/my_constants.dart +++ b/lib/core/constants/my_constants.dart @@ -13,4 +13,8 @@ class MyConstants { static const String selectLanguage = 'SELECT_LANGUAGE'; static const String firstDownload = 'FIRST_DOWNLOAD'; static const String currentLevel = 'CURRENT_LEVEL'; + static const String mainAudioService = 'MAIN_AUDIO_SERVICE'; + static const String effectAudioService = 'EFFECT_AUDIO_SERVICE'; + static const String firstIntro = 'FIRST_INTRO'; + static const double mainAudioVolume = 0.3; } \ No newline at end of file diff --git a/lib/core/middlewares/my_middlewares.dart b/lib/core/middlewares/my_middlewares.dart index 40972de..b903036 100644 --- a/lib/core/middlewares/my_middlewares.dart +++ b/lib/core/middlewares/my_middlewares.dart @@ -11,7 +11,7 @@ class MyMiddlewares { const MyMiddlewares._internal(); factory MyMiddlewares() => _i; - static FutureOr splash(BuildContext context, GoRouterState state) { + static FutureOr splash(BuildContext context, GoRouterState state) { final String? firstDownload = LocalStorage.readData( key: MyConstants.firstDownload); if (firstDownload != 'true') { @@ -20,4 +20,14 @@ class MyMiddlewares { return null; } } + + static FutureOr intro(BuildContext context, GoRouterState state) { + final String? firstIntro = LocalStorage.readData( + key: MyConstants.firstIntro); + if (firstIntro == 'true') { + return Routes.levelPage; + } else { + return null; + } + } } diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index 92ad404..900366f 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -1,5 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/middlewares/my_middlewares.dart'; import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_bloc.dart'; @@ -46,6 +47,7 @@ GoRouter get appPages => GoRouter( GoRoute( name: Routes.introPage, path: Routes.introPage, + redirect: MyMiddlewares.intro, builder: (context, state) => BlocProvider( create: (context) => IntroBloc(), child: const IntroPage(), @@ -93,7 +95,10 @@ GoRouter get appPages => GoRouter( name: Routes.homePage, path: Routes.homePage, builder: (context, state) => BlocProvider( - create: (context) => HomeBloc(locator()), + create: (context) => + HomeBloc(locator(instanceName: MyConstants.mainAudioService), + locator(instanceName: MyConstants.effectAudioService), + ), child: const HomePage(), ), ), @@ -101,7 +106,11 @@ GoRouter get appPages => GoRouter( name: Routes.levelPage, path: Routes.levelPage, builder: (context, state) => BlocProvider( - create: (context) => LevelBloc(locator(), locator())..add(SetCurrentLevelEvent()), + create: (context) => + LevelBloc( + locator(), + locator(instanceName: MyConstants.mainAudioService), + )..add(SetCurrentLevelEvent()), child: const LevelPage(), ), ), diff --git a/lib/core/services/audio_service.dart b/lib/core/services/audio_service.dart index 9670981..0bd3def 100644 --- a/lib/core/services/audio_service.dart +++ b/lib/core/services/audio_service.dart @@ -3,21 +3,32 @@ import 'package:just_audio/just_audio.dart'; class AudioService { final AudioPlayer _player = AudioPlayer(); + final double? volume; - Future setAudio({String? filePath}) async { + AudioService({this.volume}) { + _player.setVolume(volume ?? 1); + } + + Future setAudio({String? filePath, String? assetPath}) async { try { - return _player.setAudioSource(AudioSource.file(filePath ?? '')); + if (filePath != null) { + return await _player.setAudioSource(AudioSource.file(filePath)); + } else if (assetPath != null) { + return await _player.setAudioSource(AudioSource.asset(assetPath)); + } else { + return null; + } } catch (e) { if (kDebugMode) { print('$e'); } - return Duration.zero; + return null; } } Future play() async { try { - return _player.play(); + await _player.play(); } catch (e) { if (kDebugMode) { print('$e'); @@ -27,7 +38,7 @@ class AudioService { Future pause() async { try { - return _player.pause(); + await _player.pause(); } catch (e) { if (kDebugMode) { print('$e'); @@ -37,7 +48,7 @@ class AudioService { Future stop() async { try { - return _player.stop(); + await _player.stop(); } catch (e) { if (kDebugMode) { print('$e'); @@ -47,7 +58,7 @@ class AudioService { Future dispose() async { try { - return _player.dispose(); + await _player.dispose(); } catch (e) { if (kDebugMode) { print('$e'); @@ -58,7 +69,7 @@ class AudioService { Future changeMute() async { try { if (_player.volume == 0) { - await _player.setVolume(1); + await _player.setVolume(volume ?? 1); } else { await _player.setVolume(0); } @@ -69,6 +80,16 @@ class AudioService { } } + Future setVolume({required double volume}) async { + try { + await _player.setVolume(volume); + } catch (e) { + if (kDebugMode) { + print('$e'); + } + } + } + Stream volumeStream() async* { try { yield* _player.volumeStream; @@ -78,4 +99,18 @@ class AudioService { } } } + + Future setLoopMode({bool isLoop = false}) async { + try { + if (isLoop) { + await _player.setLoopMode(LoopMode.all); + } else { + await _player.setLoopMode(LoopMode.off); + } + } catch (e) { + if (kDebugMode) { + print('$e'); + } + } + } } diff --git a/lib/core/widgets/button/my_blue_button.dart b/lib/core/widgets/button/my_blue_button.dart index 8006b49..b90f8b1 100644 --- a/lib/core/widgets/button/my_blue_button.dart +++ b/lib/core/widgets/button/my_blue_button.dart @@ -5,6 +5,7 @@ import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; +import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; class MyBlueButton extends StatelessWidget { const MyBlueButton({ @@ -20,7 +21,7 @@ class MyBlueButton extends StatelessWidget { @override Widget build(BuildContext context) { - return InkWell( + return MyInkwell( onTap: onTap, highlightColor: MyColors.transparent, splashColor: MyColors.transparent, @@ -36,7 +37,7 @@ class MyBlueButton extends StatelessWidget { '', ), PositionedDirectional( - top: top ?? setSize(context: context, mobile: MySpaces.s10, tablet: MySpaces.s20), + top: top ?? setSize(context: context, mobile: MySpaces.s6, tablet: MySpaces.s20), child: Text( title ?? '', style: MYTextStyle.button1.copyWith( diff --git a/lib/core/widgets/button/my_yellow_button.dart b/lib/core/widgets/button/my_yellow_button.dart index b6364b4..33fc12e 100644 --- a/lib/core/widgets/button/my_yellow_button.dart +++ b/lib/core/widgets/button/my_yellow_button.dart @@ -5,6 +5,7 @@ import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; +import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; class MyYellowButton extends StatelessWidget { const MyYellowButton({ @@ -20,7 +21,7 @@ class MyYellowButton extends StatelessWidget { @override Widget build(BuildContext context) { - return InkWell( + return MyInkwell( onTap: onTap, highlightColor: MyColors.transparent, splashColor: MyColors.transparent, diff --git a/lib/core/widgets/about_us_dialog/about_us_dialog.dart b/lib/core/widgets/dialog/about_us_dialog.dart similarity index 94% rename from lib/core/widgets/about_us_dialog/about_us_dialog.dart rename to lib/core/widgets/dialog/about_us_dialog.dart index e575dd9..4992978 100644 --- a/lib/core/widgets/about_us_dialog/about_us_dialog.dart +++ b/lib/core/widgets/dialog/about_us_dialog.dart @@ -7,8 +7,9 @@ import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; -import 'package:hadi_hoda_flutter/core/widgets/about_us_dialog/styles/background.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/styles/dialog_background.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; +import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; Future showAboutUsDialog({required BuildContext context}) async { await showDialog( @@ -40,7 +41,7 @@ class AboutUsDialog extends StatelessWidget { child: Stack( clipBehavior: Clip.none, children: [ - AboutUSDialogBackground( + DialogBackground( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -91,9 +92,8 @@ class AboutUsDialog extends StatelessWidget { Positioned( right: setSize(context: context, mobile: 30, tablet: 40), top: setSize(context: context, mobile: -12, tablet: -20), - child: GestureDetector( + child: MyInkwell( onTap: context.pop, - behavior: HitTestBehavior.opaque, child: MyImage( image: MyAssets.closeBtn, size: setSize(context: context, mobile: 40, tablet: 60), diff --git a/lib/core/widgets/dialog/exit_dialog.dart b/lib/core/widgets/dialog/exit_dialog.dart new file mode 100644 index 0000000..9d4a7bf --- /dev/null +++ b/lib/core/widgets/dialog/exit_dialog.dart @@ -0,0 +1,104 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:go_router/go_router.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/my_localization.dart'; +import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/styles/dialog_background.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/styles/dialog_button.dart'; + +Future showExitDialog({required BuildContext context}) async { + await showDialog( + context: context, + builder: (context) => ExitDialog(), + barrierColor: MyColors.purple.withValues(alpha: 0.82), + useSafeArea: false, + ); +} + +class ExitDialog extends StatelessWidget { + const ExitDialog({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: MyColors.transparent, + body: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), + child: Center( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: setSize(context: context, mobile: 18, tablet: 160) ?? 0, + ), + child: DialogBackground( + height: 260, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + context.translate.want_to_exit, + style: MYTextStyle.titr0.copyWith(color: Color(0XFF322386)), + ), + Text( + context.translate.exit_dialog_desc, + style: MYTextStyle.titr3.copyWith(color: Color(0XFF6272A9)), + textAlign: TextAlign.center, + ), + Row( + spacing: MySpaces.s20, + children: [ + Expanded( + child: DialogButton( + onTap: () { + context.pop(); + }, + height: 72, + color: Color(0XFFC0BDD3), + child: Text( + context.translate.cancel, + style: MYTextStyle.button2.copyWith( + shadows: [ + BoxShadow( + color: Color(0XFF9895AE), + offset: Offset(0, 3.32), + ), + ], + ), + ), + ), + ), + Expanded( + child: DialogButton( + onTap: () { + SystemNavigator.pop(); + }, + height: 72, + color: Color(0XFFD42427), + child: Text( + context.translate.exit, + style: MYTextStyle.button2.copyWith( + shadows: [ + BoxShadow( + color: Color(0XFFC82020), + offset: Offset(0, 3.32), + ), + ], + ), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/core/widgets/hadith_dialog/hadith_dialog.dart b/lib/core/widgets/dialog/hadith_dialog.dart similarity index 95% rename from lib/core/widgets/hadith_dialog/hadith_dialog.dart rename to lib/core/widgets/dialog/hadith_dialog.dart index 9e195b3..4e2259e 100644 --- a/lib/core/widgets/hadith_dialog/hadith_dialog.dart +++ b/lib/core/widgets/dialog/hadith_dialog.dart @@ -6,7 +6,7 @@ import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; import 'package:hadi_hoda_flutter/core/utils/set_platform_size.dart'; -import 'package:hadi_hoda_flutter/core/widgets/about_us_dialog/styles/background.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/styles/dialog_background.dart'; import 'package:hadi_hoda_flutter/core/widgets/images/my_image.dart'; import 'package:hadi_hoda_flutter/features/question/domain/entity/hadith_entity.dart'; @@ -45,7 +45,7 @@ class HadithDialog extends StatelessWidget { child: Stack( clipBehavior: Clip.none, children: [ - AboutUSDialogBackground( + DialogBackground( child: ListView.separated( itemCount: hadith.length, separatorBuilder: (context, index) => Divider( diff --git a/lib/core/widgets/about_us_dialog/styles/background.dart b/lib/core/widgets/dialog/styles/dialog_background.dart similarity index 92% rename from lib/core/widgets/about_us_dialog/styles/background.dart rename to lib/core/widgets/dialog/styles/dialog_background.dart index 2105738..099be2f 100644 --- a/lib/core/widgets/about_us_dialog/styles/background.dart +++ b/lib/core/widgets/dialog/styles/dialog_background.dart @@ -3,10 +3,15 @@ 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'; -class AboutUSDialogBackground extends StatelessWidget { - const AboutUSDialogBackground({super.key, this.child}); +class DialogBackground extends StatelessWidget { + const DialogBackground({ + super.key, + this.child, + this.height = 525, + }); final Widget? child; + final double height; @override Widget build(BuildContext context) { @@ -14,7 +19,7 @@ class AboutUSDialogBackground extends StatelessWidget { clipper: _BottomShapeClipper(), child: Container( width: context.widthScreen, - height: 525, + height: height, padding: EdgeInsets.symmetric( vertical: MySpaces.s30, horizontal: setSize(context: context, mobile: MySpaces.s30, tablet: 60) ?? 0, diff --git a/lib/core/widgets/dialog/styles/dialog_button.dart b/lib/core/widgets/dialog/styles/dialog_button.dart new file mode 100644 index 0000000..ef3a819 --- /dev/null +++ b/lib/core/widgets/dialog/styles/dialog_button.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/core/widgets/inkwell/my_inkwell.dart'; + +class DialogButton extends StatelessWidget { + const DialogButton({ + super.key, + this.color, + this.height = 72.0, + this.child, + this.onTap, + }); + + final Color? color; + final double height; + final Widget? child; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + return ClipPath( + clipper: ButtonDialogClipper(), + child: Material( + type: MaterialType.transparency, + child: MyInkwell( + onTap: onTap, + child: Ink( + height: height, + color: color, + child: Center( + child: child, + ), + ), + ), + ), + ); + } +} + + + +class ButtonDialogClipper extends CustomClipper { + @override + Path getClip(Size size) { + final path = Path(); + path.moveTo(size.width * 0.01841077, size.height * 0.8753694); + path.cubicTo( + size.width * 0.05368083, + size.height * 1.03396, + size.width * 0.888405, + size.height * 1.04665, + size.width * 0.961125, + size.height * 0.881918); + path.cubicTo( + size.width * 1.02749, + size.height * 0.732121, + size.width * 1.00029, + size.height * 0.195965, + size.width * 0.943774, + size.height * 0.0891425); + path.cubicTo( + size.width * 0.866786, + size.height * -0.0565611, + size.width * 0.122135, + size.height * -0.00478720, + size.width * 0.0598435, + size.height * 0.109607); + path.cubicTo( + size.width * 0.00172381, + size.height * 0.216429, + size.width * -0.0181157, + size.height * 0.711249, + size.width * 0.01841077, + size.height * 0.8753694); + path.close(); + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) { + return true; + } +} \ No newline at end of file diff --git a/lib/core/widgets/inkwell/my_inkwell.dart b/lib/core/widgets/inkwell/my_inkwell.dart new file mode 100644 index 0000000..2967c7d --- /dev/null +++ b/lib/core/widgets/inkwell/my_inkwell.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_audios.dart'; +import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; +import 'package:hadi_hoda_flutter/core/services/audio_service.dart'; +import 'package:hadi_hoda_flutter/init_bindings.dart'; + +class MyInkwell extends StatefulWidget { + const MyInkwell({ + super.key, + this.onTap, + this.child, + this.borderRadius, + this.highlightColor, + this.splashColor, + }); + + final VoidCallback? onTap; + final Widget? child; + final BorderRadius? borderRadius; + final Color? highlightColor; + final Color? splashColor; + + @override + State createState() => _MyInkwellState(); +} + +class _MyInkwellState extends State { + final AudioService audioService = locator( + instanceName: MyConstants.effectAudioService, + ); + + @override + void initState() { + super.initState(); + } + + void playAudio() { + audioService.setAudio(assetPath: MyAudios.clickButton); + audioService.play(); + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () { + playAudio(); + widget.onTap?.call(); + }, + borderRadius: widget.borderRadius, + highlightColor: widget.highlightColor, + splashColor: widget.splashColor, + child: widget.child, + ); + } +} diff --git a/lib/features/home/presentation/bloc/home_bloc.dart b/lib/features/home/presentation/bloc/home_bloc.dart index 219c7ed..8b2daeb 100644 --- a/lib/features/home/presentation/bloc/home_bloc.dart +++ b/lib/features/home/presentation/bloc/home_bloc.dart @@ -3,11 +3,14 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/common_ui/resources/my_audios.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; import 'package:hadi_hoda_flutter/core/services/audio_service.dart'; +import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; -import 'package:hadi_hoda_flutter/core/widgets/about_us_dialog/about_us_dialog.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/about_us_dialog.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/exit_dialog.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'; import 'package:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart'; @@ -16,9 +19,11 @@ import 'package:hive/hive.dart'; class HomeBloc extends Bloc { /// ------------constructor------------ HomeBloc( - this._audioService, + this._mainAudioService, + this._effectAudioService, ) : super(const HomeState()) { - volumeStream = _audioService.volumeStream(); + volumeStream = _mainAudioService.volumeStream(); + playMusic(); on(_getHomeEvent); } @@ -28,7 +33,8 @@ class HomeBloc extends Bloc { late final Stream volumeStream; /// ------------Controllers------------ - final AudioService _audioService; + final AudioService _mainAudioService; + final AudioService _effectAudioService; /// ------------Functions------------ void goToLevelPage(BuildContext context){ @@ -39,7 +45,7 @@ class HomeBloc extends Bloc { orElse: () => TotalDataEntity(), ); if (findData.levels?.isNotEmpty ?? false) { - context.pushNamed(Routes.levelPage); + context.pushNamed(Routes.introPage); } else { context.goNamed(Routes.downloadPage); } @@ -54,8 +60,24 @@ class HomeBloc extends Bloc { } Future changeMute() async { - await _audioService.changeMute(); + await Future.wait([ + _mainAudioService.changeMute(), + _effectAudioService.changeMute(), + ]); } + + Future playMusic() async { + Future.wait([ + _mainAudioService.setAudio(assetPath: MyAudios.homeMusic), + _mainAudioService.setLoopMode(isLoop: true), + ]); + await _mainAudioService.play(); + } + + void onPopInvokedWithResult(bool didPop, dynamic result) { + showExitDialog(context: ContextProvider.context); + } + /// ------------Api Calls------------ FutureOr _getHomeEvent(event, emit) async {} } diff --git a/lib/features/home/presentation/ui/home_page.dart b/lib/features/home/presentation/ui/home_page.dart index 04338fc..9a2a1b5 100644 --- a/lib/features/home/presentation/ui/home_page.dart +++ b/lib/features/home/presentation/ui/home_page.dart @@ -7,6 +7,7 @@ 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/button/my_yellow_button.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/home/presentation/bloc/home_bloc.dart'; class HomePage extends StatelessWidget { @@ -15,21 +16,27 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - body: DecoratedBox( - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage(MyAssets.backgroundHome), - fit: BoxFit.cover, + body: PopScope( + canPop: false, + onPopInvokedWithResult: context + .read() + .onPopInvokedWithResult, + child: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage(MyAssets.backgroundHome), + fit: BoxFit.cover, + ), ), - ), - child: SizedBox.expand( - child: Stack( - alignment: Alignment.center, - children: [ - _music(context), - _image(context), - _bottomBtns(context), - ], + child: SizedBox.expand( + child: Stack( + alignment: Alignment.center, + children: [ + _music(context), + _image(context), + _bottomBtns(context), + ], + ), ), ), ), @@ -43,10 +50,10 @@ class HomePage extends StatelessWidget { child: 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, size: setSize(context: context, tablet: 100), ), ), @@ -84,7 +91,7 @@ class HomePage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - InkWell( + MyInkwell( onTap: () => context.read().goToLanguagePage(context), child: MyImage( image: MyAssets.language, @@ -95,7 +102,7 @@ class HomePage extends StatelessWidget { onTap: () => context.read().goToLevelPage(context), title: context.translate.start, ), - InkWell( + MyInkwell( onTap: () => context.read().showAboutUs(context), child: MyImage( image: MyAssets.theme, diff --git a/lib/features/intro/presentation/bloc/intro_bloc.dart b/lib/features/intro/presentation/bloc/intro_bloc.dart index 127197b..8f446c0 100644 --- a/lib/features/intro/presentation/bloc/intro_bloc.dart +++ b/lib/features/intro/presentation/bloc/intro_bloc.dart @@ -3,8 +3,10 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; +import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; +import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_event.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/ui/screens/intro_1_screen.dart'; @@ -33,8 +35,11 @@ class IntroBloc extends Bloc { /// ------------Controllers------------ /// ------------Functions------------ - void goToLevelPage(){ - ContextProvider.context.go(Routes.levelPage); + Future goToLevelPage() async { + await LocalStorage.saveData(key: MyConstants.firstIntro, value: 'true'); + if (ContextProvider.context.mounted) { + ContextProvider.context.replaceNamed(Routes.levelPage); + } } /// ------------Api Calls------------ diff --git a/lib/features/language/presentation/bloc/language_bloc.dart b/lib/features/language/presentation/bloc/language_bloc.dart index f907683..5a19460 100644 --- a/lib/features/language/presentation/bloc/language_bloc.dart +++ b/lib/features/language/presentation/bloc/language_bloc.dart @@ -52,7 +52,11 @@ class LanguageBloc extends Bloc { ]); if (Directory( - '${StoragePath.documentDir.path}/${state.selectedLang.code}/audio') + '${StoragePath.documentDir.path}/${state.selectedLang + .code}/answer_audio') + .existsSync() && Directory( + '${StoragePath.documentDir.path}/${state.selectedLang + .code}/question_audio') .existsSync()) { if (ContextProvider.context.mounted) { ContextProvider.context.goNamed(Routes.homePage); diff --git a/lib/features/question/presentation/bloc/question_bloc.dart b/lib/features/question/presentation/bloc/question_bloc.dart index 3d5613f..446802b 100644 --- a/lib/features/question/presentation/bloc/question_bloc.dart +++ b/lib/features/question/presentation/bloc/question_bloc.dart @@ -12,7 +12,7 @@ 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/context_provider.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; -import 'package:hadi_hoda_flutter/core/widgets/hadith_dialog/hadith_dialog.dart'; +import 'package:hadi_hoda_flutter/core/widgets/dialog/hadith_dialog.dart'; import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart'; diff --git a/lib/init_bindings.dart b/lib/init_bindings.dart index b85c523..f81c487 100644 --- a/lib/init_bindings.dart +++ b/lib/init_bindings.dart @@ -39,7 +39,14 @@ final GetIt locator = GetIt.I; void initBindings() { /// Classes locator.registerSingleton(HttpRequestImpl()); - locator.registerSingleton(AudioService()); + locator.registerSingleton( + AudioService(volume: MyConstants.mainAudioVolume), + instanceName: MyConstants.mainAudioService, + ); + locator.registerSingleton( + AudioService(), + instanceName: MyConstants.effectAudioService, + ); /// Sample Feature locator.registerLazySingleton(() => SampleDatasourceImpl(locator())); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3c3c83e..07c32b4 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -24,5 +24,9 @@ "intro_2": "The purity of faith... \nIt means cleanliness is a sign of faith!", "intro_3": "These good deeds make our souls strong and beautiful!", "intro_4": "Do you want to travel to the Promised Garden?", - "intro_5": "Yessss....\nWe are ready!" + "intro_5": "Yessss....\nWe are ready!", + "want_to_exit": "Want To Exit?", + "exit_dialog_desc": "Come back, hero!\nThe adventure isn’t over yet", + "cancel": "Cancel", + "exit": "Exit" } \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 0bb94a7..205ea03 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -249,6 +249,30 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Yessss....\nWe are ready!'** String get intro_5; + + /// No description provided for @want_to_exit. + /// + /// In en, this message translates to: + /// **'Want To Exit?'** + String get want_to_exit; + + /// No description provided for @exit_dialog_desc. + /// + /// In en, this message translates to: + /// **'Come back, hero!\nThe adventure isn’t over yet'** + String get exit_dialog_desc; + + /// No description provided for @cancel. + /// + /// In en, this message translates to: + /// **'Cancel'** + String get cancel; + + /// No description provided for @exit. + /// + /// In en, this message translates to: + /// **'Exit'** + String get exit; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index fa617e0..fbc64fa 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -90,4 +90,17 @@ class AppLocalizationsEn extends AppLocalizations { @override String get intro_5 => 'Yessss....\nWe are ready!'; + + @override + String get want_to_exit => 'Want To Exit?'; + + @override + String get exit_dialog_desc => + 'Come back, hero!\nThe adventure isn’t over yet'; + + @override + String get cancel => 'Cancel'; + + @override + String get exit => 'Exit'; } diff --git a/pubspec.yaml b/pubspec.yaml index c367fd7..62fc865 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,7 @@ flutter: - assets/fonts/ - assets/images/ - assets/animations/ + - assets/audios/ - path: assets/svg/ transformers: - package: vector_graphics_compiler