You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							227 lines
						
					
					
						
							7.4 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							227 lines
						
					
					
						
							7.4 KiB
						
					
					
				
								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<QuestionEvent, QuestionState> {
							 | 
						|
								  /// ------------constructor------------
							 | 
						|
								  QuestionBloc(
							 | 
						|
								      this._getLevelUseCase,
							 | 
						|
								      this._getNextLevelUseCase,
							 | 
						|
								      this._mainAudioService,
							 | 
						|
								      this._effectAudioService,
							 | 
						|
								      ) : super(QuestionState()) {
							 | 
						|
								    volumeStream = _mainAudioService.volumeStream();
							 | 
						|
								    stopMusic();
							 | 
						|
								    on<GetLevelEvent>(_getLevelEvent);
							 | 
						|
								    on<ChooseAnswerEvent>(_chooseAnswerEvent);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /// ------------UseCases------------
							 | 
						|
								  final GetLevelUseCase _getLevelUseCase;
							 | 
						|
								  final GetNextLevelUseCase _getNextLevelUseCase;
							 | 
						|
								
							 | 
						|
								  /// ------------Variables------------
							 | 
						|
								  final List<GlobalKey> keys = [
							 | 
						|
								    GlobalKey(),
							 | 
						|
								    GlobalKey(),
							 | 
						|
								    GlobalKey(),
							 | 
						|
								    GlobalKey(),
							 | 
						|
								  ];
							 | 
						|
								  late final Stream<double> 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<void> playDiamondAudio() async {
							 | 
						|
								    await _effectAudioService.setAudio(assetPath: MyAudios.diamondEnd);
							 | 
						|
								    await _effectAudioService.play();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  Future<void> stopMusic() async {
							 | 
						|
								    await _mainAudioService.stop();
							 | 
						|
								    await _mainAudioService.setLoopMode(isLoop: false);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  Future<void> playCorrectAudio() async {
							 | 
						|
								    await _effectAudioService.setAudio(assetPath: MyAudios.rightAnswer);
							 | 
						|
								    await _effectAudioService.play();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  Future<void> playWrongAudio() async {
							 | 
						|
								    await _effectAudioService.setAudio(assetPath: MyAudios.incorrectAnswer);
							 | 
						|
								    await _effectAudioService.play();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  Future<void> playAnswerAudio({String? audio}) async {
							 | 
						|
								    await _mainAudioService.setAudio(filePath: audio);
							 | 
						|
								    await _mainAudioService.play();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  Future<void> playQuestionAudio() async {
							 | 
						|
								    await _mainAudioService.setAudio(filePath: state.currentQuestion?.audio);
							 | 
						|
								    await _mainAudioService.play();
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  Future<void> changeMute() async {
							 | 
						|
								    await Future.wait([
							 | 
						|
								      _mainAudioService.changeMute(),
							 | 
						|
								      _effectAudioService.changeMute(),
							 | 
						|
								    ]);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  Future<void> 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<void> 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<void> _getLevelEvent(GetLevelEvent event, Emitter<QuestionState> 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<void> _chooseAnswerEvent(ChooseAnswerEvent event,
							 | 
						|
								      Emitter<QuestionState> 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();
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								}
							 |