Blame view

lib/pages/reading/bloc/reading_bloc.dart 15.6 KB
a506beff   吴启风   feat:先声sdk方法找不到问题...
1
  import 'package:audioplayers/audioplayers.dart';
1dc46cf7   吴启风   feat:绘本ui
2
  import 'package:flutter/cupertino.dart';
a506beff   吴启风   feat:先声sdk方法找不到问题...
3
4
  import 'package:flutter/foundation.dart';
  import 'package:flutter/services.dart';
1dc46cf7   吴启风   feat:绘本ui
5
  import 'package:flutter_bloc/flutter_bloc.dart';
a506beff   吴启风   feat:先声sdk方法找不到问题...
6
  import 'package:flutter_easyloading/flutter_easyloading.dart';
fd737d6a   吴启风   feat:绘本作答结果以单词为单位...
7
  import 'package:flutter_screenutil/flutter_screenutil.dart';
6051f850   吴启风   feat:带隐私合规权限申请描述的...
8
  import 'package:permission_handler/permission_handler.dart';
2a427e12   吴启风   feat:绘本静态ui基本完成
9
  import 'package:wow_english/pages/reading/widgets/ReadingModeType.dart';
820997e6   吴启风   feat:过渡页-绘本环节
10
11
12
  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';
1dc46cf7   吴启风   feat:绘本ui
13
  
dae7f2fd   吴启风   feat:增加android端先声...
14
  import '../../../common/core/user_util.dart';
e811f164   吴启风   feat:权限申请页面增加隐私合规...
15
  import '../../../common/permission/permissionRequester.dart';
a506beff   吴启风   feat:先声sdk方法找不到问题...
16
17
  import '../../../common/request/dao/listen_dao.dart';
  import '../../../common/request/exception.dart';
d0623cfd   吴启风   feat:绘本作答结果动效
18
  import '../../../common/utils/show_star_reward_dialog.dart';
a506beff   吴启风   feat:先声sdk方法找不到问题...
19
  import '../../../models/course_process_entity.dart';
fd737d6a   吴启风   feat:绘本作答结果以单词为单位...
20
  import '../../../models/singsound_result_detail_entity.dart';
d0623cfd   吴启风   feat:绘本作答结果动效
21
  import '../../../models/voice_result_type.dart';
820997e6   吴启风   feat:过渡页-绘本环节
22
  import '../../../route/route.dart';
951eb853   吴启风   feat:代码优化-星星等动效对话...
23
  import '../../../utils/audio_player_util.dart';
a506beff   吴启风   feat:先声sdk方法找不到问题...
24
  import '../../../utils/loading.dart';
a506beff   吴启风   feat:先声sdk方法找不到问题...
25
  
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
26
  import '../../../utils/log_util.dart';
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
27
  
1dc46cf7   吴启风   feat:绘本ui
28
  part 'reading_event.dart';
d0623cfd   吴启风   feat:绘本作答结果动效
29
  
1dc46cf7   吴启风   feat:绘本ui
30
31
  part 'reading_state.dart';
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  enum VoicePlayState {
    ///未知
    unKnow,
  
    ///播放中
    playing,
  
    ///播放完成
    completed,
  
    ///播放终止
    stop
  }
  
820997e6   吴启风   feat:过渡页-绘本环节
46
47
  class ReadingPageBloc
      extends BaseSectionBloc<ReadingPageEvent, ReadingPageState> {
2a427e12   吴启风   feat:绘本静态ui基本完成
48
49
    final PageController pageController;
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
50
51
    final String courseLessonId;
  
2a427e12   吴启风   feat:绘本静态ui基本完成
52
53
54
55
    ///当前页索引
    int _currentPage = 0;
  
    ///当前播放模式
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
56
    ReadingModeType _currentMode = ReadingModeType.manual;
2a427e12   吴启风   feat:绘本静态ui基本完成
57
58
59
60
61
  
    int get currentPage => _currentPage + 1;
  
    ReadingModeType get currentMode => _currentMode;
  
a506beff   吴启风   feat:先声sdk方法找不到问题...
62
63
64
65
66
67
68
69
70
    CourseProcessEntity? _entity;
  
    CourseProcessEntity? get entity => _entity;
  
    ///正在评测
    bool _isRecording = false;
  
    bool get isRecording => _isRecording;
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    ///原始音频是否正在播放
    bool _isOriginAudioPlaying = false;
  
    bool get isOriginAudioPlaying => _isOriginAudioPlaying;
  
    ///录音音频是否正在播放
    bool _isRecordAudioPlaying = false;
  
    bool get isRecordAudioPlaying => _isRecordAudioPlaying;
  
    ///正在播放音频状态
    VoicePlayState _voicePlayState = VoicePlayState.unKnow;
  
    VoicePlayState get voicePlayState => _voicePlayState;
  
a506beff   吴启风   feat:先声sdk方法找不到问题...
86
87
88
89
    late MethodChannel methodChannel;
  
    late AudioPlayer audioPlayer;
  
6051f850   吴启风   feat:带隐私合规权限申请描述的...
90
91
    final BuildContext context;
  
d1ab5cb2   吴启风   feat:绘本跟读页上方进度信息改...
92
93
94
    final Color? moduleColor;
  
    ReadingPageBloc(this.context, this.pageController, this.courseLessonId, this.moduleColor)
53e9e6db   吴启风   feat:绘本语音评测逻辑
95
        : super(ReadingPageInitial()) {
2a427e12   吴启风   feat:绘本静态ui基本完成
96
      on<CurrentPageIndexChangeEvent>(_pageControllerChange);
53e9e6db   吴启风   feat:绘本语音评测逻辑
97
      on<CurrentModeChangeEvent>(_playModeChange);
2a427e12   吴启风   feat:绘本静态ui基本完成
98
99
100
      // pageController.addListener(() {
      //   _currentPage = pageController.page!.round();
      // });
a506beff   吴启风   feat:先声sdk方法找不到问题...
101
      on<RequestDataEvent>(_requestData);
53e9e6db   吴启风   feat:绘本语音评测逻辑
102
      on<InitBlocEvent>((event, emit) {
a506beff   吴启风   feat:先声sdk方法找不到问题...
103
104
        //音频播放器
        audioPlayer = AudioPlayer();
53e9e6db   吴启风   feat:绘本语音评测逻辑
105
        audioPlayer.onPlayerStateChanged.listen((event) async {
2ee6209a   吴启风   feat:绘本播放状态优化
106
          Log.d("播放状态变化 event=$event");
a506beff   吴启风   feat:先声sdk方法找不到问题...
107
          if (event == PlayerState.completed) {
53e9e6db   吴启风   feat:绘本语音评测逻辑
108
109
            debugPrint('播放完成');
            _voicePlayState = VoicePlayState.completed;
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
110
            _onAudioPlayComplete();
53e9e6db   吴启风   feat:绘本语音评测逻辑
111
112
113
114
          }
          if (event == PlayerState.stopped) {
            debugPrint('播放结束');
            _voicePlayState = VoicePlayState.stop;
53e9e6db   吴启风   feat:绘本语音评测逻辑
115
          }
a506beff   吴启风   feat:先声sdk方法找不到问题...
116
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
117
118
119
120
          if (event == PlayerState.playing) {
            debugPrint('正在播放中');
            _voicePlayState = VoicePlayState.playing;
          }
2ee6209a   吴启风   feat:绘本播放状态优化
121
122
123
124
125
126
  
          if (event == PlayerState.disposed) {
            debugPrint('播放器释放');
            _voicePlayState = VoicePlayState.unKnow;
          }
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
127
128
          if (isClosed) {
            return;
a506beff   吴启风   feat:先声sdk方法找不到问题...
129
          }
53e9e6db   吴启风   feat:绘本语音评测逻辑
130
          add(VoicePlayStateChangeEvent());
a506beff   吴启风   feat:先声sdk方法找不到问题...
131
132
        });
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
133
134
135
        methodChannel =
            const MethodChannel('wow_english/sing_sound_method_channel');
        methodChannel.invokeMethod('initVoiceSdk', {}); //初始化评测
a506beff   吴启风   feat:先声sdk方法找不到问题...
136
        methodChannel.setMethodCallHandler((call) async {
6051f850   吴启风   feat:带隐私合规权限申请描述的...
137
138
          Log.d(
              "setMethodCallHandler method=${call.method} arguments=${call.arguments}");
53e9e6db   吴启风   feat:绘本语音评测逻辑
139
140
          if (call.method == 'voiceResult') {
            //评测结果
1f5969b8   biao   修复 练习和绘本播放音频问题
141
142
143
            await audioPlayer.setAudioContext(AudioContext());
            await audioPlayer.setBalance(0.0);
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
144
145
146
147
148
149
150
151
152
            add(XSVoiceResultEvent(call.arguments));
            return;
          }
  
          if (call.method == 'voiceStart') {
            //评测开始
            if (kDebugMode) {
              print('评测开始');
            }
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
153
154
            _isRecording = true;
            add(OnXSVoiceStateChangeEvent());
53e9e6db   吴启风   feat:绘本语音评测逻辑
155
156
157
            return;
          }
  
46c68b45   吴启风   feat:翻页取消先声评测&增加先...
158
159
          if (call.method == 'voiceEnd' || call.method == 'voiceCancel') {
            //评测结束or评测取消
53e9e6db   吴启风   feat:绘本语音评测逻辑
160
            if (kDebugMode) {
46c68b45   吴启风   feat:翻页取消先声评测&增加先...
161
              print(call.method == 'voiceEnd' ? '评测结束' : '评测取消');
53e9e6db   吴启风   feat:绘本语音评测逻辑
162
            }
1f5969b8   biao   修复 练习和绘本播放音频问题
163
164
165
            await audioPlayer.setAudioContext(AudioContext());
            await audioPlayer.setBalance(0.0);
  
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
166
            _isRecording = false;
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
167
            add(OnXSVoiceStateChangeEvent());
53e9e6db   吴启风   feat:绘本语音评测逻辑
168
169
170
171
172
            return;
          }
  
          if (call.method == 'voiceFail') {
            //评测失败
1f5969b8   biao   修复 练习和绘本播放音频问题
173
174
175
            await audioPlayer.setAudioContext(AudioContext());
            await audioPlayer.setBalance(0.0);
  
8fb5f860   吴启风   feat:先声录音状态优化
176
177
            _isRecording = false;
            add(OnXSVoiceStateChangeEvent());
53e9e6db   吴启风   feat:绘本语音评测逻辑
178
179
            EasyLoading.showToast('评测失败');
            return;
a506beff   吴启风   feat:先声sdk方法找不到问题...
180
181
182
          }
        });
      });
53e9e6db   吴启风   feat:绘本语音评测逻辑
183
      on<VoicePlayStateChangeEvent>(_voicePlayStateChange);
a506beff   吴启风   feat:先声sdk方法找不到问题...
184
      on<PlayOriginalAudioEvent>(_playOriginalAudio);
53e9e6db   吴启风   feat:绘本语音评测逻辑
185
186
187
      on<XSVoiceInitEvent>(_initVoiceSdk);
      on<XSVoiceStartEvent>(_voiceXsStart);
      on<XSVoiceStopEvent>(_voiceXsStop);
a506beff   吴启风   feat:先声sdk方法找不到问题...
188
      on<XSVoiceResultEvent>(_voiceXsResult);
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
189
      on<OnXSVoiceStateChangeEvent>(_onVoiceXsStateChange);
53e9e6db   吴启风   feat:绘本语音评测逻辑
190
191
  
      on<PlayRecordAudioEvent>(_playRecordAudio);
2a427e12   吴启风   feat:绘本静态ui基本完成
192
193
194
195
196
    }
  
    @override
    Future<void> close() {
      pageController.dispose();
a506beff   吴启风   feat:先声sdk方法找不到问题...
197
198
      audioPlayer.release();
      audioPlayer.dispose();
081fbff7   吴启风   feat:性能优化-录音内存泄漏
199
      _voiceXsCancel(force: true);
2a427e12   吴启风   feat:绘本静态ui基本完成
200
201
202
      return super.close();
    }
  
a506beff   吴启风   feat:先声sdk方法找不到问题...
203
204
    void _pageControllerChange(CurrentPageIndexChangeEvent event,
        Emitter<ReadingPageState> emitter) async {
2a427e12   吴启风   feat:绘本静态ui基本完成
205
      _currentPage = event.pageIndex;
46c68b45   吴启风   feat:翻页取消先声评测&增加先...
206
      _voiceXsCancel();
2ee6209a   吴启风   feat:绘本播放状态优化
207
      _playOriginalAudioInner(null, forcePlay: true);
2a427e12   吴启风   feat:绘本静态ui基本完成
208
209
210
      emitter(CurrentPageIndexState());
    }
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
211
    void _playModeChange(
a506beff   吴启风   feat:先声sdk方法找不到问题...
212
        CurrentModeChangeEvent event, Emitter<ReadingPageState> emitter) async {
2a427e12   吴启风   feat:绘本静态ui基本完成
213
214
215
216
217
218
      if (_currentMode == ReadingModeType.auto) {
        _currentMode = ReadingModeType.manual;
      } else {
        _currentMode = ReadingModeType.auto;
      }
      emitter(CurrentModeState());
1dc46cf7   吴启风   feat:绘本ui
219
    }
a506beff   吴启风   feat:先声sdk方法找不到问题...
220
221
222
223
224
225
  
    ///请求数据
    void _requestData(
        RequestDataEvent event, Emitter<ReadingPageState> emitter) async {
      try {
        await loading(() async {
53e9e6db   吴启风   feat:绘本语音评测逻辑
226
          _entity = await ListenDao.process(courseLessonId);
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
227
          Log.d("reading page entity: ${_entity!.toJson()}");
a506beff   吴启风   feat:先声sdk方法找不到问题...
228
229
230
231
232
233
234
235
236
          emitter(RequestDataState());
        });
      } catch (e) {
        if (e is ApiException) {
          EasyLoading.showToast(e.message ?? '请求失败,请检查网络连接');
        }
      }
    }
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
237
238
239
240
241
242
    /// 播放绘本原音
    void _playOriginalAudio(
        PlayOriginalAudioEvent event, Emitter<ReadingPageState> emitter) async {
      _playOriginalAudioInner(event.url);
    }
  
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
243
    ///播放原音音频
2ee6209a   吴启风   feat:绘本播放状态优化
244
245
    /// - [force]: 是否强制播放(true:不管当前状态如何,都会播放目标原音音频,比如翻页场景)
    /// (false:如果正在播放,暂停播放,比如点击播放按钮场景)
93efa69f   biao   删除评测代码
246
247
    void _playOriginalAudioInner(String? audioUrl,
        {bool forcePlay = false}) async {
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
248
      if (_isRecordAudioPlaying) {
2ee6209a   吴启风   feat:绘本播放状态优化
249
        await audioPlayer.stop();
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
250
251
        _isRecordAudioPlaying = false;
      }
6051f850   吴启风   feat:带隐私合规权限申请描述的...
252
253
      Log.d(
          "_playOriginalAudio _isRecordAudioPlaying=$_isRecordAudioPlaying _isOriginAudioPlaying=$_isOriginAudioPlaying url=$audioUrl");
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
254
      if (_isOriginAudioPlaying) {
75e0dcd2   吴启风   feat:修复绘本音频ios听筒出声
255
        await audioPlayer.stop();
2ee6209a   吴启风   feat:绘本播放状态优化
256
257
258
259
260
261
        _isOriginAudioPlaying = false;
        if (forcePlay) {
          audioUrl ??= currentPageData()?.audioUrl ?? '';
          await _playAudio(audioUrl);
          _isOriginAudioPlaying = true;
        }
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
262
      } else {
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
263
        audioUrl ??= currentPageData()?.audioUrl ?? '';
2ee6209a   吴启风   feat:绘本播放状态优化
264
265
        await _playAudio(audioUrl);
        _isOriginAudioPlaying = true;
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
266
      }
a506beff   吴启风   feat:先声sdk方法找不到问题...
267
268
    }
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
269
270
271
272
273
274
    /// 播放录音
    void _playRecordAudio(
        PlayRecordAudioEvent event, Emitter<ReadingPageState> emitter) async {
      _playRecordAudioInner();
    }
  
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
275
    Future<void> _playRecordAudioInner() async {
2ee6209a   吴启风   feat:绘本播放状态优化
276
      Log.d(
93efa69f   biao   删除评测代码
277
          "_playRecordAudioInner _isOriginAudioPlaying=$_isOriginAudioPlaying _isRecordAudioPlaying=$_isRecordAudioPlaying url=${currentPageData()?.recordUrl}");
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
278
      if (_isOriginAudioPlaying) {
2ee6209a   吴启风   feat:绘本播放状态优化
279
280
        ///如果正在播放原音,暂停
        await audioPlayer.stop();
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
281
282
        _isOriginAudioPlaying = false;
      }
2ee6209a   吴启风   feat:绘本播放状态优化
283
  
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
284
      if (_isRecordAudioPlaying) {
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
285
        await audioPlayer.stop();
2ee6209a   吴启风   feat:绘本播放状态优化
286
        _isRecordAudioPlaying = false;
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
287
      } else {
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
288
        final recordAudioUrl = currentPageData()?.recordUrl;
2ee6209a   吴启风   feat:绘本播放状态优化
289
290
        await _playAudio(recordAudioUrl);
        _isRecordAudioPlaying = true;
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
291
      }
ad37b653   吴启风   feat:1、完成微信支付;2、商...
292
      // emitter(VoicePlayStateChange());
53e9e6db   吴启风   feat:绘本语音评测逻辑
293
294
    }
  
2ee6209a   吴启风   feat:绘本播放状态优化
295
    Future<void> _playAudio(String? audioUrl) async {
53e9e6db   吴启风   feat:绘本语音评测逻辑
296
      if (audioUrl!.isNotEmpty) {
1f5969b8   biao   修复 练习和绘本播放音频问题
297
298
        await audioPlayer.play(UrlSource(audioUrl),
            balance: 0.0, ctx: AudioContext());
a506beff   吴启风   feat:先声sdk方法找不到问题...
299
300
301
302
      }
    }
  
    int dataCount() {
a506beff   吴启风   feat:先声sdk方法找不到问题...
303
304
305
306
307
308
309
      return _entity?.readings?.length ?? 0;
    }
  
    CourseProcessReadings? currentPageData() {
      return _entity?.readings?[_currentPage];
    }
  
4d8b0da4   吴启风   feat:绘本跟读底部ui优化
310
311
312
313
314
    ///当前页绘本跟读内容
    String readingContent() {
      return currentPageData()?.word?.trim() ?? '';
    }
  
fd737d6a   吴启风   feat:绘本作答结果以单词为单位...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
    /// 结合单词分数返回带颜色的TextSpan数组
    List<TextSpan>? displayContent() {
      // return _textController.text.isNotEmpty ? _textController.text : readingContent();
      // 创建用于展示每个单词的 TextSpan 列表
      if (currentPageData() == null) {
        return null;
      }
      List<SingsoundResultDetailEntity> resultDetails;
      if (currentPageData()?.resultDetails != null) {
        resultDetails = currentPageData()!.resultDetails!;
      } else {
        List<String>? wordList = currentPageData()?.word?.split(RegExp(r'\s+'));
        resultDetails = wordList!
            .map(
                (word) => SingsoundResultDetailEntity.withCharAndScore(word, 0))
            .toList();
      }
      List<TextSpan> textSpans = resultDetails.asMap().entries.map((entry) {
        int index = entry.key;
        SingsoundResultDetailEntity detail = entry.value;
        // Check if this is the last word in the list
        bool isLastWord = index == resultDetails.length - 1;
        return TextSpan(
          text: '${detail.char}${isLastWord ? '' : ' '}',
          style: TextStyle(
            color: detail.score > 80
                ? const Color(0XFF35C137)
                : const Color(0xFF333333),
457ac447   吴启风   feat:代码优化-空条件调用
343
            fontSize: 18.sp,
fd737d6a   吴启风   feat:绘本作答结果以单词为单位...
344
345
346
347
348
349
          ),
        );
      }).toList();
      return textSpans;
    }
  
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
350
    void nextPage() {
820997e6   吴启风   feat:过渡页-绘本环节
351
352
353
354
355
356
357
358
359
360
361
      if (currentPage >= dataCount()) {
        sectionComplete(() {
          popPage(data: {
            'currentStep': currentPage,
            'courseLessonId': courseLessonId,
            'isCompleted': true,
            'nextSection': true
          });
        }, againSectionTap: () {
          pageController.jumpToPage(0);
        });
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
362
363
364
      } else {
        _currentPage += 1;
        pageController.nextPage(
8df5fbf9   吴启风   feat:单元列表页由于ios嵌套...
365
          duration: const Duration(milliseconds: 250),
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
366
367
368
369
370
          curve: Curves.ease,
        );
      }
    }
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
371
372
373
374
375
376
    ///初始化SDK
    _initVoiceSdk(
        XSVoiceInitEvent event, Emitter<ReadingPageState> emitter) async {
      methodChannel.invokeMethod('initVoiceSdk', event.data);
    }
  
a506beff   吴启风   feat:先声sdk方法找不到问题...
377
    ///先声测试
53e9e6db   吴启风   feat:绘本语音评测逻辑
378
379
    void _voiceXsStart(
        XSVoiceStartEvent event, Emitter<ReadingPageState> emitter) async {
2ee6209a   吴启风   feat:绘本播放状态优化
380
      await _stopAudio();
a506beff   吴启风   feat:先声sdk方法找不到问题...
381
      startRecord(event.content);
a506beff   吴启风   feat:先声sdk方法找不到问题...
382
383
    }
  
2ee6209a   吴启风   feat:绘本播放状态优化
384
    ///开始录音
a506beff   吴启风   feat:先声sdk方法找不到问题...
385
    void startRecord(String content) async {
6051f850   吴启风   feat:带隐私合规权限申请描述的...
386
      // 调用封装好的权限检查和请求方法
d0623cfd   吴启风   feat:绘本作答结果动效
387
388
      bool result = await requestPermission(
          context, Permission.microphone, "录音", "用于开启录音,识别您的开口作答并给出反馈");
6051f850   吴启风   feat:带隐私合规权限申请描述的...
389
      if (result) {
820997e6   吴启风   feat:过渡页-绘本环节
390
391
392
393
394
        methodChannel.invokeMethod('startVoice', {
          'word': content,
          'type': '0',
          'userId': UserUtil.getUser()?.id.toString()
        });
a506beff   吴启风   feat:先声sdk方法找不到问题...
395
      }
a506beff   吴启风   feat:先声sdk方法找不到问题...
396
397
    }
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
398
399
    void _voiceXsResult(
        XSVoiceResultEvent event, Emitter<ReadingPageState> emitter) async {
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
400
401
402
403
      final Map args = event.message as Map;
      final result = args['result'] as Map;
      Log.d("_voiceXsResult result=$result");
      final overall = result['overall'].toString();
fd737d6a   吴启风   feat:绘本作答结果以单词为单位...
404
405
406
407
408
409
410
411
412
      List<dynamic> resultDetailsJsons = result['details'];
      // 提取 score 和 char 字段
      List<SingsoundResultDetailEntity> detailEntities = [];
      for (var detail in resultDetailsJsons) {
        int score = detail['score'] as int;
        String char = detail['char'] as String;
        detailEntities
            .add(SingsoundResultDetailEntity.withCharAndScore(char, score));
      }
d0623cfd   吴启风   feat:绘本作答结果动效
413
414
415
416
  
      ///todo 后面可以考虑要不要传自己的服务器
      final recordFileUrl = args['audioUrl'].toString();
      int score = int.parse(overall);
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
417
      currentPageData()?.recordScore = overall;
fc048c78   吴启风   feat:绘本跟读录音文件播放失败...
418
      currentPageData()?.recordUrl = args['audioUrl'] + '.mp3';
fd737d6a   吴启风   feat:绘本作答结果以单词为单位...
419
420
      currentPageData()?.resultDetails = detailEntities;
      add(OnXSVoiceStateChangeEvent());
93efa69f   biao   删除评测代码
421
  
d0623cfd   吴启风   feat:绘本作答结果动效
422
      final voiceResult = VoiceResultType.fromScore(score);
951eb853   吴启风   feat:代码优化-星星等动效对话...
423
  
d0623cfd   吴启风   feat:绘本作答结果动效
424
      if (voiceResult.lottieFilePath != null) {
951eb853   吴启风   feat:代码优化-星星等动效对话...
425
426
427
428
429
430
431
        AudioPlayerUtil.getInstance().playAudio(voiceResult.audioType);
        await showCheerRewardDialog(context, lottieFile: voiceResult.lottieFilePath!, onDismiss: () async {
          await actionAfterRecord();
        });
      } else {
        await AudioPlayerUtil.getInstance().playAudio(voiceResult.audioType);
        await actionAfterRecord();
820997e6   吴启风   feat:过渡页-绘本环节
432
      }
951eb853   吴启风   feat:代码优化-星星等动效对话...
433
434
435
436
437
438
439
440
441
442
443
444
445
    }
  
    /// 作答音效&动效播放结束后
    Future<void> actionAfterRecord() async {
      ///完成录音后紧接着播放录音
      await _playRecordAudioInner();
      if (isLastPage()) {
        sectionComplete(() {
          popPage(data: {
            'currentStep': currentPage,
            'courseLessonId': courseLessonId,
            'isCompleted': true,
            'nextSection': true
d0623cfd   吴启风   feat:绘本作答结果动效
446
          });
951eb853   吴启风   feat:代码优化-星星等动效对话...
447
448
449
450
451
        }, againSectionTap: () {
          _resetLocalResult();
          pageController.jumpToPage(0);
        });
      }
a506beff   吴启风   feat:先声sdk方法找不到问题...
452
    }
53e9e6db   吴启风   feat:绘本语音评测逻辑
453
454
455
456
457
458
459
  
    ///终止评测
    void _voiceXsStop(
        XSVoiceStopEvent event, Emitter<ReadingPageState> emitter) async {
      methodChannel.invokeMethod('stopVoice');
    }
  
6b0947ca   吴启风   feat:绘本增加initVoic...
460
    ///取消评测(用于处理退出页面后录音未停止等异常情况的保护操作)
081fbff7   吴启风   feat:性能优化-录音内存泄漏
461
    void _voiceXsCancel({bool force = false}) {
46c68b45   吴启风   feat:翻页取消先声评测&增加先...
462
      Log.d("取消评测 _voiceXsCancel _isRecording=$_isRecording");
081fbff7   吴启风   feat:性能优化-录音内存泄漏
463
      if (_isRecording || force) {
46c68b45   吴启风   feat:翻页取消先声评测&增加先...
464
465
        methodChannel.invokeMethod('cancelVoice');
      }
6b0947ca   吴启风   feat:绘本增加initVoic...
466
467
    }
  
53e9e6db   吴启风   feat:绘本语音评测逻辑
468
469
470
471
472
    void _voicePlayStateChange(VoicePlayStateChangeEvent event,
        Emitter<ReadingPageState> emitter) async {
      emitter(VoicePlayStateChange());
    }
  
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
473
474
475
476
477
    void _onAudioPlayComplete() {
      if (_isRecordAudioPlaying && _currentMode == ReadingModeType.auto) {
        nextPage();
      }
  
820997e6   吴启风   feat:过渡页-绘本环节
478
479
480
      Log.d(
          "_onAudioPlayComplete _isOriginAudioPlaying=$_isOriginAudioPlaying _voicePlayState=$_voicePlayState recordUrl=${currentPageData()?.recordUrl?.isNotEmpty}");
      if (_isOriginAudioPlaying &&
820997e6   吴启风   feat:过渡页-绘本环节
481
          currentPageData()?.recordUrl?.isNotEmpty != true) {
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
482
483
484
485
486
487
488
489
        ///如果刚刚完成原音播放&&录音为空,则开始录音
        startRecord(currentPageData()?.word ?? '');
      }
  
      _isOriginAudioPlaying = false;
      _isRecordAudioPlaying = false;
    }
  
2ee6209a   吴启风   feat:绘本播放状态优化
490
    Future<void> _stopAudio() async {
53e9e6db   吴启风   feat:绘本语音评测逻辑
491
492
493
494
      await audioPlayer.stop();
      _isOriginAudioPlaying = false;
      _isRecordAudioPlaying = false;
    }
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
495
  
820997e6   吴启风   feat:过渡页-绘本环节
496
497
    void _onVoiceXsStateChange(OnXSVoiceStateChangeEvent event,
        Emitter<ReadingPageState> emitter) async {
ad37b653   吴启风   feat:1、完成微信支付;2、商...
498
      emitter(XSVoiceTestState());
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
499
    }
065022b7   吴启风   feat:绘本评测反馈弹窗+原音播...
500
  
820997e6   吴启风   feat:过渡页-绘本环节
501
502
503
504
505
506
507
508
509
510
511
512
513
    ///是否是最后一页
    bool isLastPage() {
      return currentPage == dataCount();
    }
  
    ///重置数据
    void _resetLocalResult() {
      _entity?.readings?.forEach((element) {
        element.recordScore = null;
        element.recordUrl = null;
      });
    }
  }