Commit 7c8ae103377406a71f677a4088c79ba18394ef7f
Merge branch 'work-wqf-20240715'
Showing
44 changed files
with
538 additions
and
220 deletions
.fvm/flutter_sdk
.fvm/fvm_config.json
.vscode/settings.json
0 → 100644
assets/images/micro_phone.gif
assets/images/read_background.png
0 → 100644
480 KB
assets/images/reade_answer.gif
assets/images/shop_desc.png
0 → 100644
746 KB
assets/images/voice.png
assets/images/xe_shop.png
0 → 100644
267 KB
assets/sounds/class_time.mp3
0 → 100644
No preview for this file type
assets/sounds/count_with_me_instrumental.mp3
0 → 100644
No preview for this file type
assets/sounds/game_time.mp3
0 → 100644
No preview for this file type
assets/sounds/in_my_tummy_instrumental.mp3
0 → 100644
No preview for this file type
assets/sounds/music_time.mp3
0 → 100644
No preview for this file type
assets/sounds/quiz_time.mp3
0 → 100644
No preview for this file type
assets/sounds/reading_time.mp3
0 → 100644
No preview for this file type
assets/sounds/touch_instrumental.mp3
0 → 100644
No preview for this file type
assets/sounds/video_time.mp3
0 → 100644
No preview for this file type
assets/sounds/welcome_to_wow.mp3
0 → 100644
No preview for this file type
ios/Runner.xcodeproj/project.pbxproj
| @@ -2327,7 +2327,7 @@ | @@ -2327,7 +2327,7 @@ | ||
| 2327 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | 2327 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; |
| 2328 | CODE_SIGN_IDENTITY = "Apple Development"; | 2328 | CODE_SIGN_IDENTITY = "Apple Development"; |
| 2329 | CODE_SIGN_STYLE = Automatic; | 2329 | CODE_SIGN_STYLE = Automatic; |
| 2330 | - CURRENT_PROJECT_VERSION = 13; | 2330 | + CURRENT_PROJECT_VERSION = 16; |
| 2331 | DEVELOPMENT_TEAM = T8P9KW8GWH; | 2331 | DEVELOPMENT_TEAM = T8P9KW8GWH; |
| 2332 | ENABLE_BITCODE = NO; | 2332 | ENABLE_BITCODE = NO; |
| 2333 | INFOPLIST_FILE = Runner/Info.plist; | 2333 | INFOPLIST_FILE = Runner/Info.plist; |
| @@ -2671,7 +2671,7 @@ | @@ -2671,7 +2671,7 @@ | ||
| 2671 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | 2671 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; |
| 2672 | CODE_SIGN_IDENTITY = "Apple Development"; | 2672 | CODE_SIGN_IDENTITY = "Apple Development"; |
| 2673 | CODE_SIGN_STYLE = Automatic; | 2673 | CODE_SIGN_STYLE = Automatic; |
| 2674 | - CURRENT_PROJECT_VERSION = 13; | 2674 | + CURRENT_PROJECT_VERSION = 16; |
| 2675 | DEVELOPMENT_TEAM = T8P9KW8GWH; | 2675 | DEVELOPMENT_TEAM = T8P9KW8GWH; |
| 2676 | ENABLE_BITCODE = NO; | 2676 | ENABLE_BITCODE = NO; |
| 2677 | HEADER_SEARCH_PATHS = ( | 2677 | HEADER_SEARCH_PATHS = ( |
| @@ -2876,7 +2876,7 @@ | @@ -2876,7 +2876,7 @@ | ||
| 2876 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | 2876 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; |
| 2877 | CODE_SIGN_IDENTITY = "Apple Development"; | 2877 | CODE_SIGN_IDENTITY = "Apple Development"; |
| 2878 | CODE_SIGN_STYLE = Automatic; | 2878 | CODE_SIGN_STYLE = Automatic; |
| 2879 | - CURRENT_PROJECT_VERSION = 13; | 2879 | + CURRENT_PROJECT_VERSION = 16; |
| 2880 | DEVELOPMENT_TEAM = T8P9KW8GWH; | 2880 | DEVELOPMENT_TEAM = T8P9KW8GWH; |
| 2881 | ENABLE_BITCODE = NO; | 2881 | ENABLE_BITCODE = NO; |
| 2882 | INFOPLIST_FILE = Runner/Info.plist; | 2882 | INFOPLIST_FILE = Runner/Info.plist; |
ios/Runner/Info.plist
| @@ -77,11 +77,11 @@ | @@ -77,11 +77,11 @@ | ||
| 77 | <true/> | 77 | <true/> |
| 78 | </dict> | 78 | </dict> |
| 79 | <key>NSCameraUsageDescription</key> | 79 | <key>NSCameraUsageDescription</key> |
| 80 | - <string>需要访问相机完成拍照</string> | 80 | + <string>需要访问相机,完成修改头像功能</string> |
| 81 | <key>NSMicrophoneUsageDescription</key> | 81 | <key>NSMicrophoneUsageDescription</key> |
| 82 | - <string>需要获取录音完成后续功能</string> | 82 | + <string>需要获取录音,完成上课功能</string> |
| 83 | <key>NSPhotoLibraryUsageDescription</key> | 83 | <key>NSPhotoLibraryUsageDescription</key> |
| 84 | - <string>需要获取照片用来修改头像</string> | 84 | + <string>需要获取照片,完成上传头像功能</string> |
| 85 | <key>UIApplicationSupportsIndirectInputEvents</key> | 85 | <key>UIApplicationSupportsIndirectInputEvents</key> |
| 86 | <true/> | 86 | <true/> |
| 87 | <key>UILaunchStoryboardName</key> | 87 | <key>UILaunchStoryboardName</key> |
lib/common/core/app_consts.dart
| @@ -2,16 +2,26 @@ import '../request/basic_config.dart'; | @@ -2,16 +2,26 @@ import '../request/basic_config.dart'; | ||
| 2 | 2 | ||
| 3 | class AppConsts { | 3 | class AppConsts { |
| 4 | /// 隐私协议 | 4 | /// 隐私协议 |
| 5 | - static const String userPrivacyPolicyUrl = 'http://page.kouyuxingqiu.com/wowenglishuserregister.html'; | 5 | + static const String userPrivacyPolicyUrl = |
| 6 | + 'http://page.kouyuxingqiu.com/wowenglishuserregister.html'; | ||
| 6 | 7 | ||
| 7 | /// 儿童隐私协议 | 8 | /// 儿童隐私协议 |
| 8 | - static const String childrenPrivacyPolicyUrl = 'http://page.kouyuxingqiu.com/wowenglishchildprotect.html'; | 9 | + static const String childrenPrivacyPolicyUrl = |
| 10 | + 'http://page.kouyuxingqiu.com/wowenglishchildprotect.html'; | ||
| 11 | + | ||
| 12 | + /// 小鵝通 | ||
| 13 | + static const String xiaoeShopUrl = 'https://appo61s7g678876.h5.xiaoeknow.com'; | ||
| 9 | 14 | ||
| 10 | /// 与第三方共享协议 | 15 | /// 与第三方共享协议 |
| 11 | - static const String userTermSdkUrl = 'http://page.kouyuxingqiu.com/term_sdk.html'; | 16 | + static const String userTermSdkUrl = |
| 17 | + 'http://page.kouyuxingqiu.com/term_sdk.html'; | ||
| 12 | 18 | ||
| 13 | /// 先声SDK | 19 | /// 先声SDK |
| 14 | - static String xsAppKey = 'a418'; | ||
| 15 | - static String xsAppSecretKey = BasicConfig.isTestDev?'1a16f31f2611bf32fb7b3fc38f5b2c81':'c11163aa6c834a028da4a4b30955be99'; | ||
| 16 | - static String xsAppService = BasicConfig.isTestDev?'ws://trial.cloud.ssapi.cn:8080':'"wss://api.cloud.ssapi.cn'; | 20 | + static String xsAppKey = 'a418'; |
| 21 | + static String xsAppSecretKey = BasicConfig.isTestDev | ||
| 22 | + ? '1a16f31f2611bf32fb7b3fc38f5b2c81' | ||
| 23 | + : 'c11163aa6c834a028da4a4b30955be99'; | ||
| 24 | + static String xsAppService = BasicConfig.isTestDev | ||
| 25 | + ? 'ws://trial.cloud.ssapi.cn:8080' | ||
| 26 | + : '"wss://api.cloud.ssapi.cn'; | ||
| 17 | } | 27 | } |
lib/pages/games/bloc.dart
| @@ -2,17 +2,17 @@ import 'package:bloc/bloc.dart'; | @@ -2,17 +2,17 @@ import 'package:bloc/bloc.dart'; | ||
| 2 | import 'package:flutter/cupertino.dart'; | 2 | import 'package:flutter/cupertino.dart'; |
| 3 | import 'package:flutter/services.dart'; | 3 | import 'package:flutter/services.dart'; |
| 4 | import 'package:wow_english/common/extension/string_extension.dart'; | 4 | import 'package:wow_english/common/extension/string_extension.dart'; |
| 5 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 5 | 6 | ||
| 6 | import 'event.dart'; | 7 | import 'event.dart'; |
| 7 | import 'game_entity.dart'; | 8 | import 'game_entity.dart'; |
| 8 | import 'state.dart'; | 9 | import 'state.dart'; |
| 9 | 10 | ||
| 10 | class GamesBloc extends Bloc<GamesEvent, GamesState> { | 11 | class GamesBloc extends Bloc<GamesEvent, GamesState> { |
| 11 | - | ||
| 12 | late MethodChannel _methodChannel; | 12 | late MethodChannel _methodChannel; |
| 13 | 13 | ||
| 14 | //手动初始化4个GameEntity对象 | 14 | //手动初始化4个GameEntity对象 |
| 15 | - final List<GameEntity> _games = [ | 15 | + final List<GameEntity> _games = [ |
| 16 | GameEntity() | 16 | GameEntity() |
| 17 | ..id = 1 | 17 | ..id = 1 |
| 18 | ..imageName = 'game_food_1'.assetPng | 18 | ..imageName = 'game_food_1'.assetPng |
| @@ -31,7 +31,7 @@ class GamesBloc extends Bloc<GamesEvent, GamesState> { | @@ -31,7 +31,7 @@ class GamesBloc extends Bloc<GamesEvent, GamesState> { | ||
| 31 | ..name = 'Animal' | 31 | ..name = 'Animal' |
| 32 | ]; | 32 | ]; |
| 33 | 33 | ||
| 34 | - List<GameEntity> get listData => _games; | 34 | + List<GameEntity> get listData => _games; |
| 35 | 35 | ||
| 36 | GamesBloc() : super(GamesState().init()) { | 36 | GamesBloc() : super(GamesState().init()) { |
| 37 | on<InitEvent>(_init); | 37 | on<InitEvent>(_init); |
| @@ -39,13 +39,16 @@ class GamesBloc extends Bloc<GamesEvent, GamesState> { | @@ -39,13 +39,16 @@ class GamesBloc extends Bloc<GamesEvent, GamesState> { | ||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void _init(InitEvent event, Emitter<GamesState> emit) async { | 41 | void _init(InitEvent event, Emitter<GamesState> emit) async { |
| 42 | + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy); | ||
| 42 | emit(state.clone()); | 43 | emit(state.clone()); |
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | void _gotoGamePage(GotoGamePageEvent event, Emitter<GamesState> emit) async { | 46 | void _gotoGamePage(GotoGamePageEvent event, Emitter<GamesState> emit) async { |
| 47 | + await AudioPlayerUtil.getInstance().pause(); | ||
| 46 | try { | 48 | try { |
| 47 | _methodChannel = const MethodChannel('wow_english/game_method_channel'); | 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 | } on PlatformException catch (e) { | 52 | } on PlatformException catch (e) { |
| 50 | debugPrint("Failed to go to native page: '${e.message}'."); | 53 | debugPrint("Failed to go to native page: '${e.message}'."); |
| 51 | } | 54 | } |
lib/pages/home/bloc.dart
| 1 | +import 'package:audioplayers/audioplayers.dart'; | ||
| 1 | import 'package:bloc/bloc.dart'; | 2 | import 'package:bloc/bloc.dart'; |
| 3 | +import 'package:wow_english/common/core/user_util.dart'; | ||
| 4 | +import 'package:wow_english/common/extension/string_extension.dart'; | ||
| 5 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 2 | 6 | ||
| 3 | import '../../common/core/app_config_helper.dart'; | 7 | import '../../common/core/app_config_helper.dart'; |
| 4 | import '../../common/request/dao/system_dao.dart'; | 8 | import '../../common/request/dao/system_dao.dart'; |
| @@ -16,6 +20,9 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> { | @@ -16,6 +20,9 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> { | ||
| 16 | bool exchangeResult = false; | 20 | bool exchangeResult = false; |
| 17 | 21 | ||
| 18 | void _init(InitEvent event, Emitter<HomeState> emit) async { | 22 | void _init(InitEvent event, Emitter<HomeState> emit) async { |
| 23 | + if (UserUtil.isLogined()) { | ||
| 24 | + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.welcomeToWow); | ||
| 25 | + } | ||
| 19 | await _checkUpdate(emit); | 26 | await _checkUpdate(emit); |
| 20 | } | 27 | } |
| 21 | 28 | ||
| @@ -37,7 +44,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> { | @@ -37,7 +44,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> { | ||
| 37 | return; | 44 | return; |
| 38 | } | 45 | } |
| 39 | Log.d( | 46 | Log.d( |
| 40 | - "WQF _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion"); | 47 | + "HomeBloc _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion"); |
| 41 | if (localVersion < int.parse(appVersionEntity.version ?? '0')) { | 48 | if (localVersion < int.parse(appVersionEntity.version ?? '0')) { |
| 42 | emit(UpdateDialogState( | 49 | emit(UpdateDialogState( |
| 43 | appVersionEntity.volType == UpdateStrategy.FORCE.name, | 50 | appVersionEntity.volType == UpdateStrategy.FORCE.name, |
lib/pages/home/view.dart
| 1 | +import 'package:audioplayers/audioplayers.dart'; | ||
| 1 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
| 2 | import 'package:flutter_app_update/azhon_app_update.dart'; | 3 | import 'package:flutter_app_update/azhon_app_update.dart'; |
| 3 | import 'package:flutter_app_update/update_model.dart'; | 4 | import 'package:flutter_app_update/update_model.dart'; |
| 4 | import 'package:flutter_bloc/flutter_bloc.dart'; | 5 | import 'package:flutter_bloc/flutter_bloc.dart'; |
| 5 | import 'package:url_launcher/url_launcher.dart'; | 6 | import 'package:url_launcher/url_launcher.dart'; |
| 6 | import 'package:wow_english/common/core/app_config_helper.dart'; | 7 | import 'package:wow_english/common/core/app_config_helper.dart'; |
| 8 | +import 'package:wow_english/common/core/app_consts.dart'; | ||
| 7 | import 'package:wow_english/common/extension/string_extension.dart'; | 9 | import 'package:wow_english/common/extension/string_extension.dart'; |
| 8 | import 'package:wow_english/models/app_version_entity.dart'; | 10 | import 'package:wow_english/models/app_version_entity.dart'; |
| 9 | import 'package:wow_english/pages/home/state.dart'; | 11 | import 'package:wow_english/pages/home/state.dart'; |
| 10 | import 'package:wow_english/pages/home/widgets/BaseHomeHeaderWidget.dart'; | 12 | import 'package:wow_english/pages/home/widgets/BaseHomeHeaderWidget.dart'; |
| 11 | import 'package:wow_english/pages/shop/exchane/bloc/exchange_lesson_bloc.dart'; | 13 | import 'package:wow_english/pages/shop/exchane/bloc/exchange_lesson_bloc.dart'; |
| 12 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; | 14 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; |
| 15 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 13 | 16 | ||
| 14 | import '../../common/core/user_util.dart'; | 17 | import '../../common/core/user_util.dart'; |
| 15 | import '../../common/dialogs/show_dialog.dart'; | 18 | import '../../common/dialogs/show_dialog.dart'; |
| @@ -57,7 +60,9 @@ class _HomePageView extends StatelessWidget { | @@ -57,7 +60,9 @@ class _HomePageView extends StatelessWidget { | ||
| 57 | child: Column( | 60 | child: Column( |
| 58 | children: [ | 61 | children: [ |
| 59 | BaseHomeHeaderWidget( | 62 | BaseHomeHeaderWidget( |
| 60 | - callBack: (value) => { | 63 | + callBack: (value) async => { |
| 64 | + await AudioPlayerUtil.getInstance() | ||
| 65 | + .playAudio(AudioPlayerUtilType.touch), | ||
| 61 | bloc.exchangeResult = value['exchange'], | 66 | bloc.exchangeResult = value['exchange'], |
| 62 | bloc.add(ExchangeSuccessEvent()) | 67 | bloc.add(ExchangeSuccessEvent()) |
| 63 | }), | 68 | }), |
| @@ -68,7 +73,9 @@ class _HomePageView extends StatelessWidget { | @@ -68,7 +73,9 @@ class _HomePageView extends StatelessWidget { | ||
| 68 | Expanded( | 73 | Expanded( |
| 69 | child: GestureDetector( | 74 | child: GestureDetector( |
| 70 | onTap: () { | 75 | onTap: () { |
| 71 | - _checkPermission(() { | 76 | + _checkPermission(() async { |
| 77 | + await AudioPlayerUtil.getInstance() | ||
| 78 | + .playAudio(AudioPlayerUtilType.classTime); | ||
| 72 | pushNamed(AppRouteName.courseUnit) | 79 | pushNamed(AppRouteName.courseUnit) |
| 73 | .then((value) => { | 80 | .then((value) => { |
| 74 | if (value != null) | 81 | if (value != null) |
| @@ -102,13 +109,45 @@ class _HomePageView extends StatelessWidget { | @@ -102,13 +109,45 @@ class _HomePageView extends StatelessWidget { | ||
| 102 | ), | 109 | ), |
| 103 | ), | 110 | ), |
| 104 | ), | 111 | ), |
| 112 | + BlocBuilder<UserBloc, UserState>( | ||
| 113 | + builder: (context, userState) { | ||
| 114 | + return GestureDetector( | ||
| 115 | + onTap: () { | ||
| 116 | + _checkPermission(() async { | ||
| 117 | + await AudioPlayerUtil.getInstance().pause(); | ||
| 118 | + Navigator.of(context).pushNamed( | ||
| 119 | + AppRouteName.webView, | ||
| 120 | + arguments: { | ||
| 121 | + 'urlStr': AppConsts.xiaoeShopUrl, | ||
| 122 | + 'webViewTitle': 'Wow精选' | ||
| 123 | + }).then((value) async => { | ||
| 124 | + await AudioPlayerUtil.getInstance().playAudio( | ||
| 125 | + AudioPlayerUtilType.touch), | ||
| 126 | + }); | ||
| 127 | + }, bloc); | ||
| 128 | + }, | ||
| 129 | + child: Offstage( | ||
| 130 | + offstage: AppConfigHelper.shouldHidePay() || | ||
| 131 | + !UserUtil.isLogined(), | ||
| 132 | + child: Image.asset('xe_shop'.assetPng, | ||
| 133 | + width: 140.5.w, height: 172.h), | ||
| 134 | + )); | ||
| 135 | + }), | ||
| 105 | Expanded( | 136 | Expanded( |
| 106 | child: BlocBuilder<UserBloc, UserState>( | 137 | child: BlocBuilder<UserBloc, UserState>( |
| 107 | builder: (context, userState) { | 138 | builder: (context, userState) { |
| 108 | return GestureDetector( | 139 | return GestureDetector( |
| 109 | onTap: () { | 140 | onTap: () { |
| 110 | - _checkPermission(() { | ||
| 111 | - pushNamed(AppRouteName.games); | 141 | + _checkPermission(() async { |
| 142 | + await AudioPlayerUtil.getInstance() | ||
| 143 | + .playAudio( | ||
| 144 | + AudioPlayerUtilType.gameTime); | ||
| 145 | + pushNamed(AppRouteName.games) | ||
| 146 | + .then((value) => { | ||
| 147 | + AudioPlayerUtil.getInstance() | ||
| 148 | + .playAudio(AudioPlayerUtilType | ||
| 149 | + .touch), | ||
| 150 | + }); | ||
| 112 | }, bloc); | 151 | }, bloc); |
| 113 | }, | 152 | }, |
| 114 | child: Column( | 153 | child: Column( |
| @@ -157,6 +196,8 @@ class _HomePageView extends StatelessWidget { | @@ -157,6 +196,8 @@ class _HomePageView extends StatelessWidget { | ||
| 157 | }, rightTap: () { | 196 | }, rightTap: () { |
| 158 | popPage(); | 197 | popPage(); |
| 159 | pushNamed(AppRouteName.shop).then((value) { | 198 | pushNamed(AppRouteName.shop).then((value) { |
| 199 | + AudioPlayerUtil.getInstance() | ||
| 200 | + .playAudio(AudioPlayerUtilType.touch); | ||
| 160 | if (value != null) { | 201 | if (value != null) { |
| 161 | bloc.exchangeResult = value['exchange']; | 202 | bloc.exchangeResult = value['exchange']; |
| 162 | bloc.add(ExchangeSuccessEvent()); | 203 | bloc.add(ExchangeSuccessEvent()); |
lib/pages/home/widgets/BaseHomeHeaderWidget.dart
| @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; | @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; | ||
| 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; | 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
| 4 | import 'package:wow_english/common/core/app_config_helper.dart'; | 4 | import 'package:wow_english/common/core/app_config_helper.dart'; |
| 5 | import 'package:wow_english/common/extension/string_extension.dart'; | 5 | import 'package:wow_english/common/extension/string_extension.dart'; |
| 6 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 6 | 7 | ||
| 7 | import '../../../common/core/user_util.dart'; | 8 | import '../../../common/core/user_util.dart'; |
| 8 | import '../../../models/course_entity.dart'; | 9 | import '../../../models/course_entity.dart'; |
| @@ -83,7 +84,8 @@ class BaseHomeHeaderWidget extends StatelessWidget { | @@ -83,7 +84,8 @@ class BaseHomeHeaderWidget extends StatelessWidget { | ||
| 83 | offstage: AppConfigHelper.shouldHidePay() || | 84 | offstage: AppConfigHelper.shouldHidePay() || |
| 84 | !UserUtil.isLogined(), | 85 | !UserUtil.isLogined(), |
| 85 | child: GestureDetector( | 86 | child: GestureDetector( |
| 86 | - onTap: () => { | 87 | + onTap: () async => { |
| 88 | + await AudioPlayerUtil.getInstance().pause(), | ||
| 87 | pushNamed(AppRouteName.shop).then((value) { | 89 | pushNamed(AppRouteName.shop).then((value) { |
| 88 | if (value != null) { | 90 | if (value != null) { |
| 89 | if (callBack == null) { | 91 | if (callBack == null) { |
| @@ -113,8 +115,9 @@ class BaseHomeHeaderWidget extends StatelessWidget { | @@ -113,8 +115,9 @@ class BaseHomeHeaderWidget extends StatelessWidget { | ||
| 113 | ); | 115 | ); |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | - void onUserClick() { | 118 | + Future<void> onUserClick() async { |
| 117 | if (UserUtil.isLogined()) { | 119 | if (UserUtil.isLogined()) { |
| 120 | + await AudioPlayerUtil.getInstance().pause(); | ||
| 118 | pushNamed(AppRouteName.user).then((value) { | 121 | pushNamed(AppRouteName.user).then((value) { |
| 119 | if (value != null) { | 122 | if (value != null) { |
| 120 | if (callBack == null) { | 123 | if (callBack == null) { |
lib/pages/practice/topic_picture_page.dart
| @@ -59,7 +59,12 @@ class _TopicPicturePage extends StatelessWidget { | @@ -59,7 +59,12 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 59 | builder: (context, state) { | 59 | builder: (context, state) { |
| 60 | final bloc = BlocProvider.of<TopicPictureBloc>(context); | 60 | final bloc = BlocProvider.of<TopicPictureBloc>(context); |
| 61 | return Container( | 61 | return Container( |
| 62 | - color: Colors.white, | 62 | + decoration: BoxDecoration( |
| 63 | + image: DecorationImage( | ||
| 64 | + image: AssetImage('read_background'.assetPng), // 背景图片路径 | ||
| 65 | + fit: BoxFit.cover, // 适应图片的方式 | ||
| 66 | + ), | ||
| 67 | + ), | ||
| 63 | child: Stack( | 68 | child: Stack( |
| 64 | children: [ | 69 | children: [ |
| 65 | Column( | 70 | Column( |
| @@ -75,6 +80,7 @@ class _TopicPicturePage extends StatelessWidget { | @@ -75,6 +80,7 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 75 | // Navigator.pop(context); | 80 | // Navigator.pop(context); |
| 76 | }, | 81 | }, |
| 77 | ), | 82 | ), |
| 83 | + 35.verticalSpace, | ||
| 78 | Expanded( | 84 | Expanded( |
| 79 | child: PageView.builder( | 85 | child: PageView.builder( |
| 80 | itemCount: bloc.entity?.topics?.length, | 86 | itemCount: bloc.entity?.topics?.length, |
| @@ -109,12 +115,7 @@ class _TopicPicturePage extends StatelessWidget { | @@ -109,12 +115,7 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 109 | }), | 115 | }), |
| 110 | ) | 116 | ) |
| 111 | ], | 117 | ], |
| 112 | - ), | ||
| 113 | - Positioned( | ||
| 114 | - left: 0, | ||
| 115 | - right: 0, | ||
| 116 | - bottom: 0, | ||
| 117 | - child: Image.asset('bottom_grass'.assetPng)) | 118 | + ) |
| 118 | ], | 119 | ], |
| 119 | ), | 120 | ), |
| 120 | ); | 121 | ); |
| @@ -299,7 +300,7 @@ class _TopicPicturePage extends StatelessWidget { | @@ -299,7 +300,7 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 299 | 26.verticalSpace, | 300 | 26.verticalSpace, |
| 300 | SizedBox( | 301 | SizedBox( |
| 301 | height: 143.h, | 302 | height: 143.h, |
| 302 | - width: 163.w * (topics?.topicAnswerList?.length ?? 0), | 303 | + width: 203.w * (topics?.topicAnswerList?.length ?? 0), |
| 303 | child: ListView.builder( | 304 | child: ListView.builder( |
| 304 | scrollDirection: Axis.horizontal, | 305 | scrollDirection: Axis.horizontal, |
| 305 | physics: const NeverScrollableScrollPhysics(), | 306 | physics: const NeverScrollableScrollPhysics(), |
| @@ -321,7 +322,7 @@ class _TopicPicturePage extends StatelessWidget { | @@ -321,7 +322,7 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 321 | builder: (context, state) { | 322 | builder: (context, state) { |
| 322 | final bloc = BlocProvider.of<TopicPictureBloc>(context); | 323 | final bloc = BlocProvider.of<TopicPictureBloc>(context); |
| 323 | return Container( | 324 | return Container( |
| 324 | - padding: EdgeInsets.symmetric(horizontal: 10.w), | 325 | + padding: EdgeInsets.symmetric(horizontal: 20.w), |
| 325 | child: GestureDetector( | 326 | child: GestureDetector( |
| 326 | onTap: () => bloc.add(SelectItemEvent(index)), | 327 | onTap: () => bloc.add(SelectItemEvent(index)), |
| 327 | child: Container( | 328 | child: Container( |
| @@ -333,15 +334,13 @@ class _TopicPicturePage extends StatelessWidget { | @@ -333,15 +334,13 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 333 | borderRadius: BorderRadius.circular(15), | 334 | borderRadius: BorderRadius.circular(15), |
| 334 | ), | 335 | ), |
| 335 | height: 143.h, | 336 | height: 143.h, |
| 336 | - width: 143.w, | 337 | + width: 163.w, |
| 337 | child: Container( | 338 | child: Container( |
| 338 | decoration: BoxDecoration( | 339 | decoration: BoxDecoration( |
| 339 | color: Colors.white, | 340 | color: Colors.white, |
| 340 | borderRadius: BorderRadius.circular(15), | 341 | borderRadius: BorderRadius.circular(15), |
| 341 | - border: Border.all( | ||
| 342 | - width: 1.0, color: const Color(0xFF140C10)), | ||
| 343 | image: DecorationImage( | 342 | image: DecorationImage( |
| 344 | - fit: BoxFit.fitWidth, | 343 | + fit: BoxFit.fill, |
| 345 | image: NetworkImage(answerList?.picUrl ?? ''))), | 344 | image: NetworkImage(answerList?.picUrl ?? ''))), |
| 346 | ), | 345 | ), |
| 347 | ), | 346 | ), |
| @@ -449,12 +448,18 @@ class _TopicPicturePage extends StatelessWidget { | @@ -449,12 +448,18 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 449 | return Row( | 448 | return Row( |
| 450 | mainAxisAlignment: MainAxisAlignment.center, | 449 | mainAxisAlignment: MainAxisAlignment.center, |
| 451 | children: [ | 450 | children: [ |
| 452 | - OwImageWidget( | ||
| 453 | - name: topics?.picUrl ?? '', | ||
| 454 | - height: 186.h, | ||
| 455 | - width: 186.w, | 451 | + ClipRRect( |
| 452 | + borderRadius: BorderRadius.circular(20), | ||
| 453 | + child: Container( | ||
| 454 | + color: Colors.white, | ||
| 455 | + child: OwImageWidget( | ||
| 456 | + name: topics?.picUrl ?? '', | ||
| 457 | + height: 186.h, | ||
| 458 | + width: 186.w, | ||
| 459 | + ), | ||
| 460 | + ), | ||
| 456 | ), | 461 | ), |
| 457 | - 160.horizontalSpace, | 462 | + 120.horizontalSpace, |
| 458 | Column( | 463 | Column( |
| 459 | mainAxisAlignment: MainAxisAlignment.center, | 464 | mainAxisAlignment: MainAxisAlignment.center, |
| 460 | children: [ | 465 | children: [ |
| @@ -472,8 +477,8 @@ class _TopicPicturePage extends StatelessWidget { | @@ -472,8 +477,8 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 472 | bloc.voicePlayState == VoicePlayState.playing | 477 | bloc.voicePlayState == VoicePlayState.playing |
| 473 | ? 'reade_answer'.assetGif | 478 | ? 'reade_answer'.assetGif |
| 474 | : 'voice'.assetPng, | 479 | : 'voice'.assetPng, |
| 475 | - height: 52.h, | ||
| 476 | - width: 46.w, | 480 | + height: 45.h, |
| 481 | + width: 45.w, | ||
| 477 | ), | 482 | ), |
| 478 | 10.horizontalSpace, | 483 | 10.horizontalSpace, |
| 479 | Text(topics?.word ?? '') | 484 | Text(topics?.word ?? '') |
| @@ -506,8 +511,8 @@ class _TopicPicturePage extends StatelessWidget { | @@ -506,8 +511,8 @@ class _TopicPicturePage extends StatelessWidget { | ||
| 506 | bloc.isVoicing | 511 | bloc.isVoicing |
| 507 | ? 'micro_phone'.assetGif | 512 | ? 'micro_phone'.assetGif |
| 508 | : 'micro_phone'.assetPng, | 513 | : 'micro_phone'.assetPng, |
| 509 | - height: 75.w, | ||
| 510 | - width: 75.w, | 514 | + height: 46.h, |
| 515 | + width: 46.w, | ||
| 511 | ), | 516 | ), |
| 512 | ) | 517 | ) |
| 513 | ], | 518 | ], |
lib/pages/practice/widgets/practice_header_widget.dart
| @@ -12,9 +12,10 @@ class PracticeHeaderWidget extends StatelessWidget { | @@ -12,9 +12,10 @@ class PracticeHeaderWidget extends StatelessWidget { | ||
| 12 | @override | 12 | @override |
| 13 | Widget build(BuildContext context) { | 13 | Widget build(BuildContext context) { |
| 14 | return Container( | 14 | return Container( |
| 15 | - color: Colors.white, | 15 | + color: Colors.transparent, |
| 16 | height: kToolbarHeight + 3.h, | 16 | height: kToolbarHeight + 3.h, |
| 17 | child: AppBar( | 17 | child: AppBar( |
| 18 | + backgroundColor: Colors.transparent, | ||
| 18 | leading: GestureDetector( | 19 | leading: GestureDetector( |
| 19 | child: Image.asset( | 20 | child: Image.asset( |
| 20 | 'back_around'.assetPng, | 21 | 'back_around'.assetPng, |
| @@ -25,7 +26,7 @@ class PracticeHeaderWidget extends StatelessWidget { | @@ -25,7 +26,7 @@ class PracticeHeaderWidget extends StatelessWidget { | ||
| 25 | ), | 26 | ), |
| 26 | centerTitle: true, | 27 | centerTitle: true, |
| 27 | title: Container( | 28 | title: Container( |
| 28 | - height: 40.h, | 29 | + height: 20.h, |
| 29 | width: 100.w, // 容器宽度 | 30 | width: 100.w, // 容器宽度 |
| 30 | // padding: EdgeInsets.symmetric(horizontal: 27.w, vertical: 10.h), | 31 | // padding: EdgeInsets.symmetric(horizontal: 27.w, vertical: 10.h), |
| 31 | alignment: Alignment.center, | 32 | alignment: Alignment.center, |
lib/pages/reading/bloc/reading_event.dart
| @@ -39,7 +39,7 @@ class XSVoiceStartEvent extends ReadingPageEvent { | @@ -39,7 +39,7 @@ class XSVoiceStartEvent extends ReadingPageEvent { | ||
| 39 | final String content; | 39 | final String content; |
| 40 | final String type; | 40 | final String type; |
| 41 | final String? userId; | 41 | final String? userId; |
| 42 | - XSVoiceStartEvent(this.content,this.type,this.userId); | 42 | + XSVoiceStartEvent(this.content, this.type, this.userId); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | ///先声评测停止 | 45 | ///先声评测停止 |
| @@ -52,4 +52,7 @@ class OnXSVoiceStateChangeEvent extends ReadingPageEvent {} | @@ -52,4 +52,7 @@ class OnXSVoiceStateChangeEvent extends ReadingPageEvent {} | ||
| 52 | class VoicePlayStateChangeEvent extends ReadingPageEvent {} | 52 | class VoicePlayStateChangeEvent extends ReadingPageEvent {} |
| 53 | 53 | ||
| 54 | ///录音播放 | 54 | ///录音播放 |
| 55 | -class PlayRecordAudioEvent extends ReadingPageEvent {} | ||
| 56 | \ No newline at end of file | 55 | \ No newline at end of file |
| 56 | +class PlayRecordAudioEvent extends ReadingPageEvent {} | ||
| 57 | + | ||
| 58 | +///播放下一页 | ||
| 59 | +class PlayNextPageEvent extends ReadingPageEvent {} |
lib/pages/reading/reading_page.dart
| @@ -21,17 +21,16 @@ class ReadingPage extends StatelessWidget { | @@ -21,17 +21,16 @@ class ReadingPage extends StatelessWidget { | ||
| 21 | @override | 21 | @override |
| 22 | Widget build(BuildContext context) { | 22 | Widget build(BuildContext context) { |
| 23 | return BlocProvider( | 23 | return BlocProvider( |
| 24 | - create: (_) => ReadingPageBloc(context, PageController(), courseLessonId ?? '') | ||
| 25 | - ..add(InitBlocEvent()) | ||
| 26 | - ..add(RequestDataEvent()) | ||
| 27 | - ..add(XSVoiceInitEvent( | ||
| 28 | - { | ||
| 29 | - 'appKey':AppConsts.xsAppKey, | ||
| 30 | - 'service':AppConsts.xsAppService, | ||
| 31 | - 'secretKey':AppConsts.xsAppSecretKey, | ||
| 32 | - 'userId':UserUtil.getUser()!.id.toString(), | ||
| 33 | - } | ||
| 34 | - )), | 24 | + create: (_) => |
| 25 | + ReadingPageBloc(context, PageController(), courseLessonId ?? '') | ||
| 26 | + ..add(InitBlocEvent()) | ||
| 27 | + ..add(RequestDataEvent()) | ||
| 28 | + ..add(XSVoiceInitEvent({ | ||
| 29 | + 'appKey': AppConsts.xsAppKey, | ||
| 30 | + 'service': AppConsts.xsAppService, | ||
| 31 | + 'secretKey': AppConsts.xsAppSecretKey, | ||
| 32 | + 'userId': UserUtil.getUser()!.id.toString(), | ||
| 33 | + })), | ||
| 35 | child: _ReadingPage(), | 34 | child: _ReadingPage(), |
| 36 | ); | 35 | ); |
| 37 | } | 36 | } |
| @@ -60,8 +59,8 @@ class _ReadingPage extends StatelessWidget { | @@ -60,8 +59,8 @@ class _ReadingPage extends StatelessWidget { | ||
| 60 | ); | 59 | ); |
| 61 | } | 60 | } |
| 62 | 61 | ||
| 63 | - Widget _readingPageView() => BlocBuilder<ReadingPageBloc, ReadingPageState>( | ||
| 64 | - builder: (context, state) { | 62 | + Widget _readingPageView() => |
| 63 | + BlocBuilder<ReadingPageBloc, ReadingPageState>(builder: (context, state) { | ||
| 65 | final bloc = BlocProvider.of<ReadingPageBloc>(context); | 64 | final bloc = BlocProvider.of<ReadingPageBloc>(context); |
| 66 | return Container( | 65 | return Container( |
| 67 | color: Colors.white, | 66 | color: Colors.white, |
| @@ -84,16 +83,14 @@ class _ReadingPage extends StatelessWidget { | @@ -84,16 +83,14 @@ class _ReadingPage extends StatelessWidget { | ||
| 84 | children: [ | 83 | children: [ |
| 85 | Padding( | 84 | Padding( |
| 86 | padding: | 85 | padding: |
| 87 | - EdgeInsets.only(left: ScreenUtil().bottomBarHeight), | 86 | + EdgeInsets.only(left: ScreenUtil().bottomBarHeight), |
| 88 | child: IconButton( | 87 | child: IconButton( |
| 89 | onPressed: () { | 88 | onPressed: () { |
| 90 | - popPage( | ||
| 91 | - data:{ | ||
| 92 | - 'currentStep':bloc.currentPage, | ||
| 93 | - 'courseLessonId':bloc.courseLessonId, | ||
| 94 | - 'isCompleted':bloc.isLastPage(), | ||
| 95 | - } | ||
| 96 | - ); | 89 | + popPage(data: { |
| 90 | + 'currentStep': bloc.currentPage, | ||
| 91 | + 'courseLessonId': bloc.courseLessonId, | ||
| 92 | + 'isCompleted': bloc.isLastPage(), | ||
| 93 | + }); | ||
| 97 | }, | 94 | }, |
| 98 | icon: Image.asset( | 95 | icon: Image.asset( |
| 99 | 'back_around'.assetPng, | 96 | 'back_around'.assetPng, |
| @@ -158,6 +155,7 @@ class _ReadingPage extends StatelessWidget { | @@ -158,6 +155,7 @@ class _ReadingPage extends StatelessWidget { | ||
| 158 | margin: EdgeInsets.symmetric(horizontal: 10.w), | 155 | margin: EdgeInsets.symmetric(horizontal: 10.w), |
| 159 | child: Row( | 156 | child: Row( |
| 160 | children: [ | 157 | children: [ |
| 158 | + 5.horizontalSpace, | ||
| 161 | GestureDetector( | 159 | GestureDetector( |
| 162 | onTap: () { | 160 | onTap: () { |
| 163 | if (bloc.isRecording) { | 161 | if (bloc.isRecording) { |
| @@ -167,7 +165,7 @@ class _ReadingPage extends StatelessWidget { | @@ -167,7 +165,7 @@ class _ReadingPage extends StatelessWidget { | ||
| 167 | }, | 165 | }, |
| 168 | child: Image.asset( | 166 | child: Image.asset( |
| 169 | bloc.voicePlayState == VoicePlayState.playing && | 167 | bloc.voicePlayState == VoicePlayState.playing && |
| 170 | - bloc.isOriginAudioPlaying | 168 | + bloc.isOriginAudioPlaying |
| 171 | ? 'reade_answer'.assetGif | 169 | ? 'reade_answer'.assetGif |
| 172 | : 'voice'.assetPng, | 170 | : 'voice'.assetPng, |
| 173 | height: 40.h, | 171 | height: 40.h, |
| @@ -179,12 +177,12 @@ class _ReadingPage extends StatelessWidget { | @@ -179,12 +177,12 @@ class _ReadingPage extends StatelessWidget { | ||
| 179 | ), | 177 | ), |
| 180 | Expanded( | 178 | Expanded( |
| 181 | child: Text( | 179 | child: Text( |
| 182 | - bloc.currentPageData()?.word?.trim() ?? '', | ||
| 183 | - style: TextStyle( | ||
| 184 | - color: const Color(0xFF333333), fontSize: 21.sp), | ||
| 185 | - maxLines: 2, | ||
| 186 | - overflow: TextOverflow.ellipsis, | ||
| 187 | - )), | 180 | + bloc.currentPageData()?.word?.trim() ?? '', |
| 181 | + style: TextStyle( | ||
| 182 | + color: const Color(0xFF333333), fontSize: 21.sp), | ||
| 183 | + maxLines: 2, | ||
| 184 | + overflow: TextOverflow.ellipsis, | ||
| 185 | + )), | ||
| 188 | SizedBox( | 186 | SizedBox( |
| 189 | width: 10.w, | 187 | width: 10.w, |
| 190 | ), | 188 | ), |
| @@ -241,8 +239,7 @@ class _ReadingPage extends StatelessWidget { | @@ -241,8 +239,7 @@ class _ReadingPage extends StatelessWidget { | ||
| 241 | return Stack( | 239 | return Stack( |
| 242 | children: [ | 240 | children: [ |
| 243 | Positioned.fill( | 241 | Positioned.fill( |
| 244 | - child: | ||
| 245 | - Image.network(readings.picUrl ?? '', fit: BoxFit.cover), | 242 | + child: Image.network(readings.picUrl ?? '', fit: BoxFit.cover), |
| 246 | ), | 243 | ), |
| 247 | ], | 244 | ], |
| 248 | ); | 245 | ); |
lib/pages/section/bloc/section_bloc.dart
| 1 | +import 'package:audioplayers/audioplayers.dart'; | ||
| 1 | import 'package:flutter/cupertino.dart'; | 2 | import 'package:flutter/cupertino.dart'; |
| 2 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
| 3 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
| 4 | import 'package:flutter_bloc/flutter_bloc.dart'; | 5 | import 'package:flutter_bloc/flutter_bloc.dart'; |
| 5 | import 'package:flutter_screenutil/flutter_screenutil.dart'; | 6 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
| 7 | +import 'package:wow_english/common/extension/string_extension.dart'; | ||
| 6 | import 'package:wow_english/common/request/dao/lesson_dao.dart'; | 8 | import 'package:wow_english/common/request/dao/lesson_dao.dart'; |
| 7 | import 'package:wow_english/common/request/exception.dart'; | 9 | import 'package:wow_english/common/request/exception.dart'; |
| 8 | import 'package:wow_english/common/request/dao/listen_dao.dart'; | 10 | import 'package:wow_english/common/request/dao/listen_dao.dart'; |
| 9 | import 'package:wow_english/models/course_process_entity.dart'; | 11 | import 'package:wow_english/models/course_process_entity.dart'; |
| 12 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 10 | import 'package:wow_english/utils/loading.dart'; | 13 | import 'package:wow_english/utils/loading.dart'; |
| 11 | import 'package:wow_english/utils/toast_util.dart'; | 14 | import 'package:wow_english/utils/toast_util.dart'; |
| 12 | 15 | ||
| @@ -61,16 +64,20 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -61,16 +64,20 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 61 | on<RequestEnterClassEvent>(_requestEnterClass); | 64 | on<RequestEnterClassEvent>(_requestEnterClass); |
| 62 | on<RequestVideoLessonEvent>(_requestVideoLesson); | 65 | on<RequestVideoLessonEvent>(_requestVideoLesson); |
| 63 | on<CurrentUnitIndexChangeEvent>(_pageControllerChange); | 66 | on<CurrentUnitIndexChangeEvent>(_pageControllerChange); |
| 67 | + on<InitEvent>((event, emit) async { | ||
| 68 | + await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe); | ||
| 69 | + }); | ||
| 64 | } | 70 | } |
| 65 | 71 | ||
| 66 | void _requestSectionsData( | 72 | void _requestSectionsData( |
| 67 | RequestDataEvent event, Emitter<SectionState> emitter) async { | 73 | RequestDataEvent event, Emitter<SectionState> emitter) async { |
| 68 | try { | 74 | try { |
| 69 | await loading(() async { | 75 | await loading(() async { |
| 70 | - List<CourseSectionEntity>? courseSectionEntities = await LessonDao.courseSection(courseUnitId: event.courseUnitId); | 76 | + List<CourseSectionEntity>? courseSectionEntities = |
| 77 | + await LessonDao.courseSection(courseUnitId: event.courseUnitId); | ||
| 71 | if (courseSectionEntities != null) { | 78 | if (courseSectionEntities != null) { |
| 72 | _courseSectionDatasMap[event.courseUnitId] = | 79 | _courseSectionDatasMap[event.courseUnitId] = |
| 73 | - await LessonDao.courseSection(courseUnitId: event.courseUnitId); | 80 | + await LessonDao.courseSection(courseUnitId: event.courseUnitId); |
| 74 | emitter(LessonDataLoadState()); | 81 | emitter(LessonDataLoadState()); |
| 75 | } | 82 | } |
| 76 | }); | 83 | }); |
| @@ -224,7 +231,8 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -224,7 +231,8 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 224 | ///查找当前unit的下一个section | 231 | ///查找当前unit的下一个section |
| 225 | CourseSectionEntity? nextCourseSectionEntity = | 232 | CourseSectionEntity? nextCourseSectionEntity = |
| 226 | findCourseSectionBySort(curSectionSort + 1); | 233 | findCourseSectionBySort(curSectionSort + 1); |
| 227 | - return checkCourseSectionLocked(courseLessonId, nextCourseSectionEntity, emitter); | 234 | + return checkCourseSectionLocked( |
| 235 | + courseLessonId, nextCourseSectionEntity, emitter); | ||
| 228 | } catch (e) { | 236 | } catch (e) { |
| 229 | if (e is ApiException) { | 237 | if (e is ApiException) { |
| 230 | showToast(e.message.toString()); | 238 | showToast(e.message.toString()); |
| @@ -234,7 +242,9 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -234,7 +242,9 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 234 | } | 242 | } |
| 235 | 243 | ||
| 236 | ///检查section是否锁定 | 244 | ///检查section是否锁定 |
| 237 | - Future<CourseSectionEntity?> checkCourseSectionLocked(int courseLessonId, CourseSectionEntity? courseSectionEntity, | 245 | + Future<CourseSectionEntity?> checkCourseSectionLocked( |
| 246 | + int courseLessonId, | ||
| 247 | + CourseSectionEntity? courseSectionEntity, | ||
| 238 | Emitter<SectionState> emitter) async { | 248 | Emitter<SectionState> emitter) async { |
| 239 | if (courseSectionEntity != null) { | 249 | if (courseSectionEntity != null) { |
| 240 | if (courseSectionEntity.lock == false) { | 250 | if (courseSectionEntity.lock == false) { |
| @@ -243,15 +253,15 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -243,15 +253,15 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 243 | } else { | 253 | } else { |
| 244 | ///如果section锁了,请求当前unit下的section数据,查询解锁状态 | 254 | ///如果section锁了,请求当前unit下的section数据,查询解锁状态 |
| 245 | int courseUnitId = courseSectionEntity.courseUnitId; | 255 | int courseUnitId = courseSectionEntity.courseUnitId; |
| 246 | - CourseSectionEntity? result = await loading(() async { | 256 | + CourseSectionEntity? result = await loading(() async { |
| 247 | List<CourseSectionEntity>? tempSectionEntities = | 257 | List<CourseSectionEntity>? tempSectionEntities = |
| 248 | - await LessonDao.courseSection(courseUnitId: courseUnitId); | 258 | + await LessonDao.courseSection(courseUnitId: courseUnitId); |
| 249 | if (tempSectionEntities != null) { | 259 | if (tempSectionEntities != null) { |
| 250 | _courseSectionDatasMap[courseUnitId] = tempSectionEntities; | 260 | _courseSectionDatasMap[courseUnitId] = tempSectionEntities; |
| 251 | emitter(LessonDataLoadState()); | 261 | emitter(LessonDataLoadState()); |
| 252 | } | 262 | } |
| 253 | courseSectionEntity = tempSectionEntities?.firstWhereOrNull( | 263 | courseSectionEntity = tempSectionEntities?.firstWhereOrNull( |
| 254 | - (element) => element.id == courseSectionEntity?.id); | 264 | + (element) => element.id == courseSectionEntity?.id); |
| 255 | if (courseSectionEntity?.lock == false) { | 265 | if (courseSectionEntity?.lock == false) { |
| 256 | ///刷新后的数据如果解锁了,直接返回 | 266 | ///刷新后的数据如果解锁了,直接返回 |
| 257 | return courseSectionEntity; | 267 | return courseSectionEntity; |
| @@ -270,18 +280,20 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -270,18 +280,20 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 270 | if (curCourseUnitDetail != null) { | 280 | if (curCourseUnitDetail != null) { |
| 271 | ///再根据当前unit的sortOrder找出下一个unit | 281 | ///再根据当前unit的sortOrder找出下一个unit |
| 272 | CourseUnitDetail? nextCourseUnitDetail = | 282 | CourseUnitDetail? nextCourseUnitDetail = |
| 273 | - _courseUnitEntity.courseUnitVOList?.firstWhereOrNull((element) => | ||
| 274 | - element.sortOrder == (curCourseUnitDetail.sortOrder! + 1)); | 283 | + _courseUnitEntity.courseUnitVOList?.firstWhereOrNull((element) => |
| 284 | + element.sortOrder == (curCourseUnitDetail.sortOrder! + 1)); | ||
| 275 | 285 | ||
| 276 | if (nextCourseUnitDetail != null) { | 286 | if (nextCourseUnitDetail != null) { |
| 277 | if (nextCourseUnitDetail.lock == true) { | 287 | if (nextCourseUnitDetail.lock == true) { |
| 278 | ///如果下一个unit是锁定状态,请求数据刷新查询解锁状态 | 288 | ///如果下一个unit是锁定状态,请求数据刷新查询解锁状态 |
| 279 | CourseSectionEntity? result = await loading(() async { | 289 | CourseSectionEntity? result = await loading(() async { |
| 280 | - CourseUnitEntity? newCourseUnitEntity = await LessonDao.courseUnit( | ||
| 281 | - _courseUnitEntity.nowCourseModuleId); | 290 | + CourseUnitEntity? newCourseUnitEntity = |
| 291 | + await LessonDao.courseUnit( | ||
| 292 | + _courseUnitEntity.nowCourseModuleId); | ||
| 282 | 293 | ||
| 283 | ///拿到重新获取到的unit后,再次判断是否解锁 | 294 | ///拿到重新获取到的unit后,再次判断是否解锁 |
| 284 | - nextCourseUnitDetail = newCourseUnitEntity?.courseUnitVOList?.firstWhereOrNull( | 295 | + nextCourseUnitDetail = newCourseUnitEntity?.courseUnitVOList |
| 296 | + ?.firstWhereOrNull( | ||
| 285 | (element) => element.id == nextCourseUnitDetail?.id); | 297 | (element) => element.id == nextCourseUnitDetail?.id); |
| 286 | if (nextCourseUnitDetail?.lock == false) { | 298 | if (nextCourseUnitDetail?.lock == false) { |
| 287 | ///解锁状态从锁定到解锁,覆盖原unit数据并刷新ui | 299 | ///解锁状态从锁定到解锁,覆盖原unit数据并刷新ui |
| @@ -289,7 +301,8 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -289,7 +301,8 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 289 | courseUnitEntityChanged = true; | 301 | courseUnitEntityChanged = true; |
| 290 | emitter(LessonDataLoadState()); | 302 | emitter(LessonDataLoadState()); |
| 291 | 303 | ||
| 292 | - return checkCourseSectionLockedOfNextUnit(courseLessonId, nextCourseUnitDetail!.id!, emitter); | 304 | + return checkCourseSectionLockedOfNextUnit( |
| 305 | + courseLessonId, nextCourseUnitDetail!.id!, emitter); | ||
| 293 | } else { | 306 | } else { |
| 294 | showToast('下个单元课程还没解锁哦'); | 307 | showToast('下个单元课程还没解锁哦'); |
| 295 | 308 | ||
| @@ -299,10 +312,12 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -299,10 +312,12 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 299 | }); | 312 | }); |
| 300 | return result; | 313 | return result; |
| 301 | } else { | 314 | } else { |
| 302 | - return checkCourseSectionLockedOfNextUnit(courseLessonId, nextCourseUnitDetail.id!, emitter); | 315 | + return checkCourseSectionLockedOfNextUnit( |
| 316 | + courseLessonId, nextCourseUnitDetail.id!, emitter); | ||
| 303 | } | 317 | } |
| 304 | } else { | 318 | } else { |
| 305 | showToast("恭喜你,本阶段学到顶啦"); | 319 | showToast("恭喜你,本阶段学到顶啦"); |
| 320 | + | ||
| 306 | ///最后一个unit了 | 321 | ///最后一个unit了 |
| 307 | return null; | 322 | return null; |
| 308 | } | 323 | } |
| @@ -314,13 +329,16 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -314,13 +329,16 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 314 | } | 329 | } |
| 315 | 330 | ||
| 316 | ///检查下一个unit的(第一个)section | 331 | ///检查下一个unit的(第一个)section |
| 317 | - Future<CourseSectionEntity?> checkCourseSectionLockedOfNextUnit(int courseLessonId, int nextCourseUnitDetailId, | 332 | + Future<CourseSectionEntity?> checkCourseSectionLockedOfNextUnit( |
| 333 | + int courseLessonId, | ||
| 334 | + int nextCourseUnitDetailId, | ||
| 318 | Emitter<SectionState> emitter) async { | 335 | Emitter<SectionState> emitter) async { |
| 319 | - CourseSectionEntity? firstSectionNextUnit = await getFirstSectionByUnitId( | ||
| 320 | - nextCourseUnitDetailId, emitter); | 336 | + CourseSectionEntity? firstSectionNextUnit = |
| 337 | + await getFirstSectionByUnitId(nextCourseUnitDetailId, emitter); | ||
| 321 | if (firstSectionNextUnit != null) { | 338 | if (firstSectionNextUnit != null) { |
| 322 | ///下个unit的第一个section如果不为空,再次检查是否锁定 | 339 | ///下个unit的第一个section如果不为空,再次检查是否锁定 |
| 323 | - CourseSectionEntity? courseSectionEntity = await checkCourseSectionLocked(courseLessonId, firstSectionNextUnit, emitter); | 340 | + CourseSectionEntity? courseSectionEntity = await checkCourseSectionLocked( |
| 341 | + courseLessonId, firstSectionNextUnit, emitter); | ||
| 324 | if (courseSectionEntity != null) { | 342 | if (courseSectionEntity != null) { |
| 325 | ///只有是下一unit的第一个section并且解锁了,才跳转 | 343 | ///只有是下一unit的第一个section并且解锁了,才跳转 |
| 326 | _pageController.nextPage( | 344 | _pageController.nextPage( |
lib/pages/section/bloc/section_event.dart
| @@ -9,6 +9,8 @@ class RequestDataEvent extends SectionEvent { | @@ -9,6 +9,8 @@ class RequestDataEvent extends SectionEvent { | ||
| 9 | RequestDataEvent(this.courseUnitId); | 9 | RequestDataEvent(this.courseUnitId); |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | +class InitEvent extends SectionEvent {} | ||
| 13 | + | ||
| 12 | ///获取视频课程内容 | 14 | ///获取视频课程内容 |
| 13 | class RequestVideoLessonEvent extends SectionEvent { | 15 | class RequestVideoLessonEvent extends SectionEvent { |
| 14 | final String courseLessonId; | 16 | final String courseLessonId; |
lib/pages/section/section_page.dart
| 1 | +import 'package:audioplayers/audioplayers.dart'; | ||
| 1 | import 'package:flutter/cupertino.dart'; | 2 | import 'package:flutter/cupertino.dart'; |
| 2 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
| 3 | import 'package:flutter_bloc/flutter_bloc.dart'; | 4 | import 'package:flutter_bloc/flutter_bloc.dart'; |
| @@ -11,6 +12,8 @@ import 'package:wow_english/pages/section/widgets/section_item.dart'; | @@ -11,6 +12,8 @@ import 'package:wow_english/pages/section/widgets/section_item.dart'; | ||
| 11 | import 'package:wow_english/pages/section/widgets/section_bouns_item.dart'; | 12 | import 'package:wow_english/pages/section/widgets/section_bouns_item.dart'; |
| 12 | import 'package:wow_english/pages/section/widgets/section_header_widget.dart'; | 13 | import 'package:wow_english/pages/section/widgets/section_header_widget.dart'; |
| 13 | import 'package:wow_english/route/route.dart'; | 14 | import 'package:wow_english/route/route.dart'; |
| 15 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 16 | +import 'package:wow_english/utils/log_util.dart'; | ||
| 14 | import 'package:wow_english/utils/toast_util.dart'; | 17 | import 'package:wow_english/utils/toast_util.dart'; |
| 15 | 18 | ||
| 16 | import '../../models/course_section_entity.dart'; | 19 | import '../../models/course_section_entity.dart'; |
| @@ -38,7 +41,8 @@ class SectionPage extends StatelessWidget { | @@ -38,7 +41,8 @@ class SectionPage extends StatelessWidget { | ||
| 38 | initialPage, | 41 | initialPage, |
| 39 | PageController(initialPage: initialPage), | 42 | PageController(initialPage: initialPage), |
| 40 | ScrollController(), | 43 | ScrollController(), |
| 41 | - ScrollController()), | 44 | + ScrollController()) |
| 45 | + ..add(InitEvent()), | ||
| 42 | //为了触发指示器进入后计算位置 | 46 | //为了触发指示器进入后计算位置 |
| 43 | // ..add(CurrentUnitIndexChangeEvent(initialPage)), | 47 | // ..add(CurrentUnitIndexChangeEvent(initialPage)), |
| 44 | child: _SectionPageView(context), | 48 | child: _SectionPageView(context), |
| @@ -55,7 +59,7 @@ class _SectionPageView extends StatelessWidget { | @@ -55,7 +59,7 @@ class _SectionPageView extends StatelessWidget { | ||
| 55 | Widget build(BuildContext context) { | 59 | Widget build(BuildContext context) { |
| 56 | final bloc = BlocProvider.of<SectionBloc>(context); | 60 | final bloc = BlocProvider.of<SectionBloc>(context); |
| 57 | return BlocListener<SectionBloc, SectionState>( | 61 | return BlocListener<SectionBloc, SectionState>( |
| 58 | - listener: (context, state) { | 62 | + listener: (context, state) async { |
| 59 | if (state is RequestVideoLessonState) { | 63 | if (state is RequestVideoLessonState) { |
| 60 | final videoUrl = bloc.processEntity?.videos?.videoUrl ?? ''; | 64 | final videoUrl = bloc.processEntity?.videos?.videoUrl ?? ''; |
| 61 | var title = ''; | 65 | var title = ''; |
| @@ -87,6 +91,8 @@ class _SectionPageView extends StatelessWidget { | @@ -87,6 +91,8 @@ class _SectionPageView extends StatelessWidget { | ||
| 87 | currentTime: dataMap['currentTime'], | 91 | currentTime: dataMap['currentTime'], |
| 88 | autoNextSection: dataMap['nextSection'])); | 92 | autoNextSection: dataMap['nextSection'])); |
| 89 | } | 93 | } |
| 94 | + AudioPlayerUtil.getInstance() | ||
| 95 | + .playAudio(AudioPlayerUtilType.countWithMe); | ||
| 90 | }); | 96 | }); |
| 91 | return; | 97 | return; |
| 92 | } | 98 | } |
| @@ -96,12 +102,22 @@ class _SectionPageView extends StatelessWidget { | @@ -96,12 +102,22 @@ class _SectionPageView extends StatelessWidget { | ||
| 96 | state.courseType != SectionType.pictureBook.value) { | 102 | state.courseType != SectionType.pictureBook.value) { |
| 97 | ///视频类型 | 103 | ///视频类型 |
| 98 | ///获取视频课程内容 | 104 | ///获取视频课程内容 |
| 105 | + if (state.courseType == 1) { | ||
| 106 | + await AudioPlayerUtil.getInstance() | ||
| 107 | + .playAudio(AudioPlayerUtilType.musicTime); | ||
| 108 | + } else { | ||
| 109 | + await AudioPlayerUtil.getInstance() | ||
| 110 | + .playAudio(AudioPlayerUtilType.videoTime); | ||
| 111 | + } | ||
| 99 | bloc.add(RequestVideoLessonEvent( | 112 | bloc.add(RequestVideoLessonEvent( |
| 100 | state.courseLessonId, state.courseType)); | 113 | state.courseLessonId, state.courseType)); |
| 114 | + | ||
| 101 | return; | 115 | return; |
| 102 | } | 116 | } |
| 103 | 117 | ||
| 104 | if (state.courseType == SectionType.pictureBook.value) { | 118 | if (state.courseType == SectionType.pictureBook.value) { |
| 119 | + await AudioPlayerUtil.getInstance() | ||
| 120 | + .playAudio(AudioPlayerUtilType.readingTime); | ||
| 105 | //绘本 | 121 | //绘本 |
| 106 | pushNamed(AppRouteName.reading, | 122 | pushNamed(AppRouteName.reading, |
| 107 | arguments: {'courseLessonId': state.courseLessonId}) | 123 | arguments: {'courseLessonId': state.courseLessonId}) |
| @@ -114,13 +130,18 @@ class _SectionPageView extends StatelessWidget { | @@ -114,13 +130,18 @@ class _SectionPageView extends StatelessWidget { | ||
| 114 | currentStep: dataMap['currentStep'], | 130 | currentStep: dataMap['currentStep'], |
| 115 | autoNextSection: dataMap['nextSection'], | 131 | autoNextSection: dataMap['nextSection'], |
| 116 | )); | 132 | )); |
| 133 | + AudioPlayerUtil.getInstance() | ||
| 134 | + .playAudio(AudioPlayerUtilType.countWithMe); | ||
| 117 | } | 135 | } |
| 118 | }); | 136 | }); |
| 137 | + | ||
| 119 | return; | 138 | return; |
| 120 | } | 139 | } |
| 121 | 140 | ||
| 122 | if (state.courseType == SectionType.practice.value) { | 141 | if (state.courseType == SectionType.practice.value) { |
| 123 | //练习 | 142 | //练习 |
| 143 | + await AudioPlayerUtil.getInstance() | ||
| 144 | + .playAudio(AudioPlayerUtilType.quizTime); | ||
| 124 | pushNamed(AppRouteName.topicPic, | 145 | pushNamed(AppRouteName.topicPic, |
| 125 | arguments: {'courseLessonId': state.courseLessonId}) | 146 | arguments: {'courseLessonId': state.courseLessonId}) |
| 126 | .then((value) { | 147 | .then((value) { |
| @@ -131,6 +152,8 @@ class _SectionPageView extends StatelessWidget { | @@ -131,6 +152,8 @@ class _SectionPageView extends StatelessWidget { | ||
| 131 | currentStep: dataMap['currentStep'], | 152 | currentStep: dataMap['currentStep'], |
| 132 | autoNextSection: dataMap['nextSection'])); | 153 | autoNextSection: dataMap['nextSection'])); |
| 133 | } | 154 | } |
| 155 | + AudioPlayerUtil.getInstance() | ||
| 156 | + .playAudio(AudioPlayerUtilType.countWithMe); | ||
| 134 | }); | 157 | }); |
| 135 | return; | 158 | return; |
| 136 | } | 159 | } |
lib/pages/shop/home/shop_desc_page.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | + | ||
| 3 | +import 'package:wow_english/common/extension/string_extension.dart'; | ||
| 4 | +import 'package:wow_english/common/widgets/we_app_bar.dart'; | ||
| 5 | + | ||
| 6 | +///购前须知页 | ||
| 7 | +class ShopDescPage extends StatelessWidget { | ||
| 8 | + const ShopDescPage({super.key}); | ||
| 9 | + | ||
| 10 | + @override | ||
| 11 | + Widget build(BuildContext context) { | ||
| 12 | + return _ShopDescPageView(); | ||
| 13 | + } | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +class _ShopDescPageView extends StatelessWidget { | ||
| 17 | + | ||
| 18 | + @override | ||
| 19 | + Widget build(BuildContext context) { | ||
| 20 | + return Scaffold( | ||
| 21 | + appBar: const WEAppBar( | ||
| 22 | + titleText: '购前须知', | ||
| 23 | + centerTitle: true, | ||
| 24 | + ), | ||
| 25 | + body: SingleChildScrollView( | ||
| 26 | + child: Center( | ||
| 27 | + child: Image.asset('shop_desc'.assetPng), | ||
| 28 | + ), | ||
| 29 | + ), | ||
| 30 | + ); | ||
| 31 | + } | ||
| 32 | +} |
lib/pages/shop/home/shop_home_page.dart
| @@ -58,7 +58,7 @@ class _ShopHomeView extends StatelessWidget { | @@ -58,7 +58,7 @@ class _ShopHomeView extends StatelessWidget { | ||
| 58 | ), | 58 | ), |
| 59 | color: Colors.white, | 59 | color: Colors.white, |
| 60 | onPressed: () { | 60 | onPressed: () { |
| 61 | - showToast('购前须知'); | 61 | + pushNamed(AppRouteName.shopDesc); |
| 62 | }, | 62 | }, |
| 63 | ) | 63 | ) |
| 64 | ], | 64 | ], |
lib/pages/unit/bloc.dart
| 1 | import 'package:bloc/bloc.dart'; | 1 | import 'package:bloc/bloc.dart'; |
| 2 | import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; | 2 | import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; |
| 3 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 3 | 4 | ||
| 4 | import '../../common/request/dao/lesson_dao.dart'; | 5 | import '../../common/request/dao/lesson_dao.dart'; |
| 5 | import '../../common/request/exception.dart'; | 6 | import '../../common/request/exception.dart'; |
| @@ -24,6 +25,9 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | @@ -24,6 +25,9 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | ||
| 24 | 25 | ||
| 25 | UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) { | 26 | UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) { |
| 26 | on<RequestUnitDataEvent>(_requestUnitDatas); | 27 | on<RequestUnitDataEvent>(_requestUnitDatas); |
| 28 | + on<UnitInitEvent>((event, emit) { | ||
| 29 | + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy); | ||
| 30 | + }); | ||
| 27 | } | 31 | } |
| 28 | 32 | ||
| 29 | void _requestUnitDatas( | 33 | void _requestUnitDatas( |
| @@ -44,16 +48,28 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | @@ -44,16 +48,28 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | ||
| 44 | return _moduleEntity?.code ?? _unitData?.courseModuleCode; | 48 | return _moduleEntity?.code ?? _unitData?.courseModuleCode; |
| 45 | } | 49 | } |
| 46 | 50 | ||
| 47 | - void headerActionEvent(HeaderActionType type) { | 51 | + Future<void> headerActionEvent(HeaderActionType type) async { |
| 52 | + await AudioPlayerUtil.getInstance().pause(); | ||
| 48 | if (type == HeaderActionType.video) { | 53 | if (type == HeaderActionType.video) { |
| 54 | + //视频跟读暂时隐藏了 | ||
| 49 | pushNamed(AppRouteName.reAfter); | 55 | pushNamed(AppRouteName.reAfter); |
| 50 | } else if (type == HeaderActionType.phase) { | 56 | } else if (type == HeaderActionType.phase) { |
| 51 | - pushNamed(AppRouteName.courseModule); | 57 | + pushNamed(AppRouteName.courseModule).then((value) => { |
| 58 | + AudioPlayerUtil.getInstance() | ||
| 59 | + .playAudio(AudioPlayerUtilType.inMyTummy) | ||
| 60 | + }); | ||
| 61 | + ; | ||
| 52 | } else if (type == HeaderActionType.listen) { | 62 | } else if (type == HeaderActionType.listen) { |
| 53 | - pushNamed(AppRouteName.listen); | 63 | + pushNamed(AppRouteName.listen).then((value) => { |
| 64 | + AudioPlayerUtil.getInstance() | ||
| 65 | + .playAudio(AudioPlayerUtilType.inMyTummy) | ||
| 66 | + }); | ||
| 54 | } else if (type == HeaderActionType.shop) { | 67 | } else if (type == HeaderActionType.shop) { |
| 55 | - pushNamed(AppRouteName.shop) | ||
| 56 | - .then((value) => {exchangeResult = value['exchange']}); | 68 | + pushNamed(AppRouteName.shop).then((value) => { |
| 69 | + AudioPlayerUtil.getInstance() | ||
| 70 | + .playAudio(AudioPlayerUtilType.inMyTummy), | ||
| 71 | + exchangeResult = value['exchange'] | ||
| 72 | + }); | ||
| 57 | } else if (type == HeaderActionType.user) { | 73 | } else if (type == HeaderActionType.user) { |
| 58 | pushNamed(AppRouteName.user); | 74 | pushNamed(AppRouteName.user); |
| 59 | } | 75 | } |
lib/pages/unit/event.dart
lib/pages/unit/view.dart
| @@ -5,6 +5,7 @@ import 'package:wow_english/pages/unit/state.dart'; | @@ -5,6 +5,7 @@ import 'package:wow_english/pages/unit/state.dart'; | ||
| 5 | import 'package:wow_english/pages/unit/widget/course_unit_item.dart'; | 5 | import 'package:wow_english/pages/unit/widget/course_unit_item.dart'; |
| 6 | import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; | 6 | import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; |
| 7 | import 'package:wow_english/route/route.dart'; | 7 | import 'package:wow_english/route/route.dart'; |
| 8 | +import 'package:wow_english/utils/audio_player_util.dart'; | ||
| 8 | 9 | ||
| 9 | import '../../models/course_module_entity.dart'; | 10 | import '../../models/course_module_entity.dart'; |
| 10 | import '../../models/course_unit_entity.dart'; | 11 | import '../../models/course_unit_entity.dart'; |
| @@ -23,6 +24,7 @@ class UnitPage extends StatelessWidget { | @@ -23,6 +24,7 @@ class UnitPage extends StatelessWidget { | ||
| 23 | Widget build(BuildContext context) { | 24 | Widget build(BuildContext context) { |
| 24 | return BlocProvider( | 25 | return BlocProvider( |
| 25 | create: (BuildContext context) => UnitBloc(courseModuleEntity) | 26 | create: (BuildContext context) => UnitBloc(courseModuleEntity) |
| 27 | + ..add(UnitInitEvent()) | ||
| 26 | ..add(RequestUnitDataEvent(courseModuleEntity?.id)), | 28 | ..add(RequestUnitDataEvent(courseModuleEntity?.id)), |
| 27 | child: Builder(builder: (context) => _buildPage(context)), | 29 | child: Builder(builder: (context) => _buildPage(context)), |
| 28 | ); | 30 | ); |
| @@ -41,6 +43,8 @@ class UnitPage extends StatelessWidget { | @@ -41,6 +43,8 @@ class UnitPage extends StatelessWidget { | ||
| 41 | HomeTabHeaderWidget( | 43 | HomeTabHeaderWidget( |
| 42 | courseModuleCode: bloc.getCourseModuleCode(), | 44 | courseModuleCode: bloc.getCourseModuleCode(), |
| 43 | onBack: () { | 45 | onBack: () { |
| 46 | + AudioPlayerUtil.getInstance() | ||
| 47 | + .playAudio(AudioPlayerUtilType.touch); | ||
| 44 | popPage(data: {'exchange': bloc.exchangeResult}); | 48 | popPage(data: {'exchange': bloc.exchangeResult}); |
| 45 | }, | 49 | }, |
| 46 | actionTap: (HeaderActionType type) { | 50 | actionTap: (HeaderActionType type) { |
| @@ -58,17 +62,19 @@ class UnitPage extends StatelessWidget { | @@ -58,17 +62,19 @@ class UnitPage extends StatelessWidget { | ||
| 58 | CourseUnitDetail? data = | 62 | CourseUnitDetail? data = |
| 59 | bloc.unitData?.courseUnitVOList?[index]; | 63 | bloc.unitData?.courseUnitVOList?[index]; |
| 60 | return GestureDetector( | 64 | return GestureDetector( |
| 61 | - onTap: () { | 65 | + onTap: () async { |
| 62 | if (data.lock == true) { | 66 | if (data.lock == true) { |
| 63 | showToast('当前单元课程暂未解锁'); | 67 | showToast('当前单元课程暂未解锁'); |
| 64 | return; | 68 | return; |
| 65 | } | 69 | } |
| 66 | - | 70 | + // await AudioPlayerUtil.getInstance().pause(); |
| 67 | pushNamed(AppRouteName.courseSection, | 71 | pushNamed(AppRouteName.courseSection, |
| 68 | arguments: { | 72 | arguments: { |
| 69 | 'courseUnitEntity': bloc.unitData, | 73 | 'courseUnitEntity': bloc.unitData, |
| 70 | 'courseUnitId': data.id | 74 | 'courseUnitId': data.id |
| 71 | }).then((value) { | 75 | }).then((value) { |
| 76 | + AudioPlayerUtil.getInstance() | ||
| 77 | + .playAudio(AudioPlayerUtilType.inMyTummy); | ||
| 72 | if (value != null) { | 78 | if (value != null) { |
| 73 | Map<String, dynamic> dataMap = | 79 | Map<String, dynamic> dataMap = |
| 74 | value as Map<String, dynamic>; | 80 | value as Map<String, dynamic>; |
lib/pages/unit/widget/course_unit_item.dart
| @@ -17,14 +17,13 @@ class CourseUnitItem extends StatelessWidget { | @@ -17,14 +17,13 @@ class CourseUnitItem extends StatelessWidget { | ||
| 17 | @override | 17 | @override |
| 18 | Widget build(BuildContext context) { | 18 | Widget build(BuildContext context) { |
| 19 | return Padding( | 19 | return Padding( |
| 20 | - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h), | ||
| 21 | - child: Stack( | ||
| 22 | - children: [ | ||
| 23 | - _normalItem(), | ||
| 24 | - _lockWidget(), | ||
| 25 | - ], | ||
| 26 | - ) | ||
| 27 | - ); | 20 | + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h), |
| 21 | + child: Stack( | ||
| 22 | + children: [ | ||
| 23 | + _normalItem(), | ||
| 24 | + _lockWidget(), | ||
| 25 | + ], | ||
| 26 | + )); | ||
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | Widget _normalItem() { | 29 | Widget _normalItem() { |
| @@ -40,17 +39,17 @@ class CourseUnitItem extends StatelessWidget { | @@ -40,17 +39,17 @@ class CourseUnitItem extends StatelessWidget { | ||
| 40 | children: [ | 39 | children: [ |
| 41 | Expanded( | 40 | Expanded( |
| 42 | child: Container( | 41 | child: Container( |
| 43 | - decoration: BoxDecoration( | ||
| 44 | - border: Border.all( | ||
| 45 | - width: 2, | ||
| 46 | - color: const Color(0xFF140C10), | ||
| 47 | - ), | ||
| 48 | - borderRadius: BorderRadius.circular(6)), | ||
| 49 | - child: OwImageWidget( | ||
| 50 | - name: unitLesson.coverUrl ?? '', | ||
| 51 | - fit: BoxFit.fitHeight, | 42 | + decoration: BoxDecoration( |
| 43 | + border: Border.all( | ||
| 44 | + width: 2, | ||
| 45 | + color: const Color(0xFF140C10), | ||
| 52 | ), | 46 | ), |
| 53 | - )), | 47 | + borderRadius: BorderRadius.circular(6)), |
| 48 | + child: OwImageWidget( | ||
| 49 | + name: unitLesson.coverUrl ?? '', | ||
| 50 | + fit: BoxFit.fitHeight, | ||
| 51 | + ), | ||
| 52 | + )), | ||
| 54 | 20.verticalSpace, | 53 | 20.verticalSpace, |
| 55 | SizedBox( | 54 | SizedBox( |
| 56 | height: 40.h, | 55 | height: 40.h, |
| @@ -58,8 +57,7 @@ class CourseUnitItem extends StatelessWidget { | @@ -58,8 +57,7 @@ class CourseUnitItem extends StatelessWidget { | ||
| 58 | unitLesson.name ?? '', | 57 | unitLesson.name ?? '', |
| 59 | maxLines: 2, | 58 | maxLines: 2, |
| 60 | overflow: TextOverflow.ellipsis, | 59 | overflow: TextOverflow.ellipsis, |
| 61 | - style: | ||
| 62 | - TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)), | 60 | + style: TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)), |
| 63 | ), | 61 | ), |
| 64 | ) | 62 | ) |
| 65 | ], | 63 | ], |
| @@ -75,12 +73,8 @@ class CourseUnitItem extends StatelessWidget { | @@ -75,12 +73,8 @@ class CourseUnitItem extends StatelessWidget { | ||
| 75 | width: 165.w, | 73 | width: 165.w, |
| 76 | decoration: BoxDecoration( | 74 | decoration: BoxDecoration( |
| 77 | image: DecorationImage( | 75 | image: DecorationImage( |
| 78 | - image: AssetImage( | ||
| 79 | - 'gendubeij_mengban'.assetPng | ||
| 80 | - ), | ||
| 81 | - fit: BoxFit.fill | ||
| 82 | - ) | ||
| 83 | - ), | 76 | + image: AssetImage('gendubeij_mengban'.assetPng), |
| 77 | + fit: BoxFit.fill)), | ||
| 84 | alignment: Alignment.center, | 78 | alignment: Alignment.center, |
| 85 | child: Image.asset( | 79 | child: Image.asset( |
| 86 | 'iv_lock'.assetPng, | 80 | 'iv_lock'.assetPng, |
lib/pages/user/setting/reback_page.dart
| @@ -26,73 +26,87 @@ class ReBackPageState extends State<ReBackPage> { | @@ -26,73 +26,87 @@ class ReBackPageState extends State<ReBackPage> { | ||
| 26 | @override | 26 | @override |
| 27 | Widget build(BuildContext context) { | 27 | Widget build(BuildContext context) { |
| 28 | return Scaffold( | 28 | return Scaffold( |
| 29 | - appBar: const WEAppBar( | ||
| 30 | - titleText: '我要反馈', | ||
| 31 | - ), | ||
| 32 | - body: Container( | ||
| 33 | - color: Colors.white, | ||
| 34 | - padding: EdgeInsets.symmetric( | ||
| 35 | - horizontal: 24.w | 29 | + appBar: const WEAppBar( |
| 30 | + titleText: '我要反馈', | ||
| 36 | ), | 31 | ), |
| 37 | - child: SafeArea( | ||
| 38 | - child: Column( | ||
| 39 | - children: [ | ||
| 40 | - 20.verticalSpace, | ||
| 41 | - Row( | ||
| 42 | - mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||
| 43 | - children: [ | ||
| 44 | - Text( | ||
| 45 | - '请输入您要反馈的问题和意见,10-500个字', | ||
| 46 | - textAlign: TextAlign.left, | ||
| 47 | - style: TextStyle( | ||
| 48 | - fontSize: 19.sp, | ||
| 49 | - color: HexColor('#333333') | ||
| 50 | - ), | ||
| 51 | - ), | ||
| 52 | - Text( | ||
| 53 | - '48/500', | ||
| 54 | - textAlign: TextAlign.right, | ||
| 55 | - style: TextStyle( | ||
| 56 | - fontSize: 19.sp, | ||
| 57 | - color: HexColor('#333333') | ||
| 58 | - ),) | ||
| 59 | - ], | ||
| 60 | - ), | ||
| 61 | - 9.5.verticalSpace, | ||
| 62 | - Expanded( | ||
| 63 | - child: Container( | ||
| 64 | - decoration: BoxDecoration( | ||
| 65 | - image: DecorationImage( | ||
| 66 | - fit: BoxFit.fill, | ||
| 67 | - image: AssetImage('bg_reback'.assetPng) | 32 | + body: Container( |
| 33 | + color: Colors.white, | ||
| 34 | + padding: EdgeInsets.symmetric(horizontal: 10.w), | ||
| 35 | + child: SafeArea( | ||
| 36 | + child: LayoutBuilder(builder: (context, constraints) { | ||
| 37 | + return SingleChildScrollView( | ||
| 38 | + child: ConstrainedBox( | ||
| 39 | + constraints: BoxConstraints( | ||
| 40 | + minHeight: constraints.maxHeight, | ||
| 41 | + ), | ||
| 42 | + child: IntrinsicHeight( | ||
| 43 | + child: Column( | ||
| 44 | + children: [ | ||
| 45 | + 20.verticalSpace, | ||
| 46 | + Row( | ||
| 47 | + mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||
| 48 | + children: [ | ||
| 49 | + Text( | ||
| 50 | + '请输入您要反馈的问题和意见,10-500个字', | ||
| 51 | + textAlign: TextAlign.left, | ||
| 52 | + style: TextStyle( | ||
| 53 | + fontSize: 19.sp, color: HexColor('#333333')), | ||
| 54 | + ), | ||
| 55 | + Text( | ||
| 56 | + '48/500', | ||
| 57 | + textAlign: TextAlign.right, | ||
| 58 | + style: TextStyle( | ||
| 59 | + fontSize: 19.sp, color: HexColor('#333333')), | ||
| 60 | + ) | ||
| 61 | + ], | ||
| 62 | + ), | ||
| 63 | + 9.5.verticalSpace, | ||
| 64 | + Expanded( | ||
| 65 | + child: Container( | ||
| 66 | + decoration: BoxDecoration( | ||
| 67 | + image: DecorationImage( | ||
| 68 | + image: AssetImage('bg_reback'.assetPng), | ||
| 69 | + fit: BoxFit.fill)), | ||
| 70 | + child: Padding( | ||
| 71 | + padding: const EdgeInsets.symmetric( | ||
| 72 | + vertical: 10, horizontal: 16), | ||
| 73 | + // 设置对称内边距 | ||
| 74 | + child: TextField( | ||
| 75 | + textInputAction: TextInputAction.done, | ||
| 76 | + decoration: InputDecoration( | ||
| 77 | + border: InputBorder.none, | ||
| 78 | + hintStyle: TextStyle( | ||
| 79 | + fontSize: 16.sp, | ||
| 80 | + color: const Color(0xFF999999))), | ||
| 81 | + ), | ||
| 82 | + ), | ||
| 83 | + ), | ||
| 84 | + ), | ||
| 85 | + 4.5.verticalSpace, | ||
| 86 | + Container( | ||
| 87 | + decoration: BoxDecoration( | ||
| 88 | + image: DecorationImage( | ||
| 89 | + fit: BoxFit.fill, | ||
| 90 | + image: AssetImage(_canEnsure | ||
| 91 | + ? 're_button'.assetPng | ||
| 92 | + : 're_button_dis'.assetPng))), | ||
| 93 | + alignment: Alignment.center, | ||
| 94 | + width: 91.w, | ||
| 95 | + height: 45.h, | ||
| 96 | + child: Text( | ||
| 97 | + '提交', | ||
| 98 | + textAlign: TextAlign.center, | ||
| 99 | + style: | ||
| 100 | + TextStyle(color: Colors.white, fontSize: 17.sp), | ||
| 101 | + ), | ||
| 68 | ) | 102 | ) |
| 103 | + ], | ||
| 69 | ), | 104 | ), |
| 70 | ), | 105 | ), |
| 71 | ), | 106 | ), |
| 72 | - 4.5.verticalSpace, | ||
| 73 | - Container( | ||
| 74 | - decoration: BoxDecoration( | ||
| 75 | - image: DecorationImage( | ||
| 76 | - fit: BoxFit.fill, | ||
| 77 | - image: AssetImage(_canEnsure?'re_button'.assetPng:'re_button_dis'.assetPng) | ||
| 78 | - ) | ||
| 79 | - ), | ||
| 80 | - alignment: Alignment.center, | ||
| 81 | - width: 91.w, | ||
| 82 | - height: 45.h, | ||
| 83 | - child: Text( | ||
| 84 | - '提交', | ||
| 85 | - textAlign: TextAlign.center, | ||
| 86 | - style: TextStyle( | ||
| 87 | - color: Colors.white, | ||
| 88 | - fontSize: 17.sp | ||
| 89 | - ), | ||
| 90 | - ), | ||
| 91 | - ) | ||
| 92 | - ], | ||
| 93 | - ), | 107 | + ); |
| 108 | + }), | ||
| 94 | ), | 109 | ), |
| 95 | - ) | ||
| 96 | - ); | 110 | + )); |
| 97 | } | 111 | } |
| 98 | -} | ||
| 99 | \ No newline at end of file | 112 | \ No newline at end of file |
| 113 | +} |
lib/pages/user/setting/setting_page.dart
| 1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; | 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
| 3 | +import 'package:package_info_plus/package_info_plus.dart'; | ||
| 3 | import 'package:wow_english/common/widgets/we_app_bar.dart'; | 4 | import 'package:wow_english/common/widgets/we_app_bar.dart'; |
| 4 | 5 | ||
| 5 | import '../../../route/route.dart'; | 6 | import '../../../route/route.dart'; |
| @@ -9,14 +10,30 @@ class SettingPage extends StatefulWidget { | @@ -9,14 +10,30 @@ class SettingPage extends StatefulWidget { | ||
| 9 | 10 | ||
| 10 | @override | 11 | @override |
| 11 | State<StatefulWidget> createState() { | 12 | State<StatefulWidget> createState() { |
| 12 | - return SettingPageState(); | 13 | + return SettingPageState(); |
| 13 | } | 14 | } |
| 14 | } | 15 | } |
| 15 | 16 | ||
| 16 | class SettingPageState extends State<SettingPage> { | 17 | class SettingPageState extends State<SettingPage> { |
| 18 | + String? _version; | ||
| 19 | + String? _buildNum; | ||
| 20 | + @override | ||
| 21 | + void initState() { | ||
| 22 | + super.initState(); | ||
| 23 | + _retrieveVersionInfo(); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + Future<void> _retrieveVersionInfo() async { | ||
| 27 | + PackageInfo packageInfo = await PackageInfo.fromPlatform(); | ||
| 28 | + setState(() { | ||
| 29 | + _version = packageInfo.version; | ||
| 30 | + _buildNum = packageInfo.buildNumber; | ||
| 31 | + }); | ||
| 32 | + } | ||
| 33 | + | ||
| 17 | @override | 34 | @override |
| 18 | Widget build(BuildContext context) { | 35 | Widget build(BuildContext context) { |
| 19 | - return Scaffold( | 36 | + return Scaffold( |
| 20 | appBar: const WEAppBar( | 37 | appBar: const WEAppBar( |
| 21 | titleText: '设置', | 38 | titleText: '设置', |
| 22 | ), | 39 | ), |
| @@ -28,17 +45,18 @@ class SettingPageState extends State<SettingPage> { | @@ -28,17 +45,18 @@ class SettingPageState extends State<SettingPage> { | ||
| 28 | child: ListView( | 45 | child: ListView( |
| 29 | children: [ | 46 | children: [ |
| 30 | 34.verticalSpace, | 47 | 34.verticalSpace, |
| 31 | - _buildItemWidget('注销账号', onPress: (){ | 48 | + _buildItemWidget('注销账号', onPress: () { |
| 32 | pushNamed(AppRouteName.deleteAccount); | 49 | pushNamed(AppRouteName.deleteAccount); |
| 33 | }), | 50 | }), |
| 34 | 12.verticalSpace, | 51 | 12.verticalSpace, |
| 35 | - _buildItemWidget('清除缓存', onPress: (){ | ||
| 36 | - | ||
| 37 | - }), | 52 | + _buildItemWidget('清除缓存', onPress: () {}), |
| 38 | 12.verticalSpace, | 53 | 12.verticalSpace, |
| 39 | - _buildItemWidget('帮助与反馈', onPress: (){ | 54 | + _buildItemWidget('帮助与反馈', onPress: () { |
| 40 | pushNamed(AppRouteName.reBack); | 55 | pushNamed(AppRouteName.reBack); |
| 41 | }), | 56 | }), |
| 57 | + 12.verticalSpace, | ||
| 58 | + _buildItemWidget('Version: $_version Build:$_buildNum', | ||
| 59 | + onPress: () {}), | ||
| 42 | ], | 60 | ], |
| 43 | ), | 61 | ), |
| 44 | ), | 62 | ), |
| @@ -46,13 +64,15 @@ class SettingPageState extends State<SettingPage> { | @@ -46,13 +64,15 @@ class SettingPageState extends State<SettingPage> { | ||
| 46 | ), | 64 | ), |
| 47 | ); | 65 | ); |
| 48 | } | 66 | } |
| 49 | - | ||
| 50 | - Widget _buildItemWidget(String text,{VoidCallback? onPress}) { | 67 | + |
| 68 | + Widget _buildItemWidget(String text, {VoidCallback? onPress}) { | ||
| 51 | return OutlinedButton( | 69 | return OutlinedButton( |
| 52 | onPressed: () => onPress?.call(), | 70 | onPressed: () => onPress?.call(), |
| 53 | style: ButtonStyle( | 71 | style: ButtonStyle( |
| 54 | - side: MaterialStateProperty.all(BorderSide(color: const Color(0xFF140C10), width: 1.5.w)), | ||
| 55 | - shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))), | 72 | + side: MaterialStateProperty.all( |
| 73 | + BorderSide(color: const Color(0xFF140C10), width: 1.5.w)), | ||
| 74 | + shape: MaterialStateProperty.all( | ||
| 75 | + RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))), | ||
| 56 | minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)), | 76 | minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)), |
| 57 | backgroundColor: MaterialStateProperty.all(Colors.white), | 77 | backgroundColor: MaterialStateProperty.all(Colors.white), |
| 58 | ), | 78 | ), |
| @@ -66,4 +86,4 @@ class SettingPageState extends State<SettingPage> { | @@ -66,4 +86,4 @@ class SettingPageState extends State<SettingPage> { | ||
| 66 | ), | 86 | ), |
| 67 | ); | 87 | ); |
| 68 | } | 88 | } |
| 69 | -} | ||
| 70 | \ No newline at end of file | 89 | \ No newline at end of file |
| 90 | +} |
lib/pages/user/user_page.dart
| @@ -173,15 +173,7 @@ class _UserView extends StatelessWidget { | @@ -173,15 +173,7 @@ class _UserView extends StatelessWidget { | ||
| 173 | UserUtil.getUser()?.phoneNum == '17718485544') | 173 | UserUtil.getUser()?.phoneNum == '17718485544') |
| 174 | ? 12.verticalSpace | 174 | ? 12.verticalSpace |
| 175 | : 1.verticalSpace), | 175 | : 1.verticalSpace), |
| 176 | - OutlinedButton( | ||
| 177 | - onPressed: () => pushNamed(AppRouteName.fogPwd), | ||
| 178 | - style: normalButtonStyle, | ||
| 179 | - child: Text( | ||
| 180 | - "修改密码", | ||
| 181 | - style: textStyle21sp, | ||
| 182 | - ), | ||
| 183 | - ), | ||
| 184 | - 12.verticalSpace, | 176 | + |
| 185 | Offstage( | 177 | Offstage( |
| 186 | offstage: AppConfigHelper.shouldHidePay(), | 178 | offstage: AppConfigHelper.shouldHidePay(), |
| 187 | child: OutlinedButton( | 179 | child: OutlinedButton( |
| @@ -199,6 +191,15 @@ class _UserView extends StatelessWidget { | @@ -199,6 +191,15 @@ class _UserView extends StatelessWidget { | ||
| 199 | style: textStyle21sp, | 191 | style: textStyle21sp, |
| 200 | )), | 192 | )), |
| 201 | ), | 193 | ), |
| 194 | + 12.verticalSpace, | ||
| 195 | + OutlinedButton( | ||
| 196 | + onPressed: () => pushNamed(AppRouteName.fogPwd), | ||
| 197 | + style: normalButtonStyle, | ||
| 198 | + child: Text( | ||
| 199 | + "修改密码", | ||
| 200 | + style: textStyle21sp, | ||
| 201 | + ), | ||
| 202 | + ), | ||
| 202 | Offstage( | 203 | Offstage( |
| 203 | offstage: AppConfigHelper.shouldHidePay(), | 204 | offstage: AppConfigHelper.shouldHidePay(), |
| 204 | child: 12.verticalSpace, | 205 | child: 12.verticalSpace, |
lib/route/route.dart
| @@ -17,6 +17,7 @@ import 'package:wow_english/pages/repeatafter/repeat_after_page.dart'; | @@ -17,6 +17,7 @@ import 'package:wow_english/pages/repeatafter/repeat_after_page.dart'; | ||
| 17 | import 'package:wow_english/pages/repeataftercontent/repeat_after_content_page.dart'; | 17 | import 'package:wow_english/pages/repeataftercontent/repeat_after_content_page.dart'; |
| 18 | import 'package:wow_english/pages/shop/exchane/exchange_lesson_page.dart'; | 18 | import 'package:wow_english/pages/shop/exchane/exchange_lesson_page.dart'; |
| 19 | import 'package:wow_english/pages/shop/exchangelist/exchange_lesson_list_page.dart'; | 19 | import 'package:wow_english/pages/shop/exchangelist/exchange_lesson_list_page.dart'; |
| 20 | +import 'package:wow_english/pages/shop/home/shop_desc_page.dart'; | ||
| 20 | import 'package:wow_english/pages/shop/home/shop_home_page.dart'; | 21 | import 'package:wow_english/pages/shop/home/shop_home_page.dart'; |
| 21 | import 'package:wow_english/pages/user/information/user_information_page.dart'; | 22 | import 'package:wow_english/pages/user/information/user_information_page.dart'; |
| 22 | import 'package:wow_english/pages/user/modify/modify_user_avatar_page.dart'; | 23 | import 'package:wow_english/pages/user/modify/modify_user_avatar_page.dart'; |
| @@ -49,6 +50,7 @@ class AppRouteName { | @@ -49,6 +50,7 @@ class AppRouteName { | ||
| 49 | static const String courseSection = 'courseSections'; | 50 | static const String courseSection = 'courseSections'; |
| 50 | static const String listen = 'listen'; | 51 | static const String listen = 'listen'; |
| 51 | static const String shop = 'shop'; | 52 | static const String shop = 'shop'; |
| 53 | + static const String shopDesc = 'shopDesc'; | ||
| 52 | static const String exLesson = 'exLesson'; | 54 | static const String exLesson = 'exLesson'; |
| 53 | static const String exList = 'exList'; | 55 | static const String exList = 'exList'; |
| 54 | static const String reAfter = 'reAfter'; | 56 | static const String reAfter = 'reAfter'; |
| @@ -141,6 +143,8 @@ class AppRouter { | @@ -141,6 +143,8 @@ class AppRouter { | ||
| 141 | return CupertinoPageRoute(builder: (_) => const ListenPage()); | 143 | return CupertinoPageRoute(builder: (_) => const ListenPage()); |
| 142 | case AppRouteName.shop: | 144 | case AppRouteName.shop: |
| 143 | return CupertinoPageRoute(builder: (_) => const ShopHomePage()); | 145 | return CupertinoPageRoute(builder: (_) => const ShopHomePage()); |
| 146 | + case AppRouteName.shopDesc: | ||
| 147 | + return CupertinoPageRoute(builder: (_) => const ShopDescPage()); | ||
| 144 | case AppRouteName.pay: | 148 | case AppRouteName.pay: |
| 145 | var productEntity = ProductEntity(); | 149 | var productEntity = ProductEntity(); |
| 146 | if (settings.arguments != null && settings.arguments is ProductEntity) { | 150 | if (settings.arguments != null && settings.arguments is ProductEntity) { |
lib/utils/audio_player_util.dart
0 → 100644
| 1 | +import 'package:audioplayers/audioplayers.dart'; | ||
| 2 | +import 'package:flutter/cupertino.dart'; | ||
| 3 | +import 'package:wow_english/common/extension/string_extension.dart'; | ||
| 4 | + | ||
| 5 | +import 'log_util.dart'; | ||
| 6 | + | ||
| 7 | +enum AudioPlayerUtilType { | ||
| 8 | + welcomeToWow('welcome_to_wow'), | ||
| 9 | + classTime('class_time'), | ||
| 10 | + gameTime('game_time'), | ||
| 11 | + musicTime('music_time'), | ||
| 12 | + readingTime('reading_time'), | ||
| 13 | + videoTime('video_time'), | ||
| 14 | + quizTime('quiz_time'), | ||
| 15 | + countWithMe('count_with_me_instrumental'), | ||
| 16 | + inMyTummy('in_my_tummy_instrumental'), | ||
| 17 | + touch('touch_instrumental'); | ||
| 18 | + | ||
| 19 | + const AudioPlayerUtilType(this.path); | ||
| 20 | + | ||
| 21 | + final String path; | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +class AudioPlayerUtil extends WidgetsBindingObserver { | ||
| 25 | + static AudioPlayerUtil? _instance; | ||
| 26 | + late AudioPlayer _audioPlayer; | ||
| 27 | + late AudioPlayerUtilType currentType; | ||
| 28 | + bool _wasPlaying = false; | ||
| 29 | + static const TAG = "AudioPlayerUtil"; | ||
| 30 | + | ||
| 31 | + // 私有构造函数 | ||
| 32 | + AudioPlayerUtil._internal() { | ||
| 33 | + // 监听应用生命周期 | ||
| 34 | + WidgetsBinding.instance.addObserver(this); | ||
| 35 | + _audioPlayer = AudioPlayer(); | ||
| 36 | + _audioPlayer.onPlayerStateChanged.listen((event) async { | ||
| 37 | + if (event == PlayerState.completed) { | ||
| 38 | + // 播放结束再次播放 | ||
| 39 | + if (currentType == AudioPlayerUtilType.inMyTummy) { | ||
| 40 | + AudioPlayerUtil.getInstance() | ||
| 41 | + .playAudio(AudioPlayerUtilType.inMyTummy); | ||
| 42 | + } | ||
| 43 | + if (currentType == AudioPlayerUtilType.countWithMe) { | ||
| 44 | + AudioPlayerUtil.getInstance() | ||
| 45 | + .playAudio(AudioPlayerUtilType.countWithMe); | ||
| 46 | + } | ||
| 47 | + if (currentType == AudioPlayerUtilType.welcomeToWow) { | ||
| 48 | + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch); | ||
| 49 | + } | ||
| 50 | + if (currentType == AudioPlayerUtilType.touch) { | ||
| 51 | + AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch); | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + }); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + static AudioPlayerUtil getInstance() { | ||
| 58 | + _instance ??= AudioPlayerUtil._internal(); | ||
| 59 | + return _instance!; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | +// 播放音频 | ||
| 63 | + Future<void> playAudio(AudioPlayerUtilType type) async { | ||
| 64 | + Log.d("$TAG playAudio $type"); | ||
| 65 | + currentType = type; | ||
| 66 | + String path = type.path; | ||
| 67 | + await _audioPlayer.play(AssetSource(path.assetMp3), volume: 0.5); | ||
| 68 | + await _audioPlayer.onPlayerComplete.first; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + // stop | ||
| 72 | + Future<void> stop() async { | ||
| 73 | + Log.d("$TAG stop _audioPlayer.state=${_audioPlayer.state}"); | ||
| 74 | + await _audioPlayer.stop(); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + // pause | ||
| 78 | + Future<void> pause() async { | ||
| 79 | + Log.d("$TAG pause _audioPlayer.state=${_audioPlayer.state}"); | ||
| 80 | + if (_audioPlayer.state == PlayerState.playing) { | ||
| 81 | + await _audioPlayer.pause(); | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + // resume | ||
| 86 | + Future<void> resume() async { | ||
| 87 | + Log.d("$TAG resume _audioPlayer.state=${_audioPlayer.state}"); | ||
| 88 | + if (_audioPlayer.state == PlayerState.paused) { | ||
| 89 | + await _audioPlayer.resume(); | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + @override | ||
| 94 | + void didChangeAppLifecycleState(AppLifecycleState state) async { | ||
| 95 | + Log.d("$TAG didChangeAppLifecycleState appState=$state _wasPlaying=$_wasPlaying _audioPlayer.state=${_audioPlayer.state}"); | ||
| 96 | + if (state == AppLifecycleState.paused) { | ||
| 97 | + if (_audioPlayer.state == PlayerState.playing) { | ||
| 98 | + _wasPlaying = true; | ||
| 99 | + await pause(); | ||
| 100 | + }; | ||
| 101 | + } else if (state == AppLifecycleState.resumed) { | ||
| 102 | + if (_wasPlaying == true) { | ||
| 103 | + _wasPlaying = false; | ||
| 104 | + await resume(); | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + void dispose() { | ||
| 110 | + Log.d("$TAG dispose _audioPlayer.state=${_audioPlayer.state}"); | ||
| 111 | + _audioPlayer.dispose(); | ||
| 112 | + WidgetsBinding.instance.removeObserver(this); | ||
| 113 | + } | ||
| 114 | +} |