reading_bloc.dart 8 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/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<ReadingPageEvent, ReadingPageState> {
  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<CurrentPageIndexChangeEvent>(_pageControllerChange);
    on<CurrentModeChangeEvent>(_playModeChange);
    // pageController.addListener(() {
    //   _currentPage = pageController.page!.round();
    // });
    on<RequestDataEvent>(_requestData);
    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.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<VoicePlayStateChangeEvent>(_voicePlayStateChange);
    on<PlayOriginalAudioEvent>(_playOriginalAudio);
    on<XSVoiceInitEvent>(_initVoiceSdk);
    on<XSVoiceStartEvent>(_voiceXsStart);
    on<XSVoiceStopEvent>(_voiceXsStop);
    on<XSVoiceResultEvent>(_voiceXsResult);

    on<PlayRecordAudioEvent>(_playRecordAudio);
  }

  @override
  Future<void> close() {
    pageController.dispose();
    audioPlayer.release();
    audioPlayer.dispose();
    return super.close();
  }

  void _pageControllerChange(CurrentPageIndexChangeEvent event,
      Emitter<ReadingPageState> emitter) async {
    _currentPage = event.pageIndex;
    _playOriginalAudioInner(null);
    emitter(CurrentPageIndexState());
  }

  void _playModeChange(
      CurrentModeChangeEvent event, Emitter<ReadingPageState> emitter) async {
    if (_currentMode == ReadingModeType.auto) {
      _currentMode = ReadingModeType.manual;
    } else {
      _currentMode = ReadingModeType.auto;
    }
    emitter(CurrentModeState());
  }

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

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

  void _voicePlayStateChange(VoicePlayStateChangeEvent event,
      Emitter<ReadingPageState> emitter) async {
    emitter(VoicePlayStateChange());
  }

  void _stopAudio() async {
    await audioPlayer.stop();
    _isOriginAudioPlaying = false;
    _isRecordAudioPlaying = false;
  }
}