Commit 3c1d5c64b66a976b75f76c9efe5dec1553e82c93

Authored by liangchengyou
1 parent a506beff

feat:练习功能完成

assets/images/micro_phone.gif 0 → 100644

17.3 KB

assets/images/reade_answer.gif 0 → 100644

5.31 KB

ios/Runner/XSMessageMehtodChannel.swift
... ... @@ -39,7 +39,7 @@ class XSMessageMehtodChannel: NSObject,SSOralEvaluatingManagerDelegate {
39 39 }
40 40  
41 41 //开始评测
42   - func evaluateVioce(dict:Dictionary<String, Any>) {
  42 + func evaluateVoice(dict:Dictionary<String, Any>) {
43 43 let text = dict["word"] as? String ?? ""
44 44 let type = dict["type"] as? String ?? "0"
45 45 let userId = dict["userId"] as? String ?? "guest"
... ... @@ -50,6 +50,7 @@ class XSMessageMehtodChannel: NSObject,SSOralEvaluatingManagerDelegate {
50 50 } else {
51 51 config.oralType = .sentence
52 52 }
  53 + config.oralType = .kidSent
53 54 config.userId = userId
54 55 SSOralEvaluatingManager.share().startEvaluateOral(with: config)
55 56 }
... ... @@ -59,8 +60,8 @@ class XSMessageMehtodChannel: NSObject,SSOralEvaluatingManagerDelegate {
59 60 self.setEvaluateConfig(dict:call.arguments as! Dictionary<String, Any>)
60 61 return
61 62 }
62   - if (call.method == "starVoice") {
63   - self.evaluateVioce(dict: call.arguments as! Dictionary<String, Any>)
  63 + if (call.method == "startVoice") {
  64 + self.evaluateVoice(dict: call.arguments as! Dictionary<String, Any>)
64 65 return
65 66 }
66 67  
... ...
lib/pages/home/bloc/home_bloc.dart
... ... @@ -4,6 +4,8 @@ import &#39;package:flutter_bloc/flutter_bloc.dart&#39;;
4 4 import 'package:wow_english/common/request/dao/home_dao.dart';
5 5 import 'package:wow_english/common/request/exception.dart';
6 6 import 'package:wow_english/models/course_entity.dart';
  7 +import 'package:wow_english/common/request/dao/listen_dao.dart';
  8 +import 'package:wow_english/models/course_process_entity.dart';
7 9 // import 'package:wow_english/models/course_lesson_entity.dart';
8 10 import 'package:wow_english/utils/loading.dart';
9 11 import 'package:wow_english/utils/toast_util.dart';
... ... @@ -18,8 +20,13 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
18 20  
19 21 CourseEntity? get modelData => _modelData;
20 22  
  23 + CourseProcessEntity? _processEntity;
  24 +
  25 + CourseProcessEntity? get processEntity => _processEntity;
  26 +
21 27 HomeBloc(this.moduleId) : super(HomeInitial()) {
22 28 on<RequestDataEvent>(_requestData);
  29 + on<RequestVideoLessonEvent>(_requestVideoLesson);
23 30 }
24 31  
25 32 void _requestData(RequestDataEvent event, Emitter<HomeState> emitter) async {
... ... @@ -34,4 +41,17 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
34 41 }
35 42 }
36 43 }
  44 +
  45 + void _requestVideoLesson(RequestVideoLessonEvent event, Emitter<HomeState> emitter) async {
  46 + try {
  47 + await loading(() async {
  48 + _processEntity = await ListenDao.process(event.courseLessonId);
  49 + emitter(RequestVideoLessonState(event.courseType));
  50 + });
  51 + } catch (e) {
  52 + if (e is ApiException) {
  53 + showToast(e.message??'请求失败,请检查网络连接');
  54 + }
  55 + }
  56 + }
37 57 }
... ...
lib/pages/home/bloc/home_event.dart
... ... @@ -4,3 +4,10 @@ part of &#39;home_bloc.dart&#39;;
4 4 abstract class HomeEvent {}
5 5  
6 6 class RequestDataEvent extends HomeEvent {}
  7 +
  8 +///获取视频课程内容
  9 +class RequestVideoLessonEvent extends HomeEvent {
  10 + final String courseLessonId;
  11 + final int courseType;
  12 + RequestVideoLessonEvent(this.courseLessonId, this.courseType);
  13 +}
... ...
lib/pages/home/bloc/home_state.dart
... ... @@ -6,3 +6,8 @@ abstract class HomeState {}
6 6 class HomeInitial extends HomeState {}
7 7  
8 8 class HomeDataLoadState extends HomeState {}
  9 +
  10 +class RequestVideoLessonState extends HomeState {
  11 + final int type;
  12 + RequestVideoLessonState(this.type);
  13 +}
... ...
lib/pages/home/home_page.dart
... ... @@ -45,8 +45,30 @@ class _HomePageView extends StatelessWidget {
45 45  
46 46 @override
47 47 Widget build(BuildContext context) {
  48 + final bloc = BlocProvider.of<HomeBloc>(context);
48 49 return BlocListener<HomeBloc, HomeState>(
49   - listener: (context, state) {},
  50 + listener: (context, state) {
  51 + if (state is RequestVideoLessonState) {
  52 + final videoUrl = bloc.processEntity?.videos?.videoUrl??'';
  53 + var title = '';
  54 + if (state.type == 1) {
  55 + title = 'song';
  56 + }
  57 +
  58 + if (state.type == 2) {
  59 + title = 'video';
  60 + }
  61 +
  62 + if (state.type == 5) {
  63 + title = 'bonus';
  64 + }
  65 + debugPrint(videoUrl);
  66 + if (videoUrl.isEmpty) {
  67 + return;
  68 + }
  69 + Navigator.of(context).pushNamed(AppRouteName.lookVideo,arguments: {'videoUrl':videoUrl,'title':title});
  70 + }
  71 + },
50 72 child: _homeView(),
51 73 );
52 74 }
... ... @@ -76,9 +98,10 @@ class _HomePageView extends StatelessWidget {
76 98 return GestureDetector(
77 99 onTap: () {
78 100 if (data!.lock!) {
  101 + showToast('当前课程暂未解锁');
79 102 return;
80 103 }
81   - showToast('点击事件');
  104 + bloc.add(RequestVideoLessonEvent(data.id!,data.courseType!));
82 105 },
83 106 child: HomeBoundsItem(
84 107 imageUrl: data?.coverUrl,
... ... @@ -87,17 +110,22 @@ class _HomePageView extends StatelessWidget {
87 110 } else {
88 111 return GestureDetector(
89 112 onTap: () {
  113 + debugPrint('>>>>>>>类型${data?.courseType}');
90 114 if (data!.lock!) {
  115 + showToast('当前课程暂未解锁');
91 116 return;
92 117 }
93   - if (data!.courseType == 4) {//绘本
  118 + if (data.courseType == 4) {//绘本
94 119 return;
95 120 }
96 121  
97 122 if (data.courseType == 3) {//练习
98   - Navigator.of(context).pushNamed(AppRouteName.topicPic,arguments: {'courseLessonId':data!.id});
  123 + Navigator.of(context).pushNamed(AppRouteName.topicPic,arguments: {'courseLessonId':data.id!});
99 124 return;
100 125 }
  126 +
  127 + //儿歌/看视频
  128 + bloc.add(RequestVideoLessonEvent(data.id!,data.courseType!));
101 129 },
102 130 child: HomeVideoItem(
103 131 lessons: data,
... ...
lib/pages/home/widgets/home_tab_header_widget.dart
... ... @@ -71,7 +71,7 @@ class HomeTabHeaderWidget extends StatelessWidget {
71 71 20.horizontalSpace,
72 72 const Expanded(
73 73 child: Text(
74   - 'learn wow!yellow',
  74 + 'learn wow',
75 75 textAlign: TextAlign.left,
76 76 style: TextStyle(color: Colors.white, fontSize: 30.0),
77 77 )),
... ...
lib/pages/practice/bloc/topic_picture_bloc.dart
... ... @@ -8,10 +8,22 @@ import &#39;package:wow_english/common/request/dao/listen_dao.dart&#39;;
8 8 import 'package:wow_english/common/request/exception.dart';
9 9 import 'package:wow_english/models/course_process_entity.dart';
10 10 import 'package:wow_english/utils/loading.dart';
  11 +import 'package:wow_english/utils/toast_util.dart';
11 12  
12 13 part 'topic_picture_event.dart';
13 14 part 'topic_picture_state.dart';
14 15  
  16 +enum VoicePlayState {
  17 + ///未知
  18 + unKnow,
  19 + ///播放中
  20 + playing,
  21 + ///播放完成
  22 + completed,
  23 + ///播放终止
  24 + stop
  25 +}
  26 +
15 27 class TopicPictureBloc extends Bloc<TopicPictureEvent, TopicPictureState> {
16 28  
17 29 final PageController pageController;
... ... @@ -27,6 +39,9 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
27 39 ///正在评测
28 40 bool _isVoicing = false;
29 41  
  42 + ///正在播放音频
  43 + VoicePlayState _voicePlayState = VoicePlayState.unKnow;
  44 +
30 45 CourseProcessEntity? get entity => _entity;
31 46  
32 47 int get currentPage => _currentPage + 1;
... ... @@ -35,29 +50,46 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
35 50  
36 51 bool get isVoicing => _isVoicing;
37 52  
  53 + VoicePlayState get voicePlayState => _voicePlayState;
  54 +
38 55 late MethodChannel methodChannel;
39 56  
40 57 late AudioPlayer audioPlayer;
41 58  
42 59 TopicPictureBloc(this.pageController, this.courseLessonId) : super(TopicPictureInitial()) {
43 60 on<CurrentPageIndexChangeEvent>(_pageControllerChange);
  61 + on<VoicePlayStateChangeEvent>(_voicePlayStateChange);
  62 + on<XSVoiceResultEvent>(_voiceXsResult);
  63 + on<XSVoiceInitEvent>(_initVoiceSdk);
44 64 on<SelectItemEvent>(_selectItemLoad);
45 65 on<RequestDataEvent>(_requestData);
46 66 on<XSVoiceTestEvent>(_voiceXsTest);
47   - on<XSVoiceResultEvent>(_voiceXsResult);
48   - on<XSVoiceInitEvent>(_initVoiceSdk);
49   - on<TopicPictureEvent>((event, emit) {
  67 + on<XSVoiceStopEvent>(_voiceXsStop);
  68 + on<VoicePlayEvent>(_voicePlay);
  69 + on<InitBlocEvent>((event, emit) {
50 70 //音频播放器
51 71 audioPlayer = AudioPlayer();
52   - audioPlayer.onPlayerStateChanged.listen((event) {
  72 + audioPlayer.onPlayerStateChanged.listen((event) async {
  73 + debugPrint('播放状态变化');
53 74 if (event == PlayerState.completed) {
54   - if (kDebugMode) {
55   - print('播放完成');
  75 + debugPrint('播放完成');
  76 + _voicePlayState = VoicePlayState.completed;
  77 + }
  78 + if (event == PlayerState.stopped) {
  79 + debugPrint('播放结束');
  80 + _voicePlayState = VoicePlayState.stop;
  81 + }
56 82  
57   - }}
  83 + if (event == PlayerState.playing) {
  84 + debugPrint('正在播放中');
  85 + _voicePlayState = VoicePlayState.playing;
  86 + }
  87 + if(isClosed) {
  88 + return;
  89 + }
  90 + add(VoicePlayStateChangeEvent());
58 91 });
59 92  
60   -
61 93 methodChannel = const MethodChannel('wow_english/sing_sound_method_channely');
62 94 methodChannel.setMethodCallHandler((call) async {
63 95 if (call.method == 'voiceResult') {//评测结果
... ... @@ -88,8 +120,9 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
88 120 }
89 121  
90 122 @override
91   - Future<void> close() {
  123 + Future<void> close(){
92 124 pageController.dispose();
  125 + audioPlayer.release();
93 126 audioPlayer.dispose();
94 127 return super.close();
95 128 }
... ... @@ -103,30 +136,26 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
103 136 });
104 137 } catch (e) {
105 138 if (e is ApiException) {
106   - EasyLoading.showToast(e.message??'请求失败,请检查网络连接');
  139 + showToast(e.message??'请求失败,请检查网络连接');
107 140 }
108 141 }
109 142 }
110 143  
111   - ///初始化SDK
112   - _initVoiceSdk(XSVoiceInitEvent event,Emitter<TopicPictureState> emitter) async {
113   - methodChannel.invokeMethod('initVoiceSdk',event.data);
114   - }
115   -
116 144 ///页面切换
117 145 void _pageControllerChange(CurrentPageIndexChangeEvent event,Emitter<TopicPictureState> emitter) async {
118 146 _currentPage = event.pageIndex;
  147 + if (voicePlayState == VoicePlayState.playing) {
  148 + await audioPlayer.stop();
  149 + }
119 150 final topics = _entity?.topics?[_currentPage];
120   - if (topics?.type == 1 || topics?.type == 2 || topics?.type == 5) {
121   - audioPlayer.stop();
  151 + if (topics?.type != 3 && topics?.type != 4) {
122 152 if (topics?.audioUrl != null) {
123 153 final urlStr = topics?.audioUrl??'';
124 154 if (urlStr.isNotEmpty) {
125   - audioPlayer.play(UrlSource(urlStr));
  155 + debugPrint(urlStr);
  156 + await audioPlayer.play(UrlSource(urlStr));
126 157 }
127 158 }
128   - } else {
129   - audioPlayer.stop();
130 159 }
131 160 _selectItem = -1;
132 161 emitter(CurrentPageIndexState());
... ... @@ -135,12 +164,24 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
135 164 ///选择
136 165 void _selectItemLoad(SelectItemEvent event,Emitter<TopicPictureState> emitter) async {
137 166 _selectItem = event.selectIndex;
  167 + CourseProcessTopics? topics = _entity?.topics?[_currentPage];
  168 + CourseProcessTopicsTopicAnswerList? answerList = topics?.topicAnswerList?[_selectItem];
  169 + if (answerList?.correct == 0) {
  170 + showToast('继续加油哦',duration: const Duration(seconds: 2));
  171 + } else {
  172 + showToast('恭喜你,答对啦!',duration: const Duration(seconds: 2));
  173 + }
138 174 emitter(SelectItemChangeState());
139 175 }
140 176  
  177 + ///初始化SDK
  178 + _initVoiceSdk(XSVoiceInitEvent event,Emitter<TopicPictureState> emitter) async {
  179 + methodChannel.invokeMethod('initVoiceSdk',event.data);
  180 + }
  181 +
141 182 ///先声测试
142 183 void _voiceXsTest(XSVoiceTestEvent event,Emitter<TopicPictureState> emitter) async {
143   - EasyLoading.show(status: '录音中....');
  184 + audioPlayer.stop();
144 185 methodChannel.invokeMethod(
145 186 'startVoice',
146 187 {'word':event.testWord,'type':event.type,'userId':event.userId.toString()}
... ... @@ -149,16 +190,36 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
149 190 emitter(XSVoiceTestState());
150 191 }
151 192  
  193 + ///终止评测
  194 + void _voiceXsStop(XSVoiceStopEvent event,Emitter<TopicPictureState> emitter) async {
  195 + methodChannel.invokeMethod('stopVoice');
  196 + }
  197 +
  198 + ///先声评测结果
152 199 void _voiceXsResult(XSVoiceResultEvent event,Emitter<TopicPictureState> emitter) async {
153 200 final Map args = event.message as Map;
154 201 final result = args['result'] as String;
155 202 if (result == '1') {
156 203 final overall = args['overall'].toString();
157   - EasyLoading.showToast('测评成功,分数是$overall',duration: const Duration(seconds: 10));
  204 + showToast('测评成功,分数是$overall',duration: const Duration(seconds: 5));
158 205 } else {
159   - EasyLoading.showToast('测评失败',duration: const Duration(seconds: 10));
  206 + showToast('测评失败',duration: const Duration(seconds: 5));
160 207 }
161 208 _isVoicing = false;
162 209 emitter(XSVoiceTestState());
163 210 }
  211 +
  212 + void _voicePlayStateChange(VoicePlayStateChangeEvent event,Emitter<TopicPictureState> emitter) async {
  213 + emitter(VoicePlayStateChange());
  214 + }
  215 +
  216 + void _voicePlay(VoicePlayEvent event,Emitter<TopicPictureState> emitter) async {
  217 + if (voicePlayState == VoicePlayState.playing) {
  218 + await audioPlayer.stop();
  219 + return;
  220 + }
  221 + final topics = _entity?.topics?[_currentPage];
  222 + final urlStr = topics?.audioUrl??'';
  223 + await audioPlayer.play(UrlSource(urlStr));
  224 + }
164 225 }
... ...
lib/pages/practice/bloc/topic_picture_event.dart
... ... @@ -3,6 +3,8 @@ part of &#39;topic_picture_bloc.dart&#39;;
3 3 @immutable
4 4 abstract class TopicPictureEvent {}
5 5  
  6 +class InitBlocEvent extends TopicPictureEvent {}
  7 +
6 8 class RequestDataEvent extends TopicPictureEvent {}
7 9  
8 10 ///初始化先声SDK
... ... @@ -11,13 +13,7 @@ class XSVoiceInitEvent extends TopicPictureEvent {
11 13 XSVoiceInitEvent(this.data);
12 14 }
13 15  
14   -///评测结果
15   -class XSVoiceResultEvent extends TopicPictureEvent {
16   - final dynamic message;
17   - XSVoiceResultEvent(this.message);
18   -}
19   -
20   -///先声测试
  16 +///开始评测
21 17 class XSVoiceTestEvent extends TopicPictureEvent {
22 18 final String testWord;
23 19 final String type;
... ... @@ -25,12 +21,32 @@ class XSVoiceTestEvent extends TopicPictureEvent {
25 21 XSVoiceTestEvent(this.testWord,this.type,this.userId);
26 22 }
27 23  
  24 +///终止评测
  25 +class XSVoiceStopEvent extends TopicPictureEvent {}
  26 +
  27 +///评测结果
  28 +class XSVoiceResultEvent extends TopicPictureEvent {
  29 + final dynamic message;
  30 + XSVoiceResultEvent(this.message);
  31 +}
  32 +
  33 +///音频播放状态变化
  34 +class VoicePlayStateChangeEvent extends TopicPictureEvent {}
  35 +
  36 +///页面切换
28 37 class CurrentPageIndexChangeEvent extends TopicPictureEvent {
29 38 final int pageIndex;
30 39 CurrentPageIndexChangeEvent(this.pageIndex);
31 40 }
32 41  
  42 +///选择答案
33 43 class SelectItemEvent extends TopicPictureEvent {
34 44 final int selectIndex;
35 45 SelectItemEvent(this.selectIndex);
36   -}
37 46 \ No newline at end of file
  47 +}
  48 +
  49 +///音频播放事件
  50 +class VoicePlayChangeEvent extends TopicPictureEvent {}
  51 +
  52 +///播放音乐
  53 +class VoicePlayEvent extends TopicPictureEvent {}
38 54 \ No newline at end of file
... ...
lib/pages/practice/bloc/topic_picture_state.dart
... ... @@ -3,12 +3,14 @@ part of &#39;topic_picture_bloc.dart&#39;;
3 3 @immutable
4 4 abstract class TopicPictureState {}
5 5  
  6 +class TopicPictureInitial extends TopicPictureState {}
  7 +
6 8 class RequestDataState extends TopicPictureState {}
7 9  
8 10 class XSVoiceTestState extends TopicPictureState {}
9 11  
10   -class TopicPictureInitial extends TopicPictureState {}
11   -
12 12 class CurrentPageIndexState extends TopicPictureState {}
13 13  
14 14 class SelectItemChangeState extends TopicPictureState {}
  15 +
  16 +class VoicePlayStateChange extends TopicPictureState {}
... ...
lib/pages/practice/topic_picture_page.dart
... ... @@ -5,11 +5,12 @@ import &#39;package:wow_english/common/core/user_util.dart&#39;;
5 5 import 'package:wow_english/common/extension/string_extension.dart';
6 6 import 'package:wow_english/common/widgets/ow_image_widget.dart';
7 7 import 'package:wow_english/models/course_process_entity.dart';
  8 +import 'package:wow_english/utils/toast_util.dart';
8 9  
9 10 import 'bloc/topic_picture_bloc.dart';
10 11 import 'widgets/practice_header_widget.dart';
11 12  
12   -class TopicPicturePage extends StatelessWidget {
  13 +class TopicPicturePage extends StatelessWidget {
13 14 const TopicPicturePage({super.key, this.courseLessonId});
14 15  
15 16 final String? courseLessonId;
... ... @@ -18,9 +19,10 @@ class TopicPicturePage extends StatelessWidget {
18 19 Widget build(BuildContext context) {
19 20 return BlocProvider(
20 21 create: (context) => TopicPictureBloc(
21   - PageController(),
22   - courseLessonId??'',
  22 + PageController(),
  23 + courseLessonId??'',
23 24 )
  25 + ..add(InitBlocEvent())
24 26 ..add(RequestDataEvent())
25 27 ..add(XSVoiceInitEvent(
26 28 {
... ... @@ -258,13 +260,23 @@ class _TopicPicturePage extends StatelessWidget {
258 260 ///听音选图
259 261 Widget _pageViewVoicePictureItemWidget(CourseProcessTopics? topics) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
260 262 builder: (context, state){
  263 + final bloc = BlocProvider.of<TopicPictureBloc>(context);
261 264 return SafeArea(
262 265 child: Column(
263 266 children: [
264 267 Row(
265 268 mainAxisAlignment: MainAxisAlignment.center,
266 269 children: [
267   - Image.asset('voice'.assetPng,height: 33.h,width: 30.w,),
  270 + GestureDetector(
  271 + onTap: () {
  272 + bloc.add(VoicePlayEvent());
  273 + },
  274 + child: Image.asset(
  275 + bloc.voicePlayState == VoicePlayState.playing?'reade_answer'.assetGif:'voice'.assetPng,
  276 + height: 33.h,
  277 + width: 30.w,
  278 + ),
  279 + ),
268 280 10.horizontalSpace,
269 281 Text(
270 282 topics?.word??'',
... ... @@ -331,10 +343,20 @@ class _TopicPicturePage extends StatelessWidget {
331 343 ///听音选字
332 344 Widget _pageViewVoiceWordItemWidget(CourseProcessTopics? topics) => BlocBuilder<TopicPictureBloc,TopicPictureState>(
333 345 builder: (context, state){
  346 + final bloc = BlocProvider.of<TopicPictureBloc>(context);
334 347 return SafeArea(
335 348 child: Column(
336 349 children: [
337   - Image.asset('voice'.assetPng,height: 33.h,width: 30.w,),
  350 + GestureDetector(
  351 + onTap: () {
  352 + bloc.add(VoicePlayEvent());
  353 + },
  354 + child: Image.asset(
  355 + bloc.voicePlayState == VoicePlayState.playing?'reade_answer'.assetGif:'voice'.assetPng,
  356 + height: 33.h,
  357 + width: 30.w
  358 + )
  359 + ),
338 360 26.verticalSpace,
339 361 SizedBox(
340 362 width: 163.w * (topics?.topicAnswerList?.length??0),
... ... @@ -426,31 +448,45 @@ class _TopicPicturePage extends StatelessWidget {
426 448 Column(
427 449 mainAxisAlignment: MainAxisAlignment.center,
428 450 children: [
429   - Row(
430   - children: [
431   - Image.asset(
432   - 'voice'.assetPng,
433   - height: 52.h,
434   - width: 46.w,
435   - ),
436   - 10.horizontalSpace,
437   - Text(topics?.word??'')
438   - ],
  451 + GestureDetector(
  452 + onTap: () {
  453 + if (bloc.isVoicing) {
  454 + showToast('正在录音,不能终止');
  455 + return;
  456 + }
  457 + bloc.add(VoicePlayEvent());
  458 + },
  459 + child: Row(
  460 + children: [
  461 + Image.asset(
  462 + bloc.voicePlayState == VoicePlayState.playing?'reade_answer'.assetGif:'voice'.assetPng,
  463 + height: 52.h,
  464 + width: 46.w,
  465 + ),
  466 + 10.horizontalSpace,
  467 + Text(topics?.word??'')
  468 + ],
  469 + ),
439 470 ),
440 471 70.verticalSpace,
441 472 GestureDetector(
442 473 onTap: () {
  474 + if (bloc.voicePlayState == VoicePlayState.playing) {
  475 + showToast('正在播放音屏,不能终止');
  476 + return;
  477 + }
  478 +
443 479 if (bloc.isVoicing) {
444 480 return;
445 481 }
446   - if (topics?.type == 5) {
  482 + if (topics?.type == 5 || topics?.type == 7) {
447 483 bloc.add(XSVoiceTestEvent(topics?.keyWord??'', '0',UserUtil.getUser()!.id.toString()));
448 484 } else {
449 485 bloc.add(XSVoiceTestEvent(topics?.word??'', '0',UserUtil.getUser()!.id.toString()));
450 486 }
451 487 },
452 488 child: Image.asset(
453   - 'micro_phone'.assetPng,
  489 + bloc.isVoicing?'micro_phone'.assetGif:'micro_phone'.assetPng,
454 490 height: 75.w,
455 491 width: 75.w,
456 492 ),
... ...
lib/pages/reading/bloc/reading_bloc.dart
... ... @@ -125,7 +125,7 @@ class ReadingPageBloc extends Bloc&lt;ReadingPageEvent, ReadingPageState&gt; {
125 125 if (readingData?.audioUrl != null) {
126 126 final urlStr = audioUrl ?? readingData?.audioUrl ?? '';
127 127 if (urlStr.isNotEmpty) {
128   - audioPlayer.play(UrlSource(urlStr));
  128 + audioPlayer.play(UrlSource(urlStr));
129 129 }
130 130 }
131 131 }
... ...
lib/pages/video/lookvideo/widgets/video_opera_widget.dart
... ... @@ -94,6 +94,7 @@ class _VideoOperaWidgetState extends State&lt;VideoOperaWidget&gt; {
94 94 child: Text(
95 95 widget.title,
96 96 textAlign: TextAlign.center,
  97 + overflow: TextOverflow.clip,
97 98 style: TextStyle(
98 99 fontSize: 20.sp,
99 100 color: const Color(0xFF333333),
... ...