repeat_after_content_bloc.dart 5.84 KB
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wow_english/common/request/dao/listen_dao.dart';

import '../../../common/request/exception.dart';
import '../../../models/read_content_entity.dart';
import '../../../utils/loading.dart';
import '../../../utils/toast_util.dart';


part 'repeat_after_content_event.dart';
part 'repeat_after_content_state.dart';

enum VoiceRecordState {
  ///未知
  voiceRecordUnkonw,
  ///开始录音
  voiceRecordStat,
  ///正在录音
  voiceRecording,
  ///录音结束
  voiceRecordEnd
}

enum VoicePlayState {
  ///未知
  unKnow,
  ///播放中
  playing,
  ///播放完成
  completed,
  ///播放终止
  stop
}

class RepeatAfterContentBloc extends Bloc<RepeatAfterContentEvent, RepeatAfterContentState> {

  final String courseLessonId;

  ///是否正在播放视频
  bool _videoPlaying = true;
  ///是否需要录音
  bool _isRecord = false;

  Map? _voiceTestResult;

  int _recordNumber = 0;

  VoiceRecordState _voiceRecordState = VoiceRecordState.voiceRecordUnkonw;

  bool get videoPlaying => _videoPlaying;

  bool get isRecord => _isRecord;

  VoiceRecordState get voiceRecordState => _voiceRecordState;

  List<ReadContentEntity?>? _entityList;

  List<ReadContentEntity?>? get entityList => _entityList ;

  Map? get voiceTestResult => _voiceTestResult;

  late MethodChannel methodChannel;

  late AudioPlayer audioPlayer;

  RepeatAfterContentBloc(this.courseLessonId) : super(RepeatAfterContentInitial()) {
    on<VoiceRecordStateChangeEvent>(_voiceRecordStateChange);
    on<PostFollowReadContentEvent>(_postFollowReadContent);
    on<VideoPlayChangeEvent>(_videoPlayStateChange);
    on<RecordeVoicePlayEvent>(_recordeVoicePlay);
    on<XSVoiceResultEvent>(_voiceXsResult);
    on<XSVoiceInitEvent>(_initVoiceSdk);
    on<RequestDataEvent>(_requestData);
    on<XSVoiceTestEvent>(_voiceXsTest);
    on<XSVoiceStopEvent>(_voiceXsStop);
    on<VoiceRecordEvent>(_voiceRecord);
    on<InitBlocEvent>((event, emit) {
      //音频播放器
      audioPlayer = AudioPlayer();
      audioPlayer.onPlayerStateChanged.listen((event) async {
        debugPrint('播放状态变化');
        if (event == PlayerState.completed) {
          debugPrint('播放完成');

        }
        if (event == PlayerState.stopped) {
          debugPrint('播放结束');

        }

        if (event == PlayerState.playing) {
          debugPrint('正在播放中');

        }
        if(isClosed) {
          return;
        }

      });

      methodChannel = const MethodChannel('wow_english/sing_sound_method_channel');
      methodChannel.setMethodCallHandler((call) async {
        if (call.method == 'voiceResult') {//评测结果
          add(XSVoiceResultEvent(call.arguments));
          add(PostFollowReadContentEvent());
          return;
        }

        if (call.method == 'voiceStart') {//评测开始
          debugPrint('评测开始');
          return;
        }

        if (call.method == 'voiceEnd') {//评测结束
          debugPrint('评测结束');
          return;
        }

        if (call.method == 'voiceFail') {//评测失败
          showToast('评测失败');
          return;
        }
      });
    });
  }

  ///请求数据
  void _requestData(RequestDataEvent event,Emitter<RepeatAfterContentState> emitter) async {
    try {
      await loading(() async {
        _entityList = await ListenDao.readContent(courseLessonId);
        emitter(RequestDataState());
      });
    } catch (e) {
      if (e is ApiException) {
        showToast(e.message??'请求失败,请检查网络连接');
      }
    }
  }

  ///跟读结果
  void _postFollowReadContent(PostFollowReadContentEvent event,Emitter<RepeatAfterContentState> emitter) async {
    try {
      await loading(() async {
        _entityList = await ListenDao.followResult(_recordNumber.toString(),courseLessonId);

      });
    } catch (e) {
      if (e is ApiException) {

      }
    }
  }

  void _videoPlayStateChange(VideoPlayChangeEvent event,Emitter<RepeatAfterContentState> emitter) async {
    _videoPlaying = !_videoPlaying;
    emitter(VideoPlayChangeState());
  }

  void _voiceRecord(VoiceRecordEvent event,Emitter<RepeatAfterContentState> emitter) async {
    _isRecord = !_isRecord;
    emitter(VoiceRecordChangeState());
  }

  void _voiceRecordStateChange(VoiceRecordStateChangeEvent event,Emitter<RepeatAfterContentState> emitter) async {
    _voiceRecordState = event.voiceRecordState;
    emitter(VoiceRecordStateChange());
  }


  _initVoiceSdk(XSVoiceInitEvent event,Emitter<RepeatAfterContentState> emitter) async {
    methodChannel.invokeMethod('initVoiceSdk',event.data);
  }

  ///先声测试
  void _voiceXsTest(XSVoiceTestEvent event,Emitter<RepeatAfterContentState> emitter) async {
    await audioPlayer.stop();
    methodChannel.invokeMethod(
        'startVoice',
        {'word':event.testWord,'type':event.type,'userId':event.userId.toString()}
    );
    _recordNumber++;
    emitter(XSVoiceTestState());
  }

  ///终止评测
  void _voiceXsStop(XSVoiceStopEvent event,Emitter<RepeatAfterContentState> emitter) async {
    methodChannel.invokeMethod('stopVoice');
  }

  ///先声评测结果
  void _voiceXsResult(XSVoiceResultEvent event,Emitter<RepeatAfterContentState> emitter) async {
    final Map args = event.message as Map;
    final result = args['result'] as Map;
    final overall = result['overall'].toString()??'';
    final audioUrl = args['audioUrl'].toString()??'';
    _voiceTestResult = {'overall':overall,'audioUrl':audioUrl};
    emitter(XSVoiceTestState());
  }

  ///播放声音
  void _recordeVoicePlay(RecordeVoicePlayEvent event,Emitter<RepeatAfterContentState> emitter) async {
    await audioPlayer.stop();
    assert(event.audioUrl.isNotEmpty);
    await audioPlayer.play(UrlSource(event.audioUrl));
  }
}