From 1e22b7d1bfc9bfeef388fe4b909281f759dd02d6 Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Thu, 25 Jul 2024 23:27:06 +0800 Subject: [PATCH] feat:儿歌/视频环节接口请求时机优化 --- lib/common/request/dao/lesson_dao.dart | 3 ++- lib/pages/practice/bloc/topic_picture_bloc.dart | 9 +++++---- lib/pages/section/bloc/section_bloc.dart | 28 ++-------------------------- lib/pages/section/bloc/section_event.dart | 8 -------- lib/pages/section/bloc/section_state.dart | 7 ------- lib/pages/section/section_page.dart | 72 +++++++++++++++++++++++++----------------------------------------------- lib/pages/video/lookvideo/bloc/look_video_bloc.dart | 30 +++++++++++++++++++++++++++--- lib/pages/video/lookvideo/bloc/look_video_event.dart | 2 ++ lib/pages/video/lookvideo/bloc/look_video_state.dart | 2 ++ lib/pages/video/lookvideo/look_video_page.dart | 45 ++++++++++++++++++++++++++++++--------------- lib/pages/video/lookvideo/widgets/video_widget.dart | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------- 11 files changed, 172 insertions(+), 187 deletions(-) diff --git a/lib/common/request/dao/lesson_dao.dart b/lib/common/request/dao/lesson_dao.dart index ba6846d..3bad5e5 100644 --- a/lib/common/request/dao/lesson_dao.dart +++ b/lib/common/request/dao/lesson_dao.dart @@ -13,6 +13,7 @@ class LessonDao { } ///课程单元列表 + ///@param moduleId 模块id static Future courseUnit(int? moduleId) async { Map mapData = {}; if (moduleId != null) { @@ -32,7 +33,7 @@ class LessonDao { return data; } - ///课程(单元)列表 + ///课程(环节)列表 static Future?> courseSection({required int courseUnitId}) async { Map mapData = {}; mapData['courseUnitId'] = courseUnitId; diff --git a/lib/pages/practice/bloc/topic_picture_bloc.dart b/lib/pages/practice/bloc/topic_picture_bloc.dart index 20aa694..4784a9e 100644 --- a/lib/pages/practice/bloc/topic_picture_bloc.dart +++ b/lib/pages/practice/bloc/topic_picture_bloc.dart @@ -19,6 +19,7 @@ import '../../../common/permission/permissionRequester.dart'; import '../../../route/route.dart'; part 'topic_picture_event.dart'; + part 'topic_picture_state.dart'; enum VoicePlayState { @@ -47,6 +48,8 @@ class TopicPictureBloc CourseProcessEntity? _entity; + CourseProcessEntity? get entity => _entity; + ///正在评测 bool _isVoicing = false; @@ -63,8 +66,6 @@ class TopicPictureBloc bool get forbiddenWhenCorrect => _forbiddenWhenCorrect; - CourseProcessEntity? get entity => _entity; - int get currentPage => _currentPage + 1; int get selectItem => _selectItem; @@ -257,8 +258,8 @@ class TopicPictureBloc XSVoiceStartEvent event, Emitter emitter) async { await audioPlayer.stop(); // 调用封装好的权限检查和请求方法 - bool result = - await requestPermission(context, Permission.microphone, "录音", "用于开启录音,识别您的开口作答并给出反馈"); + bool result = await requestPermission( + context, Permission.microphone, "录音", "用于开启录音,识别您的开口作答并给出反馈"); if (result) { methodChannel.invokeMethod('startVoice', { 'word': event.testWord, diff --git a/lib/pages/section/bloc/section_bloc.dart b/lib/pages/section/bloc/section_bloc.dart index 23a5016..5df5744 100644 --- a/lib/pages/section/bloc/section_bloc.dart +++ b/lib/pages/section/bloc/section_bloc.dart @@ -1,14 +1,11 @@ -import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:wow_english/common/extension/string_extension.dart'; 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/audio_player_util.dart'; import 'package:wow_english/utils/loading.dart'; import 'package:wow_english/utils/toast_util.dart'; @@ -53,10 +50,6 @@ class SectionBloc extends Bloc { Map?> get courseSectionDatasMap => _courseSectionDatasMap; - CourseProcessEntity? _processEntity; - - CourseProcessEntity? get processEntity => _processEntity; - ///点击环节后先请求数据再进入,标志位避免频繁点击多次请求(以及多次进入) bool _isRequesting = false; @@ -66,7 +59,6 @@ class SectionBloc extends Bloc { on(_requestSectionsData); on(_requestEndClass); on(_requestEnterClass); - on(_requestVideoLesson); on(_pageControllerChange); on((event, emit) async { await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe); @@ -92,23 +84,6 @@ class SectionBloc extends Bloc { } } - void _requestVideoLesson( - RequestVideoLessonEvent event, Emitter emitter) async { - try { - await loading(() async { - _processEntity = await ListenDao.process(event.courseLessonId); - emitter( - RequestVideoLessonState(event.courseLessonId, event.courseType)); - }); - } catch (e) { - if (e is ApiException) { - showToast(e.message ?? '请求失败,请检查网络连接'); - } - } finally { - _isRequesting = false; - } - } - void _requestEnterClass( RequestEnterClassEvent event, Emitter emitter) async { try { @@ -124,8 +99,9 @@ class SectionBloc extends Bloc { } catch (e) { if (e is ApiException) { showToast(e.message ?? '请求失败,请检查网络连接'); - _isRequesting = false; } + } finally { + _isRequesting = false; } } diff --git a/lib/pages/section/bloc/section_event.dart b/lib/pages/section/bloc/section_event.dart index 06eb1fb..3095299 100644 --- a/lib/pages/section/bloc/section_event.dart +++ b/lib/pages/section/bloc/section_event.dart @@ -11,14 +11,6 @@ class RequestDataEvent extends SectionEvent { class InitEvent extends SectionEvent {} -///获取视频课程内容 -class RequestVideoLessonEvent extends SectionEvent { - final String courseLessonId; - final int courseType; - - RequestVideoLessonEvent(this.courseLessonId, this.courseType); -} - ///进入课堂 class RequestEnterClassEvent extends SectionEvent { final String courseLessonId; diff --git a/lib/pages/section/bloc/section_state.dart b/lib/pages/section/bloc/section_state.dart index 47aec56..fe4ba41 100644 --- a/lib/pages/section/bloc/section_state.dart +++ b/lib/pages/section/bloc/section_state.dart @@ -7,13 +7,6 @@ class LessonInitial extends SectionState {} class LessonDataLoadState extends SectionState {} -class RequestVideoLessonState extends SectionState { - final String courseLessonId; - final int type; - - RequestVideoLessonState(this.courseLessonId, this.type); -} - class RequestEnterClassState extends SectionState { final String courseLessonId; final int courseType; diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart index 9b9417e..78b5429 100644 --- a/lib/pages/section/section_page.dart +++ b/lib/pages/section/section_page.dart @@ -60,58 +60,36 @@ class _SectionPageView extends StatelessWidget { final bloc = BlocProvider.of(context); return BlocListener( listener: (context, state) async { - if (state is RequestVideoLessonState) { - final videoUrl = bloc.processEntity?.videos?.videoUrl ?? ''; - var title = ''; - if (state.type == SectionType.song.value) { - title = 'song'; - } - - if (state.type == SectionType.video.value) { - title = 'video'; - } - - if (state.type == SectionType.bouns.value) { - title = 'bonus'; - } - - if (videoUrl.isEmpty || !videoUrl.contains('http')) { - return; - } - pushNamed(AppRouteName.lookVideo, arguments: { - 'videoUrl': videoUrl, - '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 is RequestEnterClassState) { - if (state.courseType != SectionType.practice.value && - state.courseType != SectionType.pictureBook.value) { - ///视频类型 - ///获取视频课程内容 - if (state.courseType == 1) { - AudioPlayerUtil.getInstance() + if (state.courseType == SectionType.song.value && + state.courseType == SectionType.video.value) { + var title = + state.courseType == SectionType.song.value ? 'song' : 'video'; + + ///儿歌/视频类型 + if (state.courseType == SectionType.song.value) { + await AudioPlayerUtil.getInstance() .playAudio(AudioPlayerUtilType.musicTime); } else { - AudioPlayerUtil.getInstance() + await AudioPlayerUtil.getInstance() .playAudio(AudioPlayerUtilType.videoTime); } - bloc.add(RequestVideoLessonEvent( - state.courseLessonId, state.courseType)); - + pushNamed(AppRouteName.lookVideo, arguments: { + 'videoUrl': "", + '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; } diff --git a/lib/pages/video/lookvideo/bloc/look_video_bloc.dart b/lib/pages/video/lookvideo/bloc/look_video_bloc.dart index 882c666..1e67c1d 100644 --- a/lib/pages/video/lookvideo/bloc/look_video_bloc.dart +++ b/lib/pages/video/lookvideo/bloc/look_video_bloc.dart @@ -5,15 +5,19 @@ import 'package:wow_english/pages/section/subsection/base_section/bloc.dart'; import 'package:wow_english/pages/section/subsection/base_section/event.dart'; import 'package:wow_english/pages/section/subsection/base_section/state.dart'; +import '../../../../common/request/dao/listen_dao.dart'; +import '../../../../common/request/exception.dart'; +import '../../../../models/course_process_entity.dart'; +import '../../../../utils/loading.dart'; +import '../../../../utils/toast_util.dart'; + part 'look_video_event.dart'; part 'look_video_state.dart'; class LookVideoBloc extends BaseSectionBloc { - VideoPlayerController? _controller; - final String? _videoUrl; - String? get videoUrl => _videoUrl; + String? get videoUrl => _videoUrl ?? _entity?.videos?.videoUrl ?? ''; final String? _typeTitle; String? get typeTitle => _typeTitle; final String? _courseLessonId; @@ -21,12 +25,32 @@ class LookVideoBloc extends BaseSectionBloc final bool _isTopic; bool get isTopic => _isTopic; + CourseProcessEntity? _entity; + + CourseProcessEntity? get entity => _entity; + LookVideoBloc(this._videoUrl, this._typeTitle, this._courseLessonId, this._isTopic) : super(LookVideoInitial()) { on((event, emit) { // TODO: implement event handler }); + on(_requestData); on((event, emit) { emit(SectionAgainState()); }); } + + ///请求数据 + void _requestData( + RequestDataEvent event, Emitter emitter) async { + try { + await loading(() async { + _entity = await ListenDao.process(courseLessonId); + emitter(RequestDataState()); + }); + } catch (e) { + if (e is ApiException) { + showToast(e.message ?? '请求失败,请检查网络连接'); + } + } + } } diff --git a/lib/pages/video/lookvideo/bloc/look_video_event.dart b/lib/pages/video/lookvideo/bloc/look_video_event.dart index d4759e2..4adb9f7 100644 --- a/lib/pages/video/lookvideo/bloc/look_video_event.dart +++ b/lib/pages/video/lookvideo/bloc/look_video_event.dart @@ -4,3 +4,5 @@ part of 'look_video_bloc.dart'; abstract class LookVideoEvent extends BaseSectionEvent {} class RestartVideoEvent extends LookVideoEvent {} + +class RequestDataEvent extends LookVideoEvent {} diff --git a/lib/pages/video/lookvideo/bloc/look_video_state.dart b/lib/pages/video/lookvideo/bloc/look_video_state.dart index cf00985..c7f0b8b 100644 --- a/lib/pages/video/lookvideo/bloc/look_video_state.dart +++ b/lib/pages/video/lookvideo/bloc/look_video_state.dart @@ -6,3 +6,5 @@ abstract class LookVideoState extends BaseSectionState {} class LookVideoInitial extends LookVideoState {} class VideoStarState extends LookVideoState {} + +class RequestDataState extends LookVideoState {} diff --git a/lib/pages/video/lookvideo/look_video_page.dart b/lib/pages/video/lookvideo/look_video_page.dart index 3575336..cd21c93 100644 --- a/lib/pages/video/lookvideo/look_video_page.dart +++ b/lib/pages/video/lookvideo/look_video_page.dart @@ -3,10 +3,15 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:wow_english/pages/section/subsection/base_section/state.dart'; import 'package:wow_english/pages/video/lookvideo/bloc/look_video_bloc.dart'; import 'package:wow_english/pages/video/lookvideo/widgets/video_widget.dart'; +import 'package:wow_english/utils/log_util.dart'; class LookVideoPage extends StatelessWidget { const LookVideoPage( - {super.key, this.videoUrl, this.typeTitle, this.courseLessonId, this.isTopic = false}); + {super.key, + this.videoUrl, + this.typeTitle, + this.courseLessonId, + this.isTopic = false}); final String? videoUrl; final String? typeTitle; @@ -16,24 +21,34 @@ class LookVideoPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => LookVideoBloc(videoUrl, typeTitle, courseLessonId, isTopic), + create: (BuildContext context) => + LookVideoBloc(videoUrl, typeTitle, courseLessonId, isTopic) + ..add(RequestDataEvent()), child: Builder(builder: (context) => _buildPage(context)), ); } } Widget _buildPage(BuildContext context) { - return BlocBuilder(builder: (context, state) { - final bloc = BlocProvider.of(context); - return Container( - color: Colors.white, - child: VideoWidget( - videoUrl: bloc.videoUrl ?? '', - typeTitle: bloc.typeTitle ?? '', - courseLessonId: bloc.courseLessonId ?? '', - isTopic: bloc.isTopic, - ) - ); - } - ); + return BlocBuilder( + builder: (context, state) { + final bloc = BlocProvider.of(context); + Log.d("WQF lookvideo BlocBuilder bloc.videoUr=${bloc.videoUrl}"); + return Center( + child: bloc.videoUrl?.isNotEmpty == true + ? Container( + color: Colors.white, + child: VideoWidget( + videoUrl: bloc.videoUrl ?? '', + typeTitle: bloc.typeTitle ?? '', + courseLessonId: bloc.courseLessonId ?? '', + isTopic: bloc.isTopic, + )) + //todo 空了需要抽一个通用的loading组件 + : Container( + color: Colors.white, + child: const CircularProgressIndicator(), + ), + ); + }); } diff --git a/lib/pages/video/lookvideo/widgets/video_widget.dart b/lib/pages/video/lookvideo/widgets/video_widget.dart index 2a88449..7987b4d 100644 --- a/lib/pages/video/lookvideo/widgets/video_widget.dart +++ b/lib/pages/video/lookvideo/widgets/video_widget.dart @@ -12,11 +12,12 @@ import '../../../section/subsection/base_section/state.dart'; import 'video_opera_widget.dart'; class VideoWidget extends StatefulWidget { - const VideoWidget({super.key, - this.videoUrl = '', - this.typeTitle, - this.courseLessonId = '', - this.isTopic = false}); + const VideoWidget( + {super.key, + this.videoUrl = '', + this.typeTitle, + this.courseLessonId = '', + this.isTopic = false}); final String videoUrl; final String? typeTitle; @@ -39,10 +40,10 @@ class _VideoWidgetState extends State { String formatDuration(Duration duration) { String hours = duration.inHours.toString().padLeft(2, '0'); - String minutes = duration.inMinutes.remainder(60).toString().padLeft( - 2, '0'); - String seconds = duration.inSeconds.remainder(60).toString().padLeft( - 2, '0'); + String minutes = + duration.inMinutes.remainder(60).toString().padLeft(2, '0'); + String seconds = + duration.inSeconds.remainder(60).toString().padLeft(2, '0'); return "$hours:$minutes:$seconds"; } @@ -71,17 +72,17 @@ class _VideoWidgetState extends State { _controller!.value.position.inSeconds == _controller!.value.duration.inSeconds) { final lookVideoBloc = context.read(); - lookVideoBloc.sectionComplete(() { - popPage(data: { - 'courseLessonId': widget.courseLessonId, - 'currentTime': getCurrentPositionSeconds(), - 'isCompleted': true, - 'nextSection': widget.isTopic - }); - } as VoidCallback, - againSectionTap: (() { - lookVideoBloc.add(SectionAgainEvent()); - }), context: context); + lookVideoBloc.sectionComplete( + () { + popPage(data: { + 'courseLessonId': widget.courseLessonId, + 'currentTime': getCurrentPositionSeconds(), + 'isCompleted': true, + 'nextSection': widget.isTopic + }); + } as VoidCallback, againSectionTap: (() { + lookVideoBloc.add(SectionAgainEvent()); + }), context: context); } } }); @@ -189,63 +190,63 @@ class _VideoWidgetState extends State { child: Center( child: _controller!.value.isInitialized ? Stack( - alignment: Alignment.center, - children: [ - SizedBox( - height: double.infinity, - width: double.infinity, - child: AspectRatio( - aspectRatio: _controller!.value.aspectRatio, - child: VideoPlayer(_controller!), - ), - ), - Offstage( - offstage: _hiddenTipView, - child: VideoOperaWidget( - title: widget.typeTitle ?? 'song', - degree: _playDegree, - totalTime: _totalTime, - currentTime: _currentTime, - isPlay: _controller!.value.isPlaying, - actionEvent: (OperationType type) { - actionType(type); - }, - sliderChangeEvent: (double degree) { - int totalSecond = _controller! - .value.duration.inMinutes - .remainder(60) * - 60 + - _controller!.value.duration.inSeconds - .remainder(60); - int positionSecond = (totalSecond * degree).toInt(); - _controller! - .seekTo(Duration(seconds: positionSecond)); - }, - ), - ), - Offstage( - offstage: _controller!.value.isPlaying, - child: IconButton( - onPressed: () { - _controller!.play(); - }, - icon: Image.asset( - 'video_stop'.assetPng, - width: 70.w, - height: 70.h, - ), - ), - ) - ], - ) + alignment: Alignment.center, + children: [ + SizedBox( + height: double.infinity, + width: double.infinity, + child: AspectRatio( + aspectRatio: _controller!.value.aspectRatio, + child: VideoPlayer(_controller!), + ), + ), + Offstage( + offstage: _hiddenTipView, + child: VideoOperaWidget( + title: widget.typeTitle ?? 'song', + degree: _playDegree, + totalTime: _totalTime, + currentTime: _currentTime, + isPlay: _controller!.value.isPlaying, + actionEvent: (OperationType type) { + actionType(type); + }, + sliderChangeEvent: (double degree) { + int totalSecond = _controller! + .value.duration.inMinutes + .remainder(60) * + 60 + + _controller!.value.duration.inSeconds + .remainder(60); + int positionSecond = (totalSecond * degree).toInt(); + _controller! + .seekTo(Duration(seconds: positionSecond)); + }, + ), + ), + Offstage( + offstage: _controller!.value.isPlaying, + child: IconButton( + onPressed: () { + _controller!.play(); + }, + icon: Image.asset( + 'video_stop'.assetPng, + width: 70.w, + height: 70.h, + ), + ), + ) + ], + ) : Container( - color: Colors.white, - child: const CircularProgressIndicator(), - // Text( - // '视频加载中....', - // style: TextStyle(fontSize: 20.sp, color: Colors.black), - // ), - ), + color: Colors.white, + child: const CircularProgressIndicator(), + // Text( + // '视频加载中....', + // style: TextStyle(fontSize: 20.sp, color: Colors.black), + // ), + ), ), ), ); -- libgit2 0.22.2