import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.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/params/question_params.dart'; import 'package:hadi_hoda_flutter/core/routers/hero_dialog_route.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/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/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'; import 'package:hadi_hoda_flutter/features/question/domain/usecases/get_level_usecase.dart'; import 'package:hadi_hoda_flutter/features/question/domain/usecases/get_next_level_usecase.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_event.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/bloc/question_state.dart'; import 'package:hadi_hoda_flutter/features/question/presentation/ui/screens/answer_screen.dart'; import 'package:showcaseview/showcaseview.dart'; class QuestionBloc extends Bloc { /// ------------constructor------------ QuestionBloc( this._getLevelUseCase, this._getNextLevelUseCase, this._mainAudioService, this._effectAudioService, ) : super(QuestionState()) { volumeStream = _mainAudioService.volumeStream(); stopMusic(); on(_getLevelEvent); on(_chooseAnswerEvent); } /// ------------UseCases------------ final GetLevelUseCase _getLevelUseCase; final GetNextLevelUseCase _getNextLevelUseCase; /// ------------Variables------------ final List keys = [ GlobalKey(), GlobalKey(), GlobalKey(), GlobalKey(), ]; late final Stream volumeStream; bool isPlaying = false; /// ------------Controllers------------ final AudioService _mainAudioService; final AudioService _effectAudioService; /// ------------Functions------------ void startShowCase({required BuildContext context}) { ShowCaseWidget.of(context).startShowCase([keys[1]]); } void showHadith({required BuildContext context}) { if(isPlaying) return; showHadithDialog( context: context, hadith: state.levelEntity?.hadith ?? [], ); } void goToHomePage({required BuildContext context}) { context.goNamed(Routes.homePage); } void goToLevelPage({required BuildContext context}) { context.goNamed(Routes.levelPage); } Future playDiamondAudio() async { await _effectAudioService.setAudio(assetPath: MyAudios.diamondEnd); await _effectAudioService.play(); } Future stopMusic() async { await _mainAudioService.stop(); await _mainAudioService.setLoopMode(isLoop: false); } Future playCorrectAudio() async { await _effectAudioService.setAudio(assetPath: MyAudios.rightAnswer); await _effectAudioService.play(); } Future playWrongAudio() async { await _effectAudioService.setAudio(assetPath: MyAudios.incorrectAnswer); await _effectAudioService.play(); } Future playAnswerAudio({String? audio}) async { await _mainAudioService.setAudio(filePath: audio); await _mainAudioService.play(); } Future playQuestionAudio() async { await _mainAudioService.setAudio(filePath: state.currentQuestion?.audio); await _mainAudioService.play(); } Future changeMute() async { await Future.wait([ _mainAudioService.changeMute(), _effectAudioService.changeMute(), ]); } Future showAnswerDialog({ required BuildContext context, required AnswerEntity answerEntity, }) async { Navigator.of(context).push( HeroDialogRoute( builder: (dialogContext) { return AnswerScreen( answerEntity: answerEntity, onNotifTap: (answer) => playAnswerAudio(audio: answer.audio), ); }, ), ); playAnswerAudio(audio: answerEntity.audio); } Future getNextLevelEvent() async { await _getNextLevelUseCase(QuestionParams()).then((value) => value.fold( (data) { ContextProvider.context.pushReplacementNamed( Routes.questionPage, pathParameters: { 'id': '${data.id}' }, ); }, (error) { goToLevelPage(context: ContextProvider.context); }, ), ); } /// ------------Event Calls------------ FutureOr _getLevelEvent(GetLevelEvent event, Emitter emit) async { await _getLevelUseCase(QuestionParams(id: int.parse(event.id ?? '0'))).then( (value) { value.fold( (data) async { final LevelEntity level = LevelEntity( id: data.id, order: data.order, title: data.title, hadith: data.hadith, questions: [ ...?data.questions, QuestionEntity(order: (data.questions?.length ?? 0) + 1) ], ); emit(state.copyWith( getQuestionStatus: BaseComplete(''), levelEntity: level, currentQuestion: data.questions?.first, )); await playQuestionAudio(); }, (error) { emit(state.copyWith(getQuestionStatus: BaseError(error.errorMessage))); }, ); }, ); } FutureOr _chooseAnswerEvent(ChooseAnswerEvent event, Emitter emit,) async { emit(state.copyWith(correctAnswer: event.chooseCorrectAnswer)); if (event.chooseCorrectAnswer) { playCorrectAudio(); await Navigator.of(ContextProvider.context).push( HeroDialogRoute( builder: (dialogContext) { return AnswerScreen( answerEntity: state.currentQuestion?.answers?.singleWhere((e) => e.order == event.correctAnswer) ?? AnswerEntity(), showConfetti: true, ); }, ), ); await Future.delayed(Duration(seconds: 1), () async { final QuestionEntity? findPreQuestion = state.currentQuestion; final int findIndex = (findPreQuestion?.order ?? 1); emit( state.copyWith( currentQuestion: state.levelEntity?.questions?[findIndex], ), ); if (state.currentQuestion?.order == state.levelEntity?.questions?.length) { playDiamondAudio(); int currentLevel = int.parse( LocalStorage.readData(key: MyConstants.currentLevel) ?? '1'); if (state.levelEntity?.order == currentLevel) { ++currentLevel; await LocalStorage.saveData( key: MyConstants.currentLevel, value: '$currentLevel', ); } } else { playQuestionAudio(); } }); } else { playWrongAudio(); } } }