Commit 951eb853271dcf1ccf7aab05a9f790956246c46a

Authored by 吴启风
1 parent 13de08d7

feat:代码优化-星星等动效对话框不受返回关闭,能保证稳定关闭

lib/common/utils/show_star_reward_dialog.dart
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 2
  3 +import '../../utils/log_util.dart';
3 import '../widgets/cheer_reward_widget.dart'; 4 import '../widgets/cheer_reward_widget.dart';
4 import '../widgets/star_reward_widget.dart'; 5 import '../widgets/star_reward_widget.dart';
5 6
6 -void showStarRewardDialog(BuildContext context, { 7 +Future<void> showStarRewardDialog(
  8 + BuildContext context, {
7 double width = 357.5, 9 double width = 357.5,
8 double height = 165, 10 double height = 165,
9 int starCount = 3, 11 int starCount = 3,
10 -}) {  
11 - showDialog( 12 + VoidCallback? onDismiss,
  13 +}) async {
  14 + ///showDialog 方法的返回值将是 Navigator.of(context).pop 传递给对话框的参数
  15 + await showDialog(
12 context: context, 16 context: context,
13 - barrierDismissible: false, // 点击对话框外部不关闭对话框 17 + barrierDismissible: false,
14 builder: (BuildContext context) { 18 builder: (BuildContext context) {
15 - return Dialog(  
16 - backgroundColor: Colors.transparent, // 设置对话框背景为透明  
17 - insetPadding: const EdgeInsets.all(0), // 去除对话框的内边距  
18 - child: StarRewardWidget(  
19 - width: width,  
20 - height: height,  
21 - isPlaying: true,  
22 - starCount: starCount,  
23 - onAnimationEnd: () {  
24 - Navigator.of(context).pop(); // 关闭对话框  
25 - }, 19 + return PopScope(
  20 + canPop: false,
  21 + onPopInvoked: (didPop) {
  22 + Log.d('WQF showStarRewardDialog onPopInvoked didPop=$didPop');
  23 + },
  24 + child: Dialog(
  25 + backgroundColor: Colors.transparent, // 设置对话框背景为透明
  26 + insetPadding: const EdgeInsets.all(0), // 去除对话框的内边距
  27 + child: StarRewardWidget(
  28 + width: width,
  29 + height: height,
  30 + isPlaying: true,
  31 + starCount: starCount,
  32 + onAnimationEnd: () {
  33 + Navigator.of(context).pop(); // 关闭对话框
  34 + },
  35 + ),
26 ), 36 ),
27 ); 37 );
28 }, 38 },
29 ); 39 );
  40 + onDismiss?.call();
30 } 41 }
31 42
32 -void showCheerRewardDialog(BuildContext context, { 43 +Future<void> showCheerRewardDialog(
  44 + BuildContext context, {
33 required String lottieFile, 45 required String lottieFile,
34 double width = 357.5, 46 double width = 357.5,
35 double height = 165, 47 double height = 165,
36 -}) {  
37 - showDialog( 48 + VoidCallback? onDismiss,
  49 +}) async {
  50 + await showDialog(
38 context: context, 51 context: context,
39 barrierDismissible: false, // 点击对话框外部不关闭对话框 52 barrierDismissible: false, // 点击对话框外部不关闭对话框
40 builder: (BuildContext context) { 53 builder: (BuildContext context) {
41 - return Dialog(  
42 - backgroundColor: Colors.transparent, // 设置对话框背景为透明  
43 - insetPadding: const EdgeInsets.all(0), // 去除对话框的内边距  
44 - child: CheerRewardWidget(  
45 - lottieFile: lottieFile,  
46 - width: width,  
47 - height: height,  
48 - isPlaying: true,  
49 - onAnimationEnd: () {  
50 - Navigator.of(context).pop(); // 关闭对话框  
51 - }, 54 + return PopScope(
  55 + canPop: false,
  56 + onPopInvoked: (didPop) {
  57 + Log.d('WQF showCheerRewardDialog onPopInvoked didPop=$didPop');
  58 + },
  59 + child: Dialog(
  60 + backgroundColor: Colors.transparent, // 设置对话框背景为透明
  61 + insetPadding: const EdgeInsets.all(0), // 去除对话框的内边距
  62 + child: CheerRewardWidget(
  63 + lottieFile: lottieFile,
  64 + width: width,
  65 + height: height,
  66 + isPlaying: true,
  67 + onAnimationEnd: () {
  68 + Navigator.of(context).pop(); // 关闭对话框
  69 + },
  70 + ),
52 ), 71 ),
53 ); 72 );
54 }, 73 },
55 ); 74 );
56 -}  
57 \ No newline at end of file 75 \ No newline at end of file
  76 + onDismiss?.call();
  77 +}
lib/common/widgets/cheer_reward_widget.dart
@@ -53,6 +53,10 @@ class _CheerRewardWidgetState extends State&lt;CheerRewardWidget&gt; @@ -53,6 +53,10 @@ class _CheerRewardWidgetState extends State&lt;CheerRewardWidget&gt;
53 } 53 }
54 } 54 }
55 55
  56 + Future<LottieComposition> _loadLottieComposition() async {
  57 + return AssetLottie(widget.lottieFile).load();
  58 + }
  59 +
56 void _startAnimation() { 60 void _startAnimation() {
57 Log.d("$TAG ${identityHashCode(this)} _startAnimation"); 61 Log.d("$TAG ${identityHashCode(this)} _startAnimation");
58 setState(() { 62 setState(() {
@@ -67,16 +71,12 @@ class _CheerRewardWidgetState extends State&lt;CheerRewardWidget&gt; @@ -67,16 +71,12 @@ class _CheerRewardWidgetState extends State&lt;CheerRewardWidget&gt;
67 setState(() { 71 setState(() {
68 _isVisible = false; 72 _isVisible = false;
69 }); 73 });
70 - widget.onAnimationEnd(); // 调用外部回调函数  
71 } 74 }
  75 + widget.onAnimationEnd(); // 调用外部回调函数
72 }); 76 });
73 }); 77 });
74 } 78 }
75 79
76 - Future<LottieComposition> _loadLottieComposition() async {  
77 - return AssetLottie(widget.lottieFile).load();  
78 - }  
79 -  
80 @override 80 @override
81 void dispose() { 81 void dispose() {
82 _controller.dispose(); 82 _controller.dispose();
lib/common/widgets/star_reward_widget.dart
@@ -73,8 +73,9 @@ class _StarRewardWidgetState extends State&lt;StarRewardWidget&gt; @@ -73,8 +73,9 @@ class _StarRewardWidgetState extends State&lt;StarRewardWidget&gt;
73 setState(() { 73 setState(() {
74 _isVisible = false; 74 _isVisible = false;
75 }); 75 });
76 - widget.onAnimationEnd(); // 调用外部回调函数  
77 } 76 }
  77 + Log.d('$StarRewardWidget whenCompleteOrCancel');
  78 + widget.onAnimationEnd(); // 调用外部回调函数
78 }); 79 });
79 }); 80 });
80 } 81 }
lib/pages/practice/bloc/topic_picture_bloc.dart
@@ -7,7 +7,6 @@ import &#39;package:flutter/services.dart&#39;; @@ -7,7 +7,6 @@ import &#39;package:flutter/services.dart&#39;;
7 import 'package:flutter_bloc/flutter_bloc.dart'; 7 import 'package:flutter_bloc/flutter_bloc.dart';
8 import 'package:flutter_easyloading/flutter_easyloading.dart'; 8 import 'package:flutter_easyloading/flutter_easyloading.dart';
9 import 'package:permission_handler/permission_handler.dart'; 9 import 'package:permission_handler/permission_handler.dart';
10 -import 'package:wow_english/common/extension/string_extension.dart';  
11 import 'package:wow_english/common/request/dao/listen_dao.dart'; 10 import 'package:wow_english/common/request/dao/listen_dao.dart';
12 import 'package:wow_english/common/request/exception.dart'; 11 import 'package:wow_english/common/request/exception.dart';
13 import 'package:wow_english/models/course_process_entity.dart'; 12 import 'package:wow_english/models/course_process_entity.dart';
@@ -207,10 +206,14 @@ class TopicPictureBloc @@ -207,10 +206,14 @@ class TopicPictureBloc
207 if (checkAnswerRight(_optionSelectItem) == true) { 206 if (checkAnswerRight(_optionSelectItem) == true) {
208 /// 如果选择题答(选)对后题目没播完,则暂停播放题目。答错的话继续播放体验也不错 207 /// 如果选择题答(选)对后题目没播完,则暂停播放题目。答错的话继续播放体验也不错
209 await closePlayerResource(); 208 await closePlayerResource();
210 - showStarRewardDialog(context);  
211 - await _playResultSound(true); 209 +
  210 + /// right音频长度比动效短,所以等动效完了再翻页
  211 + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.right);
  212 + await showStarRewardDialog(context, onDismiss: () {
  213 + autoFlipPage();
  214 + });
212 } else { 215 } else {
213 - await _playResultSound(false); 216 + await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.wrong);
214 } 217 }
215 } 218 }
216 219
@@ -276,14 +279,18 @@ class TopicPictureBloc @@ -276,14 +279,18 @@ class TopicPictureBloc
276 int score = int.parse(overall); 279 int score = int.parse(overall);
277 final voiceResult = VoiceResultType.fromScore(score); 280 final voiceResult = VoiceResultType.fromScore(score);
278 if (voiceResult.lottieFilePath != null) { 281 if (voiceResult.lottieFilePath != null) {
279 - showCheerRewardDialog(context, lottieFile: voiceResult.lottieFilePath!); 282 + AudioPlayerUtil.getInstance().playAudio(voiceResult.audioType);
  283 + await showCheerRewardDialog(context, lottieFile: voiceResult.lottieFilePath!, onDismiss: () {
  284 + if (isLastPage()) {
  285 + showStepPage();
  286 + }
  287 + });
  288 + } else {
  289 + await AudioPlayerUtil.getInstance().playAudio(voiceResult.audioType);
  290 + if (isLastPage()) {
  291 + showStepPage();
  292 + }
280 } 293 }
281 - await ClickWithMusicController.instance.playMusicAndPerformAction(  
282 - context,  
283 - voiceResult.audioType,  
284 - () {  
285 - if (isLastPage()) {showStepPage();};  
286 - });  
287 } 294 }
288 295
289 // 暂时没用上 296 // 暂时没用上
@@ -319,29 +326,24 @@ class TopicPictureBloc @@ -319,29 +326,24 @@ class TopicPictureBloc
319 await ClickWithMusicController.instance.reset(); 326 await ClickWithMusicController.instance.reset();
320 } 327 }
321 328
322 - ///播放选择结果音效  
323 - Future<void> _playResultSound(bool isCorrect) async {  
324 - await ClickWithMusicController.instance.playMusicAndPerformAction(context,  
325 - isCorrect ? AudioPlayerUtilType.right : AudioPlayerUtilType.wrong, () {  
326 - if (isCorrect) {  
327 - if (isLastPage()) {  
328 - showStepPage();  
329 - } else {  
330 - // 答对后且播放完自动翻页  
331 - pageController.nextPage(  
332 - duration: const Duration(milliseconds: 250),  
333 - curve: Curves.ease,  
334 - );  
335 - }  
336 - }  
337 - });  
338 - }  
339 -  
340 ///是否是最后一页 329 ///是否是最后一页
341 bool isLastPage() { 330 bool isLastPage() {
342 return currentPage == _entity?.topics?.length; 331 return currentPage == _entity?.topics?.length;
343 } 332 }
344 333
  334 + ///自动翻页
  335 + void autoFlipPage() {
  336 + if (isLastPage()) {
  337 + showStepPage();
  338 + } else {
  339 + // 答对后且播放完自动翻页
  340 + pageController.nextPage(
  341 + duration: const Duration(milliseconds: 250),
  342 + curve: Curves.ease,
  343 + );
  344 + }
  345 + }
  346 +
345 ///展示过渡页 347 ///展示过渡页
346 void showStepPage() { 348 void showStepPage() {
347 ///如果最后一页是语音问答题,评测完后自动翻页 349 ///如果最后一页是语音问答题,评测完后自动翻页
lib/pages/reading/bloc/reading_bloc.dart
@@ -22,6 +22,7 @@ import &#39;../../../models/course_process_entity.dart&#39;; @@ -22,6 +22,7 @@ import &#39;../../../models/course_process_entity.dart&#39;;
22 import '../../../models/singsound_result_detail_entity.dart'; 22 import '../../../models/singsound_result_detail_entity.dart';
23 import '../../../models/voice_result_type.dart'; 23 import '../../../models/voice_result_type.dart';
24 import '../../../route/route.dart'; 24 import '../../../route/route.dart';
  25 +import '../../../utils/audio_player_util.dart';
25 import '../../../utils/loading.dart'; 26 import '../../../utils/loading.dart';
26 27
27 import '../../../utils/log_util.dart'; 28 import '../../../utils/log_util.dart';
@@ -418,27 +419,35 @@ class ReadingPageBloc @@ -418,27 +419,35 @@ class ReadingPageBloc
418 add(OnXSVoiceStateChangeEvent()); 419 add(OnXSVoiceStateChangeEvent());
419 420
420 final voiceResult = VoiceResultType.fromScore(score); 421 final voiceResult = VoiceResultType.fromScore(score);
  422 +
421 if (voiceResult.lottieFilePath != null) { 423 if (voiceResult.lottieFilePath != null) {
422 - showCheerRewardDialog(context, lottieFile: voiceResult.lottieFilePath!); 424 + AudioPlayerUtil.getInstance().playAudio(voiceResult.audioType);
  425 + await showCheerRewardDialog(context, lottieFile: voiceResult.lottieFilePath!, onDismiss: () async {
  426 + await actionAfterRecord();
  427 + });
  428 + } else {
  429 + await AudioPlayerUtil.getInstance().playAudio(voiceResult.audioType);
  430 + await actionAfterRecord();
423 } 431 }
424 - await ClickWithMusicController.instance  
425 - .playMusicAndPerformAction(context, voiceResult.audioType, () async {  
426 - ///完成录音后紧接着播放录音  
427 - await _playRecordAudioInner();  
428 - if (isLastPage()) {  
429 - sectionComplete(() {  
430 - popPage(data: {  
431 - 'currentStep': currentPage,  
432 - 'courseLessonId': courseLessonId,  
433 - 'isCompleted': true,  
434 - 'nextSection': true  
435 - });  
436 - }, againSectionTap: () {  
437 - _resetLocalResult();  
438 - pageController.jumpToPage(0); 432 + }
  433 +
  434 + /// 作答音效&动效播放结束后
  435 + Future<void> actionAfterRecord() async {
  436 + ///完成录音后紧接着播放录音
  437 + await _playRecordAudioInner();
  438 + if (isLastPage()) {
  439 + sectionComplete(() {
  440 + popPage(data: {
  441 + 'currentStep': currentPage,
  442 + 'courseLessonId': courseLessonId,
  443 + 'isCompleted': true,
  444 + 'nextSection': true
439 }); 445 });
440 - }  
441 - }); 446 + }, againSectionTap: () {
  447 + _resetLocalResult();
  448 + pageController.jumpToPage(0);
  449 + });
  450 + }
442 } 451 }
443 452
444 ///终止评测 453 ///终止评测