Commit d2add4bdc6cdeaa6bafe601b0148e11ebde0f2e3

Authored by xiaoyu
2 parents 98e40f5f ecfd79f5

Merge branch 'master' into xy_phone

# Conflicts:
#	lib/pages/user/user_page.dart
lib/common/widgets/textfield_customer_widget.dart
... ... @@ -4,6 +4,20 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
4 4 import 'package:wow_english/common/extension/string_extension.dart';
5 5  
6 6 class TextFieldCustomerWidget extends StatefulWidget {
  7 + final TextEditingController? controller;
  8 + final TextStyle? hitStyle;
  9 + final TextStyle? textStyle;
  10 + final String? bgImageName;
  11 + final String? hitText;
  12 + final double? width;
  13 + final double? height;
  14 + final TextAlign? textAlign;
  15 + final TextInputType? textInputType;
  16 + final bool? obscureText;
  17 + final Function(String value)? onChangeValue;
  18 + final List<TextInputFormatter>? inputFormatters;
  19 + final bool? enabel;
  20 +
7 21 const TextFieldCustomerWidget({
8 22 super.key,
9 23 this.controller,
... ... @@ -18,21 +32,9 @@ class TextFieldCustomerWidget extends StatefulWidget {
18 32 this.obscureText,
19 33 this.onChangeValue,
20 34 this.inputFormatters,
  35 + this.enabel = true,
21 36 });
22 37  
23   - final TextEditingController? controller;
24   - final TextStyle? hitStyle;
25   - final TextStyle? textStyle;
26   - final String? bgImageName;
27   - final String? hitText;
28   - final double? width;
29   - final double? height;
30   - final TextAlign? textAlign;
31   - final TextInputType? textInputType;
32   - final bool? obscureText;
33   - final Function(String value)? onChangeValue;
34   - final List<TextInputFormatter>? inputFormatters;
35   -
36 38 @override
37 39 State<StatefulWidget> createState() {
38 40 return _TextFieldCustomerWidgetState();
... ... @@ -52,6 +54,7 @@ class _TextFieldCustomerWidgetState extends State&lt;TextFieldCustomerWidget&gt; {
52 54 fit: BoxFit.fill,
53 55 )),
54 56 child: TextField(
  57 + enabled: widget.enabel,
55 58 inputFormatters: widget.inputFormatters,
56 59 controller: widget.controller,
57 60 textAlign: widget.textAlign ?? TextAlign.center,
... ... @@ -61,7 +64,8 @@ class _TextFieldCustomerWidgetState extends State&lt;TextFieldCustomerWidget&gt; {
61 64 decoration: InputDecoration(
62 65 hintText: widget.hitText ?? '',
63 66 border: InputBorder.none,
64   - hintStyle: widget.hitStyle ?? TextStyle(fontSize: 16.sp, color: const Color(0xFF999999))),
  67 + hintStyle: widget.hitStyle ??
  68 + TextStyle(fontSize: 16.sp, color: const Color(0xFF999999))),
65 69 style: widget.textStyle ??
66 70 TextStyle(
67 71 color: const Color(0xFF333333),
... ...
lib/pages/home/bloc.dart
1 1 import 'package:bloc/bloc.dart';
2   -import 'package:flutter/cupertino.dart';
3   -import 'package:flutter/foundation.dart';
4 2  
5 3 import '../../common/core/app_config_helper.dart';
6 4 import '../../common/request/dao/system_dao.dart';
... ... @@ -12,12 +10,22 @@ import &#39;state.dart&#39;;
12 10 class HomeBloc extends Bloc<HomeEvent, HomeState> {
13 11 HomeBloc() : super(HomeState().init()) {
14 12 on<InitEvent>(_init);
  13 + on<ExchangeSuccessEvent>(_exchangeSuccess);
15 14 }
16 15  
  16 + bool exchangeResult = false;
  17 +
17 18 void _init(InitEvent event, Emitter<HomeState> emit) async {
18 19 await _checkUpdate(emit);
19 20 }
20 21  
  22 + void _exchangeSuccess(
  23 + ExchangeSuccessEvent event, Emitter<HomeState> emit) async {
  24 + if (exchangeResult) {
  25 + emit(HomeState());
  26 + }
  27 + }
  28 +
21 29 Future<void> _checkUpdate(Emitter<HomeState> emit) async {
22 30 if (AppConfigHelper.checkedUpdate) {
23 31 return;
... ... @@ -28,10 +36,12 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
28 36 if (appVersionEntity == null) {
29 37 return;
30 38 }
31   - Log.d("WQF _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion");
  39 + Log.d(
  40 + "WQF _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion");
32 41 if (localVersion < int.parse(appVersionEntity.version ?? '0')) {
33 42 emit(UpdateDialogState(
34   - appVersionEntity.volType == UpdateStrategy.FORCE.name, appVersionEntity));
  43 + appVersionEntity.volType == UpdateStrategy.FORCE.name,
  44 + appVersionEntity));
35 45 }
36 46 }
37 47 }
... ...
lib/pages/home/event.dart
1 1 abstract class HomeEvent {}
2 2  
3   -class InitEvent extends HomeEvent {}
4 3 \ No newline at end of file
  4 +class InitEvent extends HomeEvent {}
  5 +
  6 +class ExchangeSuccessEvent extends HomeEvent {}
... ...
lib/pages/home/view.dart
1   -
2 1 import 'package:flutter/material.dart';
3 2 import 'package:flutter_app_update/azhon_app_update.dart';
4 3 import 'package:flutter_app_update/update_model.dart';
... ... @@ -9,6 +8,7 @@ import &#39;package:wow_english/common/extension/string_extension.dart&#39;;
9 8 import 'package:wow_english/models/app_version_entity.dart';
10 9 import 'package:wow_english/pages/home/state.dart';
11 10 import 'package:wow_english/pages/home/widgets/BaseHomeHeaderWidget.dart';
  11 +import 'package:wow_english/pages/shop/exchane/bloc/exchange_lesson_bloc.dart';
12 12 import 'package:wow_english/pages/user/bloc/user_bloc.dart';
13 13  
14 14 import '../../common/core/user_util.dart';
... ... @@ -24,9 +24,9 @@ class HomePage extends StatelessWidget {
24 24 @override
25 25 Widget build(BuildContext context) {
26 26 return BlocProvider(
27   - create: (BuildContext context) =>
28   - HomeBloc()
29   - ..add(InitEvent()),
  27 + create: (BuildContext context) => HomeBloc()
  28 + ..add(InitEvent())
  29 + ..add(ExchangeSuccessEvent()),
30 30 child: Builder(builder: (context) => _HomePageView()),
31 31 );
32 32 }
... ... @@ -36,12 +36,12 @@ class _HomePageView extends StatelessWidget {
36 36 @override
37 37 Widget build(BuildContext context) {
38 38 return MultiBlocListener(listeners: [
39   - BlocListener<UserBloc, UserState>(listener: (context, state) {
40   - }),
  39 + BlocListener<UserBloc, UserState>(listener: (context, state) {}),
41 40 BlocListener<HomeBloc, HomeState>(
42 41 listener: (context, state) {
43 42 if (state is UpdateDialogState) {
44   - _showUpdateDialog(context, state.forceUpdate, state.appVersionEntity);
  43 + _showUpdateDialog(
  44 + context, state.forceUpdate, state.appVersionEntity);
45 45 }
46 46 },
47 47 ),
... ... @@ -49,24 +49,67 @@ class _HomePageView extends StatelessWidget {
49 49 }
50 50  
51 51 Widget _homeView() =>
52   - BlocBuilder<HomeBloc, HomeState>(
53   - builder: (context, state) {
54   - return Scaffold(
55   - body: Container(
56   - color: Colors.white,
57   - child: Column(
58   - children: [
59   - const BaseHomeHeaderWidget(),
60   - Expanded(
61   - child: Center(
62   - child: Row(
63   - children: [
64   - Expanded(
65   - child: GestureDetector(
  52 + BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
  53 + final bloc = BlocProvider.of<HomeBloc>(context);
  54 + return Scaffold(
  55 + body: Container(
  56 + color: Colors.white,
  57 + child: Column(
  58 + children: [
  59 + BaseHomeHeaderWidget(
  60 + callBack: (value) => {
  61 + bloc.exchangeResult = value['exchange'],
  62 + bloc.add(ExchangeSuccessEvent())
  63 + }),
  64 + Expanded(
  65 + child: Center(
  66 + child: Row(
  67 + children: [
  68 + Expanded(
  69 + child: GestureDetector(
  70 + onTap: () {
  71 + _checkPermission(() {
  72 + pushNamed(AppRouteName.courseUnit)
  73 + .then((value) => {
  74 + if (value != null)
  75 + {
  76 + bloc.exchangeResult =
  77 + value['exchange'],
  78 + bloc.add(ExchangeSuccessEvent())
  79 + }
  80 + });
  81 + }, bloc);
  82 + },
  83 + child: Column(
  84 + mainAxisAlignment: MainAxisAlignment.center,
  85 + children: [
  86 + Stack(
  87 + alignment: AlignmentDirectional.center,
  88 + children: [
  89 + Image.asset('bg_frame_module'.assetPng,
  90 + width: 162.5.w, height: 203.5.h),
  91 + Center(
  92 + child: Image.asset(
  93 + 'pic_module_study'.assetPng,
  94 + width: 140.5.w,
  95 + height: 172.h),
  96 + )
  97 + ]),
  98 + 10.verticalSpace,
  99 + Image.asset('label_module_study'.assetPng,
  100 + width: 124.w, height: 34.h),
  101 + ],
  102 + ),
  103 + ),
  104 + ),
  105 + Expanded(
  106 + child: BlocBuilder<UserBloc, UserState>(
  107 + builder: (context, userState) {
  108 + return GestureDetector(
66 109 onTap: () {
67 110 _checkPermission(() {
68   - pushNamed(AppRouteName.courseUnit);
69   - });
  111 + pushNamed(AppRouteName.games);
  112 + }, bloc);
70 113 },
71 114 child: Column(
72 115 mainAxisAlignment: MainAxisAlignment.center,
... ... @@ -76,69 +119,31 @@ class _HomePageView extends StatelessWidget {
76 119 children: [
77 120 Image.asset(
78 121 'bg_frame_module'.assetPng,
79   - width: 162.5.w, height: 203.5.h),
80   - Center(
81   - child: Image.asset(
82   - 'pic_module_study'.assetPng,
83   - width: 140.5.w,
84   - height: 172.h),
85   - )
  122 + width: 162.5.w,
  123 + height: 203.5.h),
  124 + Image.asset(
  125 + 'pic_module_game'.assetPng,
  126 + width: 140.5.w,
  127 + height: 172.h)
86 128 ]),
87 129 10.verticalSpace,
88   - Image.asset('label_module_study'.assetPng,
  130 + Image.asset('label_module_game'.assetPng,
89 131 width: 124.w, height: 34.h),
90 132 ],
91   - ),
92   - ),
93   - ),
94   - Expanded(
95   - child: BlocBuilder<UserBloc, UserState>(
96   - builder: (context, userState) {
97   - return GestureDetector(
98   - onTap: () {
99   - _checkPermission(() {
100   - pushNamed(AppRouteName.games);
101   - });
102   - },
103   - child: Column(
104   - mainAxisAlignment: MainAxisAlignment
105   - .center,
106   - children: [
107   - Stack(
108   - alignment: AlignmentDirectional
109   - .center,
110   - children: [
111   - Image.asset(
112   - 'bg_frame_module'
113   - .assetPng,
114   - width: 162.5.w,
115   - height: 203.5.h),
116   - Image.asset(
117   - 'pic_module_game'
118   - .assetPng,
119   - width: 140.5.w,
120   - height: 172.h)
121   - ]),
122   - 10.verticalSpace,
123   - Image.asset(
124   - 'label_module_game'.assetPng,
125   - width: 124.w, height: 34.h),
126   - ],
127   - ));
128   - }),
129   - ),
130   - ],
  133 + ));
  134 + }),
131 135 ),
132   - ),
133   - )
134   - ],
135   - ),
136   - ),
137   - );
138   - });
139   -
  136 + ],
  137 + ),
  138 + ),
  139 + )
  140 + ],
  141 + ),
  142 + ),
  143 + );
  144 + });
140 145  
141   - _checkPermission(VoidCallback onAllowed) {
  146 + _checkPermission(VoidCallback onAllowed, HomeBloc bloc) {
142 147 if (UserUtil.isLogined()) {
143 148 if (AppConfigHelper.shouldHidePay()) {
144 149 onAllowed();
... ... @@ -146,13 +151,18 @@ class _HomePageView extends StatelessWidget {
146 151 if (UserUtil.hasPermission()) {
147 152 onAllowed();
148 153 } else {
149   - showTwoActionDialog('提示', '忽略', '去续费',
150   - '您的课程已到期,请快快续费继续学习吧!', leftTap: () {
151   - popPage();
152   - }, rightTap: () {
153   - popPage();
154   - pushNamed(AppRouteName.shop);
155   - });
  154 + showTwoActionDialog('提示', '忽略', '去续费', '您的课程已到期,请快快续费继续学习吧!',
  155 + leftTap: () {
  156 + popPage();
  157 + }, rightTap: () {
  158 + popPage();
  159 + pushNamed(AppRouteName.shop).then((value) {
  160 + if (value != null) {
  161 + bloc.exchangeResult = value['exchange'];
  162 + bloc.add(ExchangeSuccessEvent());
  163 + }
  164 + });
  165 + });
156 166 }
157 167 }
158 168 } else {
... ... @@ -161,7 +171,6 @@ class _HomePageView extends StatelessWidget {
161 171 }
162 172 }
163 173  
164   -
165 174 ///Flutter侧处理升级对话框
166 175 ///[forcedUpgrade] 是否强制升级
167 176 _showUpdateDialog(BuildContext context, bool forcedUpgrade,
... ... @@ -175,20 +184,15 @@ class _HomePageView extends StatelessWidget {
175 184 onWillPop: () => Future.value(!forcedUpgrade),
176 185 child: AlertDialog(
177 186 title: const Text('发现新版本'),
178   - content: Text(
179   - appVersionEntity.remark ??
180   - '修复了一些已知问题'),
  187 + content: Text(appVersionEntity.remark ?? '修复了一些已知问题'),
181 188 actions: <Widget>[
182 189 TextButton(
183 190 child: Text(forcedUpgrade ? '退出' : '取消'),
184   - onPressed: () =>
185   - {
186   - if (forcedUpgrade) {
187   - AppConfigHelper.exitApp()
188   - } else
189   - {
190   - Navigator.of(context).pop()
191   - }
  191 + onPressed: () => {
  192 + if (forcedUpgrade)
  193 + {AppConfigHelper.exitApp()}
  194 + else
  195 + {Navigator.of(context).pop()}
192 196 },
193 197 ),
194 198 TextButton(
... ... @@ -208,8 +212,8 @@ class _HomePageView extends StatelessWidget {
208 212 "ic_launcher",
209 213 '',
210 214 );
211   - AzhonAppUpdate.update(model).then((value) =>
212   - debugPrint('$value'));
  215 + AzhonAppUpdate.update(model)
  216 + .then((value) => debugPrint('$value'));
213 217 if (!forcedUpgrade) {
214 218 Navigator.of(context).pop();
215 219 }
... ...
lib/pages/home/widgets/BaseHomeHeaderWidget.dart
... ... @@ -10,10 +10,13 @@ import &#39;../../../route/route.dart&#39;;
10 10 import '../../../utils/image_util.dart';
11 11 import '../../user/bloc/user_bloc.dart';
12 12  
  13 +typedef HeaderCallback = void Function(dynamic);
  14 +
13 15 class BaseHomeHeaderWidget extends StatelessWidget {
14   - const BaseHomeHeaderWidget({super.key, this.entity});
  16 + const BaseHomeHeaderWidget({super.key, this.entity, this.callBack});
15 17  
16 18 final CourseEntity? entity;
  19 + final HeaderCallback? callBack;
17 20  
18 21 @override
19 22 Widget build(BuildContext context) {
... ... @@ -50,9 +53,7 @@ class BaseHomeHeaderWidget extends StatelessWidget {
50 53 ),
51 54 ),
52 55 GestureDetector(
53   - onTap: () {
54   - onUserClick();
55   - },
  56 + onTap: () => {onUserClick()},
56 57 child: Container(
57 58 margin: const EdgeInsets.only(left: 7),
58 59 padding: const EdgeInsets.all(4.0),
... ... @@ -83,10 +84,16 @@ class BaseHomeHeaderWidget extends StatelessWidget {
83 84 !UserUtil.isLogined(),
84 85 child: GestureDetector(
85 86 onTap: () => {
86   - pushNamed(AppRouteName.shop),
  87 + pushNamed(AppRouteName.shop).then((value) {
  88 + if (value != null) {
  89 + if (callBack == null) {
  90 + } else {
  91 + callBack!(value);
  92 + }
  93 + }
  94 + })
87 95 },
88   - child: Row(
89   - children: <Widget>[
  96 + child: Row(children: <Widget>[
90 97 Image(
91 98 width: 20.0.w,
92 99 height: 20.0.h,
... ... @@ -94,7 +101,9 @@ class BaseHomeHeaderWidget extends StatelessWidget {
94 101 // 替换为你的图片资源路径
95 102 const SizedBox(width: 6.0),
96 103 // 图片和文本之间的间隔
97   - Text('还剩${UserUtil.getRemainingValidity()}天'),
  104 + UserUtil.hasPermission()
  105 + ? Text('还剩${UserUtil.getRemainingValidity()}天')
  106 + : const Text('未购买'),
98 107 ]),
99 108 )),
100 109 ScreenUtil().bottomBarHeight.horizontalSpace,
... ... @@ -103,12 +112,19 @@ class BaseHomeHeaderWidget extends StatelessWidget {
103 112 },
104 113 );
105 114 }
106   -}
107 115  
108   -void onUserClick() {
109   - if (UserUtil.isLogined()) {
110   - pushNamed(AppRouteName.user);
111   - } else {
112   - pushNamed(AppRouteName.login);
  116 + void onUserClick() {
  117 + if (UserUtil.isLogined()) {
  118 + pushNamed(AppRouteName.user).then((value) {
  119 + if (value != null) {
  120 + if (callBack == null) {
  121 + } else {
  122 + callBack!(value);
  123 + }
  124 + }
  125 + });
  126 + } else {
  127 + pushNamed(AppRouteName.login);
  128 + }
113 129 }
114 130 }
... ...
lib/pages/login/forgetpwd/bloc/forget_pwd_home_bloc.dart
1 1 import 'package:common_utils/common_utils.dart';
2 2 import 'package:flutter/cupertino.dart';
  3 +import 'package:flutter/material.dart';
3 4 import 'package:flutter_bloc/flutter_bloc.dart';
4 5 import 'package:wow_english/common/request/dao/user_dao.dart';
5 6 import 'package:wow_english/common/request/exception.dart';
6 7 import 'package:wow_english/utils/loading.dart';
7 8 import 'package:wow_english/utils/toast_util.dart';
8 9  
  10 +import 'package:wow_english/common/core/user_util.dart';
  11 +
9 12 part 'forget_pwd_home_event.dart';
10 13 part 'forget_pwd_home_state.dart';
11 14  
12 15 class ForgetPwdHomeBloc extends Bloc<ForgetPwdHomeEvent, ForgetPwdHomeState> {
13   - ///是否可以发送验证码
14   - bool _canSendSms = false;
15 16 bool _canSetPwd = false;
16   -
  17 + bool _canSendSms = false;
17 18 bool get canSendSms => _canSendSms;
18 19  
19 20 bool get canSetPwd => _canSetPwd;
  21 + bool get enableInputPhone {
  22 + if (UserUtil.getUser() == null) {
  23 + return true;
  24 + } else {
  25 + return UserUtil.getUser()!.phoneNum.isEmpty;
  26 + }
  27 + }
20 28  
21   - final TextEditingController phoneNumController = TextEditingController();
  29 + final TextEditingController phoneNumController =
  30 + TextEditingController(text: UserUtil.getUser()?.phoneNum);
22 31 final TextEditingController checkNumController = TextEditingController();
23   -
24 32 ForgetPwdHomeBloc() : super(ForgetPwdHomeInitial()) {
25   - on<PhoneNumChangeEvent>(_changePhoneNumber);
26 33 on<CheckCodeChangeEvent>(_changeCodeNumber);
27 34 on<SetPassWordEvent>(_setPassWord);
28 35 on<SendSmsCodeEvent>(_sendSmsCode);
  36 + on<PhoneNumChangeEvent>(_changePhoneNumber);
29 37 }
30 38  
31   - void _changePhoneNumber(PhoneNumChangeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
  39 + void _changePhoneNumber(
  40 + PhoneNumChangeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
32 41 if (phoneNumController.text.isNotEmpty) {
33 42 if (!_canSendSms) {
34 43 _canSendSms = true;
... ... @@ -44,7 +53,8 @@ class ForgetPwdHomeBloc extends Bloc&lt;ForgetPwdHomeEvent, ForgetPwdHomeState&gt; {
44 53 }
45 54 }
46 55  
47   - void _changeCodeNumber(CheckCodeChangeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
  56 + void _changeCodeNumber(
  57 + CheckCodeChangeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
48 58 if (checkNumController.text.isNotEmpty) {
49 59 if (!_canSetPwd) {
50 60 _canSetPwd = true;
... ... @@ -60,7 +70,8 @@ class ForgetPwdHomeBloc extends Bloc&lt;ForgetPwdHomeEvent, ForgetPwdHomeState&gt; {
60 70 }
61 71 }
62 72  
63   - void _setPassWord(SetPassWordEvent event, Emitter<ForgetPwdHomeState> emitter) async {
  73 + void _setPassWord(
  74 + SetPassWordEvent event, Emitter<ForgetPwdHomeState> emitter) async {
64 75 if (!RegexUtil.isMobileExact(phoneNumController.text)) {
65 76 showToast('手机号不正确!');
66 77 return;
... ... @@ -68,7 +79,8 @@ class ForgetPwdHomeBloc extends Bloc&lt;ForgetPwdHomeEvent, ForgetPwdHomeState&gt; {
68 79 emitter(SetPwdCheckCodeState());
69 80 }
70 81  
71   - void _sendSmsCode(SendSmsCodeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
  82 + void _sendSmsCode(
  83 + SendSmsCodeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
72 84 final phoneNumber = phoneNumController.text;
73 85 if (!RegexUtil.isMobileExact(phoneNumber)) {
74 86 showToast('请检查手机号');
... ... @@ -76,12 +88,12 @@ class ForgetPwdHomeBloc extends Bloc&lt;ForgetPwdHomeEvent, ForgetPwdHomeState&gt; {
76 88 }
77 89 try {
78 90 await loading(() async {
79   - await UserDao.sendCode(phoneNumber,smsType:'change_passWord');
  91 + await UserDao.sendCode(phoneNumber, smsType: 'change_passWord');
80 92 });
81 93 emitter(SendSmsCodeState());
82 94 } catch (e) {
83   - if(e is ApiException) {
84   - showToast(e.message??'网络请求失败');
  95 + if (e is ApiException) {
  96 + showToast(e.message ?? '网络请求失败');
85 97 }
86 98 }
87 99 }
... ...
lib/pages/login/forgetpwd/bloc/forget_pwd_home_event.dart
... ... @@ -3,10 +3,10 @@ part of &#39;forget_pwd_home_bloc.dart&#39;;
3 3 @immutable
4 4 abstract class ForgetPwdHomeEvent {}
5 5  
6   -class PhoneNumChangeEvent extends ForgetPwdHomeEvent {}
7   -
8 6 class CheckCodeChangeEvent extends ForgetPwdHomeEvent {}
9 7  
10 8 class SetPassWordEvent extends ForgetPwdHomeEvent {}
11 9  
12 10 class SendSmsCodeEvent extends ForgetPwdHomeEvent {}
  11 +
  12 +class PhoneNumChangeEvent extends ForgetPwdHomeEvent {}
... ...
lib/pages/login/forgetpwd/forget_password_home_page.dart
... ... @@ -41,44 +41,49 @@ class _ForgetPasswordHomePageView extends StatelessWidget {
41 41 }
42 42 // todo 后续需要改成在当前页面,验证过验证码后,再跳转到设置密码页面
43 43 // change_passWord
44   - SetPassWordPage.push(context, SetPwdPageType.resetPwd, phoneNum: phoneNum, smsCode: smsCode);
  44 + SetPassWordPage.push(context, SetPwdPageType.resetPwd,
  45 + phoneNum: phoneNum, smsCode: smsCode);
45 46 }
46 47 },
47 48 child: _buildForgetPwdView(),
48 49 );
49 50 }
50 51  
51   - Widget _buildForgetPwdView() => BlocBuilder<ForgetPwdHomeBloc, ForgetPwdHomeState>(builder: (context, state) {
52   - final bloc = BlocProvider.of<ForgetPwdHomeBloc>(context);
53   - return Scaffold(
54   - appBar: const WEAppBar(),
55   - body: Container(
56   - color: Colors.white,
57   - child: SafeArea(
58   - child: SingleChildScrollView(
59   - child: Padding(
60   - padding: EdgeInsets.only(left: 49.w, right: 10.w),
61   - child: Column(
62   - children: [
63   - Row(
  52 + Widget _buildForgetPwdView() =>
  53 + BlocBuilder<ForgetPwdHomeBloc, ForgetPwdHomeState>(
  54 + builder: (context, state) {
  55 + final bloc = BlocProvider.of<ForgetPwdHomeBloc>(context);
  56 + return Scaffold(
  57 + appBar: const WEAppBar(),
  58 + body: Container(
  59 + color: Colors.white,
  60 + child: SafeArea(
  61 + child: SingleChildScrollView(
  62 + child: Padding(
  63 + padding: EdgeInsets.only(left: 49.w, right: 10.w),
  64 + child: Column(
64 65 children: [
65   - Image.asset(
66   - 'wow_logo'.assetPng,
67   - height: 49.w,
68   - width: 83.5.h,
  66 + Row(
  67 + children: [
  68 + Image.asset(
  69 + 'wow_logo'.assetPng,
  70 + height: 49.w,
  71 + width: 83.5.h,
  72 + ),
  73 + 12.5.horizontalSpace,
  74 + Text(
  75 + '修改密码\n请输入您的手机号和验证码吧',
  76 + style: TextStyle(
  77 + fontSize: 16.sp,
  78 + color: const Color(0xFF666666)),
  79 + )
  80 + ],
69 81 ),
70   - 12.5.horizontalSpace,
71   - Text(
72   - '修改密码\n请输入您的手机号和验证码吧',
73   - style: TextStyle(fontSize: 16.sp, color: const Color(0xFF666666)),
74   - )
75   - ],
76   - ),
77   - Row(
78   - crossAxisAlignment: CrossAxisAlignment.start,
79   - children: [
80   - Expanded(
81   - child: Column(
  82 + Row(
  83 + crossAxisAlignment: CrossAxisAlignment.start,
  84 + children: [
  85 + Expanded(
  86 + child: Column(
82 87 children: [
83 88 44.5.verticalSpace,
84 89 Row(
... ... @@ -91,20 +96,31 @@ class _ForgetPasswordHomePageView extends StatelessWidget {
91 96 15.horizontalSpace,
92 97 Expanded(
93 98 child: TextFieldCustomerWidget(
94   - height: 50.h,
95   - hitText: '请输入当前手机号',
96   - textInputType: TextInputType.phone,
97   - bgImageName: 'Input_layer_up',
98   - onChangeValue: (String value) {
99   - bloc.add(PhoneNumChangeEvent());
100   - },
101   - controller: bloc.phoneNumController,
102   - ))
  99 + height: 50.h,
  100 + textStyle: !bloc.enableInputPhone
  101 + ? TextStyle(
  102 + fontWeight: FontWeight.w500,
  103 + color: const Color(0xFF999999),
  104 + fontSize: 21.sp,
  105 + )
  106 + : TextStyle(
  107 + color: const Color(0xFF333333),
  108 + fontSize: 16.sp,
  109 + ),
  110 + textInputType: TextInputType.phone,
  111 + bgImageName: 'Input_layer_up',
  112 + enabel: bloc.enableInputPhone,
  113 + onChangeValue: (String value) {
  114 + bloc.add(PhoneNumChangeEvent());
  115 + },
  116 + controller: bloc.phoneNumController,
  117 + ))
103 118 ],
104 119 ),
105 120 11.5.verticalSpace,
106 121 Row(
107   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
  122 + mainAxisAlignment:
  123 + MainAxisAlignment.spaceBetween,
108 124 children: [
109 125 Image.asset(
110 126 'lock'.assetPng,
... ... @@ -114,57 +130,64 @@ class _ForgetPasswordHomePageView extends StatelessWidget {
114 130 18.5.horizontalSpace,
115 131 Expanded(
116 132 child: TextFieldCustomerWidget(
117   - hitText: '请输入验证码',
118   - bgImageName: 'Input_layer_down',
119   - onChangeValue: (String value) {
120   - bloc.add(CheckCodeChangeEvent());
121   - },
122   - textInputType: TextInputType.emailAddress,
123   - controller: bloc.checkNumController,
124   - )),
  133 + hitText: '请输入验证码',
  134 + bgImageName: 'Input_layer_down',
  135 + onChangeValue: (String value) {
  136 + bloc.add(CheckCodeChangeEvent());
  137 + },
  138 + textInputType: TextInputType.emailAddress,
  139 + controller: bloc.checkNumController,
  140 + )),
125 141 16.5.horizontalSpace,
126 142 TimerWidget(
127 143 pageType: 1,
128   - canSendSms: bloc.canSendSms,
129   - sendSmsEvent: () => bloc.add(SendSmsCodeEvent()),
  144 + canSendSms: bloc.enableInputPhone
  145 + ? bloc.canSendSms
  146 + : true,
  147 + sendSmsEvent: () =>
  148 + bloc.add(SendSmsCodeEvent()),
130 149 )
131 150 ],
132 151 )
133 152 ],
134 153 )),
135   - 2.verticalSpace,
136   - Image.asset(
137   - 'steven_bride'.assetPng,
138   - height: 173.h,
139   - width: 157.w,
  154 + 2.verticalSpace,
  155 + Image.asset(
  156 + 'steven_bride'.assetPng,
  157 + height: 173.h,
  158 + width: 157.w,
  159 + )
  160 + ],
  161 + ),
  162 + GestureDetector(
  163 + onTap: () {
  164 + if (bloc.canSetPwd) {
  165 + bloc.add(SetPassWordEvent());
  166 + }
  167 + },
  168 + child: Container(
  169 + decoration: BoxDecoration(
  170 + image: DecorationImage(
  171 + image: AssetImage(bloc.canSetPwd
  172 + ? 'login_enter'.assetPng
  173 + : 'login_enter_dis'.assetPng),
  174 + fit: BoxFit.fill),
  175 + ),
  176 + padding: EdgeInsets.symmetric(
  177 + horizontal: 28.w, vertical: 14.h),
  178 + child: Text(
  179 + '确定',
  180 + style:
  181 + TextStyle(fontSize: 16.sp, color: Colors.white),
  182 + ),
  183 + ),
140 184 )
141 185 ],
142 186 ),
143   - GestureDetector(
144   - onTap: () {
145   - if (bloc.canSetPwd) {
146   - bloc.add(SetPassWordEvent());
147   - }
148   - },
149   - child: Container(
150   - decoration: BoxDecoration(
151   - image: DecorationImage(
152   - image: AssetImage(bloc.canSetPwd ? 'login_enter'.assetPng : 'login_enter_dis'.assetPng),
153   - fit: BoxFit.fill),
154   - ),
155   - padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 14.h),
156   - child: Text(
157   - '确定',
158   - style: TextStyle(fontSize: 16.sp, color: Colors.white),
159   - ),
160   - ),
161   - )
162   - ],
  187 + ),
163 188 ),
164 189 ),
165 190 ),
166   - ),
167   - ),
168   - );
169   - });
  191 + );
  192 + });
170 193 }
... ...
lib/pages/reading/bloc/reading_bloc.dart
... ... @@ -130,8 +130,6 @@ class ReadingPageBloc
130 130 "setMethodCallHandler method=${call.method} arguments=${call.arguments}");
131 131 if (call.method == 'voiceResult') {
132 132 //评测结果
133   - await audioPlayer.setAudioContext(AudioContext());
134   - await audioPlayer.setBalance(0.0);
135 133 add(XSVoiceResultEvent(call.arguments));
136 134 return;
137 135 }
... ... @@ -152,8 +150,6 @@ class ReadingPageBloc
152 150 print(call.method == 'voiceEnd' ? '评测结束' : '评测取消');
153 151 }
154 152 _isRecording = false;
155   - await audioPlayer.setAudioContext(AudioContext());
156   - await audioPlayer.setBalance(0.0);
157 153 add(OnXSVoiceStateChangeEvent());
158 154 return;
159 155 }
... ... @@ -161,8 +157,6 @@ class ReadingPageBloc
161 157 if (call.method == 'voiceFail') {
162 158 //评测失败
163 159 _isRecording = false;
164   - await audioPlayer.setAudioContext(AudioContext());
165   - await audioPlayer.setBalance(0.0);
166 160 EasyLoading.showToast('评测失败');
167 161 return;
168 162 }
... ... @@ -231,7 +225,8 @@ class ReadingPageBloc
231 225 ///播放原音音频
232 226 /// - [force]: 是否强制播放(true:不管当前状态如何,都会播放目标原音音频,比如翻页场景)
233 227 /// (false:如果正在播放,暂停播放,比如点击播放按钮场景)
234   - void _playOriginalAudioInner(String? audioUrl, {bool forcePlay = false}) async {
  228 + void _playOriginalAudioInner(String? audioUrl,
  229 + {bool forcePlay = false}) async {
235 230 if (_isRecordAudioPlaying) {
236 231 await audioPlayer.stop();
237 232 _isRecordAudioPlaying = false;
... ... @@ -261,8 +256,7 @@ class ReadingPageBloc
261 256  
262 257 Future<void> _playRecordAudioInner() async {
263 258 Log.d(
264   - "_playRecordAudioInner _isOriginAudioPlaying=$_isOriginAudioPlaying _isRecordAudioPlaying=$_isRecordAudioPlaying url=${currentPageData()
265   - ?.recordUrl}");
  259 + "_playRecordAudioInner _isOriginAudioPlaying=$_isOriginAudioPlaying _isRecordAudioPlaying=$_isRecordAudioPlaying url=${currentPageData()?.recordUrl}");
266 260 if (_isOriginAudioPlaying) {
267 261 ///如果正在播放原音,暂停
268 262 await audioPlayer.stop();
... ... @@ -282,9 +276,7 @@ class ReadingPageBloc
282 276  
283 277 Future<void> _playAudio(String? audioUrl) async {
284 278 if (audioUrl!.isNotEmpty) {
285   - await audioPlayer.play(UrlSource(audioUrl),
286   - balance: 0.0, ctx: AudioContext()
287   - );
  279 + await audioPlayer.play(UrlSource(audioUrl));
288 280 }
289 281 }
290 282  
... ... @@ -354,6 +346,7 @@ class ReadingPageBloc
354 346 duration: const Duration(seconds: 2));
355 347 currentPageData()?.recordScore = overall;
356 348 currentPageData()?.recordUrl = args['audioUrl'] + '.mp3';
  349 +
357 350 ///完成录音后紧接着播放录音
358 351 await _playRecordAudioInner();
359 352 if (isLastPage()) {
... ...
lib/pages/shop/exchane/bloc/exchange_lesson_bloc.dart
1 1 import 'package:flutter/cupertino.dart';
2 2 import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:wow_english/common/request/dao/user_dao.dart';
3 4 import 'package:wow_english/utils/loading.dart';
4 5  
  6 +import 'package:wow_english/common/core/user_util.dart';
  7 +import 'package:wow_english/models/user_entity.dart';
  8 +
5 9 import '../../../../common/request/dao/request_dao.dart';
6 10  
7 11 part 'exchange_lesson_event.dart';
8 12 part 'exchange_lesson_state.dart';
9 13  
10   -class ExchangeLessonBloc extends Bloc<ExchangeLessonEvent, ExchangeLessonState> {
11   -
  14 +class ExchangeLessonBloc
  15 + extends Bloc<ExchangeLessonEvent, ExchangeLessonState> {
12 16 final TextEditingController codeNumberController = TextEditingController();
13 17  
14 18 bool _checkCode = false;
  19 + bool exchangeSuccess = false;
15 20  
16 21 bool get checkCode => _checkCode;
17 22  
... ... @@ -20,8 +25,9 @@ class ExchangeLessonBloc extends Bloc&lt;ExchangeLessonEvent, ExchangeLessonState&gt;
20 25 on<CheckCodeEvent>(_requestCheckCode);
21 26 }
22 27  
23   - _codeNumberChange(CodeNumberChangeEvent event,Emitter<ExchangeLessonState> emitter) async {
24   - if(codeNumberController.text.isNotEmpty) {
  28 + _codeNumberChange(
  29 + CodeNumberChangeEvent event, Emitter<ExchangeLessonState> emitter) async {
  30 + if (codeNumberController.text.isNotEmpty) {
25 31 if (!_checkCode) {
26 32 _checkCode = true;
27 33 emitter(CheckCodeTypeChangeState());
... ... @@ -34,13 +40,23 @@ class ExchangeLessonBloc extends Bloc&lt;ExchangeLessonEvent, ExchangeLessonState&gt;
34 40 }
35 41 }
36 42  
37   - _requestCheckCode(CheckCodeEvent event, Emitter<ExchangeLessonState> emitter) async {
  43 + _requestCheckCode(
  44 + CheckCodeEvent event, Emitter<ExchangeLessonState> emitter) async {
38 45 try {
39 46 await loading(() async {
40 47 await RequestDao.exchange(codeNumberController.text);
  48 + // 更新本地数据
  49 + UserEntity? userEntity = await UserDao.getUserInfo();
  50 + final token = UserUtil.getUser()?.token;
  51 + if (userEntity != null) {
  52 + userEntity.token = token;
  53 + UserUtil.saveUser(userEntity);
  54 + }
  55 + exchangeSuccess = true;
41 56 emitter(CheckCodeResultState(true));
42 57 });
43 58 } catch (e) {
  59 + exchangeSuccess = false;
44 60 emitter(CheckCodeResultState(false));
45 61 }
46 62 }
... ...
lib/pages/shop/exchane/exchange_lesson_page.dart
... ... @@ -3,6 +3,7 @@ import &#39;package:flutter_bloc/flutter_bloc.dart&#39;;
3 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
4 4 import 'package:wow_english/common/extension/string_extension.dart';
5 5 import 'package:wow_english/common/widgets/textfield_customer_widget.dart';
  6 +import 'package:wow_english/pages/home/event.dart';
6 7 import 'package:wow_english/pages/shop/exchane/widegts/exchange_result_dialog.dart';
7 8 import 'package:wow_english/route/route.dart';
8 9  
... ... @@ -27,6 +28,8 @@ class _ExchangeLessonPage extends StatelessWidget {
27 28 return BlocListener<ExchangeLessonBloc, ExchangeLessonState>(
28 29 listener: (context, state) {
29 30 if (state is CheckCodeResultState) {
  31 + final bloc = BlocProvider.of<ExchangeLessonBloc>(context);
  32 + bloc.exchangeSuccess = state.result;
30 33 showDialog<ExChangeResultDialog>(
31 34 context: context,
32 35 barrierDismissible: !state.result,
... ... @@ -34,7 +37,7 @@ class _ExchangeLessonPage extends StatelessWidget {
34 37 return ExChangeResultDialog(
35 38 resultType: state.result,
36 39 onTap: () {
37   - popPage();
  40 + popPage(data: {'exchange': bloc.exchangeSuccess});
38 41 });
39 42 });
40 43 }
... ... @@ -117,12 +120,15 @@ class _ExchangeLessonPage extends StatelessWidget {
117 120 ],
118 121 ),
119 122 ),
120   - const Positioned(
  123 + Positioned(
121 124 top: 0,
122 125 left: 0,
123 126 right: 0,
124 127 child: WEAppBar(
125 128 backgroundColor: Colors.transparent,
  129 + onBack: () {
  130 + popPage(data: {'exchange': bloc.exchangeSuccess});
  131 + },
126 132 ),
127 133 ),
128 134 ],
... ...
lib/pages/shop/home/bloc/shop_home_bloc.dart
  1 +import 'dart:ffi';
1 2  
2 3 import 'package:bloc/bloc.dart';
3 4 import 'package:meta/meta.dart';
... ... @@ -12,11 +13,12 @@ part &#39;shop_home_event.dart&#39;;
12 13 part 'shop_home_state.dart';
13 14  
14 15 class ShopHomeBloc extends Bloc<ShopHomeEvent, ShopHomeState> {
15   -
16 16 List<ProductEntity?> _productDatas = [];
17 17  
18 18 List<ProductEntity?> get productDatas => _productDatas;
19 19  
  20 + bool exchangeResult = false;
  21 +
20 22 ShopHomeBloc() : super(ShopHomeInitial()) {
21 23 on<ShopHomeEvent>((event, emit) {
22 24 // TODO: implement event handler
... ... @@ -24,7 +26,8 @@ class ShopHomeBloc extends Bloc&lt;ShopHomeEvent, ShopHomeState&gt; {
24 26 on<RequestDataEvent>(_requestData);
25 27 }
26 28  
27   - void _requestData(RequestDataEvent event, Emitter<ShopHomeState> emitter) async {
  29 + void _requestData(
  30 + RequestDataEvent event, Emitter<ShopHomeState> emitter) async {
28 31 try {
29 32 await loading(() async {
30 33 _productDatas = await ShopDao.productList() ?? [];
... ...
lib/pages/shop/home/shop_home_page.dart
... ... @@ -44,7 +44,10 @@ class _ShopHomeView extends StatelessWidget {
44 44 ),
45 45 color: Colors.white,
46 46 onPressed: () {
47   - Navigator.of(context).pushNamed(AppRouteName.exLesson);
  47 + pushNamed(AppRouteName.exLesson).then((value) => {
  48 + if (value != null)
  49 + {bloc.exchangeResult = value['exchange']}
  50 + });
48 51 },
49 52 ),
50 53 IconButton(
... ... @@ -59,6 +62,9 @@ class _ShopHomeView extends StatelessWidget {
59 62 },
60 63 )
61 64 ],
  65 + onBack: () {
  66 + popPage(data: {'exchange': bloc.exchangeResult});
  67 + },
62 68 ),
63 69 body: Center(
64 70 child: Padding(
... ... @@ -73,9 +79,11 @@ class _ShopHomeView extends StatelessWidget {
73 79 ),
74 80 itemBuilder: (BuildContext context, int index) {
75 81 final productEntity = bloc.productDatas[index];
76   - return ProductItem(onTap: () {
77   - pushNamed(AppRouteName.pay, arguments: productEntity);
78   - }, entity: productEntity);
  82 + return ProductItem(
  83 + onTap: () {
  84 + pushNamed(AppRouteName.pay, arguments: productEntity);
  85 + },
  86 + entity: productEntity);
79 87 }),
80 88 ),
81 89 ),
... ...
lib/pages/unit/bloc.dart
... ... @@ -12,7 +12,6 @@ import &#39;event.dart&#39;;
12 12 import 'state.dart';
13 13  
14 14 class UnitBloc extends Bloc<UnitEvent, UnitState> {
15   -
16 15 CourseModuleEntity? _moduleEntity;
17 16  
18 17 CourseModuleEntity? get moduleEntity => _moduleEntity;
... ... @@ -21,12 +20,14 @@ class UnitBloc extends Bloc&lt;UnitEvent, UnitState&gt; {
21 20  
22 21 CourseUnitEntity? get unitData => _unitData;
23 22  
  23 + bool exchangeResult = false;
24 24  
25 25 UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) {
26 26 on<RequestUnitDataEvent>(_requestUnitDatas);
27 27 }
28 28  
29   - void _requestUnitDatas(RequestUnitDataEvent event, Emitter<UnitState> emitter) async {
  29 + void _requestUnitDatas(
  30 + RequestUnitDataEvent event, Emitter<UnitState> emitter) async {
30 31 try {
31 32 await loading(() async {
32 33 _unitData = await LessonDao.courseUnit(event.moduleId);
... ... @@ -51,7 +52,8 @@ class UnitBloc extends Bloc&lt;UnitEvent, UnitState&gt; {
51 52 } else if (type == HeaderActionType.listen) {
52 53 pushNamed(AppRouteName.listen);
53 54 } else if (type == HeaderActionType.shop) {
54   - pushNamed(AppRouteName.shop);
  55 + pushNamed(AppRouteName.shop)
  56 + .then((value) => {exchangeResult = value['exchange']});
55 57 } else if (type == HeaderActionType.user) {
56 58 pushNamed(AppRouteName.user);
57 59 }
... ...
lib/pages/unit/view.dart
... ... @@ -40,6 +40,9 @@ class UnitPage extends StatelessWidget {
40 40 children: [
41 41 HomeTabHeaderWidget(
42 42 courseModuleCode: bloc.getCourseModuleCode(),
  43 + onBack: () {
  44 + popPage(data: {'exchange': bloc.exchangeResult});
  45 + },
43 46 actionTap: (HeaderActionType type) {
44 47 bloc.headerActionEvent(type);
45 48 },
... ... @@ -67,10 +70,12 @@ class UnitPage extends StatelessWidget {
67 70 'courseUnitId': data.id
68 71 }).then((value) {
69 72 if (value != null) {
70   - Map<String, dynamic> dataMap = value as Map<String, dynamic>;
  73 + Map<String, dynamic> dataMap =
  74 + value as Map<String, dynamic>;
71 75 bool needRefresh = dataMap['needRefresh'];
72 76 if (needRefresh) {
73   - bloc.add(RequestUnitDataEvent(courseModuleEntity?.id));
  77 + bloc.add(RequestUnitDataEvent(
  78 + courseModuleEntity?.id));
74 79 }
75 80 }
76 81 });
... ...
lib/pages/unit/widget/home_tab_header_widget.dart
... ... @@ -21,12 +21,13 @@ enum HeaderActionType {
21 21 }
22 22  
23 23 class HomeTabHeaderWidget extends StatelessWidget {
24   - const HomeTabHeaderWidget({super.key, this.courseModuleCode, this.actionTap});
  24 + const HomeTabHeaderWidget(
  25 + {super.key, this.courseModuleCode, this.actionTap, this.onBack});
25 26  
26 27 final String? courseModuleCode;
27 28  
28 29 final Function(HeaderActionType type)? actionTap;
29   -
  30 + final VoidCallback? onBack;
30 31 @override
31 32 Widget build(BuildContext context) {
32 33 return BlocBuilder<UserBloc, UserState>(
... ... @@ -34,15 +35,18 @@ class HomeTabHeaderWidget extends StatelessWidget {
34 35 return Container(
35 36 height: 45,
36 37 width: double.infinity,
37   - color:
38   - CourseModuleModel(courseModuleCode ?? 'Phase-1').color,
  38 + color: CourseModuleModel(courseModuleCode ?? 'Phase-1').color,
39 39 padding: EdgeInsets.symmetric(horizontal: 9.5.w),
40 40 child: Row(
41 41 children: [
42 42 ScreenUtil().bottomBarHeight.horizontalSpace,
43 43 GestureDetector(
44 44 onTap: () {
45   - Navigator.pop(context);
  45 + if (onBack == null) {
  46 + Navigator.pop(context);
  47 + } else {
  48 + onBack!();
  49 + }
46 50 },
47 51 child: Container(
48 52 alignment: Alignment.center,
... ... @@ -65,21 +69,25 @@ class HomeTabHeaderWidget extends StatelessWidget {
65 69 onTap: () {
66 70 if (actionTap != null) {
67 71 actionTap!(HeaderActionType.phase);
68   - };
  72 + }
69 73 },
70   - child: Image(image: AssetImage('home'.assetPng),
71   - width: 36.0.w, height: 36.0.h, fit: BoxFit.contain)
72   - ),
  74 + child: Image(
  75 + image: AssetImage('home'.assetPng),
  76 + width: 36.0.w,
  77 + height: 36.0.h,
  78 + fit: BoxFit.contain)),
73 79 8.horizontalSpace,
74 80 GestureDetector(
75   - onTap: () {
76   - if (actionTap != null) {
77   - actionTap!(HeaderActionType.listen);
78   - };
79   - },
80   - child: Image(image: AssetImage('listen'.assetPng),
81   - width: 36.0.w, height: 36.0.h, fit: BoxFit.contain)
82   - ),
  81 + onTap: () {
  82 + if (actionTap != null) {
  83 + actionTap!(HeaderActionType.listen);
  84 + }
  85 + },
  86 + child: Image(
  87 + image: AssetImage('listen'.assetPng),
  88 + width: 36.0.w,
  89 + height: 36.0.h,
  90 + fit: BoxFit.contain)),
83 91 8.horizontalSpace,
84 92 Offstage(
85 93 offstage: AppConfigHelper.shouldHidePay(),
... ... @@ -87,11 +95,13 @@ class HomeTabHeaderWidget extends StatelessWidget {
87 95 onTap: () {
88 96 if (actionTap != null) {
89 97 actionTap!(HeaderActionType.shop);
90   - };
  98 + }
91 99 },
92   - child: Image(image: AssetImage('shop'.assetPng),
93   - width: 36.0.w, height: 36.0.h, fit: BoxFit.contain)
94   - ),
  100 + child: Image(
  101 + image: AssetImage('shop'.assetPng),
  102 + width: 36.0.w,
  103 + height: 36.0.h,
  104 + fit: BoxFit.contain)),
95 105 ),
96 106 ScreenUtil().bottomBarHeight.horizontalSpace,
97 107 ],
... ...
lib/pages/user/bloc/user_bloc.dart
... ... @@ -16,6 +16,7 @@ class UserBloc extends Bloc&lt;UserEvent, UserState&gt; {
16 16  
17 17 UserEntity? get userEntityForPay => _userEntityForPay;
18 18  
  19 + bool exchangeResult = false;
19 20 UserBloc() : super(UserInitial()) {
20 21 on<UserLogout>(_logout);
21 22 on<UserDelete>(_deleteAccount);
... ... @@ -37,7 +38,8 @@ class UserBloc extends Bloc&lt;UserEvent, UserState&gt; {
37 38 }
38 39  
39 40 void _updateUser(UserUpdate event, Emitter<UserState> emitter) async {
40   - Log.d('_updateUser, event: ${event.type}, emitter.isDone: ${emitter.isDone}, text=${event.content}');
  41 + Log.d(
  42 + '_updateUser, event: ${event.type}, emitter.isDone: ${emitter.isDone}, text=${event.content}');
41 43 UserEntity user = UserUtil.getUser()!;
42 44 try {
43 45 switch (event.type) {
... ... @@ -84,7 +86,8 @@ class UserBloc extends Bloc&lt;UserEvent, UserState&gt; {
84 86 }
85 87  
86 88 //支付状态变化
87   - void _patStateChanged(PayStateChangeEvent event, Emitter<UserState> emitter) async {
  89 + void _patStateChanged(
  90 + PayStateChangeEvent event, Emitter<UserState> emitter) async {
88 91 // 由于userInfo接口不会返回token,所以这里需要再次保存一下token
89 92 final token = UserUtil.getUser()?.token;
90 93 _userEntityForPay = await UserDao.getUserInfo();
... ...
lib/pages/user/user_page.dart
... ... @@ -29,7 +29,8 @@ class _UserView extends StatelessWidget {
29 29 final String bannerUrl = '';
30 30  
31 31 /// 方法
32   - final MethodChannel methodChannel = const MethodChannel('wow_english/game_method_channel');
  32 + final MethodChannel methodChannel =
  33 + const MethodChannel('wow_english/game_method_channel');
33 34  
34 35 @override
35 36 Widget build(BuildContext context) {
... ... @@ -37,34 +38,41 @@ class _UserView extends StatelessWidget {
37 38 }
38 39  
39 40 Widget _pageWidget() => BlocBuilder<UserBloc, UserState>(
40   - builder: (context, state) {
41   - UserEntity user = UserUtil.getUser()!;
42   - final userBloc = BlocProvider.of<UserBloc>(context);
  41 + builder: (context, state) {
  42 + UserEntity user = UserUtil.getUser()!;
  43 + final userBloc = BlocProvider.of<UserBloc>(context);
43 44  
44   - // 常规按钮的字体样式
45   - final textStyle21sp = TextStyle(
46   - //fontWeight: FontWeight.w600,
47   - color: const Color(0xFF333333),
48   - fontSize: 21.sp,
49   - );
  45 + // 常规按钮的字体样式
  46 + final textStyle21sp = TextStyle(
  47 + //fontWeight: FontWeight.w600,
  48 + color: const Color(0xFF333333),
  49 + fontSize: 21.sp,
  50 + );
50 51  
51   - // 常规按钮的样式
52   - var normalButtonStyle = ButtonStyle(
53   - side: MaterialStateProperty.all(BorderSide(color: const Color(0xFF140C10), width: 1.5.w)),
54   - shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
55   - minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)),
56   - backgroundColor: MaterialStateProperty.all(Colors.white),
57   - );
  52 + // 常规按钮的样式
  53 + var normalButtonStyle = ButtonStyle(
  54 + side: MaterialStateProperty.all(
  55 + BorderSide(color: const Color(0xFF140C10), width: 1.5.w)),
  56 + shape: MaterialStateProperty.all(RoundedRectangleBorder(
  57 + borderRadius: BorderRadius.circular(15.r))),
  58 + minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)),
  59 + backgroundColor: MaterialStateProperty.all(Colors.white),
  60 + );
58 61  
59   - return Scaffold(
60   - appBar: const WEAppBar(),
61   - body: SingleChildScrollView(
62   - padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 10.h, bottom: 22.h),
63   - child: Column(
64   - mainAxisAlignment: MainAxisAlignment.center,
65   - children: <Widget>[
66   - // todo banner,暂时没有接口获取banner URL
67   - /*Offstage(
  62 + return Scaffold(
  63 + appBar: WEAppBar(
  64 + onBack: () {
  65 + popPage(data: {'exchange': userBloc.exchangeResult});
  66 + },
  67 + ),
  68 + body: SingleChildScrollView(
  69 + padding: EdgeInsets.only(
  70 + left: 17.w, right: 17.w, top: 10.h, bottom: 22.h),
  71 + child: Column(
  72 + mainAxisAlignment: MainAxisAlignment.center,
  73 + children: <Widget>[
  74 + // todo banner,暂时没有接口获取banner URL
  75 + /*Offstage(
68 76 child: Column(
69 77 children: [
70 78 Container(child: Image.asset(bannerUrl), constraints: BoxConstraints(maxHeight: 196.h)),
... ... @@ -72,23 +80,25 @@ class _UserView extends StatelessWidget {
72 80 ],
73 81 ),
74 82 ),*/
75   - Row(
76   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
77   - children: [
78   - CircleAvatar(
79   - radius: 40.r,
80   - backgroundColor: const Color(0xFF140C10),
81   - child: CircleAvatar(
82   - radius: 38.5.r,
83   - backgroundImage: ImageUtil.getImageProviderOnDefault(user.avatarUrl),
84   - ),
85   - /*child: ClipOval(
  83 + Row(
  84 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  85 + children: [
  86 + CircleAvatar(
  87 + radius: 40.r,
  88 + backgroundColor: const Color(0xFF140C10),
  89 + child: CircleAvatar(
  90 + radius: 38.5.r,
  91 + backgroundImage:
  92 + ImageUtil.getImageProviderOnDefault(
  93 + user.avatarUrl),
  94 + ),
  95 + /*child: ClipOval(
86 96 child: OwImageWidget(name: user.avatarUrl ?? AssetsConst.wowLogo, fit: BoxFit.contain,),
87 97 )*/
88   - ),
89   - 32.horizontalSpace,
90   - Expanded(
91   - child: Column(
  98 + ),
  99 + 32.horizontalSpace,
  100 + Expanded(
  101 + child: Column(
92 102 children: [
93 103 Row(
94 104 children: [
... ... @@ -108,7 +118,8 @@ class _UserView extends StatelessWidget {
108 118 ),
109 119 14.horizontalSpace,
110 120 Offstage(
111   - offstage: user.effectiveDate == null || AppConfigHelper.shouldHidePay(),
  121 + offstage: user.effectiveDate == null ||
  122 + AppConfigHelper.shouldHidePay(),
112 123 child: Image.asset(
113 124 AssetsConst.icVip,
114 125 height: 18.h,
... ... @@ -117,7 +128,8 @@ class _UserView extends StatelessWidget {
117 128 ],
118 129 ),
119 130 Offstage(
120   - offstage: user.effectiveDate == null || AppConfigHelper.shouldHidePay(),
  131 + offstage: user.effectiveDate == null ||
  132 + AppConfigHelper.shouldHidePay(),
121 133 child: Row(
122 134 children: [
123 135 Text(
... ... @@ -132,132 +144,158 @@ class _UserView extends StatelessWidget {
132 144 )
133 145 ],
134 146 )),
135   - TextButton(
  147 + TextButton(
  148 + child: Text(
  149 + "修改个人信息>",
  150 + style: textStyle21sp,
  151 + ),
  152 + onPressed: () {
  153 + pushNamed(AppRouteName.userInformation);
  154 + },
  155 + )
  156 + ],
  157 + ),
  158 + 30.verticalSpace,
  159 + // 打开游戏界面 供审核用
  160 + ((UserUtil.getUser()?.phoneNum == '17730280759' ||
  161 + UserUtil.getUser()?.phoneNum == '17718485544')
  162 + ? OutlinedButton(
  163 + onPressed: () {
  164 + methodChannel
  165 + .invokeMethod('openGamePage', {"gameId": 1});
  166 + },
  167 + style: normalButtonStyle,
  168 + child: Text(
  169 + "进入游戏",
  170 + style: textStyle21sp,
  171 + ),
  172 + )
  173 + : 1.verticalSpace),
  174 + ((UserUtil.getUser()?.phoneNum == '17730280759' ||
  175 + UserUtil.getUser()?.phoneNum == '17718485544')
  176 + ? 12.verticalSpace
  177 + : 1.verticalSpace),
  178 + OutlinedButton(
  179 + onPressed: () => pushNamed(AppRouteName.fogPwd),
  180 + style: normalButtonStyle,
136 181 child: Text(
137   - "修改个人信息>",
  182 + "修改密码",
138 183 style: textStyle21sp,
139 184 ),
140   - onPressed: () {
141   - pushNamed(AppRouteName.userInformation);
142   - },
143   - )
  185 + ),
  186 + 12.verticalSpace,
  187 + Offstage(
  188 + offstage: AppConfigHelper.shouldHidePay(),
  189 + child: OutlinedButton(
  190 + onPressed: () =>
  191 + pushNamed(AppRouteName.exLesson).then((value) => {
  192 + if (value != null)
  193 + {
  194 + userBloc.exchangeResult =
  195 + value['exchange']
  196 + }
  197 + }),
  198 + style: normalButtonStyle,
  199 + child: Text(
  200 + "兑换课程",
  201 + style: textStyle21sp,
  202 + )),
  203 + ),
  204 + Offstage(
  205 + offstage: AppConfigHelper.shouldHidePay(),
  206 + child: 12.verticalSpace,
  207 + ),
  208 + OutlinedButton(
  209 + onPressed: () {
  210 + pushNamed(AppRouteName.webView, arguments: {
  211 + 'urlStr': AppConsts.userPrivacyPolicyUrl,
  212 + 'webViewTitle': '隐私协议'
  213 + });
  214 + },
  215 + style: normalButtonStyle,
  216 + child: Text(
  217 + "隐私协议",
  218 + style: textStyle21sp,
  219 + )),
  220 + 12.verticalSpace,
  221 + OutlinedButton(
  222 + onPressed: () {
  223 + String phone = 'tel:+8618856084180';
  224 + _launchPhone(phone);
  225 + },
  226 + style: normalButtonStyle,
  227 + child: Text(
  228 + "联系客服",
  229 + style: textStyle21sp,
  230 + )),
  231 + 12.verticalSpace,
  232 + OutlinedButton(
  233 + onPressed: () {
  234 + pushNamed(AppRouteName.setting);
  235 + },
  236 + style: normalButtonStyle,
  237 + child: Text(
  238 + "设置",
  239 + style: textStyle21sp,
  240 + )),
  241 + 30.verticalSpace,
  242 + OutlinedButton(
  243 + onPressed: () {
  244 + showTwoActionDialog(
  245 + barrierDismissible: false,
  246 + '提示',
  247 + '取消',
  248 + '确认',
  249 + '您确认要退出Wow English吗?', leftTap: () {
  250 + popPage();
  251 + }, rightTap: () {
  252 + popPage();
  253 + userBloc.add(UserLogout());
  254 + });
  255 + },
  256 + style: ButtonStyle(
  257 + side: MaterialStateProperty.all(const BorderSide(
  258 + color: Color(0xFF140C10), width: 1.5)),
  259 + shape: MaterialStateProperty.all(
  260 + RoundedRectangleBorder(
  261 + borderRadius: BorderRadius.circular(15.r))),
  262 + minimumSize:
  263 + MaterialStateProperty.all(Size(295.w, 40.h)),
  264 + backgroundColor: MaterialStateProperty.all(
  265 + const Color(0xFFFBB621)),
  266 + ),
  267 + child: Text(
  268 + "退出登录",
  269 + style: TextStyle(
  270 + //fontWeight: FontWeight.w600,
  271 + color: Colors.white,
  272 + fontSize: 17.sp,
  273 + ),
  274 + )),
  275 + // 30.verticalSpace,
  276 + // TextButton(
  277 + // onPressed: () {
  278 + // //userBloc.add(UserDelete())
  279 + // showTwoActionDialog('注销账号', '取消', '注销', '请谨慎操作!\n注销后不可恢复哦!', () {
  280 + // popPage();
  281 + // }, () {
  282 + // userBloc.add(UserDelete());
  283 + // popPage();
  284 + // });
  285 + // },
  286 + // child: Text(
  287 + // "注销账号",
  288 + // style: TextStyle(
  289 + // //fontWeight: FontWeight.w600,
  290 + // color: Colors.red,
  291 + // fontSize: 15.sp,
  292 + // ),
  293 + // )),
144 294 ],
145 295 ),
146   - 30.verticalSpace,
147   - // 打开游戏界面 供审核用
148   - ((UserUtil.getUser()?.phoneNum == '17730280759' || UserUtil.getUser()?.phoneNum == '17718485544') ? OutlinedButton(
149   - onPressed: () {
150   - methodChannel.invokeMethod('openGamePage', { "gameId": 1 });
151   - },
152   - style: normalButtonStyle,
153   - child: Text(
154   - "进入游戏",
155   - style: textStyle21sp,
156   - ),
157   - ) : 1.verticalSpace),
158   - ((UserUtil.getUser()?.phoneNum == '17730280759' || UserUtil.getUser()?.phoneNum == '17718485544') ? 12.verticalSpace : 1.verticalSpace),
159   - OutlinedButton(
160   - onPressed: () => pushNamed(AppRouteName.fogPwd),
161   - style: normalButtonStyle,
162   - child: Text(
163   - "修改密码",
164   - style: textStyle21sp,
165   - ),
166   - ),
167   - 12.verticalSpace,
168   - Offstage(
169   - offstage: AppConfigHelper.shouldHidePay(),
170   - child: OutlinedButton(
171   - onPressed: () => pushNamed(AppRouteName.exLesson),
172   - style: normalButtonStyle,
173   - child: Text(
174   - "兑换课程",
175   - style: textStyle21sp,
176   - )),
177   - ),
178   - Offstage(
179   - offstage: AppConfigHelper.shouldHidePay(),
180   - child: 12.verticalSpace,
181   - ),
182   - OutlinedButton(
183   - onPressed: () {
184   - pushNamed(AppRouteName.webView,arguments: {'urlStr': AppConsts.userPrivacyPolicyUrl, 'webViewTitle': '隐私协议'});
185   - },
186   - style: normalButtonStyle,
187   - child: Text(
188   - "隐私协议",
189   - style: textStyle21sp,
190   - )),
191   - 12.verticalSpace,
192   - OutlinedButton(
193   - onPressed: () {
194   - String phone ='tel:+8618827093087';
195   - _launchPhone(phone);
196   - },
197   - style: normalButtonStyle,
198   - child: Text(
199   - "联系客服",
200   - style: textStyle21sp,
201   - )),
202   - 12.verticalSpace,
203   - OutlinedButton(
204   - onPressed: () {
205   - pushNamed(AppRouteName.setting);
206   - },
207   - style: normalButtonStyle,
208   - child: Text(
209   - "设置",
210   - style: textStyle21sp,
211   - )),
212   - 30.verticalSpace,
213   - OutlinedButton(
214   - onPressed: () {
215   - showTwoActionDialog(barrierDismissible:false,'提示', '取消', '确认', '您确认要退出Wow English吗?',leftTap: (){
216   - popPage();
217   - },rightTap: (){
218   - popPage();
219   - userBloc.add(UserLogout());
220   - });
221   - },
222   - style: ButtonStyle(
223   - side: MaterialStateProperty.all(const BorderSide(color: Color(0xFF140C10), width: 1.5)),
224   - shape: MaterialStateProperty.all(
225   - RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
226   - minimumSize: MaterialStateProperty.all(Size(295.w, 40.h)),
227   - backgroundColor: MaterialStateProperty.all(const Color(0xFFFBB621)),
228   - ),
229   - child: Text(
230   - "退出登录",
231   - style: TextStyle(
232   - //fontWeight: FontWeight.w600,
233   - color: Colors.white,
234   - fontSize: 17.sp,
235   - ),
236   - )),
237   - // 30.verticalSpace,
238   - // TextButton(
239   - // onPressed: () {
240   - // //userBloc.add(UserDelete())
241   - // showTwoActionDialog('注销账号', '取消', '注销', '请谨慎操作!\n注销后不可恢复哦!', () {
242   - // popPage();
243   - // }, () {
244   - // userBloc.add(UserDelete());
245   - // popPage();
246   - // });
247   - // },
248   - // child: Text(
249   - // "注销账号",
250   - // style: TextStyle(
251   - // //fontWeight: FontWeight.w600,
252   - // color: Colors.red,
253   - // fontSize: 15.sp,
254   - // ),
255   - // )),
256   - ],
257   - ),
258   - ));
259   - },
260   - );
  296 + ));
  297 + },
  298 + );
261 299  
262 300 void _launchPhone(String phone) async {
263 301 if (await canLaunchUrl(Uri.parse(phone))) {
... ...