diff --git a/lib/pages/games/bloc.dart b/lib/pages/games/bloc.dart index a118794..3570c72 100644 --- a/lib/pages/games/bloc.dart +++ b/lib/pages/games/bloc.dart @@ -2,17 +2,17 @@ import 'package:bloc/bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; import 'event.dart'; import 'game_entity.dart'; import 'state.dart'; class GamesBloc extends Bloc { - late MethodChannel _methodChannel; //手动初始化4个GameEntity对象 - final List _games = [ + final List _games = [ GameEntity() ..id = 1 ..imageName = 'game_food_1'.assetPng @@ -31,7 +31,7 @@ class GamesBloc extends Bloc { ..name = 'Animal' ]; - List get listData => _games; + List get listData => _games; GamesBloc() : super(GamesState().init()) { on(_init); @@ -39,13 +39,16 @@ class GamesBloc extends Bloc { } void _init(InitEvent event, Emitter emit) async { + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy); emit(state.clone()); } void _gotoGamePage(GotoGamePageEvent event, Emitter emit) async { + AudioPlayerUtil.getInstance().pause(); try { _methodChannel = const MethodChannel('wow_english/game_method_channel'); - await _methodChannel.invokeMethod('openGamePage', { "gameId": event.gameId }); + await _methodChannel + .invokeMethod('openGamePage', {"gameId": event.gameId}); } on PlatformException catch (e) { debugPrint("Failed to go to native page: '${e.message}'."); } diff --git a/lib/pages/home/bloc.dart b/lib/pages/home/bloc.dart index 6c6333f..38141ae 100644 --- a/lib/pages/home/bloc.dart +++ b/lib/pages/home/bloc.dart @@ -2,6 +2,7 @@ import 'package:audioplayers/audioplayers.dart'; import 'package:bloc/bloc.dart'; import 'package:wow_english/common/core/user_util.dart'; import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; import '../../common/core/app_config_helper.dart'; import '../../common/request/dao/system_dao.dart'; @@ -17,16 +18,10 @@ class HomeBloc extends Bloc { } bool exchangeResult = false; - late AudioPlayer audioPlayer; - late AudioPlayer studyPlayer; - late AudioPlayer gamePlayer; void _init(InitEvent event, Emitter emit) async { if (UserUtil.isLogined()) { - audioPlayer = AudioPlayer(playerId: 'audio'); - gamePlayer = AudioPlayer(playerId: 'game'); - studyPlayer = AudioPlayer(playerId: 'study'); - audioPlayer.play(AssetSource('welcome_to_wow'.assetMp3)); + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.welcomeToWow); } await _checkUpdate(emit); } diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index 6f54e3f..41515e2 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -12,6 +12,7 @@ import 'package:wow_english/pages/home/state.dart'; import 'package:wow_english/pages/home/widgets/BaseHomeHeaderWidget.dart'; import 'package:wow_english/pages/shop/exchane/bloc/exchange_lesson_bloc.dart'; import 'package:wow_english/pages/user/bloc/user_bloc.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; import '../../common/core/user_util.dart'; import '../../common/dialogs/show_dialog.dart'; @@ -60,6 +61,8 @@ class _HomePageView extends StatelessWidget { children: [ BaseHomeHeaderWidget( callBack: (value) => { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.touch), bloc.exchangeResult = value['exchange'], bloc.add(ExchangeSuccessEvent()) }), @@ -71,8 +74,8 @@ class _HomePageView extends StatelessWidget { child: GestureDetector( onTap: () { _checkPermission(() { - bloc.studyPlayer - .play(AssetSource('class_time'.assetMp3)); + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.classTime); Future.delayed(const Duration(seconds: 1), () { pushNamed(AppRouteName.courseUnit) .then((value) => { @@ -108,29 +111,38 @@ class _HomePageView extends StatelessWidget { ), ), ), - Expanded( - child: BlocBuilder( - builder: (context, userState) { - return GestureDetector( - onTap: () { - _checkPermission(() { - Navigator.of(context).pushNamed( - AppRouteName.webView, - arguments: { - 'urlStr': AppConsts.xiaoeShopUrl, - 'webViewTitle': 'Wow精选' - }); - }, bloc); - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset('xe_shop'.assetPng, - width: 140.5.w, height: 172.h), - 44.verticalSpace - ], - )); - }), + Offstage( + offstage: AppConfigHelper.shouldHidePay() || + !UserUtil.isLogined(), + child: Expanded( + child: BlocBuilder( + builder: (context, userState) { + return GestureDetector( + onTap: () { + _checkPermission(() { + AudioPlayerUtil.getInstance().pause(); + Navigator.of(context).pushNamed( + AppRouteName.webView, + arguments: { + 'urlStr': AppConsts.xiaoeShopUrl, + 'webViewTitle': 'Wow精选' + }).then((value) => { + AudioPlayerUtil.getInstance() + .playAudio( + AudioPlayerUtilType.touch), + }); + }, bloc); + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset('xe_shop'.assetPng, + width: 140.5.w, height: 172.h), + 44.verticalSpace + ], + )); + }), + ), ), Expanded( child: BlocBuilder( @@ -138,9 +150,14 @@ class _HomePageView extends StatelessWidget { return GestureDetector( onTap: () { _checkPermission(() { - bloc.gamePlayer.play( - AssetSource('game_time'.assetMp3)); - pushNamed(AppRouteName.games); + AudioPlayerUtil.getInstance().playAudio( + AudioPlayerUtilType.gameTime); + pushNamed(AppRouteName.games) + .then((value) => { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType + .touch), + }); }, bloc); }, child: Column( @@ -189,6 +206,8 @@ class _HomePageView extends StatelessWidget { }, rightTap: () { popPage(); pushNamed(AppRouteName.shop).then((value) { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.touch); if (value != null) { bloc.exchangeResult = value['exchange']; bloc.add(ExchangeSuccessEvent()); diff --git a/lib/pages/home/widgets/BaseHomeHeaderWidget.dart b/lib/pages/home/widgets/BaseHomeHeaderWidget.dart index 4866201..8c2711a 100644 --- a/lib/pages/home/widgets/BaseHomeHeaderWidget.dart +++ b/lib/pages/home/widgets/BaseHomeHeaderWidget.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/core/app_config_helper.dart'; import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; import '../../../common/core/user_util.dart'; import '../../../models/course_entity.dart'; @@ -84,6 +85,7 @@ class BaseHomeHeaderWidget extends StatelessWidget { !UserUtil.isLogined(), child: GestureDetector( onTap: () => { + AudioPlayerUtil.getInstance().pause(), pushNamed(AppRouteName.shop).then((value) { if (value != null) { if (callBack == null) { @@ -115,6 +117,7 @@ class BaseHomeHeaderWidget extends StatelessWidget { void onUserClick() { if (UserUtil.isLogined()) { + AudioPlayerUtil.getInstance().pause(); pushNamed(AppRouteName.user).then((value) { if (value != null) { if (callBack == null) { diff --git a/lib/pages/section/bloc/section_bloc.dart b/lib/pages/section/bloc/section_bloc.dart index 86e069e..64b4862 100644 --- a/lib/pages/section/bloc/section_bloc.dart +++ b/lib/pages/section/bloc/section_bloc.dart @@ -9,6 +9,7 @@ import 'package:wow_english/common/request/dao/lesson_dao.dart'; import 'package:wow_english/common/request/exception.dart'; import 'package:wow_english/common/request/dao/listen_dao.dart'; import 'package:wow_english/models/course_process_entity.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; import 'package:wow_english/utils/loading.dart'; import 'package:wow_english/utils/toast_util.dart'; @@ -45,8 +46,6 @@ class SectionBloc extends Bloc { ///单元列表是否有刷新,有的话返回上一页时通知其刷新接口数据 bool courseUnitEntityChanged = false; - late AudioPlayer audioPlayer; // 点击播放器 - late AudioPlayer backgroundPlayer; // 背景播放器 ///courseUnitId与课程环节列表的映射 final Map?> _courseSectionDatasMap = {}; @@ -66,25 +65,12 @@ class SectionBloc extends Bloc { on(_requestVideoLesson); on(_pageControllerChange); on((event, emit) { - audioPlayer = AudioPlayer(playerId: 'section'); - backgroundPlayer = AudioPlayer(playerId: 'back'); - backgroundPlayer.play(AssetSource('count_with_me_instrumental'.assetMp3)); - - backgroundPlayer.onPlayerStateChanged.listen((event) async { - if (event == PlayerState.completed) { - // 播放结束再次播放 - backgroundPlayer - .play(AssetSource('count_with_me_instrumental'.assetMp3)); - } - }); + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe); }); } @override Future close() { - audioPlayer.release(); - audioPlayer.dispose(); - backgroundPlayer.release(); - backgroundPlayer.dispose(); + AudioPlayerUtil.getInstance().pause(); return super.close(); } diff --git a/lib/pages/section/bloc/section_state.dart b/lib/pages/section/bloc/section_state.dart index b598397..47aec56 100644 --- a/lib/pages/section/bloc/section_state.dart +++ b/lib/pages/section/bloc/section_state.dart @@ -22,5 +22,3 @@ class RequestEnterClassState extends SectionState { } class CurrentPageIndexState extends SectionState {} - -class VoicePlayChangeState extends SectionState {} diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart index eb801bc..86dc993 100644 --- a/lib/pages/section/section_page.dart +++ b/lib/pages/section/section_page.dart @@ -12,6 +12,8 @@ import 'package:wow_english/pages/section/widgets/section_item.dart'; import 'package:wow_english/pages/section/widgets/section_bouns_item.dart'; import 'package:wow_english/pages/section/widgets/section_header_widget.dart'; import 'package:wow_english/route/route.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; +import 'package:wow_english/utils/log_util.dart'; import 'package:wow_english/utils/toast_util.dart'; import '../../models/course_section_entity.dart'; @@ -89,23 +91,23 @@ class _SectionPageView extends StatelessWidget { currentTime: dataMap['currentTime'], autoNextSection: dataMap['nextSection'])); } - if (bloc.backgroundPlayer.state == PlayerState.paused) { - bloc.backgroundPlayer.resume(); - } + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); }); return; } if (state is RequestEnterClassState) { - bloc.backgroundPlayer.pause(); if (state.courseType != SectionType.practice.value && state.courseType != SectionType.pictureBook.value) { ///视频类型 ///获取视频课程内容 if (state.courseType == 1) { - bloc.audioPlayer.play(AssetSource('music_time'.assetMp3)); + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.musicTime); } else { - bloc.audioPlayer.play(AssetSource('video_time'.assetMp3)); + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.videoTime); } Future.delayed(const Duration(seconds: 1), () { bloc.add(RequestVideoLessonEvent( @@ -116,7 +118,8 @@ class _SectionPageView extends StatelessWidget { } if (state.courseType == SectionType.pictureBook.value) { - bloc.audioPlayer.play(AssetSource('reading_time'.assetMp3)); + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.readingTime); Future.delayed(const Duration(seconds: 1), () { //绘本 pushNamed(AppRouteName.reading, @@ -130,9 +133,8 @@ class _SectionPageView extends StatelessWidget { currentStep: dataMap['currentStep'], autoNextSection: dataMap['nextSection'], )); - if (bloc.backgroundPlayer.state == PlayerState.paused) { - bloc.backgroundPlayer.resume(); - } + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); } }); }); @@ -142,7 +144,8 @@ class _SectionPageView extends StatelessWidget { if (state.courseType == SectionType.practice.value) { //练习 - bloc.audioPlayer.play(AssetSource('quiz_time'.assetMp3)); + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.quizTime); Future.delayed(const Duration(seconds: 1), () { pushNamed(AppRouteName.topicPic, arguments: {'courseLessonId': state.courseLessonId}) @@ -154,9 +157,8 @@ class _SectionPageView extends StatelessWidget { currentStep: dataMap['currentStep'], autoNextSection: dataMap['nextSection'])); } - if (bloc.backgroundPlayer.state == PlayerState.paused) { - bloc.backgroundPlayer.resume(); - } + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); }); }); return; diff --git a/lib/pages/unit/bloc.dart b/lib/pages/unit/bloc.dart index 7609fdc..27b4271 100644 --- a/lib/pages/unit/bloc.dart +++ b/lib/pages/unit/bloc.dart @@ -1,5 +1,6 @@ import 'package:bloc/bloc.dart'; import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; import '../../common/request/dao/lesson_dao.dart'; import '../../common/request/exception.dart'; @@ -24,6 +25,9 @@ class UnitBloc extends Bloc { UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) { on(_requestUnitDatas); + on((event, emit) { + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy); + }); } void _requestUnitDatas( @@ -45,15 +49,26 @@ class UnitBloc extends Bloc { } void headerActionEvent(HeaderActionType type) { + AudioPlayerUtil.getInstance().pause(); if (type == HeaderActionType.video) { pushNamed(AppRouteName.reAfter); } else if (type == HeaderActionType.phase) { - pushNamed(AppRouteName.courseModule); + pushNamed(AppRouteName.courseModule).then((value) => { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.inMyTummy) + }); + ; } else if (type == HeaderActionType.listen) { - pushNamed(AppRouteName.listen); + pushNamed(AppRouteName.listen).then((value) => { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.inMyTummy) + }); } else if (type == HeaderActionType.shop) { - pushNamed(AppRouteName.shop) - .then((value) => {exchangeResult = value['exchange']}); + pushNamed(AppRouteName.shop).then((value) => { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.inMyTummy), + exchangeResult = value['exchange'] + }); } else if (type == HeaderActionType.user) { pushNamed(AppRouteName.user); } diff --git a/lib/pages/unit/event.dart b/lib/pages/unit/event.dart index 53a8b93..be374dc 100644 --- a/lib/pages/unit/event.dart +++ b/lib/pages/unit/event.dart @@ -6,3 +6,5 @@ class RequestUnitDataEvent extends UnitEvent { RequestUnitDataEvent(this.moduleId); } + +class UnitInitEvent extends UnitEvent {} diff --git a/lib/pages/unit/view.dart b/lib/pages/unit/view.dart index bb3d3f6..c37ecdf 100644 --- a/lib/pages/unit/view.dart +++ b/lib/pages/unit/view.dart @@ -5,6 +5,7 @@ import 'package:wow_english/pages/unit/state.dart'; import 'package:wow_english/pages/unit/widget/course_unit_item.dart'; import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; import 'package:wow_english/route/route.dart'; +import 'package:wow_english/utils/audioplayer_util.dart'; import '../../models/course_module_entity.dart'; import '../../models/course_unit_entity.dart'; @@ -23,6 +24,7 @@ class UnitPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (BuildContext context) => UnitBloc(courseModuleEntity) + ..add(UnitInitEvent()) ..add(RequestUnitDataEvent(courseModuleEntity?.id)), child: Builder(builder: (context) => _buildPage(context)), ); @@ -41,6 +43,8 @@ class UnitPage extends StatelessWidget { HomeTabHeaderWidget( courseModuleCode: bloc.getCourseModuleCode(), onBack: () { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.touch); popPage(data: {'exchange': bloc.exchangeResult}); }, actionTap: (HeaderActionType type) { @@ -63,12 +67,14 @@ class UnitPage extends StatelessWidget { showToast('当前单元课程暂未解锁'); return; } - + AudioPlayerUtil.getInstance().pause(); pushNamed(AppRouteName.courseSection, arguments: { 'courseUnitEntity': bloc.unitData, 'courseUnitId': data.id }).then((value) { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.inMyTummy); if (value != null) { Map dataMap = value as Map; diff --git a/lib/utils/audioplayer_util.dart b/lib/utils/audioplayer_util.dart new file mode 100644 index 0000000..db913cf --- /dev/null +++ b/lib/utils/audioplayer_util.dart @@ -0,0 +1,81 @@ +import 'package:audioplayers/audioplayers.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; + +enum AudioPlayerUtilType { + welcomeToWow('welcome_to_wow'), + classTime('class_time'), + gameTime('game_time'), + musicTime('music_time'), + readingTime('reading_time'), + videoTime('video_time'), + quizTime('quiz_time'), + countWithMe('count_with_me_instrumental'), + inMyTummy('in_my_tummy_instrumental'), + touch('touch_instrumental'); + + const AudioPlayerUtilType(this.path); + + final String path; +} + +class AudioPlayerUtil { + static AudioPlayerUtil? _instance; + late AudioPlayer audioPlayer; + late AudioPlayerUtilType currentType; + + // 私有构造函数 + AudioPlayerUtil._internal() { + audioPlayer = AudioPlayer(); + audioPlayer.onPlayerStateChanged.listen((event) async { + if (event == PlayerState.completed) { + // 播放结束再次播放 + if (currentType == AudioPlayerUtilType.inMyTummy) { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.inMyTummy); + } + if (currentType == AudioPlayerUtilType.countWithMe) { + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); + } + if (currentType == AudioPlayerUtilType.welcomeToWow) { + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch); + } + if (currentType == AudioPlayerUtilType.touch) { + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch); + } + } + }); + } + + static AudioPlayerUtil getInstance() { + _instance ??= AudioPlayerUtil._internal(); + return _instance!; + } + +// 播放音频 + Future playAudio(AudioPlayerUtilType type) async { + currentType = type; + String path = type.path; + await audioPlayer.play(AssetSource(path.assetMp3), volume: 0.5); + await audioPlayer.onPlayerComplete.first; + } + + // stop + void stop() { + audioPlayer.stop(); + } + + // pause + void pause() { + if (audioPlayer.state == PlayerState.playing) { + audioPlayer.pause(); + } + } + + // resume + void resume() { + if (audioPlayer.state == PlayerState.paused) { + audioPlayer.resume(); + } + } +}