From bbad3a9f1389f9e1806b00425ca057b22941d796 Mon Sep 17 00:00:00 2001 From: AmirrezaChegini Date: Wed, 3 Dec 2025 10:28:07 +0330 Subject: [PATCH] add: app life cycle observer --- lib/core/utils/app_life_cycle.dart | 32 +++++++++++++++++++ .../presentation/bloc/question_bloc.dart | 12 +++++++ .../ui/screens/question_screen.dart | 21 +++++++++++- lib/main.dart | 2 ++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 lib/core/utils/app_life_cycle.dart diff --git a/lib/core/utils/app_life_cycle.dart b/lib/core/utils/app_life_cycle.dart new file mode 100644 index 0000000..79f1fec --- /dev/null +++ b/lib/core/utils/app_life_cycle.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.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/init_bindings.dart'; + +class AppLifeCycleController extends WidgetsBindingObserver { + AppLifeCycleController() { + WidgetsBinding.instance.addObserver(this); + } + + void dispose() { + WidgetsBinding.instance.removeObserver(this); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + final AudioService mainAudio = locator( + instanceName: MyConstants.mainAudioService, + ); + final AudioService effect = locator( + instanceName: MyConstants.effectAudioService, + ); + + if (state == AppLifecycleState.paused || state == AppLifecycleState.inactive) { + mainAudio.pause(); + effect.pause(); + } else if (state == AppLifecycleState.resumed) { + mainAudio.play(); + effect.play(); + } + } +} diff --git a/lib/features/question/presentation/bloc/question_bloc.dart b/lib/features/question/presentation/bloc/question_bloc.dart index a78836a..f02823f 100644 --- a/lib/features/question/presentation/bloc/question_bloc.dart +++ b/lib/features/question/presentation/bloc/question_bloc.dart @@ -236,6 +236,18 @@ class QuestionBloc extends Bloc { showAnswerSequence = show; } + Future pausePlaying() async { + await _mainAudioService.pause(); + } + + Future pauseBackgroundPlaying() async { + await _backgroundAudioService.pause(); + } + + Future playBackgroundPlaying() async { + await _backgroundAudioService.play(); + } + /// ------------Event Calls------------ FutureOr _getLevelEvent(GetLevelEvent event, Emitter emit) async { await _getLevelUseCase(QuestionParams(id: int.parse(event.id ?? '0'))).then( diff --git a/lib/features/question/presentation/ui/screens/question_screen.dart b/lib/features/question/presentation/ui/screens/question_screen.dart index 39a4892..a0a8586 100644 --- a/lib/features/question/presentation/ui/screens/question_screen.dart +++ b/lib/features/question/presentation/ui/screens/question_screen.dart @@ -34,11 +34,12 @@ class QuestionScreen extends StatefulWidget { State createState() => _QuestionScreenState(); } -class _QuestionScreenState extends State with TickerProviderStateMixin { +class _QuestionScreenState extends State with TickerProviderStateMixin, WidgetsBindingObserver { @override void initState() { super.initState(); + WidgetsBinding.instance.addObserver(this); context.read().answerAnimationController = AnimationController( vsync: this, duration: Duration(milliseconds: 500), @@ -55,6 +56,22 @@ class _QuestionScreenState extends State with TickerProviderStat } } + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + if(state == AppLifecycleState.paused || state == AppLifecycleState.inactive){ + context.read().pauseBackgroundPlaying(); + } else if (state == AppLifecycleState.resumed) { + context.read().playBackgroundPlaying(); + } + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + @override Widget build(BuildContext context) { return Column( @@ -145,6 +162,7 @@ class _QuestionScreenState extends State with TickerProviderStat itemCount: state.currentQuestion?.answers?.length ?? 0, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, + clipBehavior: Clip.none, padding: EdgeInsets.symmetric( horizontal: setSize(context: context, tablet: 70) ?? 0, ), @@ -219,6 +237,7 @@ class _QuestionScreenState extends State with TickerProviderStat context.read().imageAnimationController.reverse(); context.read().answerAnimationController.forward(); context.read().showingAnswerSequence(show: false); + context.read().pausePlaying(); }, style: TextButton.styleFrom( foregroundColor: MyColors.white.withValues(alpha: 0.7), diff --git a/lib/main.dart b/lib/main.dart index b9bd653..b09833c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart'; import 'package:hadi_hoda_flutter/common_ui/theme/theme_service.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; +import 'package:hadi_hoda_flutter/core/utils/app_life_cycle.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; import 'package:hadi_hoda_flutter/core/utils/my_device.dart'; import 'package:hadi_hoda_flutter/core/utils/storage_path.dart'; @@ -17,6 +18,7 @@ import 'features/app/presentation/bloc/app_state.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + AppLifeCycleController(); initBindings(); await Future.wait([ LocalStorage.init(), -- 2.30.2