Browse Source

fix: question image

pull/62/head
AmirrezaChegini 5 days ago
parent
commit
d84a3cc992
  1. 5
      lib/features/question/data/datasource/question_datasource.dart
  2. 47
      lib/features/question/presentation/bloc/question_bloc.dart
  3. 1
      lib/features/question/presentation/ui/question_page.dart
  4. 252
      lib/features/question/presentation/ui/screens/question_screen.dart
  5. 2
      pubspec.yaml

5
lib/features/question/data/datasource/question_datasource.dart

@ -48,7 +48,10 @@ class QuestionDatasourceImpl implements IQuestionDatasource {
(e) => e.code == selectedLanguage,
orElse: () => TotalDataEntity(),
);
if(index > (findData.nodes?.length ?? 0)){
final List<NodeEntity>? levelList = findData.nodes?.where(
(e) => e.nodeType == NodeType.level,
).toList();
if(index > (levelList?.length ?? 0)){
throw const MyException();
}
final NodeEntity? findLevel = findData.nodes?.singleWhere(

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

@ -31,7 +31,6 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
this._effectAudioService,
) : super(const QuestionState()) {
volumeStream = _mainAudioService.volumeStream();
playingStream = _mainAudioService.playingStream();
initAudios();
on<GetLevelEvent>(_getLevelEvent);
on<ChooseAnswerEvent>(_chooseAnswerEvent);
@ -43,8 +42,8 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
_mainAudioService.setVolume(volume: MyConstants.musicAudioVolume);
}
_backgroundAudioService.dispose();
answerAnimationController.dispose();
imageAnimationController.dispose();
answerAnimationController?.dispose();
imageAnimationController?.dispose();
scrollController.dispose();
return super.close();
}
@ -67,16 +66,15 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
'hadith_key': GlobalKey(),
'guide_key': GlobalKey(),
};
late final Stream<double> volumeStream;
late final Stream<bool> playingStream;
Stream<double>? volumeStream;
bool showAnswerSequence = true;
/// ------------Controllers------------
final AudioService _mainAudioService;
final AudioService _backgroundAudioService = AudioService(volume: 0);
final AudioService _effectAudioService;
late final AnimationController answerAnimationController;
late final AnimationController imageAnimationController;
AnimationController? answerAnimationController;
AnimationController? imageAnimationController;
final ScrollController scrollController = ScrollController();
/// ------------Functions------------
@ -89,10 +87,10 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
// );
// }
Future<void> showImageWithDelayed() async {
await Future.delayed(const Duration(milliseconds: 500));
imageAnimationController.forward();
}
// Future<void> showImageWithDelayed() async {
// await Future.delayed(const Duration(milliseconds: 500));
// imageAnimationController?.forward();
// }
void showHadith({required BuildContext context}) {
showHadithDialog(
@ -194,15 +192,10 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
}
Future<void> getNextLevelEvent({required BuildContext context}) async {
_backgroundAudioService.dispose();
await _getNextLevelUseCase(QuestionParams()).then((value) => value.fold(
(data) {
context.pushNamed(
Routes.questionPage,
pathParameters: {'id': '${data.id}'},
);
},
(error) {
await _getNextLevelUseCase(QuestionParams()).then((value) =>
value.fold((data) {
add(GetLevelEvent('${data.id}', context));
}, (error) {
goToLevelPage(context: MyContext.get);
},
),
@ -244,10 +237,12 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
getQuestionStatus: const BaseComplete(''),
levelEntity: level,
currentQuestion: data.questions?.first,
showAnswers: false,
correctAnswer: false,
));
await playQuestionAudio();
imageAnimationController.reverse();
answerAnimationController.forward().then((value) {
imageAnimationController?.reverse();
answerAnimationController?.forward().then((value) {
showQueueAnswer();
});
},
@ -271,6 +266,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
e.order == event.correctAnswer) ?? AnswerEntity(),
showConfetti: true,
);
answerAnimationController?.reverse();
await Future.delayed(const Duration(seconds: 1), () async {
final QuestionEntity? findPreQuestion = state.currentQuestion;
final int findIndex = (findPreQuestion?.order ?? 1);
@ -293,13 +289,12 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
}
} else {
showingAnswerSequence(show: true);
answerAnimationController.reverse();
await Future.delayed(const Duration(seconds: 1));
imageAnimationController.forward();
imageAnimationController?.forward();
scrollController.jumpTo(0);
await playQuestionAudio();
imageAnimationController.reverse();
answerAnimationController.forward().then((value) {
imageAnimationController?.reverse();
answerAnimationController?.forward().then((value) {
showQueueAnswer();
});
}

1
lib/features/question/presentation/ui/question_page.dart

@ -22,6 +22,7 @@ class QuestionPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: MyPopScope(
backHome: true,
child: Directionality(
textDirection: TextDirection.ltr,
child: Container(

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

@ -1,3 +1,4 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gif/gif.dart';
@ -33,8 +34,8 @@ class QuestionScreen extends StatefulWidget {
State<QuestionScreen> createState() => _QuestionScreenState();
}
class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStateMixin, WidgetsBindingObserver {
class _QuestionScreenState extends State<QuestionScreen>
with TickerProviderStateMixin, WidgetsBindingObserver {
@override
void initState() {
super.initState();
@ -50,15 +51,16 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
duration: const Duration(milliseconds: 500),
reverseDuration: const Duration(milliseconds: 500),
);
if(LocalStorage.readData(key: MyConstants.firstShowcase) == 'true') {
context.read<QuestionBloc>().imageAnimationController.forward();
if (LocalStorage.readData(key: MyConstants.firstShowcase) == 'true') {
context.read<QuestionBloc>().imageAnimationController?.forward();
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if(state == AppLifecycleState.paused || state == AppLifecycleState.inactive){
if (state == AppLifecycleState.paused ||
state == AppLifecycleState.inactive) {
context.read<QuestionBloc>().pauseBackgroundPlaying();
} else if (state == AppLifecycleState.resumed) {
context.read<QuestionBloc>().playBackgroundPlaying();
@ -93,12 +95,11 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
return FadeAnimDelayed(
duration: const Duration(seconds: 1),
child: FadeAnimController(
controller: context.read<QuestionBloc>().imageAnimationController,
controller: context.read<QuestionBloc>().imageAnimationController!,
child: Column(
children: [
10.0.gapHeight,
_titles(context),
const Spacer(),
20.0.gapHeight,
BlocBuilder<QuestionBloc, QuestionState>(
builder: (context, state) => AnswerPictureBox(
key: Key('${state.currentQuestion?.image}'),
@ -110,7 +111,6 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
autostart: Autostart.loop,
),
),
const Spacer(),
],
),
),
@ -134,10 +134,12 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
return BlocBuilder<QuestionBloc, QuestionState>(
buildWhen: (previous, current) =>
previous.currentQuestion?.id != current.currentQuestion?.id,
builder: (context, state) =>
Text(
builder: (context, state) => AutoSizeText(
state.currentQuestion?.title ?? '',
textAlign: TextAlign.center,
minFontSize: 16,
maxFontSize: 20,
maxLines: 8,
style: MYTextStyle.titr1.copyWith(
shadows: [
BoxShadow(
@ -156,7 +158,7 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
padding: const EdgeInsets.only(top: 10),
children: [
FadeAnimController(
controller: context.read<QuestionBloc>().answerAnimationController,
controller: context.read<QuestionBloc>().answerAnimationController!,
child: _titles(context),
),
50.0.gapHeight,
@ -165,27 +167,37 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
child: BlocBuilder<QuestionBloc, QuestionState>(
buildWhen: (previous, current) =>
previous.currentQuestion?.id != current.currentQuestion?.id,
builder: (context, state) =>
Wrap(
alignment: WrapAlignment.center,
spacing: 10,
runSpacing: 20,
children: List.generate(
state.currentQuestion?.answers?.length ?? 0,
(index) =>
state.currentQuestion?.answers?[index].imageId == null
? const SizedBox.shrink()
: SizedBox(
key: Key('${state.currentQuestion?.id}$index'),
builder: (context, state) => Column(
spacing: 30,
children: [
Row(
key: Key('${state.currentQuestion?.id}answer0'),
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Builder(
key: Key('${state.currentQuestion?.id}0'),
builder: (context) {
if (state.currentQuestion?.answers?[0].imageId ==
null) {
return const SizedBox.shrink();
} else {
return SizedBox(
width: 180,
height: 250,
child: SlideAnim(
controller: context.read<QuestionBloc>().answerAnimationController,
index: index,
controller: context
.read<QuestionBloc>()
.answerAnimationController!,
index: 0,
child: AnswerBox(
index: state.currentQuestion?.answers?[index].order ?? 1,
answer: state.currentQuestion?.answers?[index] ?? AnswerEntity(),
correctAnswer: state.currentQuestion?.correctAnswer ?? 0,
index:
state.currentQuestion?.answers?[0].order ??
1,
answer:
state.currentQuestion?.answers?[0] ??
AnswerEntity(),
correctAnswer:
state.currentQuestion?.correctAnswer ?? 0,
onNotifTap: (AnswerEntity answer) {
context.read<QuestionBloc>().showAnswerDialog(
context: context,
@ -194,12 +206,174 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
},
onTap: (isCorrect, correctAnswer) =>
context.read<QuestionBloc>().add(
ChooseAnswerEvent(isCorrect, correctAnswer, context),
ChooseAnswerEvent(
isCorrect,
correctAnswer,
context,
),
),
),
),
);
}
},
),
Builder(
key: Key('${state.currentQuestion?.id}1'),
builder: (context) {
if (state.currentQuestion?.answers?[1].imageId ==
null) {
return const SizedBox.shrink();
} else {
return SizedBox(
width: 180,
height: 250,
child: SlideAnim(
controller: context
.read<QuestionBloc>()
.answerAnimationController!,
index: 1,
child: AnswerBox(
index:
state.currentQuestion?.answers?[1].order ??
1,
answer:
state.currentQuestion?.answers?[1] ??
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,
),
),
),
),
);
}
},
),
],
),
Row(
key: Key('${state.currentQuestion?.id}answer1'),
mainAxisAlignment:
(state.currentQuestion?.answers?.length ?? 0) > 3
? MainAxisAlignment.spaceBetween
: MainAxisAlignment.center,
children: [
if ((state.currentQuestion?.answers?.length ?? 0) > 2)
Builder(
key: Key('${state.currentQuestion?.id}2'),
builder: (context) {
if (state.currentQuestion?.answers?[2].imageId ==
null) {
return const SizedBox.shrink();
} else {
return SizedBox(
width: 180,
height: 250,
child: SlideAnim(
controller: context
.read<QuestionBloc>()
.answerAnimationController!,
index: 2,
child: AnswerBox(
index:
state
.currentQuestion
?.answers?[2]
.order ??
1,
answer:
state.currentQuestion?.answers?[2] ??
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,
),
),
),
),
);
}
},
),
if ((state.currentQuestion?.answers?.length ?? 0) > 3)
Builder(
key: Key('${state.currentQuestion?.id}1'),
builder: (context) {
if (state.currentQuestion?.answers?[3].imageId ==
null) {
return const SizedBox.shrink();
} else {
return SizedBox(
width: 180,
height: 250,
child: SlideAnim(
controller: context
.read<QuestionBloc>()
.answerAnimationController!,
index: 3,
child: AnswerBox(
index:
state
.currentQuestion
?.answers?[3]
.order ??
1,
answer:
state.currentQuestion?.answers?[3] ??
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,
),
),
),
),
);
}
},
),
],
),
],
),
),
),
@ -214,27 +388,23 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
child: Stack(
alignment: AlignmentDirectional.centerStart,
children: [
StreamBuilder<bool>(
initialData: false,
stream: context.read<QuestionBloc>().playingStream,
builder: (context, snapshot) => GlobeAnimation(
state: snapshot.data ?? false,
GlobeAnimation(
state: true,
child: MyImage(
image: MyAssets.globe,
fit: BoxFit.cover,
size: setSize(context: context, tablet: 120),
),
),
),
Positioned(
left: 90,
right: 90,
child: FadeAnimController(
controller: context.read<QuestionBloc>().imageAnimationController,
controller: context.read<QuestionBloc>().imageAnimationController!,
child: TextButton(
onPressed: () async {
context.read<QuestionBloc>().imageAnimationController.reverse();
context.read<QuestionBloc>().answerAnimationController.forward();
context.read<QuestionBloc>().imageAnimationController?.reverse();
context.read<QuestionBloc>().answerAnimationController?.forward();
context.read<QuestionBloc>().showingAnswerSequence(show: false);
context.read<QuestionBloc>().pausePlaying();
},
@ -244,10 +414,10 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
child: FittedBox(
child: Text(
context.translate.skip,
style: MYTextStyle.button2
),
style: MYTextStyle.button2,
),
),
)
),
),
PositionedDirectional(

2
pubspec.yaml

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

Loading…
Cancel
Save