Commit b1869cf8c5a103abd2206171c56033fe68ce78c8

Authored by biao
1 parent d5fb5080

背景音乐添加

lib/pages/games/bloc.dart
... ... @@ -2,17 +2,17 @@ import 'package:bloc/bloc.dart';
2 2 import 'package:flutter/cupertino.dart';
3 3 import 'package:flutter/services.dart';
4 4 import 'package:wow_english/common/extension/string_extension.dart';
  5 +import 'package:wow_english/utils/audioplayer_util.dart';
5 6  
6 7 import 'event.dart';
7 8 import 'game_entity.dart';
8 9 import 'state.dart';
9 10  
10 11 class GamesBloc extends Bloc<GamesEvent, GamesState> {
11   -
12 12 late MethodChannel _methodChannel;
13 13  
14 14 //手动初始化4个GameEntity对象
15   - final List<GameEntity> _games = [
  15 + final List<GameEntity> _games = [
16 16 GameEntity()
17 17 ..id = 1
18 18 ..imageName = 'game_food_1'.assetPng
... ... @@ -31,7 +31,7 @@ class GamesBloc extends Bloc&lt;GamesEvent, GamesState&gt; {
31 31 ..name = 'Animal'
32 32 ];
33 33  
34   - List<GameEntity> get listData => _games;
  34 + List<GameEntity> get listData => _games;
35 35  
36 36 GamesBloc() : super(GamesState().init()) {
37 37 on<InitEvent>(_init);
... ... @@ -39,13 +39,16 @@ class GamesBloc extends Bloc&lt;GamesEvent, GamesState&gt; {
39 39 }
40 40  
41 41 void _init(InitEvent event, Emitter<GamesState> emit) async {
  42 + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy);
42 43 emit(state.clone());
43 44 }
44 45  
45 46 void _gotoGamePage(GotoGamePageEvent event, Emitter<GamesState> emit) async {
  47 + AudioPlayerUtil.getInstance().pause();
46 48 try {
47 49 _methodChannel = const MethodChannel('wow_english/game_method_channel');
48   - await _methodChannel.invokeMethod('openGamePage', { "gameId": event.gameId });
  50 + await _methodChannel
  51 + .invokeMethod('openGamePage', {"gameId": event.gameId});
49 52 } on PlatformException catch (e) {
50 53 debugPrint("Failed to go to native page: '${e.message}'.");
51 54 }
... ...
lib/pages/home/bloc.dart
... ... @@ -2,6 +2,7 @@ import &#39;package:audioplayers/audioplayers.dart&#39;;
2 2 import 'package:bloc/bloc.dart';
3 3 import 'package:wow_english/common/core/user_util.dart';
4 4 import 'package:wow_english/common/extension/string_extension.dart';
  5 +import 'package:wow_english/utils/audioplayer_util.dart';
5 6  
6 7 import '../../common/core/app_config_helper.dart';
7 8 import '../../common/request/dao/system_dao.dart';
... ... @@ -17,16 +18,10 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
17 18 }
18 19  
19 20 bool exchangeResult = false;
20   - late AudioPlayer audioPlayer;
21   - late AudioPlayer studyPlayer;
22   - late AudioPlayer gamePlayer;
23 21  
24 22 void _init(InitEvent event, Emitter<HomeState> emit) async {
25 23 if (UserUtil.isLogined()) {
26   - audioPlayer = AudioPlayer(playerId: 'audio');
27   - gamePlayer = AudioPlayer(playerId: 'game');
28   - studyPlayer = AudioPlayer(playerId: 'study');
29   - audioPlayer.play(AssetSource('welcome_to_wow'.assetMp3));
  24 + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.welcomeToWow);
30 25 }
31 26 await _checkUpdate(emit);
32 27 }
... ...
lib/pages/home/view.dart
... ... @@ -12,6 +12,7 @@ import &#39;package:wow_english/pages/home/state.dart&#39;;
12 12 import 'package:wow_english/pages/home/widgets/BaseHomeHeaderWidget.dart';
13 13 import 'package:wow_english/pages/shop/exchane/bloc/exchange_lesson_bloc.dart';
14 14 import 'package:wow_english/pages/user/bloc/user_bloc.dart';
  15 +import 'package:wow_english/utils/audioplayer_util.dart';
15 16  
16 17 import '../../common/core/user_util.dart';
17 18 import '../../common/dialogs/show_dialog.dart';
... ... @@ -60,6 +61,8 @@ class _HomePageView extends StatelessWidget {
60 61 children: [
61 62 BaseHomeHeaderWidget(
62 63 callBack: (value) => {
  64 + AudioPlayerUtil.getInstance()
  65 + .playAudio(AudioPlayerUtilType.touch),
63 66 bloc.exchangeResult = value['exchange'],
64 67 bloc.add(ExchangeSuccessEvent())
65 68 }),
... ... @@ -71,8 +74,8 @@ class _HomePageView extends StatelessWidget {
71 74 child: GestureDetector(
72 75 onTap: () {
73 76 _checkPermission(() {
74   - bloc.studyPlayer
75   - .play(AssetSource('class_time'.assetMp3));
  77 + AudioPlayerUtil.getInstance()
  78 + .playAudio(AudioPlayerUtilType.classTime);
76 79 Future.delayed(const Duration(seconds: 1), () {
77 80 pushNamed(AppRouteName.courseUnit)
78 81 .then((value) => {
... ... @@ -108,29 +111,38 @@ class _HomePageView extends StatelessWidget {
108 111 ),
109 112 ),
110 113 ),
111   - Expanded(
112   - child: BlocBuilder<UserBloc, UserState>(
113   - builder: (context, userState) {
114   - return GestureDetector(
115   - onTap: () {
116   - _checkPermission(() {
117   - Navigator.of(context).pushNamed(
118   - AppRouteName.webView,
119   - arguments: {
120   - 'urlStr': AppConsts.xiaoeShopUrl,
121   - 'webViewTitle': 'Wow精选'
122   - });
123   - }, bloc);
124   - },
125   - child: Column(
126   - mainAxisAlignment: MainAxisAlignment.center,
127   - children: [
128   - Image.asset('xe_shop'.assetPng,
129   - width: 140.5.w, height: 172.h),
130   - 44.verticalSpace
131   - ],
132   - ));
133   - }),
  114 + Offstage(
  115 + offstage: AppConfigHelper.shouldHidePay() ||
  116 + !UserUtil.isLogined(),
  117 + child: Expanded(
  118 + child: BlocBuilder<UserBloc, UserState>(
  119 + builder: (context, userState) {
  120 + return GestureDetector(
  121 + onTap: () {
  122 + _checkPermission(() {
  123 + AudioPlayerUtil.getInstance().pause();
  124 + Navigator.of(context).pushNamed(
  125 + AppRouteName.webView,
  126 + arguments: {
  127 + 'urlStr': AppConsts.xiaoeShopUrl,
  128 + 'webViewTitle': 'Wow精选'
  129 + }).then((value) => {
  130 + AudioPlayerUtil.getInstance()
  131 + .playAudio(
  132 + AudioPlayerUtilType.touch),
  133 + });
  134 + }, bloc);
  135 + },
  136 + child: Column(
  137 + mainAxisAlignment: MainAxisAlignment.center,
  138 + children: [
  139 + Image.asset('xe_shop'.assetPng,
  140 + width: 140.5.w, height: 172.h),
  141 + 44.verticalSpace
  142 + ],
  143 + ));
  144 + }),
  145 + ),
134 146 ),
135 147 Expanded(
136 148 child: BlocBuilder<UserBloc, UserState>(
... ... @@ -138,9 +150,14 @@ class _HomePageView extends StatelessWidget {
138 150 return GestureDetector(
139 151 onTap: () {
140 152 _checkPermission(() {
141   - bloc.gamePlayer.play(
142   - AssetSource('game_time'.assetMp3));
143   - pushNamed(AppRouteName.games);
  153 + AudioPlayerUtil.getInstance().playAudio(
  154 + AudioPlayerUtilType.gameTime);
  155 + pushNamed(AppRouteName.games)
  156 + .then((value) => {
  157 + AudioPlayerUtil.getInstance()
  158 + .playAudio(AudioPlayerUtilType
  159 + .touch),
  160 + });
144 161 }, bloc);
145 162 },
146 163 child: Column(
... ... @@ -189,6 +206,8 @@ class _HomePageView extends StatelessWidget {
189 206 }, rightTap: () {
190 207 popPage();
191 208 pushNamed(AppRouteName.shop).then((value) {
  209 + AudioPlayerUtil.getInstance()
  210 + .playAudio(AudioPlayerUtilType.touch);
192 211 if (value != null) {
193 212 bloc.exchangeResult = value['exchange'];
194 213 bloc.add(ExchangeSuccessEvent());
... ...
lib/pages/home/widgets/BaseHomeHeaderWidget.dart
... ... @@ -3,6 +3,7 @@ import &#39;package:flutter_bloc/flutter_bloc.dart&#39;;
3 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
4 4 import 'package:wow_english/common/core/app_config_helper.dart';
5 5 import 'package:wow_english/common/extension/string_extension.dart';
  6 +import 'package:wow_english/utils/audioplayer_util.dart';
6 7  
7 8 import '../../../common/core/user_util.dart';
8 9 import '../../../models/course_entity.dart';
... ... @@ -84,6 +85,7 @@ class BaseHomeHeaderWidget extends StatelessWidget {
84 85 !UserUtil.isLogined(),
85 86 child: GestureDetector(
86 87 onTap: () => {
  88 + AudioPlayerUtil.getInstance().pause(),
87 89 pushNamed(AppRouteName.shop).then((value) {
88 90 if (value != null) {
89 91 if (callBack == null) {
... ... @@ -115,6 +117,7 @@ class BaseHomeHeaderWidget extends StatelessWidget {
115 117  
116 118 void onUserClick() {
117 119 if (UserUtil.isLogined()) {
  120 + AudioPlayerUtil.getInstance().pause();
118 121 pushNamed(AppRouteName.user).then((value) {
119 122 if (value != null) {
120 123 if (callBack == null) {
... ...
lib/pages/section/bloc/section_bloc.dart
... ... @@ -9,6 +9,7 @@ import &#39;package:wow_english/common/request/dao/lesson_dao.dart&#39;;
9 9 import 'package:wow_english/common/request/exception.dart';
10 10 import 'package:wow_english/common/request/dao/listen_dao.dart';
11 11 import 'package:wow_english/models/course_process_entity.dart';
  12 +import 'package:wow_english/utils/audioplayer_util.dart';
12 13 import 'package:wow_english/utils/loading.dart';
13 14 import 'package:wow_english/utils/toast_util.dart';
14 15  
... ... @@ -45,8 +46,6 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; {
45 46 ///单元列表是否有刷新,有的话返回上一页时通知其刷新接口数据
46 47 bool courseUnitEntityChanged = false;
47 48  
48   - late AudioPlayer audioPlayer; // 点击播放器
49   - late AudioPlayer backgroundPlayer; // 背景播放器
50 49 ///courseUnitId与课程环节列表的映射
51 50 final Map<int, List<CourseSectionEntity>?> _courseSectionDatasMap = {};
52 51  
... ... @@ -66,25 +65,12 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; {
66 65 on<RequestVideoLessonEvent>(_requestVideoLesson);
67 66 on<CurrentUnitIndexChangeEvent>(_pageControllerChange);
68 67 on<InitEvent>((event, emit) {
69   - audioPlayer = AudioPlayer(playerId: 'section');
70   - backgroundPlayer = AudioPlayer(playerId: 'back');
71   - backgroundPlayer.play(AssetSource('count_with_me_instrumental'.assetMp3));
72   -
73   - backgroundPlayer.onPlayerStateChanged.listen((event) async {
74   - if (event == PlayerState.completed) {
75   - // 播放结束再次播放
76   - backgroundPlayer
77   - .play(AssetSource('count_with_me_instrumental'.assetMp3));
78   - }
79   - });
  68 + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe);
80 69 });
81 70 }
82 71 @override
83 72 Future<void> close() {
84   - audioPlayer.release();
85   - audioPlayer.dispose();
86   - backgroundPlayer.release();
87   - backgroundPlayer.dispose();
  73 + AudioPlayerUtil.getInstance().pause();
88 74 return super.close();
89 75 }
90 76  
... ...
lib/pages/section/bloc/section_state.dart
... ... @@ -22,5 +22,3 @@ class RequestEnterClassState extends SectionState {
22 22 }
23 23  
24 24 class CurrentPageIndexState extends SectionState {}
25   -
26   -class VoicePlayChangeState extends SectionState {}
... ...
lib/pages/section/section_page.dart
... ... @@ -12,6 +12,8 @@ import &#39;package:wow_english/pages/section/widgets/section_item.dart&#39;;
12 12 import 'package:wow_english/pages/section/widgets/section_bouns_item.dart';
13 13 import 'package:wow_english/pages/section/widgets/section_header_widget.dart';
14 14 import 'package:wow_english/route/route.dart';
  15 +import 'package:wow_english/utils/audioplayer_util.dart';
  16 +import 'package:wow_english/utils/log_util.dart';
15 17 import 'package:wow_english/utils/toast_util.dart';
16 18  
17 19 import '../../models/course_section_entity.dart';
... ... @@ -89,23 +91,23 @@ class _SectionPageView extends StatelessWidget {
89 91 currentTime: dataMap['currentTime'],
90 92 autoNextSection: dataMap['nextSection']));
91 93 }
92   - if (bloc.backgroundPlayer.state == PlayerState.paused) {
93   - bloc.backgroundPlayer.resume();
94   - }
  94 + AudioPlayerUtil.getInstance()
  95 + .playAudio(AudioPlayerUtilType.countWithMe);
95 96 });
96 97 return;
97 98 }
98 99  
99 100 if (state is RequestEnterClassState) {
100   - bloc.backgroundPlayer.pause();
101 101 if (state.courseType != SectionType.practice.value &&
102 102 state.courseType != SectionType.pictureBook.value) {
103 103 ///视频类型
104 104 ///获取视频课程内容
105 105 if (state.courseType == 1) {
106   - bloc.audioPlayer.play(AssetSource('music_time'.assetMp3));
  106 + AudioPlayerUtil.getInstance()
  107 + .playAudio(AudioPlayerUtilType.musicTime);
107 108 } else {
108   - bloc.audioPlayer.play(AssetSource('video_time'.assetMp3));
  109 + AudioPlayerUtil.getInstance()
  110 + .playAudio(AudioPlayerUtilType.videoTime);
109 111 }
110 112 Future.delayed(const Duration(seconds: 1), () {
111 113 bloc.add(RequestVideoLessonEvent(
... ... @@ -116,7 +118,8 @@ class _SectionPageView extends StatelessWidget {
116 118 }
117 119  
118 120 if (state.courseType == SectionType.pictureBook.value) {
119   - bloc.audioPlayer.play(AssetSource('reading_time'.assetMp3));
  121 + AudioPlayerUtil.getInstance()
  122 + .playAudio(AudioPlayerUtilType.readingTime);
120 123 Future.delayed(const Duration(seconds: 1), () {
121 124 //绘本
122 125 pushNamed(AppRouteName.reading,
... ... @@ -130,9 +133,8 @@ class _SectionPageView extends StatelessWidget {
130 133 currentStep: dataMap['currentStep'],
131 134 autoNextSection: dataMap['nextSection'],
132 135 ));
133   - if (bloc.backgroundPlayer.state == PlayerState.paused) {
134   - bloc.backgroundPlayer.resume();
135   - }
  136 + AudioPlayerUtil.getInstance()
  137 + .playAudio(AudioPlayerUtilType.countWithMe);
136 138 }
137 139 });
138 140 });
... ... @@ -142,7 +144,8 @@ class _SectionPageView extends StatelessWidget {
142 144  
143 145 if (state.courseType == SectionType.practice.value) {
144 146 //练习
145   - bloc.audioPlayer.play(AssetSource('quiz_time'.assetMp3));
  147 + AudioPlayerUtil.getInstance()
  148 + .playAudio(AudioPlayerUtilType.quizTime);
146 149 Future.delayed(const Duration(seconds: 1), () {
147 150 pushNamed(AppRouteName.topicPic,
148 151 arguments: {'courseLessonId': state.courseLessonId})
... ... @@ -154,9 +157,8 @@ class _SectionPageView extends StatelessWidget {
154 157 currentStep: dataMap['currentStep'],
155 158 autoNextSection: dataMap['nextSection']));
156 159 }
157   - if (bloc.backgroundPlayer.state == PlayerState.paused) {
158   - bloc.backgroundPlayer.resume();
159   - }
  160 + AudioPlayerUtil.getInstance()
  161 + .playAudio(AudioPlayerUtilType.countWithMe);
160 162 });
161 163 });
162 164 return;
... ...
lib/pages/unit/bloc.dart
1 1 import 'package:bloc/bloc.dart';
2 2 import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart';
  3 +import 'package:wow_english/utils/audioplayer_util.dart';
3 4  
4 5 import '../../common/request/dao/lesson_dao.dart';
5 6 import '../../common/request/exception.dart';
... ... @@ -24,6 +25,9 @@ class UnitBloc extends Bloc&lt;UnitEvent, UnitState&gt; {
24 25  
25 26 UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) {
26 27 on<RequestUnitDataEvent>(_requestUnitDatas);
  28 + on<UnitInitEvent>((event, emit) {
  29 + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy);
  30 + });
27 31 }
28 32  
29 33 void _requestUnitDatas(
... ... @@ -45,15 +49,26 @@ class UnitBloc extends Bloc&lt;UnitEvent, UnitState&gt; {
45 49 }
46 50  
47 51 void headerActionEvent(HeaderActionType type) {
  52 + AudioPlayerUtil.getInstance().pause();
48 53 if (type == HeaderActionType.video) {
49 54 pushNamed(AppRouteName.reAfter);
50 55 } else if (type == HeaderActionType.phase) {
51   - pushNamed(AppRouteName.courseModule);
  56 + pushNamed(AppRouteName.courseModule).then((value) => {
  57 + AudioPlayerUtil.getInstance()
  58 + .playAudio(AudioPlayerUtilType.inMyTummy)
  59 + });
  60 + ;
52 61 } else if (type == HeaderActionType.listen) {
53   - pushNamed(AppRouteName.listen);
  62 + pushNamed(AppRouteName.listen).then((value) => {
  63 + AudioPlayerUtil.getInstance()
  64 + .playAudio(AudioPlayerUtilType.inMyTummy)
  65 + });
54 66 } else if (type == HeaderActionType.shop) {
55   - pushNamed(AppRouteName.shop)
56   - .then((value) => {exchangeResult = value['exchange']});
  67 + pushNamed(AppRouteName.shop).then((value) => {
  68 + AudioPlayerUtil.getInstance()
  69 + .playAudio(AudioPlayerUtilType.inMyTummy),
  70 + exchangeResult = value['exchange']
  71 + });
57 72 } else if (type == HeaderActionType.user) {
58 73 pushNamed(AppRouteName.user);
59 74 }
... ...
lib/pages/unit/event.dart
... ... @@ -6,3 +6,5 @@ class RequestUnitDataEvent extends UnitEvent {
6 6  
7 7 RequestUnitDataEvent(this.moduleId);
8 8 }
  9 +
  10 +class UnitInitEvent extends UnitEvent {}
... ...
lib/pages/unit/view.dart
... ... @@ -5,6 +5,7 @@ import &#39;package:wow_english/pages/unit/state.dart&#39;;
5 5 import 'package:wow_english/pages/unit/widget/course_unit_item.dart';
6 6 import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart';
7 7 import 'package:wow_english/route/route.dart';
  8 +import 'package:wow_english/utils/audioplayer_util.dart';
8 9  
9 10 import '../../models/course_module_entity.dart';
10 11 import '../../models/course_unit_entity.dart';
... ... @@ -23,6 +24,7 @@ class UnitPage extends StatelessWidget {
23 24 Widget build(BuildContext context) {
24 25 return BlocProvider(
25 26 create: (BuildContext context) => UnitBloc(courseModuleEntity)
  27 + ..add(UnitInitEvent())
26 28 ..add(RequestUnitDataEvent(courseModuleEntity?.id)),
27 29 child: Builder(builder: (context) => _buildPage(context)),
28 30 );
... ... @@ -41,6 +43,8 @@ class UnitPage extends StatelessWidget {
41 43 HomeTabHeaderWidget(
42 44 courseModuleCode: bloc.getCourseModuleCode(),
43 45 onBack: () {
  46 + AudioPlayerUtil.getInstance()
  47 + .playAudio(AudioPlayerUtilType.touch);
44 48 popPage(data: {'exchange': bloc.exchangeResult});
45 49 },
46 50 actionTap: (HeaderActionType type) {
... ... @@ -63,12 +67,14 @@ class UnitPage extends StatelessWidget {
63 67 showToast('当前单元课程暂未解锁');
64 68 return;
65 69 }
66   -
  70 + AudioPlayerUtil.getInstance().pause();
67 71 pushNamed(AppRouteName.courseSection,
68 72 arguments: {
69 73 'courseUnitEntity': bloc.unitData,
70 74 'courseUnitId': data.id
71 75 }).then((value) {
  76 + AudioPlayerUtil.getInstance()
  77 + .playAudio(AudioPlayerUtilType.inMyTummy);
72 78 if (value != null) {
73 79 Map<String, dynamic> dataMap =
74 80 value as Map<String, dynamic>;
... ...
lib/utils/audioplayer_util.dart 0 → 100644
  1 +import 'package:audioplayers/audioplayers.dart';
  2 +import 'package:wow_english/common/extension/string_extension.dart';
  3 +
  4 +enum AudioPlayerUtilType {
  5 + welcomeToWow('welcome_to_wow'),
  6 + classTime('class_time'),
  7 + gameTime('game_time'),
  8 + musicTime('music_time'),
  9 + readingTime('reading_time'),
  10 + videoTime('video_time'),
  11 + quizTime('quiz_time'),
  12 + countWithMe('count_with_me_instrumental'),
  13 + inMyTummy('in_my_tummy_instrumental'),
  14 + touch('touch_instrumental');
  15 +
  16 + const AudioPlayerUtilType(this.path);
  17 +
  18 + final String path;
  19 +}
  20 +
  21 +class AudioPlayerUtil {
  22 + static AudioPlayerUtil? _instance;
  23 + late AudioPlayer audioPlayer;
  24 + late AudioPlayerUtilType currentType;
  25 +
  26 + // 私有构造函数
  27 + AudioPlayerUtil._internal() {
  28 + audioPlayer = AudioPlayer();
  29 + audioPlayer.onPlayerStateChanged.listen((event) async {
  30 + if (event == PlayerState.completed) {
  31 + // 播放结束再次播放
  32 + if (currentType == AudioPlayerUtilType.inMyTummy) {
  33 + AudioPlayerUtil.getInstance()
  34 + .playAudio(AudioPlayerUtilType.inMyTummy);
  35 + }
  36 + if (currentType == AudioPlayerUtilType.countWithMe) {
  37 + AudioPlayerUtil.getInstance()
  38 + .playAudio(AudioPlayerUtilType.countWithMe);
  39 + }
  40 + if (currentType == AudioPlayerUtilType.welcomeToWow) {
  41 + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch);
  42 + }
  43 + if (currentType == AudioPlayerUtilType.touch) {
  44 + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch);
  45 + }
  46 + }
  47 + });
  48 + }
  49 +
  50 + static AudioPlayerUtil getInstance() {
  51 + _instance ??= AudioPlayerUtil._internal();
  52 + return _instance!;
  53 + }
  54 +
  55 +// 播放音频
  56 + Future<void> playAudio(AudioPlayerUtilType type) async {
  57 + currentType = type;
  58 + String path = type.path;
  59 + await audioPlayer.play(AssetSource(path.assetMp3), volume: 0.5);
  60 + await audioPlayer.onPlayerComplete.first;
  61 + }
  62 +
  63 + // stop
  64 + void stop() {
  65 + audioPlayer.stop();
  66 + }
  67 +
  68 + // pause
  69 + void pause() {
  70 + if (audioPlayer.state == PlayerState.playing) {
  71 + audioPlayer.pause();
  72 + }
  73 + }
  74 +
  75 + // resume
  76 + void resume() {
  77 + if (audioPlayer.state == PlayerState.paused) {
  78 + audioPlayer.resume();
  79 + }
  80 + }
  81 +}
... ...