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.
258 lines
8.3 KiB
258 lines
8.3 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();
|
|
registerShowCase();
|
|
on<GetLevelEvent>(_getLevelEvent);
|
|
on<ChooseAnswerEvent>(_chooseAnswerEvent);
|
|
}
|
|
|
|
@override
|
|
Future<void> close() {
|
|
ShowcaseView.get().unregister();
|
|
return super.close();
|
|
}
|
|
|
|
/// ------------UseCases------------
|
|
final GetLevelUseCase _getLevelUseCase;
|
|
final GetNextLevelUseCase _getNextLevelUseCase;
|
|
|
|
/// ------------Variables------------
|
|
final Map<String, GlobalKey> showCaseKey = {
|
|
'answer_key_0': GlobalKey(),
|
|
'answer_key_1': GlobalKey(),
|
|
'answer_key_2': GlobalKey(),
|
|
'answer_key_3': GlobalKey(),
|
|
'notif_key_0': GlobalKey(),
|
|
'notif_key_1': GlobalKey(),
|
|
'notif_key_2': GlobalKey(),
|
|
'notif_key_3': GlobalKey(),
|
|
'stepper_key': GlobalKey(),
|
|
'hadith_key': GlobalKey(),
|
|
'guide_key': GlobalKey(),
|
|
};
|
|
late final Stream<double> volumeStream;
|
|
bool isPlaying = false;
|
|
|
|
/// ------------Controllers------------
|
|
final AudioService _mainAudioService;
|
|
final AudioService _effectAudioService;
|
|
|
|
/// ------------Functions------------
|
|
void registerShowCase() {
|
|
ShowcaseView.register(
|
|
onStart: (showcaseIndex, key) {
|
|
LocalStorage.saveData(key: MyConstants.firstShowcase, value: 'true');
|
|
},
|
|
);
|
|
}
|
|
|
|
void startShowcase() {
|
|
if (LocalStorage.readData(key: MyConstants.firstShowcase) != 'true') {
|
|
ShowcaseView.get().startShowCase([
|
|
showCaseKey['answer_key_1']!,
|
|
showCaseKey['notif_key_0']!,
|
|
showCaseKey['stepper_key']!,
|
|
showCaseKey['hadith_key']!,
|
|
showCaseKey['guide_key']!,
|
|
]);
|
|
}
|
|
}
|
|
|
|
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();
|
|
startShowcase();
|
|
},
|
|
(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();
|
|
}
|
|
}
|
|
}
|