topic_picture_bloc.dart 6.52 KB
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<TopicPictureEvent, TopicPictureState> {

  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<CurrentPageIndexChangeEvent>(_pageControllerChange);
    on<VoicePlayStateChangeEvent>(_voicePlayStateChange);
    on<XSVoiceResultEvent>(_voiceXsResult);
    on<XSVoiceInitEvent>(_initVoiceSdk);
    on<SelectItemEvent>(_selectItemLoad);
    on<RequestDataEvent>(_requestData);
    on<XSVoiceTestEvent>(_voiceXsTest);
    on<XSVoiceStopEvent>(_voiceXsStop);
    on<VoicePlayEvent>(_voicePlay);
    on<InitBlocEvent>((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<void> close(){
    pageController.dispose();
    audioPlayer.release();
    audioPlayer.dispose();
    return super.close();
  }

  ///请求数据
  void _requestData(RequestDataEvent event,Emitter<TopicPictureState> 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<TopicPictureState> 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<TopicPictureState> 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<TopicPictureState> emitter) async {
    methodChannel.invokeMethod('initVoiceSdk',event.data);
  }

  ///先声测试
  void _voiceXsTest(XSVoiceTestEvent event,Emitter<TopicPictureState> 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<TopicPictureState> emitter) async {
    methodChannel.invokeMethod('stopVoice');
  }

  ///先声评测结果
  void _voiceXsResult(XSVoiceResultEvent event,Emitter<TopicPictureState> 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<TopicPictureState> emitter) async {
    emitter(VoicePlayStateChange());
  }

  void _voicePlay(VoicePlayEvent event,Emitter<TopicPictureState> emitter) async {
    if (voicePlayState == VoicePlayState.playing) {
      await audioPlayer.stop();
      return;
    }
    final topics = _entity?.topics?[_currentPage];
    final urlStr = topics?.audioUrl??'';
    await audioPlayer.play(UrlSource(urlStr));
  }
}