From cd32eb01c2cc308d80db020aa05f8860259410cb Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Fri, 26 Jul 2024 12:37:34 +0800 Subject: [PATCH] feat:播放音乐防抖处理(课程环节页) --- lib/common/utils/action_with_music_controller.dart | 36 ++++++++++++++++++++++++++++++++++++ lib/pages/section/bloc/section_bloc.dart | 45 +++++++++++++++++++++++---------------------- lib/pages/section/section_page.dart | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------- 3 files changed, 118 insertions(+), 75 deletions(-) create mode 100644 lib/common/utils/action_with_music_controller.dart diff --git a/lib/common/utils/action_with_music_controller.dart b/lib/common/utils/action_with_music_controller.dart new file mode 100644 index 0000000..d04b234 --- /dev/null +++ b/lib/common/utils/action_with_music_controller.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +import '../../utils/audio_player_util.dart'; + +/// action前播放音乐控制类,维护状态做防抖处理 +/// todo 需要结合生命周期,尤其是在声明周期结束后及时中断,避免action泄漏 +class ActionWithMusicController { + ActionWithMusicController._privateConstructor(); + + static final ActionWithMusicController _instance = ActionWithMusicController._privateConstructor(); + + factory ActionWithMusicController() { + return _instance; + } + + bool _isPlaying = false; + + Future playMusicAndPerformAction(BuildContext context, + AudioPlayerUtilType audioType, Function action) async { + if (_isPlaying) return; + + _isPlaying = true; + + // Play the music + await AudioPlayerUtil.getInstance() + .playAudio(audioType); + + action(); + + _isPlaying = false; + } + + // void dispose() { + // _audioPlayer.dispose(); + // } +} \ No newline at end of file diff --git a/lib/pages/section/bloc/section_bloc.dart b/lib/pages/section/bloc/section_bloc.dart index 5df5744..37617d4 100644 --- a/lib/pages/section/bloc/section_bloc.dart +++ b/lib/pages/section/bloc/section_bloc.dart @@ -13,7 +13,6 @@ import 'package:wow_english/utils/toast_util.dart'; import '../../../models/course_section_entity.dart'; import '../../../models/course_unit_entity.dart'; import '../../../utils/list_ext.dart'; -import '../../../utils/log_util.dart'; part 'section_event.dart'; @@ -50,15 +49,12 @@ class SectionBloc extends Bloc { Map?> get courseSectionDatasMap => _courseSectionDatasMap; - ///点击环节后先请求数据再进入,标志位避免频繁点击多次请求(以及多次进入) - bool _isRequesting = false; - SectionBloc(this._courseUnitEntity, this._currentPage, this._pageController, this._listController, this._indicatorSrollController) : super(LessonInitial()) { on(_requestSectionsData); on(_requestEndClass); - on(_requestEnterClass); + on(_onEnterClass); on(_pageControllerChange); on((event, emit) async { await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe); @@ -84,25 +80,30 @@ class SectionBloc extends Bloc { } } - void _requestEnterClass( + void _onEnterClass( RequestEnterClassEvent event, Emitter emitter) async { - try { - Log.d("WQF _requestVideoLesson _isRequesting=$_isRequesting"); - if (_isRequesting) { - return; - } - _isRequesting = true; - await loading(() async { - await ListenDao.enterClass(event.courseLessonId); - emitter(RequestEnterClassState(event.courseLessonId, event.courseType)); - }); - } catch (e) { - if (e is ApiException) { - showToast(e.message ?? '请求失败,请检查网络连接'); + emitter(RequestEnterClassState(event.courseLessonId, event.courseType)); + } + + ///进入课程接口请求函数封装 + ///onRequestEnterSuccess 接口请求成功后行为函数,比如跳转课程页面 + Future requestEnterClass(String courseLessonId, Function onRequestEnterSuccess, + {Function? onRequestEnterFailed}) async { + await loading(() async { + try { + await ListenDao.enterClass(courseLessonId); + onRequestEnterSuccess(); + } catch (e) { + if (e is ApiException) { + showToast(e.message ?? '请求失败,请检查网络连接'); + } else { + showToast('$e'); + } + if (onRequestEnterFailed != null) { + onRequestEnterFailed(e); + } } - } finally { - _isRequesting = false; - } + }); } void _requestEndClass( diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart index 5d3ba0f..424d562 100644 --- a/lib/pages/section/section_page.dart +++ b/lib/pages/section/section_page.dart @@ -1,11 +1,10 @@ -import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; 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/extension/string_extension.dart'; +import 'package:wow_english/common/utils/action_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'; @@ -13,7 +12,6 @@ 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/audio_player_util.dart'; -import 'package:wow_english/utils/log_util.dart'; import 'package:wow_english/utils/toast_util.dart'; import '../../models/course_section_entity.dart'; @@ -58,6 +56,7 @@ class _SectionPageView extends StatelessWidget { @override Widget build(BuildContext context) { final bloc = BlocProvider.of(context); + final controller = ActionWithMusicController(); return BlocListener( listener: (context, state) async { if (state is RequestEnterClassState) { @@ -66,72 +65,79 @@ class _SectionPageView extends StatelessWidget { var title = state.courseType == SectionType.song.value ? 'song' : 'video'; + AudioPlayerUtilType audioType; ///儿歌/视频类型 if (state.courseType == SectionType.song.value) { - await AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.musicTime); + audioType = AudioPlayerUtilType.musicTime; } else { - await AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.videoTime); + audioType = AudioPlayerUtilType.videoTime; } - pushNamed(AppRouteName.lookVideo, arguments: { - 'videoUrl': null, - 'title': title, - 'courseLessonId': state.courseLessonId, - 'isTopic': true - }).then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestEndClassEvent( - dataMap['courseLessonId']!, dataMap['isCompleted'], - currentTime: dataMap['currentTime'], - autoNextSection: dataMap['nextSection'])); - } - AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.countWithMe); + + controller.playMusicAndPerformAction(context, audioType, () async { + ///播放音乐->调进入课程接口->跳转课程页面 + bloc.requestEnterClass(state.courseLessonId, () { + pushNamed(AppRouteName.lookVideo, arguments: { + 'videoUrl': null, + 'title': title, + 'courseLessonId': state.courseLessonId, + 'isTopic': true + }).then((value) { + if (value != null) { + Map dataMap = + value as Map; + bloc.add(RequestEndClassEvent( + dataMap['courseLessonId']!, dataMap['isCompleted'], + currentTime: dataMap['currentTime'], + autoNextSection: dataMap['nextSection'])); + } + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); + }); + }); }); return; } if (state.courseType == SectionType.pictureBook.value) { - await AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.readingTime); //绘本 - 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); - } + controller.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); + } + }); }); - return; } if (state.courseType == SectionType.practice.value) { //练习 - await AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.quizTime); - 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); + controller.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); + }); }); return; } -- libgit2 0.22.2