Commit aeafd474a56ea23a9a1d1b5e121aab9cd5031360

Authored by 吴启风
1 parent 8fec4713

feat:选择题作答后播放音效&答对自动翻页

assets/sounds/correct_voice.mp3 0 → 100644
No preview for this file type
assets/sounds/incorrect_voice.mp3 0 → 100644
No preview for this file type
lib/common/extension/string_extension.dart
1 1 /// 资源类扩展方法
2 2 extension AssetExtension on String {
3 3 static const String _assetImagePrefix = "assets/images/";
  4 + static const String _assetSoundPrefix = 'sounds/';
4 5  
5 6 /// 图片url
6 7 String get assetImg => _assetImagePrefix + this;
... ... @@ -10,6 +11,10 @@ extension AssetExtension on String {
10 11 String get assetWebp => '$assetImg.webp';
11 12  
12 13 String get assetGif => '$assetImg.gif';
  14 +
  15 + String get assetSound => _assetSoundPrefix + this;
  16 +
  17 + String get assetMp3 => '$assetSound.mp3';
13 18 }
14 19  
15 20 extension StringExtension on String {
... ...
lib/pages/practice/bloc/topic_picture_bloc.dart
... ... @@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
5 5 import 'package:flutter_bloc/flutter_bloc.dart';
6 6 import 'package:flutter_easyloading/flutter_easyloading.dart';
7 7 import 'package:permission_handler/permission_handler.dart';
  8 +import 'package:wow_english/common/extension/string_extension.dart';
8 9 import 'package:wow_english/common/request/dao/listen_dao.dart';
9 10 import 'package:wow_english/common/request/exception.dart';
10 11 import 'package:wow_english/models/course_process_entity.dart';
... ... @@ -45,6 +46,16 @@ class TopicPictureBloc extends Bloc<TopicPictureEvent, TopicPictureState> {
45 46 ///正在播放音频
46 47 VoicePlayState _voicePlayState = VoicePlayState.unKnow;
47 48  
  49 + // 是否是回答(选择)结果音效
  50 + bool _isResultSoundPlaying = false;
  51 +
  52 + bool get isResultSoundPlaying => _isResultSoundPlaying;
  53 +
  54 + // 答对播放音效时禁止任何点击(选择)操作
  55 + bool _forbiddenWhenCorrect = false;
  56 +
  57 + bool get forbiddenWhenCorrect => _forbiddenWhenCorrect;
  58 +
48 59 CourseProcessEntity? get entity => _entity;
49 60  
50 61 int get currentPage => _currentPage + 1;
... ... @@ -70,29 +81,43 @@ class TopicPictureBloc extends Bloc<TopicPictureEvent, TopicPictureState> {
70 81 on<RequestDataEvent>(_requestData);
71 82 on<XSVoiceTestEvent>(_voiceXsTest);
72 83 on<XSVoiceStopEvent>(_voiceXsStop);
73   - on<VoicePlayEvent>(_voicePlay);
  84 + on<VoicePlayEvent>(_questionVoicePlay);
74 85 on<InitBlocEvent>((event, emit) {
75 86 //音频播放器
76 87 audioPlayer = AudioPlayer();
77 88 audioPlayer.onPlayerStateChanged.listen((event) async {
78   - debugPrint('播放状态变化');
79   - if (event == PlayerState.completed) {
80   - debugPrint('播放完成');
81   - _voicePlayState = VoicePlayState.completed;
82   - }
83   - if (event == PlayerState.stopped) {
84   - debugPrint('播放结束');
85   - _voicePlayState = VoicePlayState.stop;
86   - }
  89 + debugPrint('播放状态变化 _voicePlayState=$_voicePlayState event=$event _isResultSoundPlaying=$_isResultSoundPlaying _forbiddenWhenCorrect=$_forbiddenWhenCorrect');
  90 + if (_isResultSoundPlaying) {
  91 + if (event != PlayerState.playing) {
  92 + _isResultSoundPlaying = false;
  93 + if (_forbiddenWhenCorrect) {
  94 + _forbiddenWhenCorrect = false;
  95 + // 答对后自动翻页
  96 + pageController.nextPage(
  97 + duration: const Duration(milliseconds: 500),
  98 + curve: Curves.ease,
  99 + );
  100 + }
  101 + }
  102 + } else {
  103 + if (event == PlayerState.completed) {
  104 + debugPrint('播放完成');
  105 + _voicePlayState = VoicePlayState.completed;
  106 + }
  107 + if (event == PlayerState.stopped) {
  108 + debugPrint('播放结束');
  109 + _voicePlayState = VoicePlayState.stop;
  110 + }
87 111  
88   - if (event == PlayerState.playing) {
89   - debugPrint('正在播放中');
90   - _voicePlayState = VoicePlayState.playing;
91   - }
92   - if(isClosed) {
93   - return;
  112 + if (event == PlayerState.playing) {
  113 + debugPrint('正在播放中');
  114 + _voicePlayState = VoicePlayState.playing;
  115 + }
  116 + if (isClosed) {
  117 + return;
  118 + }
  119 + add(VoicePlayStateChangeEvent());
94 120 }
95   - add(VoicePlayStateChangeEvent());
96 121 });
97 122  
98 123 methodChannel = const MethodChannel('wow_english/sing_sound_method_channel');
... ... @@ -129,6 +154,8 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
129 154 pageController.dispose();
130 155 audioPlayer.release();
131 156 audioPlayer.dispose();
  157 + _isResultSoundPlaying = false;
  158 + _forbiddenWhenCorrect = false;
132 159 _voiceXsCancel();
133 160 return super.close();
134 161 }
... ... @@ -149,10 +176,12 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
149 176  
150 177 ///页面切换
151 178 void _pageControllerChange(CurrentPageIndexChangeEvent event,Emitter<TopicPictureState> emitter) async {
152   - _currentPage = event.pageIndex;
153   - if (voicePlayState == VoicePlayState.playing) {
154   - await audioPlayer.stop();
  179 + await closePlayerResource();
  180 + debugPrint('翻页 $_currentPage->${event.pageIndex}');
  181 + if (_currentPage == _entity?.topics?.length) {
  182 + return;
155 183 }
  184 + _currentPage = event.pageIndex;
156 185 final topics = _entity?.topics?[_currentPage];
157 186 if (topics?.type != 3 && topics?.type != 4) {
158 187 if (topics?.audioUrl != null) {
... ... @@ -169,13 +198,18 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
169 198  
170 199 ///选择
171 200 void _selectItemLoad(SelectItemEvent event,Emitter<TopicPictureState> emitter) async {
  201 + if (_forbiddenWhenCorrect) {
  202 + return;
  203 + }
172 204 _selectItem = event.selectIndex;
173 205 CourseProcessTopics? topics = _entity?.topics?[_currentPage];
174 206 CourseProcessTopicsTopicAnswerList? answerList = topics?.topicAnswerList?[_selectItem];
175 207 if (answerList?.correct == 0) {
176   - showToast('继续加油哦',duration: const Duration(seconds: 2));
  208 + _playResultSound(false);
  209 + // showToast('继续加油哦',duration: const Duration(seconds: 2));
177 210 } else {
178   - showToast('恭喜你,答对啦!',duration: const Duration(seconds: 2));
  211 + _playResultSound(true);
  212 + // showToast('恭喜你,答对啦!',duration: const Duration(seconds: 2));
179 213 }
180 214 emitter(SelectItemChangeState());
181 215 }
... ... @@ -228,17 +262,37 @@ class TopicPictureBloc extends Bloc&lt;TopicPictureEvent, TopicPictureState&gt; {
228 262 emitter(XSVoiceTestState());
229 263 }
230 264  
  265 + // 暂时没用上
231 266 void _voicePlayStateChange(VoicePlayStateChangeEvent event,Emitter<TopicPictureState> emitter) async {
232 267 emitter(VoicePlayStateChange());
233 268 }
234 269  
235   - void _voicePlay(VoicePlayEvent event,Emitter<TopicPictureState> emitter) async {
236   - if (voicePlayState == VoicePlayState.playing) {
237   - await audioPlayer.stop();
  270 + // 题目音频播放
  271 + void _questionVoicePlay(VoicePlayEvent event,Emitter<TopicPictureState> emitter) async {
  272 + if (_forbiddenWhenCorrect) {
238 273 return;
239 274 }
  275 + _forbiddenWhenCorrect = false;
  276 + await closePlayerResource();
240 277 final topics = _entity?.topics?[_currentPage];
241 278 final urlStr = topics?.audioUrl??'';
242 279 await audioPlayer.play(UrlSource(urlStr));
243 280 }
  281 +
  282 + Future<void> closePlayerResource() async {
  283 + if (voicePlayState == VoicePlayState.playing || _isResultSoundPlaying) {
  284 + await audioPlayer.stop();
  285 + }
  286 + }
  287 +
  288 + void _playResultSound(bool isCorrect) async {
  289 + await audioPlayer.stop();
  290 + _isResultSoundPlaying = true;
  291 + _forbiddenWhenCorrect = isCorrect;
  292 + if (isCorrect) {
  293 + await audioPlayer.play(AssetSource('correct_voice'.assetMp3));
  294 + } else {
  295 + await audioPlayer.play(AssetSource('incorrect_voice'.assetMp3));
  296 + }
  297 + }
244 298 }
... ...
lib/pages/practice/bloc/topic_picture_event.dart
... ... @@ -48,5 +48,5 @@ class SelectItemEvent extends TopicPictureEvent {
48 48 ///音频播放事件
49 49 class VoicePlayChangeEvent extends TopicPictureEvent {}
50 50  
51   -///播放音乐
  51 +///播放(题目)音乐
52 52 class VoicePlayEvent extends TopicPictureEvent {}
53 53 \ No newline at end of file
... ...
pubspec.yaml
... ... @@ -94,15 +94,15 @@ dependencies:
94 94 # UI适配 https://pub.dev/packages/responsive_framework
95 95 responsive_framework: ^1.0.0
96 96 # 音频播放 https://pub.dev/packages/audioplayers
97   - audioplayers: ^4.1.0
  97 + audioplayers: ^6.0.0
98 98 # 语音录制 https://pub.dev/packages/flutter_sound
99 99 flutter_sound: ^9.2.13
100 100 # 音频播放 https://pub.dev/packages/audio_session
101   - audio_session: ^0.1.16
  101 + audio_session: ^0.1.19
102 102 # 文件管理 https://pub.dev/packages/path_provider
103 103 path_provider: ^2.0.15
104 104 # 阿里云oss https://pub.dev/packages/flutter_oss_aliyun
105   - flutter_oss_aliyun: ^6.2.7
  105 + flutter_oss_aliyun: ^6.4.2
106 106 # App信息 https://pub.dev/packages/package_info_plus
107 107 package_info_plus: ^4.2.0
108 108 # 应用内更新 https://pub-web.flutter-io.cn/packages/flutter_app_update
... ... @@ -135,6 +135,7 @@ flutter:
135 135 assets:
136 136 - assets/images/
137 137 - assets/fonts/
  138 + - assets/sounds/
138 139 fonts:
139 140 - family: HannotateSC
140 141 fonts:
... ...