Commit 1e22b7d1bfc9bfeef388fe4b909281f759dd02d6
1 parent
26982eea
feat:儿歌/视频环节接口请求时机优化
Showing
11 changed files
with
172 additions
and
187 deletions
lib/common/request/dao/lesson_dao.dart
| ... | ... | @@ -13,6 +13,7 @@ class LessonDao { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | ///课程单元列表 |
| 16 | + ///@param moduleId 模块id | |
| 16 | 17 | static Future<CourseUnitEntity?> courseUnit(int? moduleId) async { |
| 17 | 18 | Map<String, dynamic> mapData = {}; |
| 18 | 19 | if (moduleId != null) { |
| ... | ... | @@ -32,7 +33,7 @@ class LessonDao { |
| 32 | 33 | return data; |
| 33 | 34 | } |
| 34 | 35 | |
| 35 | - ///课程(单元)列表 | |
| 36 | + ///课程(环节)列表 | |
| 36 | 37 | static Future<List<CourseSectionEntity>?> courseSection({required int courseUnitId}) async { |
| 37 | 38 | Map<String, dynamic> mapData = {}; |
| 38 | 39 | mapData['courseUnitId'] = courseUnitId; | ... | ... |
lib/pages/practice/bloc/topic_picture_bloc.dart
| ... | ... | @@ -19,6 +19,7 @@ import '../../../common/permission/permissionRequester.dart'; |
| 19 | 19 | import '../../../route/route.dart'; |
| 20 | 20 | |
| 21 | 21 | part 'topic_picture_event.dart'; |
| 22 | + | |
| 22 | 23 | part 'topic_picture_state.dart'; |
| 23 | 24 | |
| 24 | 25 | enum VoicePlayState { |
| ... | ... | @@ -47,6 +48,8 @@ class TopicPictureBloc |
| 47 | 48 | |
| 48 | 49 | CourseProcessEntity? _entity; |
| 49 | 50 | |
| 51 | + CourseProcessEntity? get entity => _entity; | |
| 52 | + | |
| 50 | 53 | ///正在评测 |
| 51 | 54 | bool _isVoicing = false; |
| 52 | 55 | |
| ... | ... | @@ -63,8 +66,6 @@ class TopicPictureBloc |
| 63 | 66 | |
| 64 | 67 | bool get forbiddenWhenCorrect => _forbiddenWhenCorrect; |
| 65 | 68 | |
| 66 | - CourseProcessEntity? get entity => _entity; | |
| 67 | - | |
| 68 | 69 | int get currentPage => _currentPage + 1; |
| 69 | 70 | |
| 70 | 71 | int get selectItem => _selectItem; |
| ... | ... | @@ -257,8 +258,8 @@ class TopicPictureBloc |
| 257 | 258 | XSVoiceStartEvent event, Emitter<TopicPictureState> emitter) async { |
| 258 | 259 | await audioPlayer.stop(); |
| 259 | 260 | // 调用封装好的权限检查和请求方法 |
| 260 | - bool result = | |
| 261 | - await requestPermission(context, Permission.microphone, "录音", "用于开启录音,识别您的开口作答并给出反馈"); | |
| 261 | + bool result = await requestPermission( | |
| 262 | + context, Permission.microphone, "录音", "用于开启录音,识别您的开口作答并给出反馈"); | |
| 262 | 263 | if (result) { |
| 263 | 264 | methodChannel.invokeMethod('startVoice', { |
| 264 | 265 | 'word': event.testWord, | ... | ... |
lib/pages/section/bloc/section_bloc.dart
| 1 | -import 'package:audioplayers/audioplayers.dart'; | |
| 2 | 1 | import 'package:flutter/cupertino.dart'; |
| 3 | 2 | import 'package:flutter/foundation.dart'; |
| 4 | 3 | import 'package:flutter/material.dart'; |
| 5 | 4 | import 'package:flutter_bloc/flutter_bloc.dart'; |
| 6 | 5 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
| 7 | -import 'package:wow_english/common/extension/string_extension.dart'; | |
| 8 | 6 | import 'package:wow_english/common/request/dao/lesson_dao.dart'; |
| 9 | 7 | import 'package:wow_english/common/request/exception.dart'; |
| 10 | 8 | import 'package:wow_english/common/request/dao/listen_dao.dart'; |
| 11 | -import 'package:wow_english/models/course_process_entity.dart'; | |
| 12 | 9 | import 'package:wow_english/utils/audio_player_util.dart'; |
| 13 | 10 | import 'package:wow_english/utils/loading.dart'; |
| 14 | 11 | import 'package:wow_english/utils/toast_util.dart'; |
| ... | ... | @@ -53,10 +50,6 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { |
| 53 | 50 | Map<int, List<CourseSectionEntity>?> get courseSectionDatasMap => |
| 54 | 51 | _courseSectionDatasMap; |
| 55 | 52 | |
| 56 | - CourseProcessEntity? _processEntity; | |
| 57 | - | |
| 58 | - CourseProcessEntity? get processEntity => _processEntity; | |
| 59 | - | |
| 60 | 53 | ///点击环节后先请求数据再进入,标志位避免频繁点击多次请求(以及多次进入) |
| 61 | 54 | bool _isRequesting = false; |
| 62 | 55 | |
| ... | ... | @@ -66,7 +59,6 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { |
| 66 | 59 | on<RequestDataEvent>(_requestSectionsData); |
| 67 | 60 | on<RequestEndClassEvent>(_requestEndClass); |
| 68 | 61 | on<RequestEnterClassEvent>(_requestEnterClass); |
| 69 | - on<RequestVideoLessonEvent>(_requestVideoLesson); | |
| 70 | 62 | on<CurrentUnitIndexChangeEvent>(_pageControllerChange); |
| 71 | 63 | on<InitEvent>((event, emit) async { |
| 72 | 64 | await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe); |
| ... | ... | @@ -92,23 +84,6 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { |
| 92 | 84 | } |
| 93 | 85 | } |
| 94 | 86 | |
| 95 | - void _requestVideoLesson( | |
| 96 | - RequestVideoLessonEvent event, Emitter<SectionState> emitter) async { | |
| 97 | - try { | |
| 98 | - await loading(() async { | |
| 99 | - _processEntity = await ListenDao.process(event.courseLessonId); | |
| 100 | - emitter( | |
| 101 | - RequestVideoLessonState(event.courseLessonId, event.courseType)); | |
| 102 | - }); | |
| 103 | - } catch (e) { | |
| 104 | - if (e is ApiException) { | |
| 105 | - showToast(e.message ?? '请求失败,请检查网络连接'); | |
| 106 | - } | |
| 107 | - } finally { | |
| 108 | - _isRequesting = false; | |
| 109 | - } | |
| 110 | - } | |
| 111 | - | |
| 112 | 87 | void _requestEnterClass( |
| 113 | 88 | RequestEnterClassEvent event, Emitter<SectionState> emitter) async { |
| 114 | 89 | try { |
| ... | ... | @@ -124,8 +99,9 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { |
| 124 | 99 | } catch (e) { |
| 125 | 100 | if (e is ApiException) { |
| 126 | 101 | showToast(e.message ?? '请求失败,请检查网络连接'); |
| 127 | - _isRequesting = false; | |
| 128 | 102 | } |
| 103 | + } finally { | |
| 104 | + _isRequesting = false; | |
| 129 | 105 | } |
| 130 | 106 | } |
| 131 | 107 | ... | ... |
lib/pages/section/bloc/section_event.dart
| ... | ... | @@ -11,14 +11,6 @@ class RequestDataEvent extends SectionEvent { |
| 11 | 11 | |
| 12 | 12 | class InitEvent extends SectionEvent {} |
| 13 | 13 | |
| 14 | -///获取视频课程内容 | |
| 15 | -class RequestVideoLessonEvent extends SectionEvent { | |
| 16 | - final String courseLessonId; | |
| 17 | - final int courseType; | |
| 18 | - | |
| 19 | - RequestVideoLessonEvent(this.courseLessonId, this.courseType); | |
| 20 | -} | |
| 21 | - | |
| 22 | 14 | ///进入课堂 |
| 23 | 15 | class RequestEnterClassEvent extends SectionEvent { |
| 24 | 16 | final String courseLessonId; | ... | ... |
lib/pages/section/bloc/section_state.dart
| ... | ... | @@ -7,13 +7,6 @@ class LessonInitial extends SectionState {} |
| 7 | 7 | |
| 8 | 8 | class LessonDataLoadState extends SectionState {} |
| 9 | 9 | |
| 10 | -class RequestVideoLessonState extends SectionState { | |
| 11 | - final String courseLessonId; | |
| 12 | - final int type; | |
| 13 | - | |
| 14 | - RequestVideoLessonState(this.courseLessonId, this.type); | |
| 15 | -} | |
| 16 | - | |
| 17 | 10 | class RequestEnterClassState extends SectionState { |
| 18 | 11 | final String courseLessonId; |
| 19 | 12 | final int courseType; | ... | ... |
lib/pages/section/section_page.dart
| ... | ... | @@ -60,58 +60,36 @@ class _SectionPageView extends StatelessWidget { |
| 60 | 60 | final bloc = BlocProvider.of<SectionBloc>(context); |
| 61 | 61 | return BlocListener<SectionBloc, SectionState>( |
| 62 | 62 | listener: (context, state) async { |
| 63 | - if (state is RequestVideoLessonState) { | |
| 64 | - final videoUrl = bloc.processEntity?.videos?.videoUrl ?? ''; | |
| 65 | - var title = ''; | |
| 66 | - if (state.type == SectionType.song.value) { | |
| 67 | - title = 'song'; | |
| 68 | - } | |
| 69 | - | |
| 70 | - if (state.type == SectionType.video.value) { | |
| 71 | - title = 'video'; | |
| 72 | - } | |
| 73 | - | |
| 74 | - if (state.type == SectionType.bouns.value) { | |
| 75 | - title = 'bonus'; | |
| 76 | - } | |
| 77 | - | |
| 78 | - if (videoUrl.isEmpty || !videoUrl.contains('http')) { | |
| 79 | - return; | |
| 80 | - } | |
| 81 | - pushNamed(AppRouteName.lookVideo, arguments: { | |
| 82 | - 'videoUrl': videoUrl, | |
| 83 | - 'title': title, | |
| 84 | - 'courseLessonId': state.courseLessonId, | |
| 85 | - 'isTopic': true | |
| 86 | - }).then((value) { | |
| 87 | - if (value != null) { | |
| 88 | - Map<String, dynamic> dataMap = value as Map<String, dynamic>; | |
| 89 | - bloc.add(RequestEndClassEvent( | |
| 90 | - dataMap['courseLessonId']!, dataMap['isCompleted'], | |
| 91 | - currentTime: dataMap['currentTime'], | |
| 92 | - autoNextSection: dataMap['nextSection'])); | |
| 93 | - } | |
| 94 | - AudioPlayerUtil.getInstance() | |
| 95 | - .playAudio(AudioPlayerUtilType.countWithMe); | |
| 96 | - }); | |
| 97 | - return; | |
| 98 | - } | |
| 99 | - | |
| 100 | 63 | if (state is RequestEnterClassState) { |
| 101 | - if (state.courseType != SectionType.practice.value && | |
| 102 | - state.courseType != SectionType.pictureBook.value) { | |
| 103 | - ///视频类型 | |
| 104 | - ///获取视频课程内容 | |
| 105 | - if (state.courseType == 1) { | |
| 106 | - AudioPlayerUtil.getInstance() | |
| 64 | + if (state.courseType == SectionType.song.value && | |
| 65 | + state.courseType == SectionType.video.value) { | |
| 66 | + var title = | |
| 67 | + state.courseType == SectionType.song.value ? 'song' : 'video'; | |
| 68 | + | |
| 69 | + ///儿歌/视频类型 | |
| 70 | + if (state.courseType == SectionType.song.value) { | |
| 71 | + await AudioPlayerUtil.getInstance() | |
| 107 | 72 | .playAudio(AudioPlayerUtilType.musicTime); |
| 108 | 73 | } else { |
| 109 | - AudioPlayerUtil.getInstance() | |
| 74 | + await AudioPlayerUtil.getInstance() | |
| 110 | 75 | .playAudio(AudioPlayerUtilType.videoTime); |
| 111 | 76 | } |
| 112 | - bloc.add(RequestVideoLessonEvent( | |
| 113 | - state.courseLessonId, state.courseType)); | |
| 114 | - | |
| 77 | + pushNamed(AppRouteName.lookVideo, arguments: { | |
| 78 | + 'videoUrl': "", | |
| 79 | + 'title': title, | |
| 80 | + 'courseLessonId': state.courseLessonId, | |
| 81 | + 'isTopic': true | |
| 82 | + }).then((value) { | |
| 83 | + if (value != null) { | |
| 84 | + Map<String, dynamic> dataMap = value as Map<String, dynamic>; | |
| 85 | + bloc.add(RequestEndClassEvent( | |
| 86 | + dataMap['courseLessonId']!, dataMap['isCompleted'], | |
| 87 | + currentTime: dataMap['currentTime'], | |
| 88 | + autoNextSection: dataMap['nextSection'])); | |
| 89 | + } | |
| 90 | + AudioPlayerUtil.getInstance() | |
| 91 | + .playAudio(AudioPlayerUtilType.countWithMe); | |
| 92 | + }); | |
| 115 | 93 | return; |
| 116 | 94 | } |
| 117 | 95 | ... | ... |
lib/pages/video/lookvideo/bloc/look_video_bloc.dart
| ... | ... | @@ -5,15 +5,19 @@ import 'package:wow_english/pages/section/subsection/base_section/bloc.dart'; |
| 5 | 5 | import 'package:wow_english/pages/section/subsection/base_section/event.dart'; |
| 6 | 6 | import 'package:wow_english/pages/section/subsection/base_section/state.dart'; |
| 7 | 7 | |
| 8 | +import '../../../../common/request/dao/listen_dao.dart'; | |
| 9 | +import '../../../../common/request/exception.dart'; | |
| 10 | +import '../../../../models/course_process_entity.dart'; | |
| 11 | +import '../../../../utils/loading.dart'; | |
| 12 | +import '../../../../utils/toast_util.dart'; | |
| 13 | + | |
| 8 | 14 | part 'look_video_event.dart'; |
| 9 | 15 | part 'look_video_state.dart'; |
| 10 | 16 | |
| 11 | 17 | class LookVideoBloc extends BaseSectionBloc<BaseSectionEvent, BaseSectionState> { |
| 12 | 18 | |
| 13 | - VideoPlayerController? _controller; | |
| 14 | - | |
| 15 | 19 | final String? _videoUrl; |
| 16 | - String? get videoUrl => _videoUrl; | |
| 20 | + String? get videoUrl => _videoUrl ?? _entity?.videos?.videoUrl ?? ''; | |
| 17 | 21 | final String? _typeTitle; |
| 18 | 22 | String? get typeTitle => _typeTitle; |
| 19 | 23 | final String? _courseLessonId; |
| ... | ... | @@ -21,12 +25,32 @@ class LookVideoBloc extends BaseSectionBloc<BaseSectionEvent, BaseSectionState> |
| 21 | 25 | final bool _isTopic; |
| 22 | 26 | bool get isTopic => _isTopic; |
| 23 | 27 | |
| 28 | + CourseProcessEntity? _entity; | |
| 29 | + | |
| 30 | + CourseProcessEntity? get entity => _entity; | |
| 31 | + | |
| 24 | 32 | LookVideoBloc(this._videoUrl, this._typeTitle, this._courseLessonId, this._isTopic) : super(LookVideoInitial()) { |
| 25 | 33 | on<LookVideoEvent>((event, emit) { |
| 26 | 34 | // TODO: implement event handler |
| 27 | 35 | }); |
| 36 | + on<RequestDataEvent>(_requestData); | |
| 28 | 37 | on<SectionAgainEvent>((event, emit) { |
| 29 | 38 | emit(SectionAgainState()); |
| 30 | 39 | }); |
| 31 | 40 | } |
| 41 | + | |
| 42 | + ///请求数据 | |
| 43 | + void _requestData( | |
| 44 | + RequestDataEvent event, Emitter<BaseSectionState> emitter) async { | |
| 45 | + try { | |
| 46 | + await loading(() async { | |
| 47 | + _entity = await ListenDao.process(courseLessonId); | |
| 48 | + emitter(RequestDataState()); | |
| 49 | + }); | |
| 50 | + } catch (e) { | |
| 51 | + if (e is ApiException) { | |
| 52 | + showToast(e.message ?? '请求失败,请检查网络连接'); | |
| 53 | + } | |
| 54 | + } | |
| 55 | + } | |
| 32 | 56 | } | ... | ... |
lib/pages/video/lookvideo/bloc/look_video_event.dart
lib/pages/video/lookvideo/bloc/look_video_state.dart
lib/pages/video/lookvideo/look_video_page.dart
| ... | ... | @@ -3,10 +3,15 @@ import 'package:flutter_bloc/flutter_bloc.dart'; |
| 3 | 3 | import 'package:wow_english/pages/section/subsection/base_section/state.dart'; |
| 4 | 4 | import 'package:wow_english/pages/video/lookvideo/bloc/look_video_bloc.dart'; |
| 5 | 5 | import 'package:wow_english/pages/video/lookvideo/widgets/video_widget.dart'; |
| 6 | +import 'package:wow_english/utils/log_util.dart'; | |
| 6 | 7 | |
| 7 | 8 | class LookVideoPage extends StatelessWidget { |
| 8 | 9 | const LookVideoPage( |
| 9 | - {super.key, this.videoUrl, this.typeTitle, this.courseLessonId, this.isTopic = false}); | |
| 10 | + {super.key, | |
| 11 | + this.videoUrl, | |
| 12 | + this.typeTitle, | |
| 13 | + this.courseLessonId, | |
| 14 | + this.isTopic = false}); | |
| 10 | 15 | |
| 11 | 16 | final String? videoUrl; |
| 12 | 17 | final String? typeTitle; |
| ... | ... | @@ -16,24 +21,34 @@ class LookVideoPage extends StatelessWidget { |
| 16 | 21 | @override |
| 17 | 22 | Widget build(BuildContext context) { |
| 18 | 23 | return BlocProvider( |
| 19 | - create: (BuildContext context) => LookVideoBloc(videoUrl, typeTitle, courseLessonId, isTopic), | |
| 24 | + create: (BuildContext context) => | |
| 25 | + LookVideoBloc(videoUrl, typeTitle, courseLessonId, isTopic) | |
| 26 | + ..add(RequestDataEvent()), | |
| 20 | 27 | child: Builder(builder: (context) => _buildPage(context)), |
| 21 | 28 | ); |
| 22 | 29 | } |
| 23 | 30 | } |
| 24 | 31 | |
| 25 | 32 | Widget _buildPage(BuildContext context) { |
| 26 | - return BlocBuilder<LookVideoBloc, BaseSectionState>(builder: (context, state) { | |
| 27 | - final bloc = BlocProvider.of<LookVideoBloc>(context); | |
| 28 | - return Container( | |
| 29 | - color: Colors.white, | |
| 30 | - child: VideoWidget( | |
| 31 | - videoUrl: bloc.videoUrl ?? '', | |
| 32 | - typeTitle: bloc.typeTitle ?? '', | |
| 33 | - courseLessonId: bloc.courseLessonId ?? '', | |
| 34 | - isTopic: bloc.isTopic, | |
| 35 | - ) | |
| 36 | - ); | |
| 37 | - } | |
| 38 | - ); | |
| 33 | + return BlocBuilder<LookVideoBloc, BaseSectionState>( | |
| 34 | + builder: (context, state) { | |
| 35 | + final bloc = BlocProvider.of<LookVideoBloc>(context); | |
| 36 | + Log.d("WQF lookvideo BlocBuilder bloc.videoUr=${bloc.videoUrl}"); | |
| 37 | + return Center( | |
| 38 | + child: bloc.videoUrl?.isNotEmpty == true | |
| 39 | + ? Container( | |
| 40 | + color: Colors.white, | |
| 41 | + child: VideoWidget( | |
| 42 | + videoUrl: bloc.videoUrl ?? '', | |
| 43 | + typeTitle: bloc.typeTitle ?? '', | |
| 44 | + courseLessonId: bloc.courseLessonId ?? '', | |
| 45 | + isTopic: bloc.isTopic, | |
| 46 | + )) | |
| 47 | + //todo 空了需要抽一个通用的loading组件 | |
| 48 | + : Container( | |
| 49 | + color: Colors.white, | |
| 50 | + child: const CircularProgressIndicator(), | |
| 51 | + ), | |
| 52 | + ); | |
| 53 | + }); | |
| 39 | 54 | } | ... | ... |
lib/pages/video/lookvideo/widgets/video_widget.dart
| ... | ... | @@ -12,11 +12,12 @@ import '../../../section/subsection/base_section/state.dart'; |
| 12 | 12 | import 'video_opera_widget.dart'; |
| 13 | 13 | |
| 14 | 14 | class VideoWidget extends StatefulWidget { |
| 15 | - const VideoWidget({super.key, | |
| 16 | - this.videoUrl = '', | |
| 17 | - this.typeTitle, | |
| 18 | - this.courseLessonId = '', | |
| 19 | - this.isTopic = false}); | |
| 15 | + const VideoWidget( | |
| 16 | + {super.key, | |
| 17 | + this.videoUrl = '', | |
| 18 | + this.typeTitle, | |
| 19 | + this.courseLessonId = '', | |
| 20 | + this.isTopic = false}); | |
| 20 | 21 | |
| 21 | 22 | final String videoUrl; |
| 22 | 23 | final String? typeTitle; |
| ... | ... | @@ -39,10 +40,10 @@ class _VideoWidgetState extends State<VideoWidget> { |
| 39 | 40 | |
| 40 | 41 | String formatDuration(Duration duration) { |
| 41 | 42 | String hours = duration.inHours.toString().padLeft(2, '0'); |
| 42 | - String minutes = duration.inMinutes.remainder(60).toString().padLeft( | |
| 43 | - 2, '0'); | |
| 44 | - String seconds = duration.inSeconds.remainder(60).toString().padLeft( | |
| 45 | - 2, '0'); | |
| 43 | + String minutes = | |
| 44 | + duration.inMinutes.remainder(60).toString().padLeft(2, '0'); | |
| 45 | + String seconds = | |
| 46 | + duration.inSeconds.remainder(60).toString().padLeft(2, '0'); | |
| 46 | 47 | return "$hours:$minutes:$seconds"; |
| 47 | 48 | } |
| 48 | 49 | |
| ... | ... | @@ -71,17 +72,17 @@ class _VideoWidgetState extends State<VideoWidget> { |
| 71 | 72 | _controller!.value.position.inSeconds == |
| 72 | 73 | _controller!.value.duration.inSeconds) { |
| 73 | 74 | final lookVideoBloc = context.read<LookVideoBloc>(); |
| 74 | - lookVideoBloc.sectionComplete(() { | |
| 75 | - popPage(data: { | |
| 76 | - 'courseLessonId': widget.courseLessonId, | |
| 77 | - 'currentTime': getCurrentPositionSeconds(), | |
| 78 | - 'isCompleted': true, | |
| 79 | - 'nextSection': widget.isTopic | |
| 80 | - }); | |
| 81 | - } as VoidCallback, | |
| 82 | - againSectionTap: (() { | |
| 83 | - lookVideoBloc.add(SectionAgainEvent()); | |
| 84 | - }), context: context); | |
| 75 | + lookVideoBloc.sectionComplete( | |
| 76 | + () { | |
| 77 | + popPage(data: { | |
| 78 | + 'courseLessonId': widget.courseLessonId, | |
| 79 | + 'currentTime': getCurrentPositionSeconds(), | |
| 80 | + 'isCompleted': true, | |
| 81 | + 'nextSection': widget.isTopic | |
| 82 | + }); | |
| 83 | + } as VoidCallback, againSectionTap: (() { | |
| 84 | + lookVideoBloc.add(SectionAgainEvent()); | |
| 85 | + }), context: context); | |
| 85 | 86 | } |
| 86 | 87 | } |
| 87 | 88 | }); |
| ... | ... | @@ -189,63 +190,63 @@ class _VideoWidgetState extends State<VideoWidget> { |
| 189 | 190 | child: Center( |
| 190 | 191 | child: _controller!.value.isInitialized |
| 191 | 192 | ? Stack( |
| 192 | - alignment: Alignment.center, | |
| 193 | - children: [ | |
| 194 | - SizedBox( | |
| 195 | - height: double.infinity, | |
| 196 | - width: double.infinity, | |
| 197 | - child: AspectRatio( | |
| 198 | - aspectRatio: _controller!.value.aspectRatio, | |
| 199 | - child: VideoPlayer(_controller!), | |
| 200 | - ), | |
| 201 | - ), | |
| 202 | - Offstage( | |
| 203 | - offstage: _hiddenTipView, | |
| 204 | - child: VideoOperaWidget( | |
| 205 | - title: widget.typeTitle ?? 'song', | |
| 206 | - degree: _playDegree, | |
| 207 | - totalTime: _totalTime, | |
| 208 | - currentTime: _currentTime, | |
| 209 | - isPlay: _controller!.value.isPlaying, | |
| 210 | - actionEvent: (OperationType type) { | |
| 211 | - actionType(type); | |
| 212 | - }, | |
| 213 | - sliderChangeEvent: (double degree) { | |
| 214 | - int totalSecond = _controller! | |
| 215 | - .value.duration.inMinutes | |
| 216 | - .remainder(60) * | |
| 217 | - 60 + | |
| 218 | - _controller!.value.duration.inSeconds | |
| 219 | - .remainder(60); | |
| 220 | - int positionSecond = (totalSecond * degree).toInt(); | |
| 221 | - _controller! | |
| 222 | - .seekTo(Duration(seconds: positionSecond)); | |
| 223 | - }, | |
| 224 | - ), | |
| 225 | - ), | |
| 226 | - Offstage( | |
| 227 | - offstage: _controller!.value.isPlaying, | |
| 228 | - child: IconButton( | |
| 229 | - onPressed: () { | |
| 230 | - _controller!.play(); | |
| 231 | - }, | |
| 232 | - icon: Image.asset( | |
| 233 | - 'video_stop'.assetPng, | |
| 234 | - width: 70.w, | |
| 235 | - height: 70.h, | |
| 236 | - ), | |
| 237 | - ), | |
| 238 | - ) | |
| 239 | - ], | |
| 240 | - ) | |
| 193 | + alignment: Alignment.center, | |
| 194 | + children: [ | |
| 195 | + SizedBox( | |
| 196 | + height: double.infinity, | |
| 197 | + width: double.infinity, | |
| 198 | + child: AspectRatio( | |
| 199 | + aspectRatio: _controller!.value.aspectRatio, | |
| 200 | + child: VideoPlayer(_controller!), | |
| 201 | + ), | |
| 202 | + ), | |
| 203 | + Offstage( | |
| 204 | + offstage: _hiddenTipView, | |
| 205 | + child: VideoOperaWidget( | |
| 206 | + title: widget.typeTitle ?? 'song', | |
| 207 | + degree: _playDegree, | |
| 208 | + totalTime: _totalTime, | |
| 209 | + currentTime: _currentTime, | |
| 210 | + isPlay: _controller!.value.isPlaying, | |
| 211 | + actionEvent: (OperationType type) { | |
| 212 | + actionType(type); | |
| 213 | + }, | |
| 214 | + sliderChangeEvent: (double degree) { | |
| 215 | + int totalSecond = _controller! | |
| 216 | + .value.duration.inMinutes | |
| 217 | + .remainder(60) * | |
| 218 | + 60 + | |
| 219 | + _controller!.value.duration.inSeconds | |
| 220 | + .remainder(60); | |
| 221 | + int positionSecond = (totalSecond * degree).toInt(); | |
| 222 | + _controller! | |
| 223 | + .seekTo(Duration(seconds: positionSecond)); | |
| 224 | + }, | |
| 225 | + ), | |
| 226 | + ), | |
| 227 | + Offstage( | |
| 228 | + offstage: _controller!.value.isPlaying, | |
| 229 | + child: IconButton( | |
| 230 | + onPressed: () { | |
| 231 | + _controller!.play(); | |
| 232 | + }, | |
| 233 | + icon: Image.asset( | |
| 234 | + 'video_stop'.assetPng, | |
| 235 | + width: 70.w, | |
| 236 | + height: 70.h, | |
| 237 | + ), | |
| 238 | + ), | |
| 239 | + ) | |
| 240 | + ], | |
| 241 | + ) | |
| 241 | 242 | : Container( |
| 242 | - color: Colors.white, | |
| 243 | - child: const CircularProgressIndicator(), | |
| 244 | - // Text( | |
| 245 | - // '视频加载中....', | |
| 246 | - // style: TextStyle(fontSize: 20.sp, color: Colors.black), | |
| 247 | - // ), | |
| 248 | - ), | |
| 243 | + color: Colors.white, | |
| 244 | + child: const CircularProgressIndicator(), | |
| 245 | + // Text( | |
| 246 | + // '视频加载中....', | |
| 247 | + // style: TextStyle(fontSize: 20.sp, color: Colors.black), | |
| 248 | + // ), | |
| 249 | + ), | |
| 249 | 250 | ), |
| 250 | 251 | ), |
| 251 | 252 | ); | ... | ... |