From 52716d23786140a140cad3f1a221483a33acd5df Mon Sep 17 00:00:00 2001 From: AmirrezaChegini Date: Sat, 20 Dec 2025 11:48:53 +0330 Subject: [PATCH] fix: question animations --- ios/Runner/Info.plist | 5 + .../answer_box/styles/picture_box.dart | 33 +++-- .../presentation/bloc/question_bloc.dart | 29 ++-- .../ui/screens/question_screen.dart | 134 +++++++++--------- pubspec.yaml | 2 +- 5 files changed, 104 insertions(+), 99 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 4d55364..3291dc0 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,11 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName diff --git a/lib/core/widgets/answer_box/styles/picture_box.dart b/lib/core/widgets/answer_box/styles/picture_box.dart index b5d34f5..6566b12 100644 --- a/lib/core/widgets/answer_box/styles/picture_box.dart +++ b/lib/core/widgets/answer_box/styles/picture_box.dart @@ -19,6 +19,7 @@ class AnswerPictureBox extends StatelessWidget { required this.correctAnswer, this.onTap, this.autostart = Autostart.no, + this.showIndex = true, }); final bool selected; @@ -27,6 +28,7 @@ class AnswerPictureBox extends StatelessWidget { final int correctAnswer; final VoidCallback? onTap; final Autostart autostart; + final bool showIndex; @override Widget build(BuildContext context) { @@ -72,25 +74,26 @@ class AnswerPictureBox extends StatelessWidget { ), ), ), - PositionedDirectional( - top: 0, - child: Container( - width: MySpaces.s34, - alignment: Alignment.center, - decoration: BoxDecoration( - color: Color(0XFFF2F7FF), - borderRadius: BorderRadius.vertical( - bottom: Radius.circular(10), + if (showIndex) + PositionedDirectional( + top: 0, + child: Container( + width: MySpaces.s34, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFFF2F7FF), + borderRadius: BorderRadius.vertical( + bottom: Radius.circular(10), + ), ), - ), - child: Text( - '$index', - style: MYTextStyle.titr1.copyWith( - color: Color(0XFF9B85D8), + child: Text( + '$index', + style: MYTextStyle.titr1.copyWith( + color: Color(0XFF9B85D8), + ), ), ), ), - ), if(selected) PositionedDirectional( top: setSize(context: context, mobile: MySpaces.s8, tablet: MySpaces.s20), diff --git a/lib/features/question/presentation/bloc/question_bloc.dart b/lib/features/question/presentation/bloc/question_bloc.dart index 4fe07d3..08873ad 100644 --- a/lib/features/question/presentation/bloc/question_bloc.dart +++ b/lib/features/question/presentation/bloc/question_bloc.dart @@ -45,7 +45,6 @@ class QuestionBloc extends Bloc { _backgroundAudioService.dispose(); answerAnimationController.dispose(); imageAnimationController.dispose(); - titleController.dispose(); return super.close(); } @@ -77,16 +76,20 @@ class QuestionBloc extends Bloc { final AudioService _effectAudioService; late final AnimationController answerAnimationController; late final AnimationController imageAnimationController; - final ScrollController titleController = ScrollController(); /// ------------Functions------------ - void startScrollTitle({Duration? audioDuration}) { - if (audioDuration == null || audioDuration == Duration.zero) return; - titleController.animateTo( - titleController.position.maxScrollExtent, - duration: audioDuration, - curve: Curves.linear - ); + // void startScrollTitle({Duration? audioDuration}) { + // if (audioDuration == null || audioDuration == Duration.zero) return; + // titleController.animateTo( + // titleController.position.maxScrollExtent, + // duration: audioDuration, + // curve: Curves.linear + // ); + // } + + Future showImageWithDelayed() async { + await Future.delayed(const Duration(milliseconds: 500)); + imageAnimationController.forward(); } void showHadith({required BuildContext context}) { @@ -136,11 +139,7 @@ class QuestionBloc extends Bloc { } Future playQuestionAudio() async { - if(titleController.hasClients){ - titleController.jumpTo(0); - } - Duration? duration = await _mainAudioService.setAudio(filePath: state.currentQuestion?.audio); - startScrollTitle(audioDuration: duration); + await _mainAudioService.setAudio(filePath: state.currentQuestion?.audio); await _mainAudioService.play(); } @@ -262,7 +261,6 @@ class QuestionBloc extends Bloc { emit(state.copyWith(correctAnswer: event.chooseCorrectAnswer)); if (event.chooseCorrectAnswer) { - answerAnimationController.reverse(); await showAnswerDialog( context: MyContext.get, correctAudio: state.currentQuestion?.correctAudio, @@ -292,6 +290,7 @@ class QuestionBloc extends Bloc { } } else { showingAnswerSequence(show: true); + answerAnimationController.reverse(); imageAnimationController.forward(); await playQuestionAudio(); imageAnimationController.reverse(); diff --git a/lib/features/question/presentation/ui/screens/question_screen.dart b/lib/features/question/presentation/ui/screens/question_screen.dart index d0d1afb..ba2f40b 100644 --- a/lib/features/question/presentation/ui/screens/question_screen.dart +++ b/lib/features/question/presentation/ui/screens/question_screen.dart @@ -76,8 +76,6 @@ class _QuestionScreenState extends State with TickerProviderStat return Column( children: [ _stepper(), - _titles(context), - MySpaces.s20.gapHeight, Expanded( child: Stack( children: [ @@ -95,11 +93,13 @@ class _QuestionScreenState extends State with TickerProviderStat return Column( children: [ Spacer(), - FadeAnimController( - controller: context.read().imageAnimationController, - child: BlocBuilder( - builder: (context, state) => AnswerPictureBox( + BlocBuilder( + builder: (context, state) => FadeAnimController( + key: Key('${state.currentQuestion?.image}'), + controller: context.read().imageAnimationController, + child: AnswerPictureBox( selected: false, + showIndex: false, correctAnswer: 0, index: 0, image: state.currentQuestion?.image ?? '', @@ -128,75 +128,73 @@ class _QuestionScreenState extends State with TickerProviderStat Widget _titles(BuildContext context) { return BlocBuilder( buildWhen: (previous, current) => - previous.currentQuestion?.id != current.currentQuestion?.id, - builder: (context, state) => - FadeAnim( - child: SizedBox( - height: 100, - child: ListView( - controller: context.read().titleController, - children: [ - Text( - state.currentQuestion?.title ?? '', - textAlign: TextAlign.center, - style: MYTextStyle.titr1.copyWith( - shadows: [ - BoxShadow( - offset: Offset(0, 2), - color: MyColors.black.withValues(alpha: 0.25), - ), - ], - ), - ), - ], + previous.currentQuestion?.id != current.currentQuestion?.id, + builder: (context, state) => FadeAnimController( + controller: context.read().answerAnimationController, + child: Text( + state.currentQuestion?.title ?? '', + textAlign: TextAlign.center, + style: MYTextStyle.titr1.copyWith( + shadows: [ + BoxShadow( + offset: Offset(0, 2), + color: MyColors.black.withValues(alpha: 0.25), ), - ), + ], ), + ), + ), ); } Widget _answers(BuildContext context) { - return BlocBuilder( - buildWhen: (previous, current) => - previous.currentQuestion?.id != current.currentQuestion?.id, - builder: (context, state) => GridView.builder( - itemCount: state.currentQuestion?.answers?.length ?? 0, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - clipBehavior: Clip.none, - padding: EdgeInsets.symmetric( - horizontal: setSize(context: context, tablet: 70) ?? 0, - ), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: MySpaces.s20, - mainAxisSpacing: 20, - childAspectRatio: 0.75, + return ListView( + children: [ + _titles(context), + 30.0.gapHeight, + BlocBuilder( + buildWhen: (previous, current) => + previous.currentQuestion?.id != current.currentQuestion?.id, + builder: (context, state) => GridView.builder( + itemCount: state.currentQuestion?.answers?.length ?? 0, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + clipBehavior: Clip.none, + padding: EdgeInsets.symmetric( + horizontal: setSize(context: context, tablet: 70) ?? 0, + ), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: MySpaces.s20, + mainAxisSpacing: 20, + childAspectRatio: 0.75, + ), + itemBuilder: (context, index) => + state.currentQuestion?.answers?[index].imageId == null + ? SizedBox.shrink() + : SlideAnim( + key: Key('${state.currentQuestion?.id}'), + controller: context.read().answerAnimationController, + index: index, + child: AnswerBox( + index: state.currentQuestion?.answers?[index].order ?? 1, + answer: state.currentQuestion?.answers?[index] ?? AnswerEntity(), + correctAnswer: state.currentQuestion?.correctAnswer ?? 0, + onNotifTap: (AnswerEntity answer) { + context.read().showAnswerDialog( + context: context, + answerEntity: answer, + ); + }, + onTap: (isCorrect, correctAnswer) => + context.read().add( + ChooseAnswerEvent(isCorrect, correctAnswer, context), + ), + ), + ), + ), ), - itemBuilder: (context, index) => - state.currentQuestion?.answers?[index].imageId == null - ? SizedBox.shrink() - : SlideAnim( - key: Key('${state.currentQuestion?.id}'), - controller: context.read().answerAnimationController, - index: index, - child: AnswerBox( - index: state.currentQuestion?.answers?[index].order ?? 1, - answer: state.currentQuestion?.answers?[index] ?? AnswerEntity(), - correctAnswer: state.currentQuestion?.correctAnswer ?? 0, - onNotifTap: (AnswerEntity answer) { - context.read().showAnswerDialog( - context: context, - answerEntity: answer, - ); - }, - onTap: (isCorrect, correctAnswer) => - context.read().add( - ChooseAnswerEvent(isCorrect, correctAnswer, context), - ), - ), - ), - ), + ], ); } diff --git a/pubspec.yaml b/pubspec.yaml index 6522277..5be1773 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hadi_hoda_flutter description: "A new Flutter project." publish_to: 'none' -version: 0.2.0+1 +version: 0.2.1+1 environment: sdk: ^3.9.2