import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:wow_english/common/request/dao/listen_dao.dart'; import 'package:wow_english/common/request/exception.dart'; import 'package:wow_english/models/course_process_entity.dart'; import 'package:wow_english/utils/loading.dart'; import 'package:wow_english/utils/toast_util.dart'; part 'topic_picture_event.dart'; part 'topic_picture_state.dart'; enum VoicePlayState { ///未知 unKnow, ///播放中 playing, ///播放完成 completed, ///播放终止 stop } class TopicPictureBloc extends Bloc { final PageController pageController; final String courseLessonId; int _currentPage = 0; int _selectItem = -1; CourseProcessEntity? _entity; ///正在评测 bool _isVoicing = false; ///正在播放音频 VoicePlayState _voicePlayState = VoicePlayState.unKnow; CourseProcessEntity? get entity => _entity; int get currentPage => _currentPage + 1; int get selectItem => _selectItem; bool get isVoicing => _isVoicing; VoicePlayState get voicePlayState => _voicePlayState; late MethodChannel methodChannel; late AudioPlayer audioPlayer; TopicPictureBloc(this.pageController, this.courseLessonId) : super(TopicPictureInitial()) { on(_pageControllerChange); on(_voicePlayStateChange); on(_voiceXsResult); on(_initVoiceSdk); on(_selectItemLoad); on(_requestData); on(_voiceXsTest); on(_voiceXsStop); on(_voicePlay); on((event, emit) { //音频播放器 audioPlayer = AudioPlayer(); audioPlayer.onPlayerStateChanged.listen((event) async { debugPrint('播放状态变化'); if (event == PlayerState.completed) { debugPrint('播放完成'); _voicePlayState = VoicePlayState.completed; } if (event == PlayerState.stopped) { debugPrint('播放结束'); _voicePlayState = VoicePlayState.stop; } if (event == PlayerState.playing) { debugPrint('正在播放中'); _voicePlayState = VoicePlayState.playing; } if(isClosed) { return; } add(VoicePlayStateChangeEvent()); }); methodChannel = const MethodChannel('wow_english/sing_sound_method_channel'); methodChannel.setMethodCallHandler((call) async { if (call.method == 'voiceResult') {//评测结果 add(XSVoiceResultEvent(call.arguments)); return; } if (call.method == 'voiceStart') {//评测开始 if (kDebugMode) { print('评测开始'); } return; } if (call.method == 'voiceEnd') {//评测结束 if (kDebugMode) { print('评测结束'); } return; } if (call.method == 'voiceFail') {//评测失败 EasyLoading.showToast('评测失败'); return; } }); }); } @override Future close(){ pageController.dispose(); audioPlayer.release(); audioPlayer.dispose(); _voiceXsCancel(); return super.close(); } ///请求数据 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??'请求失败,请检查网络连接'); } } } ///页面切换 void _pageControllerChange(CurrentPageIndexChangeEvent event,Emitter emitter) async { _currentPage = event.pageIndex; if (voicePlayState == VoicePlayState.playing) { await audioPlayer.stop(); } final topics = _entity?.topics?[_currentPage]; if (topics?.type != 3 && topics?.type != 4) { if (topics?.audioUrl != null) { final urlStr = topics?.audioUrl??''; if (urlStr.isNotEmpty) { debugPrint(urlStr); await audioPlayer.play(UrlSource(urlStr)); } } } _selectItem = -1; emitter(CurrentPageIndexState()); } ///选择 void _selectItemLoad(SelectItemEvent event,Emitter emitter) async { _selectItem = event.selectIndex; CourseProcessTopics? topics = _entity?.topics?[_currentPage]; CourseProcessTopicsTopicAnswerList? answerList = topics?.topicAnswerList?[_selectItem]; if (answerList?.correct == 0) { showToast('继续加油哦',duration: const Duration(seconds: 2)); } else { showToast('恭喜你,答对啦!',duration: const Duration(seconds: 2)); } emitter(SelectItemChangeState()); } ///初始化SDK _initVoiceSdk(XSVoiceInitEvent event,Emitter emitter) async { methodChannel.invokeMethod('initVoiceSdk',event.data); } ///先声测试 void _voiceXsTest(XSVoiceTestEvent event,Emitter emitter) async { await audioPlayer.stop(); methodChannel.invokeMethod( 'startVoice', {'word':event.testWord,'type':event.type,'userId':event.userId.toString()} ); _isVoicing = true; emitter(XSVoiceTestState()); } ///终止评测 void _voiceXsStop(XSVoiceStopEvent event,Emitter emitter) async { methodChannel.invokeMethod('stopVoice'); } ///取消评测(用于处理退出页面后录音未停止等异常情况的保护操作) void _voiceXsCancel() { methodChannel.invokeMethod('cancelVoice'); } ///先声评测结果 void _voiceXsResult(XSVoiceResultEvent event,Emitter emitter) async { final Map args = event.message as Map; final result = args['result'] as Map; final overall = result['overall'].toString(); showToast('测评成功,分数是$overall',duration: const Duration(seconds: 5)); _isVoicing = false; emitter(XSVoiceTestState()); } void _voicePlayStateChange(VoicePlayStateChangeEvent event,Emitter emitter) async { emitter(VoicePlayStateChange()); } void _voicePlay(VoicePlayEvent event,Emitter emitter) async { if (voicePlayState == VoicePlayState.playing) { await audioPlayer.stop(); return; } final topics = _entity?.topics?[_currentPage]; final urlStr = topics?.audioUrl??''; await audioPlayer.play(UrlSource(urlStr)); } }