diff --git a/.fvm/flutter_sdk b/.fvm/flutter_sdk
index 143ba8c..18fa846 120000
--- a/.fvm/flutter_sdk
+++ b/.fvm/flutter_sdk
@@ -1 +1 @@
-/Users/stay/fvm/versions/3.19.2
\ No newline at end of file
+/Users/biao/fvm/versions/3.19.2
\ No newline at end of file
diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json
index 7691f75..e4dbfda 100644
--- a/.fvm/fvm_config.json
+++ b/.fvm/fvm_config.json
@@ -1,4 +1,3 @@
{
- "flutterSdkVersion": "3.19.2",
- "flavors": {}
+ "flutterSdkVersion": "3.19.2"
}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..8a15cae
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "dart.flutterSdkPath": ".fvm/versions/3.19.2"
+}
\ No newline at end of file
diff --git a/assets/images/micro_phone.gif b/assets/images/micro_phone.gif
index d1da100..6aa5b32 100644
--- a/assets/images/micro_phone.gif
+++ b/assets/images/micro_phone.gif
diff --git a/assets/images/read_background.png b/assets/images/read_background.png
new file mode 100644
index 0000000..05e66c4
--- /dev/null
+++ b/assets/images/read_background.png
diff --git a/assets/images/reade_answer.gif b/assets/images/reade_answer.gif
index 39f882f..be6c871 100644
--- a/assets/images/reade_answer.gif
+++ b/assets/images/reade_answer.gif
diff --git a/assets/images/shop_desc.png b/assets/images/shop_desc.png
new file mode 100644
index 0000000..5d3de69
--- /dev/null
+++ b/assets/images/shop_desc.png
diff --git a/assets/images/voice.png b/assets/images/voice.png
index 01a1aed..d186c69 100644
--- a/assets/images/voice.png
+++ b/assets/images/voice.png
diff --git a/assets/images/xe_shop.png b/assets/images/xe_shop.png
new file mode 100644
index 0000000..28d040d
--- /dev/null
+++ b/assets/images/xe_shop.png
diff --git a/assets/sounds/class_time.mp3 b/assets/sounds/class_time.mp3
new file mode 100644
index 0000000..3b5226e
--- /dev/null
+++ b/assets/sounds/class_time.mp3
diff --git a/assets/sounds/count_with_me_instrumental.mp3 b/assets/sounds/count_with_me_instrumental.mp3
new file mode 100644
index 0000000..483dbc8
--- /dev/null
+++ b/assets/sounds/count_with_me_instrumental.mp3
diff --git a/assets/sounds/game_time.mp3 b/assets/sounds/game_time.mp3
new file mode 100644
index 0000000..e0b4391
--- /dev/null
+++ b/assets/sounds/game_time.mp3
diff --git a/assets/sounds/in_my_tummy_instrumental.mp3 b/assets/sounds/in_my_tummy_instrumental.mp3
new file mode 100644
index 0000000..0edc830
--- /dev/null
+++ b/assets/sounds/in_my_tummy_instrumental.mp3
diff --git a/assets/sounds/music_time.mp3 b/assets/sounds/music_time.mp3
new file mode 100644
index 0000000..bf94df1
--- /dev/null
+++ b/assets/sounds/music_time.mp3
diff --git a/assets/sounds/quiz_time.mp3 b/assets/sounds/quiz_time.mp3
new file mode 100644
index 0000000..026a2ee
--- /dev/null
+++ b/assets/sounds/quiz_time.mp3
diff --git a/assets/sounds/reading_time.mp3 b/assets/sounds/reading_time.mp3
new file mode 100644
index 0000000..3fa3f2b
--- /dev/null
+++ b/assets/sounds/reading_time.mp3
diff --git a/assets/sounds/touch_instrumental.mp3 b/assets/sounds/touch_instrumental.mp3
new file mode 100644
index 0000000..5b224cc
--- /dev/null
+++ b/assets/sounds/touch_instrumental.mp3
diff --git a/assets/sounds/video_time.mp3 b/assets/sounds/video_time.mp3
new file mode 100644
index 0000000..4837f74
--- /dev/null
+++ b/assets/sounds/video_time.mp3
diff --git a/assets/sounds/welcome_to_wow.mp3 b/assets/sounds/welcome_to_wow.mp3
new file mode 100644
index 0000000..fb6c66d
--- /dev/null
+++ b/assets/sounds/welcome_to_wow.mp3
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index ed3741a..45bb20f 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -2327,7 +2327,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 13;
+ CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = T8P9KW8GWH;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -2671,7 +2671,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 13;
+ CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = T8P9KW8GWH;
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = (
@@ -2876,7 +2876,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 13;
+ CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = T8P9KW8GWH;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index b7b9e34..493f0d2 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -77,11 +77,11 @@
NSCameraUsageDescription
- 需要访问相机完成拍照
+ 需要访问相机,完成修改头像功能
NSMicrophoneUsageDescription
- 需要获取录音完成后续功能
+ 需要获取录音,完成上课功能
NSPhotoLibraryUsageDescription
- 需要获取照片用来修改头像
+ 需要获取照片,完成上传头像功能
UIApplicationSupportsIndirectInputEvents
UILaunchStoryboardName
diff --git a/lib/common/core/app_consts.dart b/lib/common/core/app_consts.dart
index 39c8fb2..e5902c4 100644
--- a/lib/common/core/app_consts.dart
+++ b/lib/common/core/app_consts.dart
@@ -2,16 +2,26 @@ import '../request/basic_config.dart';
class AppConsts {
/// 隐私协议
- static const String userPrivacyPolicyUrl = 'http://page.kouyuxingqiu.com/wowenglishuserregister.html';
+ static const String userPrivacyPolicyUrl =
+ 'http://page.kouyuxingqiu.com/wowenglishuserregister.html';
/// 儿童隐私协议
- static const String childrenPrivacyPolicyUrl = 'http://page.kouyuxingqiu.com/wowenglishchildprotect.html';
+ static const String childrenPrivacyPolicyUrl =
+ 'http://page.kouyuxingqiu.com/wowenglishchildprotect.html';
+
+ /// 小鵝通
+ static const String xiaoeShopUrl = 'https://appo61s7g678876.h5.xiaoeknow.com';
/// 与第三方共享协议
- static const String userTermSdkUrl = 'http://page.kouyuxingqiu.com/term_sdk.html';
+ static const String userTermSdkUrl =
+ 'http://page.kouyuxingqiu.com/term_sdk.html';
/// 先声SDK
- static String xsAppKey = 'a418';
- static String xsAppSecretKey = BasicConfig.isTestDev?'1a16f31f2611bf32fb7b3fc38f5b2c81':'c11163aa6c834a028da4a4b30955be99';
- static String xsAppService = BasicConfig.isTestDev?'ws://trial.cloud.ssapi.cn:8080':'"wss://api.cloud.ssapi.cn';
+ static String xsAppKey = 'a418';
+ static String xsAppSecretKey = BasicConfig.isTestDev
+ ? '1a16f31f2611bf32fb7b3fc38f5b2c81'
+ : 'c11163aa6c834a028da4a4b30955be99';
+ static String xsAppService = BasicConfig.isTestDev
+ ? 'ws://trial.cloud.ssapi.cn:8080'
+ : '"wss://api.cloud.ssapi.cn';
}
diff --git a/lib/pages/games/bloc.dart b/lib/pages/games/bloc.dart
index a118794..632fc9a 100644
--- a/lib/pages/games/bloc.dart
+++ b/lib/pages/games/bloc.dart
@@ -2,17 +2,17 @@ import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:wow_english/common/extension/string_extension.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
import 'event.dart';
import 'game_entity.dart';
import 'state.dart';
class GamesBloc extends Bloc {
-
late MethodChannel _methodChannel;
//手动初始化4个GameEntity对象
- final List _games = [
+ final List _games = [
GameEntity()
..id = 1
..imageName = 'game_food_1'.assetPng
@@ -31,7 +31,7 @@ class GamesBloc extends Bloc {
..name = 'Animal'
];
- List get listData => _games;
+ List get listData => _games;
GamesBloc() : super(GamesState().init()) {
on(_init);
@@ -39,13 +39,16 @@ class GamesBloc extends Bloc {
}
void _init(InitEvent event, Emitter emit) async {
+ AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy);
emit(state.clone());
}
void _gotoGamePage(GotoGamePageEvent event, Emitter emit) async {
+ await AudioPlayerUtil.getInstance().pause();
try {
_methodChannel = const MethodChannel('wow_english/game_method_channel');
- await _methodChannel.invokeMethod('openGamePage', { "gameId": event.gameId });
+ await _methodChannel
+ .invokeMethod('openGamePage', {"gameId": event.gameId});
} on PlatformException catch (e) {
debugPrint("Failed to go to native page: '${e.message}'.");
}
diff --git a/lib/pages/home/bloc.dart b/lib/pages/home/bloc.dart
index eaf337d..6cf5a7c 100644
--- a/lib/pages/home/bloc.dart
+++ b/lib/pages/home/bloc.dart
@@ -1,4 +1,8 @@
+import 'package:audioplayers/audioplayers.dart';
import 'package:bloc/bloc.dart';
+import 'package:wow_english/common/core/user_util.dart';
+import 'package:wow_english/common/extension/string_extension.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
import '../../common/core/app_config_helper.dart';
import '../../common/request/dao/system_dao.dart';
@@ -16,6 +20,9 @@ class HomeBloc extends Bloc {
bool exchangeResult = false;
void _init(InitEvent event, Emitter emit) async {
+ if (UserUtil.isLogined()) {
+ AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.welcomeToWow);
+ }
await _checkUpdate(emit);
}
@@ -37,7 +44,7 @@ class HomeBloc extends Bloc {
return;
}
Log.d(
- "WQF _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion");
+ "HomeBloc _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion");
if (localVersion < int.parse(appVersionEntity.version ?? '0')) {
emit(UpdateDialogState(
appVersionEntity.volType == UpdateStrategy.FORCE.name,
diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart
index 09c344c..c1d86b7 100644
--- a/lib/pages/home/view.dart
+++ b/lib/pages/home/view.dart
@@ -1,15 +1,18 @@
+import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_update/azhon_app_update.dart';
import 'package:flutter_app_update/update_model.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:wow_english/common/core/app_config_helper.dart';
+import 'package:wow_english/common/core/app_consts.dart';
import 'package:wow_english/common/extension/string_extension.dart';
import 'package:wow_english/models/app_version_entity.dart';
import 'package:wow_english/pages/home/state.dart';
import 'package:wow_english/pages/home/widgets/BaseHomeHeaderWidget.dart';
import 'package:wow_english/pages/shop/exchane/bloc/exchange_lesson_bloc.dart';
import 'package:wow_english/pages/user/bloc/user_bloc.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
import '../../common/core/user_util.dart';
import '../../common/dialogs/show_dialog.dart';
@@ -57,7 +60,9 @@ class _HomePageView extends StatelessWidget {
child: Column(
children: [
BaseHomeHeaderWidget(
- callBack: (value) => {
+ callBack: (value) async => {
+ await AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.touch),
bloc.exchangeResult = value['exchange'],
bloc.add(ExchangeSuccessEvent())
}),
@@ -68,7 +73,9 @@ class _HomePageView extends StatelessWidget {
Expanded(
child: GestureDetector(
onTap: () {
- _checkPermission(() {
+ _checkPermission(() async {
+ await AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.classTime);
pushNamed(AppRouteName.courseUnit)
.then((value) => {
if (value != null)
@@ -102,13 +109,45 @@ class _HomePageView extends StatelessWidget {
),
),
),
+ BlocBuilder(
+ builder: (context, userState) {
+ return GestureDetector(
+ onTap: () {
+ _checkPermission(() async {
+ await AudioPlayerUtil.getInstance().pause();
+ Navigator.of(context).pushNamed(
+ AppRouteName.webView,
+ arguments: {
+ 'urlStr': AppConsts.xiaoeShopUrl,
+ 'webViewTitle': 'Wow精选'
+ }).then((value) async => {
+ await AudioPlayerUtil.getInstance().playAudio(
+ AudioPlayerUtilType.touch),
+ });
+ }, bloc);
+ },
+ child: Offstage(
+ offstage: AppConfigHelper.shouldHidePay() ||
+ !UserUtil.isLogined(),
+ child: Image.asset('xe_shop'.assetPng,
+ width: 140.5.w, height: 172.h),
+ ));
+ }),
Expanded(
child: BlocBuilder(
builder: (context, userState) {
return GestureDetector(
onTap: () {
- _checkPermission(() {
- pushNamed(AppRouteName.games);
+ _checkPermission(() async {
+ await AudioPlayerUtil.getInstance()
+ .playAudio(
+ AudioPlayerUtilType.gameTime);
+ pushNamed(AppRouteName.games)
+ .then((value) => {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType
+ .touch),
+ });
}, bloc);
},
child: Column(
@@ -157,6 +196,8 @@ class _HomePageView extends StatelessWidget {
}, rightTap: () {
popPage();
pushNamed(AppRouteName.shop).then((value) {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.touch);
if (value != null) {
bloc.exchangeResult = value['exchange'];
bloc.add(ExchangeSuccessEvent());
diff --git a/lib/pages/home/widgets/BaseHomeHeaderWidget.dart b/lib/pages/home/widgets/BaseHomeHeaderWidget.dart
index 4866201..0db3d8e 100644
--- a/lib/pages/home/widgets/BaseHomeHeaderWidget.dart
+++ b/lib/pages/home/widgets/BaseHomeHeaderWidget.dart
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:wow_english/common/core/app_config_helper.dart';
import 'package:wow_english/common/extension/string_extension.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
import '../../../common/core/user_util.dart';
import '../../../models/course_entity.dart';
@@ -83,7 +84,8 @@ class BaseHomeHeaderWidget extends StatelessWidget {
offstage: AppConfigHelper.shouldHidePay() ||
!UserUtil.isLogined(),
child: GestureDetector(
- onTap: () => {
+ onTap: () async => {
+ await AudioPlayerUtil.getInstance().pause(),
pushNamed(AppRouteName.shop).then((value) {
if (value != null) {
if (callBack == null) {
@@ -113,8 +115,9 @@ class BaseHomeHeaderWidget extends StatelessWidget {
);
}
- void onUserClick() {
+ Future onUserClick() async {
if (UserUtil.isLogined()) {
+ await AudioPlayerUtil.getInstance().pause();
pushNamed(AppRouteName.user).then((value) {
if (value != null) {
if (callBack == null) {
diff --git a/lib/pages/practice/topic_picture_page.dart b/lib/pages/practice/topic_picture_page.dart
index 7de6e92..274e5a0 100644
--- a/lib/pages/practice/topic_picture_page.dart
+++ b/lib/pages/practice/topic_picture_page.dart
@@ -59,7 +59,12 @@ class _TopicPicturePage extends StatelessWidget {
builder: (context, state) {
final bloc = BlocProvider.of(context);
return Container(
- color: Colors.white,
+ decoration: BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage('read_background'.assetPng), // 背景图片路径
+ fit: BoxFit.cover, // 适应图片的方式
+ ),
+ ),
child: Stack(
children: [
Column(
@@ -75,6 +80,7 @@ class _TopicPicturePage extends StatelessWidget {
// Navigator.pop(context);
},
),
+ 35.verticalSpace,
Expanded(
child: PageView.builder(
itemCount: bloc.entity?.topics?.length,
@@ -109,12 +115,7 @@ class _TopicPicturePage extends StatelessWidget {
}),
)
],
- ),
- Positioned(
- left: 0,
- right: 0,
- bottom: 0,
- child: Image.asset('bottom_grass'.assetPng))
+ )
],
),
);
@@ -299,7 +300,7 @@ class _TopicPicturePage extends StatelessWidget {
26.verticalSpace,
SizedBox(
height: 143.h,
- width: 163.w * (topics?.topicAnswerList?.length ?? 0),
+ width: 203.w * (topics?.topicAnswerList?.length ?? 0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
@@ -321,7 +322,7 @@ class _TopicPicturePage extends StatelessWidget {
builder: (context, state) {
final bloc = BlocProvider.of(context);
return Container(
- padding: EdgeInsets.symmetric(horizontal: 10.w),
+ padding: EdgeInsets.symmetric(horizontal: 20.w),
child: GestureDetector(
onTap: () => bloc.add(SelectItemEvent(index)),
child: Container(
@@ -333,15 +334,13 @@ class _TopicPicturePage extends StatelessWidget {
borderRadius: BorderRadius.circular(15),
),
height: 143.h,
- width: 143.w,
+ width: 163.w,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
- border: Border.all(
- width: 1.0, color: const Color(0xFF140C10)),
image: DecorationImage(
- fit: BoxFit.fitWidth,
+ fit: BoxFit.fill,
image: NetworkImage(answerList?.picUrl ?? ''))),
),
),
@@ -449,12 +448,18 @@ class _TopicPicturePage extends StatelessWidget {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- OwImageWidget(
- name: topics?.picUrl ?? '',
- height: 186.h,
- width: 186.w,
+ ClipRRect(
+ borderRadius: BorderRadius.circular(20),
+ child: Container(
+ color: Colors.white,
+ child: OwImageWidget(
+ name: topics?.picUrl ?? '',
+ height: 186.h,
+ width: 186.w,
+ ),
+ ),
),
- 160.horizontalSpace,
+ 120.horizontalSpace,
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@@ -472,8 +477,8 @@ class _TopicPicturePage extends StatelessWidget {
bloc.voicePlayState == VoicePlayState.playing
? 'reade_answer'.assetGif
: 'voice'.assetPng,
- height: 52.h,
- width: 46.w,
+ height: 45.h,
+ width: 45.w,
),
10.horizontalSpace,
Text(topics?.word ?? '')
@@ -506,8 +511,8 @@ class _TopicPicturePage extends StatelessWidget {
bloc.isVoicing
? 'micro_phone'.assetGif
: 'micro_phone'.assetPng,
- height: 75.w,
- width: 75.w,
+ height: 46.h,
+ width: 46.w,
),
)
],
diff --git a/lib/pages/practice/widgets/practice_header_widget.dart b/lib/pages/practice/widgets/practice_header_widget.dart
index 493977a..635d0a0 100644
--- a/lib/pages/practice/widgets/practice_header_widget.dart
+++ b/lib/pages/practice/widgets/practice_header_widget.dart
@@ -12,9 +12,10 @@ class PracticeHeaderWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
- color: Colors.white,
+ color: Colors.transparent,
height: kToolbarHeight + 3.h,
child: AppBar(
+ backgroundColor: Colors.transparent,
leading: GestureDetector(
child: Image.asset(
'back_around'.assetPng,
@@ -25,7 +26,7 @@ class PracticeHeaderWidget extends StatelessWidget {
),
centerTitle: true,
title: Container(
- height: 40.h,
+ height: 20.h,
width: 100.w, // 容器宽度
// padding: EdgeInsets.symmetric(horizontal: 27.w, vertical: 10.h),
alignment: Alignment.center,
diff --git a/lib/pages/reading/bloc/reading_event.dart b/lib/pages/reading/bloc/reading_event.dart
index 9d4ae4d..2adfac8 100644
--- a/lib/pages/reading/bloc/reading_event.dart
+++ b/lib/pages/reading/bloc/reading_event.dart
@@ -39,7 +39,7 @@ class XSVoiceStartEvent extends ReadingPageEvent {
final String content;
final String type;
final String? userId;
- XSVoiceStartEvent(this.content,this.type,this.userId);
+ XSVoiceStartEvent(this.content, this.type, this.userId);
}
///先声评测停止
@@ -52,4 +52,7 @@ class OnXSVoiceStateChangeEvent extends ReadingPageEvent {}
class VoicePlayStateChangeEvent extends ReadingPageEvent {}
///录音播放
-class PlayRecordAudioEvent extends ReadingPageEvent {}
\ No newline at end of file
+class PlayRecordAudioEvent extends ReadingPageEvent {}
+
+///播放下一页
+class PlayNextPageEvent extends ReadingPageEvent {}
diff --git a/lib/pages/reading/reading_page.dart b/lib/pages/reading/reading_page.dart
index 4b6f27d..cf13c4b 100644
--- a/lib/pages/reading/reading_page.dart
+++ b/lib/pages/reading/reading_page.dart
@@ -21,17 +21,16 @@ class ReadingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
- create: (_) => ReadingPageBloc(context, PageController(), courseLessonId ?? '')
- ..add(InitBlocEvent())
- ..add(RequestDataEvent())
- ..add(XSVoiceInitEvent(
- {
- 'appKey':AppConsts.xsAppKey,
- 'service':AppConsts.xsAppService,
- 'secretKey':AppConsts.xsAppSecretKey,
- 'userId':UserUtil.getUser()!.id.toString(),
- }
- )),
+ create: (_) =>
+ ReadingPageBloc(context, PageController(), courseLessonId ?? '')
+ ..add(InitBlocEvent())
+ ..add(RequestDataEvent())
+ ..add(XSVoiceInitEvent({
+ 'appKey': AppConsts.xsAppKey,
+ 'service': AppConsts.xsAppService,
+ 'secretKey': AppConsts.xsAppSecretKey,
+ 'userId': UserUtil.getUser()!.id.toString(),
+ })),
child: _ReadingPage(),
);
}
@@ -60,8 +59,8 @@ class _ReadingPage extends StatelessWidget {
);
}
- Widget _readingPageView() => BlocBuilder(
- builder: (context, state) {
+ Widget _readingPageView() =>
+ BlocBuilder(builder: (context, state) {
final bloc = BlocProvider.of(context);
return Container(
color: Colors.white,
@@ -84,16 +83,14 @@ class _ReadingPage extends StatelessWidget {
children: [
Padding(
padding:
- EdgeInsets.only(left: ScreenUtil().bottomBarHeight),
+ EdgeInsets.only(left: ScreenUtil().bottomBarHeight),
child: IconButton(
onPressed: () {
- popPage(
- data:{
- 'currentStep':bloc.currentPage,
- 'courseLessonId':bloc.courseLessonId,
- 'isCompleted':bloc.isLastPage(),
- }
- );
+ popPage(data: {
+ 'currentStep': bloc.currentPage,
+ 'courseLessonId': bloc.courseLessonId,
+ 'isCompleted': bloc.isLastPage(),
+ });
},
icon: Image.asset(
'back_around'.assetPng,
@@ -158,6 +155,7 @@ class _ReadingPage extends StatelessWidget {
margin: EdgeInsets.symmetric(horizontal: 10.w),
child: Row(
children: [
+ 5.horizontalSpace,
GestureDetector(
onTap: () {
if (bloc.isRecording) {
@@ -167,7 +165,7 @@ class _ReadingPage extends StatelessWidget {
},
child: Image.asset(
bloc.voicePlayState == VoicePlayState.playing &&
- bloc.isOriginAudioPlaying
+ bloc.isOriginAudioPlaying
? 'reade_answer'.assetGif
: 'voice'.assetPng,
height: 40.h,
@@ -179,12 +177,12 @@ class _ReadingPage extends StatelessWidget {
),
Expanded(
child: Text(
- bloc.currentPageData()?.word?.trim() ?? '',
- style: TextStyle(
- color: const Color(0xFF333333), fontSize: 21.sp),
- maxLines: 2,
- overflow: TextOverflow.ellipsis,
- )),
+ bloc.currentPageData()?.word?.trim() ?? '',
+ style: TextStyle(
+ color: const Color(0xFF333333), fontSize: 21.sp),
+ maxLines: 2,
+ overflow: TextOverflow.ellipsis,
+ )),
SizedBox(
width: 10.w,
),
@@ -241,8 +239,7 @@ class _ReadingPage extends StatelessWidget {
return Stack(
children: [
Positioned.fill(
- child:
- Image.network(readings.picUrl ?? '', fit: BoxFit.cover),
+ child: Image.network(readings.picUrl ?? '', fit: BoxFit.cover),
),
],
);
diff --git a/lib/pages/section/bloc/section_bloc.dart b/lib/pages/section/bloc/section_bloc.dart
index 0c1d94c..4df2807 100644
--- a/lib/pages/section/bloc/section_bloc.dart
+++ b/lib/pages/section/bloc/section_bloc.dart
@@ -1,12 +1,15 @@
+import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:wow_english/common/extension/string_extension.dart';
import 'package:wow_english/common/request/dao/lesson_dao.dart';
import 'package:wow_english/common/request/exception.dart';
import 'package:wow_english/common/request/dao/listen_dao.dart';
import 'package:wow_english/models/course_process_entity.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
import 'package:wow_english/utils/loading.dart';
import 'package:wow_english/utils/toast_util.dart';
@@ -61,16 +64,20 @@ class SectionBloc extends Bloc {
on(_requestEnterClass);
on(_requestVideoLesson);
on(_pageControllerChange);
+ on((event, emit) async {
+ await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe);
+ });
}
void _requestSectionsData(
RequestDataEvent event, Emitter emitter) async {
try {
await loading(() async {
- List? courseSectionEntities = await LessonDao.courseSection(courseUnitId: event.courseUnitId);
+ List? courseSectionEntities =
+ await LessonDao.courseSection(courseUnitId: event.courseUnitId);
if (courseSectionEntities != null) {
_courseSectionDatasMap[event.courseUnitId] =
- await LessonDao.courseSection(courseUnitId: event.courseUnitId);
+ await LessonDao.courseSection(courseUnitId: event.courseUnitId);
emitter(LessonDataLoadState());
}
});
@@ -224,7 +231,8 @@ class SectionBloc extends Bloc {
///查找当前unit的下一个section
CourseSectionEntity? nextCourseSectionEntity =
findCourseSectionBySort(curSectionSort + 1);
- return checkCourseSectionLocked(courseLessonId, nextCourseSectionEntity, emitter);
+ return checkCourseSectionLocked(
+ courseLessonId, nextCourseSectionEntity, emitter);
} catch (e) {
if (e is ApiException) {
showToast(e.message.toString());
@@ -234,7 +242,9 @@ class SectionBloc extends Bloc {
}
///检查section是否锁定
- Future checkCourseSectionLocked(int courseLessonId, CourseSectionEntity? courseSectionEntity,
+ Future checkCourseSectionLocked(
+ int courseLessonId,
+ CourseSectionEntity? courseSectionEntity,
Emitter emitter) async {
if (courseSectionEntity != null) {
if (courseSectionEntity.lock == false) {
@@ -243,15 +253,15 @@ class SectionBloc extends Bloc {
} else {
///如果section锁了,请求当前unit下的section数据,查询解锁状态
int courseUnitId = courseSectionEntity.courseUnitId;
- CourseSectionEntity? result = await loading(() async {
+ CourseSectionEntity? result = await loading(() async {
List? tempSectionEntities =
- await LessonDao.courseSection(courseUnitId: courseUnitId);
+ await LessonDao.courseSection(courseUnitId: courseUnitId);
if (tempSectionEntities != null) {
_courseSectionDatasMap[courseUnitId] = tempSectionEntities;
emitter(LessonDataLoadState());
}
courseSectionEntity = tempSectionEntities?.firstWhereOrNull(
- (element) => element.id == courseSectionEntity?.id);
+ (element) => element.id == courseSectionEntity?.id);
if (courseSectionEntity?.lock == false) {
///刷新后的数据如果解锁了,直接返回
return courseSectionEntity;
@@ -270,18 +280,20 @@ class SectionBloc extends Bloc {
if (curCourseUnitDetail != null) {
///再根据当前unit的sortOrder找出下一个unit
CourseUnitDetail? nextCourseUnitDetail =
- _courseUnitEntity.courseUnitVOList?.firstWhereOrNull((element) =>
- element.sortOrder == (curCourseUnitDetail.sortOrder! + 1));
+ _courseUnitEntity.courseUnitVOList?.firstWhereOrNull((element) =>
+ element.sortOrder == (curCourseUnitDetail.sortOrder! + 1));
if (nextCourseUnitDetail != null) {
if (nextCourseUnitDetail.lock == true) {
///如果下一个unit是锁定状态,请求数据刷新查询解锁状态
CourseSectionEntity? result = await loading(() async {
- CourseUnitEntity? newCourseUnitEntity = await LessonDao.courseUnit(
- _courseUnitEntity.nowCourseModuleId);
+ CourseUnitEntity? newCourseUnitEntity =
+ await LessonDao.courseUnit(
+ _courseUnitEntity.nowCourseModuleId);
///拿到重新获取到的unit后,再次判断是否解锁
- nextCourseUnitDetail = newCourseUnitEntity?.courseUnitVOList?.firstWhereOrNull(
+ nextCourseUnitDetail = newCourseUnitEntity?.courseUnitVOList
+ ?.firstWhereOrNull(
(element) => element.id == nextCourseUnitDetail?.id);
if (nextCourseUnitDetail?.lock == false) {
///解锁状态从锁定到解锁,覆盖原unit数据并刷新ui
@@ -289,7 +301,8 @@ class SectionBloc extends Bloc {
courseUnitEntityChanged = true;
emitter(LessonDataLoadState());
- return checkCourseSectionLockedOfNextUnit(courseLessonId, nextCourseUnitDetail!.id!, emitter);
+ return checkCourseSectionLockedOfNextUnit(
+ courseLessonId, nextCourseUnitDetail!.id!, emitter);
} else {
showToast('下个单元课程还没解锁哦');
@@ -299,10 +312,12 @@ class SectionBloc extends Bloc {
});
return result;
} else {
- return checkCourseSectionLockedOfNextUnit(courseLessonId, nextCourseUnitDetail.id!, emitter);
+ return checkCourseSectionLockedOfNextUnit(
+ courseLessonId, nextCourseUnitDetail.id!, emitter);
}
} else {
showToast("恭喜你,本阶段学到顶啦");
+
///最后一个unit了
return null;
}
@@ -314,13 +329,16 @@ class SectionBloc extends Bloc {
}
///检查下一个unit的(第一个)section
- Future checkCourseSectionLockedOfNextUnit(int courseLessonId, int nextCourseUnitDetailId,
+ Future checkCourseSectionLockedOfNextUnit(
+ int courseLessonId,
+ int nextCourseUnitDetailId,
Emitter emitter) async {
- CourseSectionEntity? firstSectionNextUnit = await getFirstSectionByUnitId(
- nextCourseUnitDetailId, emitter);
+ CourseSectionEntity? firstSectionNextUnit =
+ await getFirstSectionByUnitId(nextCourseUnitDetailId, emitter);
if (firstSectionNextUnit != null) {
///下个unit的第一个section如果不为空,再次检查是否锁定
- CourseSectionEntity? courseSectionEntity = await checkCourseSectionLocked(courseLessonId, firstSectionNextUnit, emitter);
+ CourseSectionEntity? courseSectionEntity = await checkCourseSectionLocked(
+ courseLessonId, firstSectionNextUnit, emitter);
if (courseSectionEntity != null) {
///只有是下一unit的第一个section并且解锁了,才跳转
_pageController.nextPage(
diff --git a/lib/pages/section/bloc/section_event.dart b/lib/pages/section/bloc/section_event.dart
index e9fa3ad..06eb1fb 100644
--- a/lib/pages/section/bloc/section_event.dart
+++ b/lib/pages/section/bloc/section_event.dart
@@ -9,6 +9,8 @@ class RequestDataEvent extends SectionEvent {
RequestDataEvent(this.courseUnitId);
}
+class InitEvent extends SectionEvent {}
+
///获取视频课程内容
class RequestVideoLessonEvent extends SectionEvent {
final String courseLessonId;
diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart
index 8adbc11..2a31395 100644
--- a/lib/pages/section/section_page.dart
+++ b/lib/pages/section/section_page.dart
@@ -1,3 +1,4 @@
+import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -11,6 +12,8 @@ import 'package:wow_english/pages/section/widgets/section_item.dart';
import 'package:wow_english/pages/section/widgets/section_bouns_item.dart';
import 'package:wow_english/pages/section/widgets/section_header_widget.dart';
import 'package:wow_english/route/route.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
+import 'package:wow_english/utils/log_util.dart';
import 'package:wow_english/utils/toast_util.dart';
import '../../models/course_section_entity.dart';
@@ -38,7 +41,8 @@ class SectionPage extends StatelessWidget {
initialPage,
PageController(initialPage: initialPage),
ScrollController(),
- ScrollController()),
+ ScrollController())
+ ..add(InitEvent()),
//为了触发指示器进入后计算位置
// ..add(CurrentUnitIndexChangeEvent(initialPage)),
child: _SectionPageView(context),
@@ -55,7 +59,7 @@ class _SectionPageView extends StatelessWidget {
Widget build(BuildContext context) {
final bloc = BlocProvider.of(context);
return BlocListener(
- listener: (context, state) {
+ listener: (context, state) async {
if (state is RequestVideoLessonState) {
final videoUrl = bloc.processEntity?.videos?.videoUrl ?? '';
var title = '';
@@ -87,6 +91,8 @@ class _SectionPageView extends StatelessWidget {
currentTime: dataMap['currentTime'],
autoNextSection: dataMap['nextSection']));
}
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.countWithMe);
});
return;
}
@@ -96,12 +102,22 @@ class _SectionPageView extends StatelessWidget {
state.courseType != SectionType.pictureBook.value) {
///视频类型
///获取视频课程内容
+ if (state.courseType == 1) {
+ await AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.musicTime);
+ } else {
+ await AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.videoTime);
+ }
bloc.add(RequestVideoLessonEvent(
state.courseLessonId, state.courseType));
+
return;
}
if (state.courseType == SectionType.pictureBook.value) {
+ await AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.readingTime);
//绘本
pushNamed(AppRouteName.reading,
arguments: {'courseLessonId': state.courseLessonId})
@@ -114,13 +130,18 @@ class _SectionPageView extends StatelessWidget {
currentStep: dataMap['currentStep'],
autoNextSection: dataMap['nextSection'],
));
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.countWithMe);
}
});
+
return;
}
if (state.courseType == SectionType.practice.value) {
//练习
+ await AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.quizTime);
pushNamed(AppRouteName.topicPic,
arguments: {'courseLessonId': state.courseLessonId})
.then((value) {
@@ -131,6 +152,8 @@ class _SectionPageView extends StatelessWidget {
currentStep: dataMap['currentStep'],
autoNextSection: dataMap['nextSection']));
}
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.countWithMe);
});
return;
}
diff --git a/lib/pages/shop/home/shop_desc_page.dart b/lib/pages/shop/home/shop_desc_page.dart
new file mode 100644
index 0000000..5121b3b
--- /dev/null
+++ b/lib/pages/shop/home/shop_desc_page.dart
@@ -0,0 +1,32 @@
+import 'package:flutter/material.dart';
+
+import 'package:wow_english/common/extension/string_extension.dart';
+import 'package:wow_english/common/widgets/we_app_bar.dart';
+
+///购前须知页
+class ShopDescPage extends StatelessWidget {
+ const ShopDescPage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return _ShopDescPageView();
+ }
+}
+
+class _ShopDescPageView extends StatelessWidget {
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: const WEAppBar(
+ titleText: '购前须知',
+ centerTitle: true,
+ ),
+ body: SingleChildScrollView(
+ child: Center(
+ child: Image.asset('shop_desc'.assetPng),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages/shop/home/shop_home_page.dart b/lib/pages/shop/home/shop_home_page.dart
index 481e22e..b33ab4a 100644
--- a/lib/pages/shop/home/shop_home_page.dart
+++ b/lib/pages/shop/home/shop_home_page.dart
@@ -58,7 +58,7 @@ class _ShopHomeView extends StatelessWidget {
),
color: Colors.white,
onPressed: () {
- showToast('购前须知');
+ pushNamed(AppRouteName.shopDesc);
},
)
],
diff --git a/lib/pages/unit/bloc.dart b/lib/pages/unit/bloc.dart
index 7609fdc..5f45097 100644
--- a/lib/pages/unit/bloc.dart
+++ b/lib/pages/unit/bloc.dart
@@ -1,5 +1,6 @@
import 'package:bloc/bloc.dart';
import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
import '../../common/request/dao/lesson_dao.dart';
import '../../common/request/exception.dart';
@@ -24,6 +25,9 @@ class UnitBloc extends Bloc {
UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) {
on(_requestUnitDatas);
+ on((event, emit) {
+ AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy);
+ });
}
void _requestUnitDatas(
@@ -44,16 +48,28 @@ class UnitBloc extends Bloc {
return _moduleEntity?.code ?? _unitData?.courseModuleCode;
}
- void headerActionEvent(HeaderActionType type) {
+ Future headerActionEvent(HeaderActionType type) async {
+ await AudioPlayerUtil.getInstance().pause();
if (type == HeaderActionType.video) {
+ //视频跟读暂时隐藏了
pushNamed(AppRouteName.reAfter);
} else if (type == HeaderActionType.phase) {
- pushNamed(AppRouteName.courseModule);
+ pushNamed(AppRouteName.courseModule).then((value) => {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.inMyTummy)
+ });
+ ;
} else if (type == HeaderActionType.listen) {
- pushNamed(AppRouteName.listen);
+ pushNamed(AppRouteName.listen).then((value) => {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.inMyTummy)
+ });
} else if (type == HeaderActionType.shop) {
- pushNamed(AppRouteName.shop)
- .then((value) => {exchangeResult = value['exchange']});
+ pushNamed(AppRouteName.shop).then((value) => {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.inMyTummy),
+ exchangeResult = value['exchange']
+ });
} else if (type == HeaderActionType.user) {
pushNamed(AppRouteName.user);
}
diff --git a/lib/pages/unit/event.dart b/lib/pages/unit/event.dart
index 53a8b93..be374dc 100644
--- a/lib/pages/unit/event.dart
+++ b/lib/pages/unit/event.dart
@@ -6,3 +6,5 @@ class RequestUnitDataEvent extends UnitEvent {
RequestUnitDataEvent(this.moduleId);
}
+
+class UnitInitEvent extends UnitEvent {}
diff --git a/lib/pages/unit/view.dart b/lib/pages/unit/view.dart
index bb3d3f6..78148c7 100644
--- a/lib/pages/unit/view.dart
+++ b/lib/pages/unit/view.dart
@@ -5,6 +5,7 @@ import 'package:wow_english/pages/unit/state.dart';
import 'package:wow_english/pages/unit/widget/course_unit_item.dart';
import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart';
import 'package:wow_english/route/route.dart';
+import 'package:wow_english/utils/audio_player_util.dart';
import '../../models/course_module_entity.dart';
import '../../models/course_unit_entity.dart';
@@ -23,6 +24,7 @@ class UnitPage extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => UnitBloc(courseModuleEntity)
+ ..add(UnitInitEvent())
..add(RequestUnitDataEvent(courseModuleEntity?.id)),
child: Builder(builder: (context) => _buildPage(context)),
);
@@ -41,6 +43,8 @@ class UnitPage extends StatelessWidget {
HomeTabHeaderWidget(
courseModuleCode: bloc.getCourseModuleCode(),
onBack: () {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.touch);
popPage(data: {'exchange': bloc.exchangeResult});
},
actionTap: (HeaderActionType type) {
@@ -58,17 +62,19 @@ class UnitPage extends StatelessWidget {
CourseUnitDetail? data =
bloc.unitData?.courseUnitVOList?[index];
return GestureDetector(
- onTap: () {
+ onTap: () async {
if (data.lock == true) {
showToast('当前单元课程暂未解锁');
return;
}
-
+ // await AudioPlayerUtil.getInstance().pause();
pushNamed(AppRouteName.courseSection,
arguments: {
'courseUnitEntity': bloc.unitData,
'courseUnitId': data.id
}).then((value) {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.inMyTummy);
if (value != null) {
Map dataMap =
value as Map;
diff --git a/lib/pages/unit/widget/course_unit_item.dart b/lib/pages/unit/widget/course_unit_item.dart
index e47a09a..9288fad 100644
--- a/lib/pages/unit/widget/course_unit_item.dart
+++ b/lib/pages/unit/widget/course_unit_item.dart
@@ -17,14 +17,13 @@ class CourseUnitItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
- padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h),
- child: Stack(
- children: [
- _normalItem(),
- _lockWidget(),
- ],
- )
- );
+ padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h),
+ child: Stack(
+ children: [
+ _normalItem(),
+ _lockWidget(),
+ ],
+ ));
}
Widget _normalItem() {
@@ -40,17 +39,17 @@ class CourseUnitItem extends StatelessWidget {
children: [
Expanded(
child: Container(
- decoration: BoxDecoration(
- border: Border.all(
- width: 2,
- color: const Color(0xFF140C10),
- ),
- borderRadius: BorderRadius.circular(6)),
- child: OwImageWidget(
- name: unitLesson.coverUrl ?? '',
- fit: BoxFit.fitHeight,
+ decoration: BoxDecoration(
+ border: Border.all(
+ width: 2,
+ color: const Color(0xFF140C10),
),
- )),
+ borderRadius: BorderRadius.circular(6)),
+ child: OwImageWidget(
+ name: unitLesson.coverUrl ?? '',
+ fit: BoxFit.fitHeight,
+ ),
+ )),
20.verticalSpace,
SizedBox(
height: 40.h,
@@ -58,8 +57,7 @@ class CourseUnitItem extends StatelessWidget {
unitLesson.name ?? '',
maxLines: 2,
overflow: TextOverflow.ellipsis,
- style:
- TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)),
+ style: TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)),
),
)
],
@@ -75,12 +73,8 @@ class CourseUnitItem extends StatelessWidget {
width: 165.w,
decoration: BoxDecoration(
image: DecorationImage(
- image: AssetImage(
- 'gendubeij_mengban'.assetPng
- ),
- fit: BoxFit.fill
- )
- ),
+ image: AssetImage('gendubeij_mengban'.assetPng),
+ fit: BoxFit.fill)),
alignment: Alignment.center,
child: Image.asset(
'iv_lock'.assetPng,
diff --git a/lib/pages/user/setting/reback_page.dart b/lib/pages/user/setting/reback_page.dart
index 879d586..33edfe0 100644
--- a/lib/pages/user/setting/reback_page.dart
+++ b/lib/pages/user/setting/reback_page.dart
@@ -26,73 +26,87 @@ class ReBackPageState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- appBar: const WEAppBar(
- titleText: '我要反馈',
- ),
- body: Container(
- color: Colors.white,
- padding: EdgeInsets.symmetric(
- horizontal: 24.w
+ appBar: const WEAppBar(
+ titleText: '我要反馈',
),
- child: SafeArea(
- child: Column(
- children: [
- 20.verticalSpace,
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Text(
- '请输入您要反馈的问题和意见,10-500个字',
- textAlign: TextAlign.left,
- style: TextStyle(
- fontSize: 19.sp,
- color: HexColor('#333333')
- ),
- ),
- Text(
- '48/500',
- textAlign: TextAlign.right,
- style: TextStyle(
- fontSize: 19.sp,
- color: HexColor('#333333')
- ),)
- ],
- ),
- 9.5.verticalSpace,
- Expanded(
- child: Container(
- decoration: BoxDecoration(
- image: DecorationImage(
- fit: BoxFit.fill,
- image: AssetImage('bg_reback'.assetPng)
+ body: Container(
+ color: Colors.white,
+ padding: EdgeInsets.symmetric(horizontal: 10.w),
+ child: SafeArea(
+ child: LayoutBuilder(builder: (context, constraints) {
+ return SingleChildScrollView(
+ child: ConstrainedBox(
+ constraints: BoxConstraints(
+ minHeight: constraints.maxHeight,
+ ),
+ child: IntrinsicHeight(
+ child: Column(
+ children: [
+ 20.verticalSpace,
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ '请输入您要反馈的问题和意见,10-500个字',
+ textAlign: TextAlign.left,
+ style: TextStyle(
+ fontSize: 19.sp, color: HexColor('#333333')),
+ ),
+ Text(
+ '48/500',
+ textAlign: TextAlign.right,
+ style: TextStyle(
+ fontSize: 19.sp, color: HexColor('#333333')),
+ )
+ ],
+ ),
+ 9.5.verticalSpace,
+ Expanded(
+ child: Container(
+ decoration: BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage('bg_reback'.assetPng),
+ fit: BoxFit.fill)),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ vertical: 10, horizontal: 16),
+ // 设置对称内边距
+ child: TextField(
+ textInputAction: TextInputAction.done,
+ decoration: InputDecoration(
+ border: InputBorder.none,
+ hintStyle: TextStyle(
+ fontSize: 16.sp,
+ color: const Color(0xFF999999))),
+ ),
+ ),
+ ),
+ ),
+ 4.5.verticalSpace,
+ Container(
+ decoration: BoxDecoration(
+ image: DecorationImage(
+ fit: BoxFit.fill,
+ image: AssetImage(_canEnsure
+ ? 're_button'.assetPng
+ : 're_button_dis'.assetPng))),
+ alignment: Alignment.center,
+ width: 91.w,
+ height: 45.h,
+ child: Text(
+ '提交',
+ textAlign: TextAlign.center,
+ style:
+ TextStyle(color: Colors.white, fontSize: 17.sp),
+ ),
)
+ ],
),
),
),
- 4.5.verticalSpace,
- Container(
- decoration: BoxDecoration(
- image: DecorationImage(
- fit: BoxFit.fill,
- image: AssetImage(_canEnsure?'re_button'.assetPng:'re_button_dis'.assetPng)
- )
- ),
- alignment: Alignment.center,
- width: 91.w,
- height: 45.h,
- child: Text(
- '提交',
- textAlign: TextAlign.center,
- style: TextStyle(
- color: Colors.white,
- fontSize: 17.sp
- ),
- ),
- )
- ],
- ),
+ );
+ }),
),
- )
- );
+ ));
}
-}
\ No newline at end of file
+}
diff --git a/lib/pages/user/setting/setting_page.dart b/lib/pages/user/setting/setting_page.dart
index b5b62b1..e28a265 100644
--- a/lib/pages/user/setting/setting_page.dart
+++ b/lib/pages/user/setting/setting_page.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:package_info_plus/package_info_plus.dart';
import 'package:wow_english/common/widgets/we_app_bar.dart';
import '../../../route/route.dart';
@@ -9,14 +10,30 @@ class SettingPage extends StatefulWidget {
@override
State createState() {
- return SettingPageState();
+ return SettingPageState();
}
}
class SettingPageState extends State {
+ String? _version;
+ String? _buildNum;
+ @override
+ void initState() {
+ super.initState();
+ _retrieveVersionInfo();
+ }
+
+ Future _retrieveVersionInfo() async {
+ PackageInfo packageInfo = await PackageInfo.fromPlatform();
+ setState(() {
+ _version = packageInfo.version;
+ _buildNum = packageInfo.buildNumber;
+ });
+ }
+
@override
Widget build(BuildContext context) {
- return Scaffold(
+ return Scaffold(
appBar: const WEAppBar(
titleText: '设置',
),
@@ -28,17 +45,18 @@ class SettingPageState extends State {
child: ListView(
children: [
34.verticalSpace,
- _buildItemWidget('注销账号', onPress: (){
+ _buildItemWidget('注销账号', onPress: () {
pushNamed(AppRouteName.deleteAccount);
}),
12.verticalSpace,
- _buildItemWidget('清除缓存', onPress: (){
-
- }),
+ _buildItemWidget('清除缓存', onPress: () {}),
12.verticalSpace,
- _buildItemWidget('帮助与反馈', onPress: (){
+ _buildItemWidget('帮助与反馈', onPress: () {
pushNamed(AppRouteName.reBack);
}),
+ 12.verticalSpace,
+ _buildItemWidget('Version: $_version Build:$_buildNum',
+ onPress: () {}),
],
),
),
@@ -46,13 +64,15 @@ class SettingPageState extends State {
),
);
}
-
- Widget _buildItemWidget(String text,{VoidCallback? onPress}) {
+
+ Widget _buildItemWidget(String text, {VoidCallback? onPress}) {
return OutlinedButton(
onPressed: () => onPress?.call(),
style: ButtonStyle(
- side: MaterialStateProperty.all(BorderSide(color: const Color(0xFF140C10), width: 1.5.w)),
- shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
+ side: MaterialStateProperty.all(
+ BorderSide(color: const Color(0xFF140C10), width: 1.5.w)),
+ shape: MaterialStateProperty.all(
+ RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)),
backgroundColor: MaterialStateProperty.all(Colors.white),
),
@@ -66,4 +86,4 @@ class SettingPageState extends State {
),
);
}
-}
\ No newline at end of file
+}
diff --git a/lib/pages/user/user_page.dart b/lib/pages/user/user_page.dart
index 0d8fa27..c57a029 100644
--- a/lib/pages/user/user_page.dart
+++ b/lib/pages/user/user_page.dart
@@ -173,15 +173,7 @@ class _UserView extends StatelessWidget {
UserUtil.getUser()?.phoneNum == '17718485544')
? 12.verticalSpace
: 1.verticalSpace),
- OutlinedButton(
- onPressed: () => pushNamed(AppRouteName.fogPwd),
- style: normalButtonStyle,
- child: Text(
- "修改密码",
- style: textStyle21sp,
- ),
- ),
- 12.verticalSpace,
+
Offstage(
offstage: AppConfigHelper.shouldHidePay(),
child: OutlinedButton(
@@ -199,6 +191,15 @@ class _UserView extends StatelessWidget {
style: textStyle21sp,
)),
),
+ 12.verticalSpace,
+ OutlinedButton(
+ onPressed: () => pushNamed(AppRouteName.fogPwd),
+ style: normalButtonStyle,
+ child: Text(
+ "修改密码",
+ style: textStyle21sp,
+ ),
+ ),
Offstage(
offstage: AppConfigHelper.shouldHidePay(),
child: 12.verticalSpace,
diff --git a/lib/route/route.dart b/lib/route/route.dart
index 8fddf58..0bc1908 100644
--- a/lib/route/route.dart
+++ b/lib/route/route.dart
@@ -17,6 +17,7 @@ import 'package:wow_english/pages/repeatafter/repeat_after_page.dart';
import 'package:wow_english/pages/repeataftercontent/repeat_after_content_page.dart';
import 'package:wow_english/pages/shop/exchane/exchange_lesson_page.dart';
import 'package:wow_english/pages/shop/exchangelist/exchange_lesson_list_page.dart';
+import 'package:wow_english/pages/shop/home/shop_desc_page.dart';
import 'package:wow_english/pages/shop/home/shop_home_page.dart';
import 'package:wow_english/pages/user/information/user_information_page.dart';
import 'package:wow_english/pages/user/modify/modify_user_avatar_page.dart';
@@ -49,6 +50,7 @@ class AppRouteName {
static const String courseSection = 'courseSections';
static const String listen = 'listen';
static const String shop = 'shop';
+ static const String shopDesc = 'shopDesc';
static const String exLesson = 'exLesson';
static const String exList = 'exList';
static const String reAfter = 'reAfter';
@@ -141,6 +143,8 @@ class AppRouter {
return CupertinoPageRoute(builder: (_) => const ListenPage());
case AppRouteName.shop:
return CupertinoPageRoute(builder: (_) => const ShopHomePage());
+ case AppRouteName.shopDesc:
+ return CupertinoPageRoute(builder: (_) => const ShopDescPage());
case AppRouteName.pay:
var productEntity = ProductEntity();
if (settings.arguments != null && settings.arguments is ProductEntity) {
diff --git a/lib/utils/audio_player_util.dart b/lib/utils/audio_player_util.dart
new file mode 100644
index 0000000..b504c70
--- /dev/null
+++ b/lib/utils/audio_player_util.dart
@@ -0,0 +1,114 @@
+import 'package:audioplayers/audioplayers.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:wow_english/common/extension/string_extension.dart';
+
+import 'log_util.dart';
+
+enum AudioPlayerUtilType {
+ welcomeToWow('welcome_to_wow'),
+ classTime('class_time'),
+ gameTime('game_time'),
+ musicTime('music_time'),
+ readingTime('reading_time'),
+ videoTime('video_time'),
+ quizTime('quiz_time'),
+ countWithMe('count_with_me_instrumental'),
+ inMyTummy('in_my_tummy_instrumental'),
+ touch('touch_instrumental');
+
+ const AudioPlayerUtilType(this.path);
+
+ final String path;
+}
+
+class AudioPlayerUtil extends WidgetsBindingObserver {
+ static AudioPlayerUtil? _instance;
+ late AudioPlayer _audioPlayer;
+ late AudioPlayerUtilType currentType;
+ bool _wasPlaying = false;
+ static const TAG = "AudioPlayerUtil";
+
+ // 私有构造函数
+ AudioPlayerUtil._internal() {
+ // 监听应用生命周期
+ WidgetsBinding.instance.addObserver(this);
+ _audioPlayer = AudioPlayer();
+ _audioPlayer.onPlayerStateChanged.listen((event) async {
+ if (event == PlayerState.completed) {
+ // 播放结束再次播放
+ if (currentType == AudioPlayerUtilType.inMyTummy) {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.inMyTummy);
+ }
+ if (currentType == AudioPlayerUtilType.countWithMe) {
+ AudioPlayerUtil.getInstance()
+ .playAudio(AudioPlayerUtilType.countWithMe);
+ }
+ if (currentType == AudioPlayerUtilType.welcomeToWow) {
+ AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch);
+ }
+ if (currentType == AudioPlayerUtilType.touch) {
+ AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.touch);
+ }
+ }
+ });
+ }
+
+ static AudioPlayerUtil getInstance() {
+ _instance ??= AudioPlayerUtil._internal();
+ return _instance!;
+ }
+
+// 播放音频
+ Future playAudio(AudioPlayerUtilType type) async {
+ Log.d("$TAG playAudio $type");
+ currentType = type;
+ String path = type.path;
+ await _audioPlayer.play(AssetSource(path.assetMp3), volume: 0.5);
+ await _audioPlayer.onPlayerComplete.first;
+ }
+
+ // stop
+ Future stop() async {
+ Log.d("$TAG stop _audioPlayer.state=${_audioPlayer.state}");
+ await _audioPlayer.stop();
+ }
+
+ // pause
+ Future pause() async {
+ Log.d("$TAG pause _audioPlayer.state=${_audioPlayer.state}");
+ if (_audioPlayer.state == PlayerState.playing) {
+ await _audioPlayer.pause();
+ }
+ }
+
+ // resume
+ Future resume() async {
+ Log.d("$TAG resume _audioPlayer.state=${_audioPlayer.state}");
+ if (_audioPlayer.state == PlayerState.paused) {
+ await _audioPlayer.resume();
+ }
+ }
+
+ @override
+ void didChangeAppLifecycleState(AppLifecycleState state) async {
+ Log.d("$TAG didChangeAppLifecycleState appState=$state _wasPlaying=$_wasPlaying _audioPlayer.state=${_audioPlayer.state}");
+ if (state == AppLifecycleState.paused) {
+ if (_audioPlayer.state == PlayerState.playing) {
+ _wasPlaying = true;
+ await pause();
+ };
+ } else if (state == AppLifecycleState.resumed) {
+ if (_wasPlaying == true) {
+ _wasPlaying = false;
+ await resume();
+ }
+ }
+ }
+
+ void dispose() {
+ Log.d("$TAG dispose _audioPlayer.state=${_audioPlayer.state}");
+ _audioPlayer.dispose();
+ WidgetsBinding.instance.removeObserver(this);
+ }
+}