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/pages/reading/widgets/ReadingModeType.dart'; import '../../../common/request/dao/listen_dao.dart'; import '../../../common/request/exception.dart'; import '../../../models/course_process_entity.dart'; import '../../../utils/loading.dart'; import 'dart:convert'; part 'reading_event.dart'; part 'reading_state.dart'; enum VoicePlayState { ///未知 unKnow, ///播放中 playing, ///播放完成 completed, ///播放终止 stop } class ReadingPageBloc extends Bloc { final PageController pageController; final String courseLessonId; ///当前页索引 int _currentPage = 0; ///当前播放模式 ReadingModeType _currentMode = ReadingModeType.auto; int get currentPage => _currentPage + 1; ReadingModeType get currentMode => _currentMode; CourseProcessEntity? _entity; CourseProcessEntity? get entity => _entity; ///正在评测 bool _isRecording = false; bool get isRecording => _isRecording; ///原始音频是否正在播放 bool _isOriginAudioPlaying = false; bool get isOriginAudioPlaying => _isOriginAudioPlaying; ///录音音频是否正在播放 bool _isRecordAudioPlaying = false; bool get isRecordAudioPlaying => _isRecordAudioPlaying; ///正在播放音频状态 VoicePlayState _voicePlayState = VoicePlayState.unKnow; VoicePlayState get voicePlayState => _voicePlayState; late MethodChannel methodChannel; late AudioPlayer audioPlayer; ReadingPageBloc(this.pageController, this.courseLessonId) : super(ReadingPageInitial()) { on(_pageControllerChange); on(_playModeChange); // pageController.addListener(() { // _currentPage = pageController.page!.round(); // }); on(_requestData); 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.invokeMethod('initVoiceSdk', {}); //初始化评测 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; } }); }); on(_voicePlayStateChange); on(_playOriginalAudio); on(_initVoiceSdk); on(_voiceXsStart); on(_voiceXsStop); on(_voiceXsResult); on(_playRecordAudio); } @override Future close() { pageController.dispose(); audioPlayer.release(); audioPlayer.dispose(); return super.close(); } void _pageControllerChange(CurrentPageIndexChangeEvent event, Emitter emitter) async { _currentPage = event.pageIndex; _playOriginalAudioInner(null); emitter(CurrentPageIndexState()); } void _playModeChange( CurrentModeChangeEvent event, Emitter emitter) async { if (_currentMode == ReadingModeType.auto) { _currentMode = ReadingModeType.manual; } else { _currentMode = ReadingModeType.auto; } emitter(CurrentModeState()); } ///请求数据 void _requestData( RequestDataEvent event, Emitter emitter) async { try { await loading(() async { _entity = await ListenDao.process(courseLessonId); print("reading page entity: ${_entity!.toJson()}"); emitter(RequestDataState()); }); } catch (e) { if (e is ApiException) { EasyLoading.showToast(e.message ?? '请求失败,请检查网络连接'); } } } /// 播放绘本原音 void _playOriginalAudio( PlayOriginalAudioEvent event, Emitter emitter) async { _playOriginalAudioInner(event.url); } void _playOriginalAudioInner(String? audioUrl) { print("_playOriginalAudio url=$audioUrl"); audioUrl ??= currentPageData()?.audioUrl ?? ''; _playAudio(audioUrl); _isOriginAudioPlaying = true; } /// 播放录音 void _playRecordAudio( PlayRecordAudioEvent event, Emitter emitter) async { _playRecordAudioInner(); } void _playRecordAudioInner() { final recordAudioUrl = currentPageData()?.recordUrl; print("_playRecordAudioInner url=${currentPageData()?.recordUrl}"); _playAudio(recordAudioUrl); _isRecordAudioPlaying = true; } void _playAudio(String? audioUrl) async { await audioPlayer.stop(); if (audioUrl!.isNotEmpty) { await audioPlayer.play(UrlSource(audioUrl)); } } int dataCount() { // print("dataCount=${_entity?.readings?.length ?? 0}"); return _entity?.readings?.length ?? 0; } CourseProcessReadings? currentPageData() { return _entity?.readings?[_currentPage]; } ///初始化SDK _initVoiceSdk( XSVoiceInitEvent event, Emitter emitter) async { methodChannel.invokeMethod('initVoiceSdk', event.data); } ///先声测试 void _voiceXsStart( XSVoiceStartEvent event, Emitter emitter) async { _stopAudio(); startRecord(event.content); emitter(XSVoiceTestState()); } void startRecord(String content) async { if (_isRecording == true) { return; } methodChannel.invokeMethod( 'startVoice', {'word': 'how old are you', 'type': '0', 'userId': '1'}); _isRecording = true; } void _voiceXsResult( XSVoiceResultEvent event, Emitter emitter) async { final Map args = json.decode(event.message); final result = args['result']; print("_voiceXsResult result=${result}"); if (result != null) { final overall = result['overall'].toString(); EasyLoading.showToast('测评成功,分数是$overall', duration: const Duration(seconds: 10)); currentPageData()?.recordScore = overall; currentPageData()?.recordUrl = args['audioUrl'] + '.mp3'; _playRecordAudioInner(); } else { EasyLoading.showToast('测评失败', duration: const Duration(seconds: 10)); } _isRecording = false; emitter(XSVoiceTestState()); } ///终止评测 void _voiceXsStop( XSVoiceStopEvent event, Emitter emitter) async { methodChannel.invokeMethod('stopVoice'); } void _voicePlayStateChange(VoicePlayStateChangeEvent event, Emitter emitter) async { emitter(VoicePlayStateChange()); } void _stopAudio() async { await audioPlayer.stop(); _isOriginAudioPlaying = false; _isRecordAudioPlaying = false; } }