Browse Source

fix: question animations

pull/54/head
AmirrezaChegini 1 week ago
parent
commit
52716d2378
  1. 5
      ios/Runner/Info.plist
  2. 33
      lib/core/widgets/answer_box/styles/picture_box.dart
  3. 29
      lib/features/question/presentation/bloc/question_bloc.dart
  4. 134
      lib/features/question/presentation/ui/screens/question_screen.dart
  5. 2
      pubspec.yaml

5
ios/Runner/Info.plist

@ -2,6 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>

33
lib/core/widgets/answer_box/styles/picture_box.dart

@ -19,6 +19,7 @@ class AnswerPictureBox extends StatelessWidget {
required this.correctAnswer, required this.correctAnswer,
this.onTap, this.onTap,
this.autostart = Autostart.no, this.autostart = Autostart.no,
this.showIndex = true,
}); });
final bool selected; final bool selected;
@ -27,6 +28,7 @@ class AnswerPictureBox extends StatelessWidget {
final int correctAnswer; final int correctAnswer;
final VoidCallback? onTap; final VoidCallback? onTap;
final Autostart autostart; final Autostart autostart;
final bool showIndex;
@override @override
Widget build(BuildContext context) { 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) if(selected)
PositionedDirectional( PositionedDirectional(
top: setSize(context: context, mobile: MySpaces.s8, tablet: MySpaces.s20), top: setSize(context: context, mobile: MySpaces.s8, tablet: MySpaces.s20),

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

@ -45,7 +45,6 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
_backgroundAudioService.dispose(); _backgroundAudioService.dispose();
answerAnimationController.dispose(); answerAnimationController.dispose();
imageAnimationController.dispose(); imageAnimationController.dispose();
titleController.dispose();
return super.close(); return super.close();
} }
@ -77,16 +76,20 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
final AudioService _effectAudioService; final AudioService _effectAudioService;
late final AnimationController answerAnimationController; late final AnimationController answerAnimationController;
late final AnimationController imageAnimationController; late final AnimationController imageAnimationController;
final ScrollController titleController = ScrollController();
/// ------------Functions------------ /// ------------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<void> showImageWithDelayed() async {
await Future.delayed(const Duration(milliseconds: 500));
imageAnimationController.forward();
} }
void showHadith({required BuildContext context}) { void showHadith({required BuildContext context}) {
@ -136,11 +139,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
} }
Future<void> playQuestionAudio() async { Future<void> 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(); await _mainAudioService.play();
} }
@ -262,7 +261,6 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
emit(state.copyWith(correctAnswer: event.chooseCorrectAnswer)); emit(state.copyWith(correctAnswer: event.chooseCorrectAnswer));
if (event.chooseCorrectAnswer) { if (event.chooseCorrectAnswer) {
answerAnimationController.reverse();
await showAnswerDialog( await showAnswerDialog(
context: MyContext.get, context: MyContext.get,
correctAudio: state.currentQuestion?.correctAudio, correctAudio: state.currentQuestion?.correctAudio,
@ -292,6 +290,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
} }
} else { } else {
showingAnswerSequence(show: true); showingAnswerSequence(show: true);
answerAnimationController.reverse();
imageAnimationController.forward(); imageAnimationController.forward();
await playQuestionAudio(); await playQuestionAudio();
imageAnimationController.reverse(); imageAnimationController.reverse();

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

@ -76,8 +76,6 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
return Column( return Column(
children: [ children: [
_stepper(), _stepper(),
_titles(context),
MySpaces.s20.gapHeight,
Expanded( Expanded(
child: Stack( child: Stack(
children: [ children: [
@ -95,11 +93,13 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
return Column( return Column(
children: [ children: [
Spacer(), Spacer(),
FadeAnimController(
controller: context.read<QuestionBloc>().imageAnimationController,
child: BlocBuilder<QuestionBloc, QuestionState>(
builder: (context, state) => AnswerPictureBox(
BlocBuilder<QuestionBloc, QuestionState>(
builder: (context, state) => FadeAnimController(
key: Key('${state.currentQuestion?.image}'),
controller: context.read<QuestionBloc>().imageAnimationController,
child: AnswerPictureBox(
selected: false, selected: false,
showIndex: false,
correctAnswer: 0, correctAnswer: 0,
index: 0, index: 0,
image: state.currentQuestion?.image ?? '', image: state.currentQuestion?.image ?? '',
@ -128,75 +128,73 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
Widget _titles(BuildContext context) { Widget _titles(BuildContext context) {
return BlocBuilder<QuestionBloc, QuestionState>( return BlocBuilder<QuestionBloc, QuestionState>(
buildWhen: (previous, current) => buildWhen: (previous, current) =>
previous.currentQuestion?.id != current.currentQuestion?.id,
builder: (context, state) =>
FadeAnim(
child: SizedBox(
height: 100,
child: ListView(
controller: context.read<QuestionBloc>().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<QuestionBloc>().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) { Widget _answers(BuildContext context) {
return BlocBuilder<QuestionBloc, QuestionState>(
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<QuestionBloc, QuestionState>(
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<QuestionBloc>().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<QuestionBloc>().showAnswerDialog(
context: context,
answerEntity: answer,
);
},
onTap: (isCorrect, correctAnswer) =>
context.read<QuestionBloc>().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<QuestionBloc>().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<QuestionBloc>().showAnswerDialog(
context: context,
answerEntity: answer,
);
},
onTap: (isCorrect, correctAnswer) =>
context.read<QuestionBloc>().add(
ChooseAnswerEvent(isCorrect, correctAnswer, context),
),
),
),
),
],
); );
} }

2
pubspec.yaml

@ -1,7 +1,7 @@
name: hadi_hoda_flutter name: hadi_hoda_flutter
description: "A new Flutter project." description: "A new Flutter project."
publish_to: 'none' publish_to: 'none'
version: 0.2.0+1
version: 0.2.1+1
environment: environment:
sdk: ^3.9.2 sdk: ^3.9.2

Loading…
Cancel
Save