Browse Source

fix: question animation

pull/41/head
AmirrezaChegini 1 month ago
parent
commit
7612218939
  1. 4
      lib/core/routers/hero_dialog_route.dart
  2. 3
      lib/core/services/audio_service.dart
  3. 89
      lib/features/question/presentation/bloc/question_bloc.dart
  4. 53
      lib/features/question/presentation/ui/screens/answer_screen.dart
  5. 2
      lib/features/question/presentation/ui/screens/question_screen.dart

4
lib/core/routers/hero_dialog_route.dart

@ -16,13 +16,13 @@ class HeroDialogRoute<T> extends PageRoute<T> {
bool get fullscreenDialog => false;
@override
bool get barrierDismissible => true;
bool get barrierDismissible => false;
@override
Duration get transitionDuration => const Duration(seconds: 1); // Adjust as needed
@override
bool get maintainState => true;
bool get maintainState => false;
@override
Color get barrierColor => Color(0XFF322386).withValues(alpha: 0.3); // Or your desired barrier color

3
lib/core/services/audio_service.dart

@ -29,6 +29,9 @@ class AudioService {
Future<void> play() async {
try {
await _player.play();
await _player.processingStateStream
.firstWhere((s) => s == ProcessingState.completed);
return;
} catch (e) {
if (kDebugMode) {
print('$e');

89
lib/features/question/presentation/bloc/question_bloc.dart

@ -40,7 +40,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
@override
Future<void> close() {
ShowcaseView.get().unregister();
unRegisterShowCase();
return super.close();
}
@ -63,7 +63,6 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
'guide_key': GlobalKey(),
};
late final Stream<double> volumeStream;
bool isPlaying = false;
/// ------------Controllers------------
final AudioService _mainAudioService;
@ -71,27 +70,37 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
/// ------------Functions------------
void registerShowCase() {
ShowcaseView.register(
onStart: (showcaseIndex, key) {
LocalStorage.saveData(key: MyConstants.firstShowcase, value: 'true');
},
);
try {
ShowcaseView.register(
onStart: (showcaseIndex, key) {
LocalStorage.saveData(key: MyConstants.firstShowcase, value: 'true');
},
);
} catch (_) {}
}
void unRegisterShowCase() {
try {
ShowcaseView.get().unregister();
} catch (_) {}
}
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']!,
]);
try {
ShowcaseView.get().startShowCase([
showCaseKey['answer_key_1']!,
showCaseKey['notif_key_0']!,
showCaseKey['stepper_key']!,
showCaseKey['hadith_key']!,
showCaseKey['guide_key']!,
]);
} catch (_) {}
}
}
void showHadith({required BuildContext context}) {
if(isPlaying) return;
showHadithDialog(
context: context,
hadith: state.levelEntity?.hadith ?? [],
@ -112,8 +121,10 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
}
Future<void> stopMusic() async {
await _mainAudioService.stop();
await _mainAudioService.setLoopMode(isLoop: false);
await Future.wait([
_mainAudioService.stop(),
_mainAudioService.setLoopMode(isLoop: false),
]);
}
Future<void> playCorrectAudio() async {
@ -134,6 +145,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
Future<void> playQuestionAudio() async {
await _mainAudioService.setAudio(filePath: state.currentQuestion?.audio);
await _mainAudioService.play();
await showQueueAnswer();
}
Future<void> changeMute() async {
@ -143,21 +155,41 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
]);
}
Future<void> showQueueAnswer() async {
final List<AnswerEntity> answers = state.currentQuestion?.answers ?? [];
if (answers.isNotEmpty) {
answers.removeWhere((e) => e.imageId == null);
}
for (final answer in answers) {
await Future.delayed(const Duration(milliseconds: 500), () async {
if (MyContext.get.mounted) {
await showAnswerDialog(
context: MyContext.get,
answerEntity: answer,
autoClose: true,
);
}
});
}
}
Future<void> showAnswerDialog({
required BuildContext context,
required AnswerEntity answerEntity,
bool showConfetti = false,
bool autoClose = false,
}) async {
Navigator.of(context).push(
await Navigator.of(context).push(
HeroDialogRoute(
builder: (dialogContext) {
return AnswerScreen(
answerEntity: answerEntity,
onNotifTap: (answer) => playAnswerAudio(audio: answer.audio),
showConfetti: showConfetti,
autoClose: autoClose,
);
},
),
);
playAnswerAudio(audio: answerEntity.audio);
}
Future<void> getNextLevelEvent({required BuildContext context}) async {
@ -213,16 +245,11 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
if (event.chooseCorrectAnswer) {
playCorrectAudio();
await Navigator.of(MyContext.get).push(
HeroDialogRoute(
builder: (dialogContext) {
return AnswerScreen(
answerEntity: state.currentQuestion?.answers?.singleWhere((e) =>
e.order == event.correctAnswer) ?? AnswerEntity(),
showConfetti: true,
);
},
),
await showAnswerDialog(
context: MyContext.get,
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;
@ -245,7 +272,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
);
}
} else {
playQuestionAudio();
await playQuestionAudio();
}
});
} else {

53
lib/features/question/presentation/ui/screens/answer_screen.dart

@ -1,50 +1,74 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_animations.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/constants/my_constants.dart';
import 'package:hadi_hoda_flutter/core/services/audio_service.dart';
import 'package:hadi_hoda_flutter/core/utils/my_context.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/utils/set_platform_size.dart';
import 'package:hadi_hoda_flutter/core/widgets/answer_box/answer_box_show.dart';
import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart';
import 'package:hadi_hoda_flutter/init_bindings.dart';
import 'package:lottie/lottie.dart';
class AnswerScreen extends StatefulWidget {
const AnswerScreen({
super.key,
required this.answerEntity,
this.onNotifTap,
this.showConfetti = false,
required this.showConfetti,
required this.autoClose,
});
final AnswerEntity answerEntity;
final Function(AnswerEntity answer)? onNotifTap;
final bool showConfetti;
final bool autoClose;
@override
State<AnswerScreen> createState() => _AnswerScreenState();
}
class _AnswerScreenState extends State<AnswerScreen> {
final AudioService audioService = locator(
instanceName: MyConstants.mainAudioService,
);
@override
void initState() {
super.initState();
back();
initWidget();
}
Future<void> back() async {
Future<void> initWidget() async {
if (widget.showConfetti) {
await Future.delayed(Duration(seconds: 3), () {
if (MyContext.get.mounted) {
if (MyContext.get.mounted && MyContext.get.canPop()) {
MyContext.get.pop();
}
});
} else {
await playAudio();
if (widget.autoClose) {
if (MyContext.get.mounted && MyContext.get.canPop()) {
MyContext.get.pop();
}
}
}
}
Future<void> playAudio() async {
await audioService.setAudio(filePath: widget.answerEntity.audio);
await audioService.play();
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
Center(
child: Padding(
@ -56,7 +80,22 @@ class _AnswerScreenState extends State<AnswerScreen> {
child: AnswerBoxShow(
answer: widget.answerEntity,
index: widget.answerEntity.order ?? 0,
onNotifTap: widget.onNotifTap,
onNotifTap: (answer) => playAudio(),
),
),
),
Positioned(
bottom: setPlatform<double>(android: MySpaces.s30),
child: TextButton(
onPressed: () {
context.pop();
},
style: TextButton.styleFrom(
foregroundColor: MyColors.white.withValues(alpha: 0.7),
),
child: Text(
context.translate.skip,
style: MYTextStyle.button2
),
),
),

2
lib/features/question/presentation/ui/screens/question_screen.dart

@ -135,7 +135,7 @@ class QuestionScreen extends StatelessWidget {
child: SizedBox(
width: context.widthScreen,
child: Stack(
alignment: Alignment.center,
alignment: AlignmentDirectional.centerStart,
children: [
MyShowcaseWidget(
globalKey: context.read<QuestionBloc>().showCaseKey['guide_key']!,

Loading…
Cancel
Save