diff --git a/lib/common/utils/action_with_music_controller.dart b/lib/common/utils/click_with_music_controller.dart index d04b234..288302b 100644 --- a/lib/common/utils/action_with_music_controller.dart +++ b/lib/common/utils/click_with_music_controller.dart @@ -1,33 +1,42 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import '../../utils/audio_player_util.dart'; +import '../../utils/log_util.dart'; /// action前播放音乐控制类,维护状态做防抖处理 /// todo 需要结合生命周期,尤其是在声明周期结束后及时中断,避免action泄漏 -class ActionWithMusicController { - ActionWithMusicController._privateConstructor(); +class ClickWithMusicController { - static final ActionWithMusicController _instance = ActionWithMusicController._privateConstructor(); + static ClickWithMusicController? _instance; - factory ActionWithMusicController() { - return _instance; - } + ClickWithMusicController._privateConstructor(); + + static ClickWithMusicController get instance => _instance ??= ClickWithMusicController._privateConstructor(); bool _isPlaying = false; + ///@param action 可以是同步函数也可以是异步函数 Future playMusicAndPerformAction(BuildContext context, - AudioPlayerUtilType audioType, Function action) async { + AudioPlayerUtilType audioType, FutureOr Function() action) async { if (_isPlaying) return; _isPlaying = true; + Log.d("WQF playMusicAndPerformAction playAudio begin"); // Play the music await AudioPlayerUtil.getInstance() .playAudio(audioType); - action(); - - _isPlaying = false; + try { + await Future.sync(action); + } catch (e) { + Log.d('WQF playMusicAndPerformAction exception $e'); + } finally { + Log.d("WQF playMusicAndPerformAction playAudio end"); + _isPlaying = false; + } } // void dispose() { diff --git a/lib/pages/section/bloc/section_bloc.dart b/lib/pages/section/bloc/section_bloc.dart index 37617d4..f447fa8 100644 --- a/lib/pages/section/bloc/section_bloc.dart +++ b/lib/pages/section/bloc/section_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -57,7 +59,8 @@ class SectionBloc extends Bloc { on(_onEnterClass); on(_pageControllerChange); on((event, emit) async { - await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe); + await AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); }); } @@ -87,20 +90,21 @@ class SectionBloc extends Bloc { ///进入课程接口请求函数封装 ///onRequestEnterSuccess 接口请求成功后行为函数,比如跳转课程页面 - Future requestEnterClass(String courseLessonId, Function onRequestEnterSuccess, - {Function? onRequestEnterFailed}) async { + Future requestEnterClass( + String courseLessonId, FutureOr Function() onRequestEnterSuccess, + {FutureOr Function(Object)? onRequestEnterFailed}) async { await loading(() async { try { await ListenDao.enterClass(courseLessonId); - onRequestEnterSuccess(); + await Future.sync(onRequestEnterSuccess); } catch (e) { if (e is ApiException) { - showToast(e.message ?? '请求失败,请检查网络连接'); + showToast('进入课堂失败 ${e.message}'); } else { - showToast('$e'); + showToast('进入课堂失败 $e'); } if (onRequestEnterFailed != null) { - onRequestEnterFailed(e); + await Future.sync(onRequestEnterFailed(e) as FutureOr Function()); } } }); diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart index 424d562..2ea9712 100644 --- a/lib/pages/section/section_page.dart +++ b/lib/pages/section/section_page.dart @@ -4,7 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:nested_scroll_views/material.dart'; import 'package:wow_english/common/core/user_util.dart'; -import 'package:wow_english/common/utils/action_with_music_controller.dart'; +import 'package:wow_english/common/utils/click_with_music_controller.dart'; import 'package:wow_english/models/course_unit_entity.dart'; import 'package:wow_english/pages/section/section_type.dart'; import 'package:wow_english/pages/section/widgets/section_item.dart'; @@ -15,6 +15,7 @@ import 'package:wow_english/utils/audio_player_util.dart'; import 'package:wow_english/utils/toast_util.dart'; import '../../models/course_section_entity.dart'; +import '../../utils/log_util.dart'; import 'bloc/section_bloc.dart'; import 'courese_module_model.dart'; @@ -56,30 +57,34 @@ class _SectionPageView extends StatelessWidget { @override Widget build(BuildContext context) { final bloc = BlocProvider.of(context); - final controller = ActionWithMusicController(); + final clickController = ClickWithMusicController.instance; return BlocListener( listener: (context, state) async { if (state is RequestEnterClassState) { - if (state.courseType == SectionType.song.value || - state.courseType == SectionType.video.value) { - var title = - state.courseType == SectionType.song.value ? 'song' : 'video'; + final courseType = state.courseType; + final courseLessonId = state.courseLessonId; + if (courseType == SectionType.song.value || + courseType == SectionType.video.value) { + final title = + courseType == SectionType.song.value ? 'song' : 'video'; + final AudioPlayerUtilType audioType; - AudioPlayerUtilType audioType; ///儿歌/视频类型 - if (state.courseType == SectionType.song.value) { + if (courseType == SectionType.song.value) { audioType = AudioPlayerUtilType.musicTime; } else { audioType = AudioPlayerUtilType.videoTime; } - controller.playMusicAndPerformAction(context, audioType, () async { + clickController.playMusicAndPerformAction(context, audioType, + () async { ///播放音乐->调进入课程接口->跳转课程页面 - bloc.requestEnterClass(state.courseLessonId, () { + await bloc.requestEnterClass(courseLessonId, () { + Log.d("WQF request finish"); pushNamed(AppRouteName.lookVideo, arguments: { 'videoUrl': null, 'title': title, - 'courseLessonId': state.courseLessonId, + 'courseLessonId': courseLessonId, 'isTopic': true }).then((value) { if (value != null) { @@ -93,50 +98,58 @@ class _SectionPageView extends StatelessWidget { AudioPlayerUtil.getInstance() .playAudio(AudioPlayerUtilType.countWithMe); }); + }, onRequestEnterFailed: (error) { + Log.d("WQF requestEnterClass failed $error"); }); }); return; } - if (state.courseType == SectionType.pictureBook.value) { + if (courseType == SectionType.pictureBook.value) { //绘本 - controller.playMusicAndPerformAction( + clickController.playMusicAndPerformAction( context, AudioPlayerUtilType.readingTime, () async { - pushNamed(AppRouteName.reading, - arguments: {'courseLessonId': state.courseLessonId}) - .then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestEndClassEvent( - dataMap['courseLessonId']!, - dataMap['isCompleted'], - currentStep: dataMap['currentStep'], - autoNextSection: dataMap['nextSection'], - )); - AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.countWithMe); - } + await bloc.requestEnterClass(courseLessonId, () { + pushNamed(AppRouteName.reading, + arguments: {'courseLessonId': courseLessonId}) + .then((value) { + if (value != null) { + Map dataMap = + value as Map; + bloc.add(RequestEndClassEvent( + dataMap['courseLessonId']!, + dataMap['isCompleted'], + currentStep: dataMap['currentStep'], + autoNextSection: dataMap['nextSection'], + )); + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); + } + }); }); }); return; } - if (state.courseType == SectionType.practice.value) { + if (courseType == SectionType.practice.value) { //练习 - controller.playMusicAndPerformAction( + clickController.playMusicAndPerformAction( context, AudioPlayerUtilType.quizTime, () async { - pushNamed(AppRouteName.topicPic, - arguments: {'courseLessonId': state.courseLessonId}) - .then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestEndClassEvent( - dataMap['courseLessonId']!, dataMap['isCompleted'], - currentStep: dataMap['currentStep'], - autoNextSection: dataMap['nextSection'])); - } - AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.countWithMe); + await bloc.requestEnterClass(courseLessonId, () { + pushNamed(AppRouteName.topicPic, + arguments: {'courseLessonId': courseLessonId}) + .then((value) { + if (value != null) { + Map dataMap = + value as Map; + bloc.add(RequestEndClassEvent( + dataMap['courseLessonId']!, dataMap['isCompleted'], + currentStep: dataMap['currentStep'], + autoNextSection: dataMap['nextSection'])); + } + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); + }); }); }); return;