Browse Source

Merge pull request 'fix/bugs' (#60) from fix/bugs into develop

Reviewed-on: https://git.nwhco.ir/amirreza.chegini/hade_hoda_flutter/pulls/60
pull/61/head
amirreza.chegini 5 days ago
parent
commit
120cf88924
  1. 25
      ios/Podfile.lock
  2. 11
      lib/common_ui/theme/my_theme.dart
  3. 2
      lib/core/widgets/answer_box/answer_box_show.dart
  4. 4
      lib/core/widgets/answer_box/styles/picture_box.dart
  5. 5
      lib/core/widgets/dialog/reward_dialog.dart
  6. 22
      lib/features/intro/presentation/bloc/intro_bloc.dart
  7. 4
      lib/features/question/presentation/bloc/question_bloc.dart
  8. 79
      lib/features/question/presentation/ui/screens/question_screen.dart
  9. 1
      lib/features/question/presentation/ui/widgets/question_title.dart

25
ios/Podfile.lock

@ -8,12 +8,19 @@ PODS:
- just_audio (0.0.1): - just_audio (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- video_player_avfoundation (0.0.1):
- Flutter
- FlutterMacOS
- wakelock_plus (0.0.1):
- Flutter
- ZIPFoundation (0.9.19) - ZIPFoundation (0.9.19)
DEPENDENCIES: DEPENDENCIES:
@ -21,8 +28,11 @@ DEPENDENCIES:
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_archive (from `.symlinks/plugins/flutter_archive/ios`) - flutter_archive (from `.symlinks/plugins/flutter_archive/ios`)
- just_audio (from `.symlinks/plugins/just_audio/darwin`) - just_audio (from `.symlinks/plugins/just_audio/darwin`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
@ -37,20 +47,29 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_archive/ios" :path: ".symlinks/plugins/flutter_archive/ios"
just_audio: just_audio:
:path: ".symlinks/plugins/just_audio/darwin" :path: ".symlinks/plugins/just_audio/darwin"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation: shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin" :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
video_player_avfoundation:
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0 audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_archive: ad8edfd7f7d1bb12058d05424ba93e27d9930efe flutter_archive: ad8edfd7f7d1bb12058d05424ba93e27d9930efe
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
PODFILE CHECKSUM: 53a6aebc29ccee84c41f92f409fc20cd4ca011f1
COCOAPODS: 1.16.2 COCOAPODS: 1.16.2

11
lib/common_ui/theme/my_theme.dart

@ -1,10 +1,17 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.dart';
class MyTheme { class MyTheme {
static const MyTheme _i = MyTheme._internal(); static const MyTheme _i = MyTheme._internal();
const MyTheme._internal(); const MyTheme._internal();
factory MyTheme() => _i; factory MyTheme() => _i;
static final ThemeData light = ThemeData(brightness: Brightness.light);
static final ThemeData dark = ThemeData(brightness: Brightness.dark);
static final ThemeData light = ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: MyColors.purple,
);
static final ThemeData dark = ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: MyColors.purple,
);
} }

2
lib/core/widgets/answer_box/answer_box_show.dart

@ -34,7 +34,7 @@ class AnswerBoxShow extends StatelessWidget {
selected: false, selected: false,
index: index, index: index,
image: answer.image ?? '', image: answer.image ?? '',
autostart: Autostart.once,
autostart: Autostart.loop,
correctAnswer: 0, correctAnswer: 0,
), ),
Positioned( Positioned(

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

@ -52,7 +52,7 @@ class AnswerPictureBox extends StatelessWidget {
width: context.widthScreen, width: context.widthScreen,
height: context.heightScreen, height: context.heightScreen,
image: FileImage(File(image)), image: FileImage(File(image)),
fps: 30,
fps: 25,
autostart: autostart, autostart: autostart,
fit: BoxFit.cover, fit: BoxFit.cover,
color: MyColors.black, color: MyColors.black,
@ -63,7 +63,7 @@ class AnswerPictureBox extends StatelessWidget {
width: context.widthScreen, width: context.widthScreen,
height: context.heightScreen, height: context.heightScreen,
image: FileImage(File(image)), image: FileImage(File(image)),
fps: 30,
fps: 25,
autostart: autostart, autostart: autostart,
fit: BoxFit.cover, fit: BoxFit.cover,
), ),

5
lib/core/widgets/dialog/reward_dialog.dart

@ -89,6 +89,11 @@ class RewardDialog extends StatelessWidget {
children: [ children: [
Image.network( Image.network(
prize.imageURL ?? '', prize.imageURL ?? '',
loadingBuilder: (context, child, loadingProgress) => SizedBox(
height: 300,
width: 300,
child: child,
),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
const MyImage( const MyImage(

22
lib/features/intro/presentation/bloc/intro_bloc.dart

@ -20,6 +20,7 @@ class IntroBloc extends Bloc<IntroEvent, IntroState> {
/// ------------constructor------------ /// ------------constructor------------
IntroBloc() : super(const IntroState()) { IntroBloc() : super(const IntroState()) {
initVideos(); initVideos();
listenController();
on<InitVideosEvent>(_initVideosEvent); on<InitVideosEvent>(_initVideosEvent);
on<ChangeVideosEvent>(_changeVideosEvent); on<ChangeVideosEvent>(_changeVideosEvent);
} }
@ -70,6 +71,27 @@ class IntroBloc extends Bloc<IntroEvent, IntroState> {
} }
} }
void listenController() {
// A helper function to check for video completion
void onVideoEnd(PodPlayerController controller, int controllerIndex) {
final position = controller.videoPlayerValue?.position;
final duration = controller.videoPlayerValue?.duration;
if (position != null && duration != null && position >= duration) {
// Only trigger the change if the completed video is the current one
if (state.currentIntro == controllerIndex) {
add(ChangeVideosEvent());
}
}
}
podController1.addListener(() => onVideoEnd(podController1, 0));
podController2.addListener(() => onVideoEnd(podController2, 1));
podController3.addListener(() => onVideoEnd(podController3, 2));
podController4.addListener(() => onVideoEnd(podController4, 3));
podController5.addListener(() => onVideoEnd(podController5, 4));
}
/// ------------Api Calls------------ /// ------------Api Calls------------
FutureOr<void> _changeVideosEvent(ChangeVideosEvent event, Emitter emit) async { FutureOr<void> _changeVideosEvent(ChangeVideosEvent event, Emitter emit) async {
switch (state.currentIntro) { switch (state.currentIntro) {

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

@ -45,6 +45,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
_backgroundAudioService.dispose(); _backgroundAudioService.dispose();
answerAnimationController.dispose(); answerAnimationController.dispose();
imageAnimationController.dispose(); imageAnimationController.dispose();
scrollController.dispose();
return super.close(); return super.close();
} }
@ -76,6 +77,7 @@ 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 scrollController = ScrollController();
/// ------------Functions------------ /// ------------Functions------------
// void startScrollTitle({Duration? audioDuration}) { // void startScrollTitle({Duration? audioDuration}) {
@ -192,6 +194,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
} }
Future<void> getNextLevelEvent({required BuildContext context}) async { Future<void> getNextLevelEvent({required BuildContext context}) async {
_backgroundAudioService.dispose();
await _getNextLevelUseCase(QuestionParams()).then((value) => value.fold( await _getNextLevelUseCase(QuestionParams()).then((value) => value.fold(
(data) { (data) {
context.pushNamed( context.pushNamed(
@ -293,6 +296,7 @@ class QuestionBloc extends Bloc<QuestionEvent, QuestionState> {
answerAnimationController.reverse(); answerAnimationController.reverse();
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
imageAnimationController.forward(); imageAnimationController.forward();
scrollController.jumpTo(0);
await playQuestionAudio(); await playQuestionAudio();
imageAnimationController.reverse(); imageAnimationController.reverse();
answerAnimationController.forward().then((value) { answerAnimationController.forward().then((value) {

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

@ -3,7 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gif/gif.dart'; import 'package:gif/gif.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_colors.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/common_ui/resources/my_text_style.dart';
import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart';
import 'package:hadi_hoda_flutter/core/utils/gap.dart'; import 'package:hadi_hoda_flutter/core/utils/gap.dart';
@ -91,28 +90,30 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
} }
Widget _questionImage(BuildContext context) { Widget _questionImage(BuildContext context) {
return Column(
return FadeAnimDelayed(
duration: const Duration(seconds: 1),
child: FadeAnimController(
controller: context.read<QuestionBloc>().imageAnimationController,
child: Column(
children: [ children: [
10.0.gapHeight,
_titles(context),
const Spacer(), const Spacer(),
BlocBuilder<QuestionBloc, QuestionState>( BlocBuilder<QuestionBloc, QuestionState>(
builder: (context, state) => FadeAnimDelayed(
duration: const Duration(seconds: 1),
child: FadeAnimController(
builder: (context, state) => AnswerPictureBox(
key: Key('${state.currentQuestion?.image}'), key: Key('${state.currentQuestion?.image}'),
controller: context.read<QuestionBloc>().imageAnimationController,
child: AnswerPictureBox(
selected: false, selected: false,
showIndex: false, showIndex: false,
correctAnswer: 0, correctAnswer: 0,
index: 0, index: 0,
image: state.currentQuestion?.image ?? '', image: state.currentQuestion?.image ?? '',
autostart: Autostart.once,
),
),
autostart: Autostart.loop,
), ),
), ),
const Spacer(), const Spacer(),
], ],
),
),
); );
} }
@ -133,9 +134,8 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
return BlocBuilder<QuestionBloc, QuestionState>( return BlocBuilder<QuestionBloc, QuestionState>(
buildWhen: (previous, current) => buildWhen: (previous, current) =>
previous.currentQuestion?.id != current.currentQuestion?.id, previous.currentQuestion?.id != current.currentQuestion?.id,
builder: (context, state) => FadeAnimController(
controller: context.read<QuestionBloc>().answerAnimationController,
child: Text(
builder: (context, state) =>
Text(
state.currentQuestion?.title ?? '', state.currentQuestion?.title ?? '',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: MYTextStyle.titr1.copyWith( style: MYTextStyle.titr1.copyWith(
@ -147,37 +147,39 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
], ],
), ),
), ),
),
); );
} }
Widget _answers(BuildContext context) { Widget _answers(BuildContext context) {
return ListView( return ListView(
controller: context.read<QuestionBloc>().scrollController,
padding: const EdgeInsets.only(top: 10),
children: [ children: [
_titles(context),
30.0.gapHeight,
BlocBuilder<QuestionBloc, QuestionState>(
FadeAnimController(
controller: context.read<QuestionBloc>().answerAnimationController,
child: _titles(context),
),
50.0.gapHeight,
SizedBox(
width: context.widthScreen,
child: BlocBuilder<QuestionBloc, QuestionState>(
buildWhen: (previous, current) => buildWhen: (previous, current) =>
previous.currentQuestion?.id != current.currentQuestion?.id, previous.currentQuestion?.id != current.currentQuestion?.id,
builder: (context, state) => GridView.builder(
itemCount: state.currentQuestion?.answers?.length ?? 0,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
clipBehavior: Clip.none,
padding: EdgeInsets.symmetric(
horizontal: setSize(context: context, tablet: 70) ?? 0,
),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: MySpaces.s20,
mainAxisSpacing: 20,
childAspectRatio: 0.75,
),
itemBuilder: (context, index) =>
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 state.currentQuestion?.answers?[index].imageId == null
? const SizedBox.shrink() ? const SizedBox.shrink()
: SlideAnim(
key: Key('${state.currentQuestion?.id}'),
: SizedBox(
key: Key('${state.currentQuestion?.id}$index'),
width: 180,
height: 250,
child: SlideAnim(
controller: context.read<QuestionBloc>().answerAnimationController, controller: context.read<QuestionBloc>().answerAnimationController,
index: index, index: index,
child: AnswerBox( child: AnswerBox(
@ -198,6 +200,9 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
), ),
), ),
), ),
),
),
),
], ],
); );
} }
@ -222,8 +227,8 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
), ),
), ),
Positioned( Positioned(
left: 120,
right: 120,
left: 90,
right: 90,
child: FadeAnimController( child: FadeAnimController(
controller: context.read<QuestionBloc>().imageAnimationController, controller: context.read<QuestionBloc>().imageAnimationController,
child: TextButton( child: TextButton(
@ -236,6 +241,7 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
style: TextButton.styleFrom( style: TextButton.styleFrom(
foregroundColor: MyColors.white.withValues(alpha: 0.7), foregroundColor: MyColors.white.withValues(alpha: 0.7),
), ),
child: FittedBox(
child: Text( child: Text(
context.translate.skip, context.translate.skip,
style: MYTextStyle.button2 style: MYTextStyle.button2
@ -243,6 +249,7 @@ class _QuestionScreenState extends State<QuestionScreen> with TickerProviderStat
), ),
), ),
), ),
),
PositionedDirectional( PositionedDirectional(
end: 0, end: 0,
child: GlassyButton( child: GlassyButton(

1
lib/features/question/presentation/ui/widgets/question_title.dart

@ -23,6 +23,7 @@ class QuestionTitle extends StatelessWidget {
'${context.translate.step} ${step ?? 0}', '${context.translate.step} ${step ?? 0}',
style: MYTextStyle.titr3, style: MYTextStyle.titr3,
), ),
if ((currentQuestion ?? 0) < (questionLength ?? 0))
Text( Text(
'${context.translate.question} ${currentQuestion ?? 0}/${(questionLength ?? 0) - 1}', '${context.translate.question} ${currentQuestion ?? 0}/${(questionLength ?? 0) - 1}',
style: MYTextStyle.matn3.copyWith( style: MYTextStyle.matn3.copyWith(

Loading…
Cancel
Save