Commit da82bd70e6b3907583c46519e8e7c34aa8d15514
1 parent
b90a1518
feat: user_information_page.dart
fixed: appbar style
Showing
22 changed files
with
257 additions
and
42 deletions
assets/images/bg_user_information_text.png
0 → 100644
31.9 KB
assets/images/ic_next.png
0 → 100644
3.99 KB
lib/app/app.dart
... | ... | @@ -4,6 +4,7 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; |
4 | 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
5 | 5 | import 'package:responsive_framework/breakpoint.dart'; |
6 | 6 | import 'package:responsive_framework/responsive_breakpoints.dart'; |
7 | +import 'package:wow_english/common/blocs/cachebloc/cache_bloc.dart'; | |
7 | 8 | import 'package:wow_english/common/widgets/hide_keyboard_widget.dart'; |
8 | 9 | import 'package:wow_english/pages/tab/blocs/tab_bloc.dart'; |
9 | 10 | import 'package:wow_english/route/route.dart'; |
... | ... | @@ -18,6 +19,7 @@ class App extends StatelessWidget { |
18 | 19 | builder: (_, __) => MultiBlocProvider( |
19 | 20 | providers: [ |
20 | 21 | BlocProvider<TabBloc>(create: (_) => TabBloc()), |
22 | + BlocProvider<CacheBloc>(create: (_) => CacheBloc()), | |
21 | 23 | ], |
22 | 24 | child: HideKeyboard( |
23 | 25 | child: MaterialApp( | ... | ... |
lib/common/blocs/cachebloc/cache_bloc.dart
lib/common/blocs/cachebloc/cache_event.dart
lib/common/blocs/cachebloc/cache_state.dart
lib/common/core/assets_const.dart
... | ... | @@ -2,5 +2,7 @@ class AssetsConst { |
2 | 2 | static const String _assetImagePrefix = 'assets/images/'; |
3 | 3 | static const String wowLogo = '${_assetImagePrefix}wow_logo.png'; |
4 | 4 | static const String icVip = '${_assetImagePrefix}ic_vip.png'; |
5 | + static const String icNext = '${_assetImagePrefix}ic_next.png'; | |
6 | + static const String bgUserInformationText = '${_assetImagePrefix}bg_user_information_text.png'; | |
5 | 7 | //static String get icVip2 =>'ic_vip.png'.assetImg; |
6 | 8 | } | ... | ... |
lib/common/request/apis.dart
... | ... | @@ -25,11 +25,14 @@ class Apis { |
25 | 25 | static const String initPassword = 'student/init/password'; |
26 | 26 | |
27 | 27 | /// 修改密码 |
28 | - static const String changePassword = 'student/init/password'; | |
28 | + static const String changePassword = 'student/change/password'; | |
29 | 29 | |
30 | 30 | /// 忘记密码 |
31 | 31 | static const String resetPassword = 'student/change/password'; |
32 | 32 | |
33 | + /// 校验验证码,用于修改密码或忘记密码,验证码有效期2分钟 | |
34 | + static const String checkSmsCode = 'student/check/code'; | |
35 | + | |
33 | 36 | /// 课程模块 |
34 | 37 | // GET /home/courseModule |
35 | 38 | // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897663 | ... | ... |
lib/common/request/dao/user_dao.dart
... | ... | @@ -3,6 +3,8 @@ import 'package:wow_english/models/user_entity.dart'; |
3 | 3 | |
4 | 4 | import '../request_client.dart'; |
5 | 5 | |
6 | +enum SmsType { login, change_passWord, stdDestroy } | |
7 | + | |
6 | 8 | class UserDao { |
7 | 9 | /// 登录 |
8 | 10 | static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) async { |
... | ... | @@ -26,6 +28,7 @@ class UserDao { |
26 | 28 | } |
27 | 29 | |
28 | 30 | /// 发送验证码 |
31 | + /// [msgType] 消息类型 登录:login, 更改密码:change_passWord, 账号注销:stdDestroy | |
29 | 32 | static Future sendCode(phoneNumber, {smsType = 'login'}) async { |
30 | 33 | final params = {'phoneNum': phoneNumber, 'smsType': smsType}; |
31 | 34 | await requestClient.post(Apis.sendSmsCode, data: params); |
... | ... | @@ -39,19 +42,30 @@ class UserDao { |
39 | 42 | } |
40 | 43 | |
41 | 44 | /// 修改密码 |
45 | + /// [phoneNum] 手机号 | |
42 | 46 | /// [password] 密码 |
43 | - static Future changePassword(String password) async { | |
44 | - final params = {'password': password}; | |
47 | + /// [smsCode] 短信验证码 | |
48 | + static Future changePassword(String phoneNum, String password, String smsCode) async { | |
49 | + final params = {'phoneNum': phoneNum, 'password': password, 'code': smsCode}; | |
45 | 50 | await requestClient.post(Apis.changePassword, data: params); |
46 | 51 | } |
47 | 52 | |
48 | 53 | /// 忘记密码 |
54 | + /// [phoneNum] 手机号 | |
49 | 55 | /// [password] 密码 |
56 | + /// [smsCode] 短信验证码 | |
50 | 57 | static Future resetPassword(String phoneNum, String password, String smsCode) async { |
51 | 58 | final params = {'phoneNum': phoneNum, 'password': password, 'code': smsCode}; |
52 | 59 | await requestClient.post(Apis.resetPassword, data: params); |
53 | 60 | } |
54 | 61 | |
62 | + /// 验证短信验证码 | |
63 | + /// [msgType] 消息类型 登录:login, 更改密码:change_passWord, 账号注销:stdDestroy | |
64 | + static Future checkSmsCode(String phoneNum, String smsCode, String msgType) async { | |
65 | + final params = {'phoneNum': phoneNum, 'code': smsCode, 'msgType': msgType}; | |
66 | + await requestClient.post(Apis.checkSmsCode, data: params); | |
67 | + } | |
68 | + | |
55 | 69 | /// 获取用户信息 |
56 | 70 | static Future<UserEntity?> getUserInfo() async { |
57 | 71 | return await requestClient.post(Apis.getUserInfo); | ... | ... |
lib/common/widgets/we_app_bar.dart
1 | 1 | import 'package:flutter/material.dart'; |
2 | +import 'package:flutter_screenutil/flutter_screenutil.dart'; | |
2 | 3 | import 'package:wow_english/common/extension/string_extension.dart'; |
3 | 4 | |
4 | 5 | class WEAppBar extends StatelessWidget implements PreferredSizeWidget { |
... | ... | @@ -9,41 +10,49 @@ class WEAppBar extends StatelessWidget implements PreferredSizeWidget { |
9 | 10 | final PreferredSizeWidget? bottom; |
10 | 11 | final Widget? leading; |
11 | 12 | final List<Widget>? actions; |
12 | - const WEAppBar({ | |
13 | - this.titleText, | |
14 | - this.centerTitle = true, | |
15 | - this.onBack, | |
16 | - this.backgroundColor, | |
17 | - this.bottom, | |
18 | - this.leading, | |
19 | - this.actions, | |
20 | - super.key}); | |
13 | + | |
14 | + const WEAppBar( | |
15 | + {this.titleText, | |
16 | + this.centerTitle = true, | |
17 | + this.onBack, | |
18 | + this.backgroundColor, | |
19 | + this.bottom, | |
20 | + this.leading, | |
21 | + this.actions, | |
22 | + super.key}); | |
21 | 23 | |
22 | 24 | @override |
23 | 25 | Widget build(BuildContext context) { |
24 | 26 | return AppBar( |
25 | 27 | centerTitle: centerTitle, |
26 | - title: Text(titleText??''), | |
27 | - leading: leading??GestureDetector( | |
28 | - onTap: () { | |
29 | - Navigator.pop(context); | |
30 | - }, | |
31 | - child: Container( | |
32 | - alignment: Alignment.center, | |
33 | - child: Image.asset( | |
34 | - 'back_around'.assetPng, | |
35 | - height: 40, | |
36 | - width: 40, | |
37 | - ), | |
28 | + title: Text( | |
29 | + titleText ?? '', | |
30 | + style: TextStyle( | |
31 | + fontSize: 25.sp, | |
32 | + color: const Color(0xFF333333), | |
33 | + fontWeight: FontWeight.w700, | |
38 | 34 | ), |
39 | 35 | ), |
40 | - backgroundColor: backgroundColor??Colors.white, | |
41 | - actions: actions??[], | |
36 | + leading: leading ?? | |
37 | + GestureDetector( | |
38 | + onTap: () { | |
39 | + Navigator.pop(context); | |
40 | + }, | |
41 | + child: Container( | |
42 | + alignment: Alignment.center, | |
43 | + child: Image.asset( | |
44 | + 'back_around'.assetPng, | |
45 | + height: 40.h, | |
46 | + width: 40.w, | |
47 | + ), | |
48 | + ), | |
49 | + ), | |
50 | + backgroundColor: backgroundColor ?? Colors.white, | |
51 | + actions: actions ?? [], | |
42 | 52 | ); |
43 | 53 | } |
44 | 54 | |
45 | 55 | @override |
46 | 56 | // TODO: implement preferredSize |
47 | - Size get preferredSize => Size.fromHeight( | |
48 | - kToolbarHeight + (bottom == null ? 0.0 : bottom!.preferredSize.height)); | |
49 | -} | |
50 | 57 | \ No newline at end of file |
58 | + Size get preferredSize => Size.fromHeight(kToolbarHeight + (bottom == null ? 0.0 : bottom!.preferredSize.height)); | |
59 | +} | ... | ... |
lib/models/user_entity.dart
lib/pages/home/widgets/home_tab_header_widget.dart
... | ... | @@ -63,7 +63,7 @@ class HomeTabHeaderWidget extends StatelessWidget { |
63 | 63 | border: Border.all(width: 1.0, color: const Color(0xFF140C10), style: BorderStyle.solid), |
64 | 64 | ), |
65 | 65 | child: Text( |
66 | - UserUtil.getUser()?.name ?? '姓名丢了', | |
66 | + UserUtil.getUser()?.name ?? '未登录', | |
67 | 67 | style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp), |
68 | 68 | ), |
69 | 69 | ), | ... | ... |
lib/pages/login/forgetpwd/forget_password_home_page.dart
... | ... | @@ -39,7 +39,8 @@ class _ForgetPasswordHomePageView extends StatelessWidget { |
39 | 39 | return; |
40 | 40 | } |
41 | 41 | // todo 后续需要改成在当前页面,验证过验证码后,再跳转到设置密码页面 |
42 | - SetPassWordPage.push(context, SetPwdPageType.changePwd, phoneNum: phoneNum, smsCode: smsCode); | |
42 | + // change_passWord | |
43 | + SetPassWordPage.push(context, SetPwdPageType.resetPwd, phoneNum: phoneNum, smsCode: smsCode); | |
43 | 44 | } |
44 | 45 | }, |
45 | 46 | child: _buildForgetPwdView(), | ... | ... |
lib/pages/login/setpwd/bloc/set_pwd_bloc.dart
... | ... | @@ -131,12 +131,13 @@ class SetPwdBloc extends Bloc<SetPwdEvent, SetPwdState> { |
131 | 131 | try { |
132 | 132 | await loading(() async { |
133 | 133 | switch (pageType) { |
134 | - case SetPwdPageType.changePwd: | |
135 | - await UserDao.changePassword(passwordText); | |
136 | - break; | |
137 | 134 | case SetPwdPageType.initPwd: |
138 | 135 | await UserDao.initPassword(passwordText); |
139 | 136 | break; |
137 | + case SetPwdPageType.changePwd: | |
138 | + // 现在走同一个流程和接口 | |
139 | + /*await UserDao.changePassword(passwordText); | |
140 | + break;*/ | |
140 | 141 | case SetPwdPageType.resetPwd: |
141 | 142 | if (phoneNumber == null || phoneNumber!.isEmpty) { |
142 | 143 | throw ApiException(ApiException.customErrorCode, '手机号为空'); | ... | ... |
lib/pages/login/setpwd/set_pwd_page.dart
... | ... | @@ -15,7 +15,7 @@ enum SetPwdPageType { |
15 | 15 | /// 忘记重设密码,必传手机号和验证码 |
16 | 16 | resetPwd, |
17 | 17 | |
18 | - /// 修改密码 | |
18 | + /// 修改密码,必传手机号和验证码,现在和忘记密码走一样的流程 | |
19 | 19 | changePwd, |
20 | 20 | } |
21 | 21 | |
... | ... | @@ -67,7 +67,7 @@ class _SetPassWordPageView extends StatelessWidget { |
67 | 67 | } |
68 | 68 | |
69 | 69 | String _getTipsText() { |
70 | - String text = ''; | |
70 | + String text = '接下来请设置一下您的新密码吧!'; | |
71 | 71 | |
72 | 72 | switch (bloc.pageType) { |
73 | 73 | case SetPwdPageType.initPwd: | ... | ... |
lib/pages/practice/topic_picture_page.dart
lib/pages/user/information/user_information_bloc.dart
0 → 100644
1 | +import 'package:bloc/bloc.dart'; | |
2 | +import 'package:meta/meta.dart'; | |
3 | + | |
4 | +part 'user_information_event.dart'; | |
5 | +part 'user_information_state.dart'; | |
6 | + | |
7 | +class UserInformationBloc extends Bloc<UserInformationEvent, UserInformationState> { | |
8 | + UserInformationBloc() : super(UserInformationInitial()) { | |
9 | + on<UserInformationEvent>((event, emit) { | |
10 | + // TODO: implement event handler | |
11 | + }); | |
12 | + } | |
13 | +} | ... | ... |
lib/pages/user/information/user_information_event.dart
0 → 100644
lib/pages/user/information/user_information_page.dart
0 → 100644
1 | +import 'package:flutter/material.dart'; | |
2 | +import 'package:flutter_bloc/flutter_bloc.dart'; | |
3 | +import 'package:flutter_screenutil/flutter_screenutil.dart'; | |
4 | +import 'package:wow_english/common/core/assets_const.dart'; | |
5 | +import 'package:wow_english/common/core/user_util.dart'; | |
6 | +import 'package:wow_english/common/widgets/we_app_bar.dart'; | |
7 | +import 'package:wow_english/models/user_entity.dart'; | |
8 | +import 'package:wow_english/utils/image_util.dart'; | |
9 | + | |
10 | +import 'user_information_bloc.dart'; | |
11 | + | |
12 | +class UserInformationPage extends StatelessWidget { | |
13 | + const UserInformationPage({super.key}); | |
14 | + | |
15 | + @override | |
16 | + Widget build(BuildContext context) { | |
17 | + return BlocProvider( | |
18 | + create: (context) => UserInformationBloc(), | |
19 | + child: const _UserInformationView(), | |
20 | + ); | |
21 | + } | |
22 | +} | |
23 | + | |
24 | +class _UserInformationView extends StatelessWidget { | |
25 | + const _UserInformationView({super.key}); | |
26 | + | |
27 | + @override | |
28 | + Widget build(BuildContext context) { | |
29 | + return BlocListener<UserInformationBloc, UserInformationState>( | |
30 | + listener: (context, state) {}, | |
31 | + child: BlocBuilder<UserInformationBloc, UserInformationState>(builder: (context, state) { | |
32 | + return const _UserInformationContentView(); | |
33 | + }), | |
34 | + ); | |
35 | + } | |
36 | +} | |
37 | + | |
38 | +class _UserInformationContentView extends StatelessWidget { | |
39 | + const _UserInformationContentView({super.key}); | |
40 | + | |
41 | + @override | |
42 | + Widget build(BuildContext context) { | |
43 | + UserEntity user = UserUtil.getUser()!; | |
44 | + return Scaffold( | |
45 | + backgroundColor: Colors.white, | |
46 | + appBar: const WEAppBar(titleText: "个人信息",), | |
47 | + body: SingleChildScrollView( | |
48 | + padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 10.h, bottom: 22.h), | |
49 | + child: Column( | |
50 | + children: [ | |
51 | + buildContentRow( | |
52 | + '头像', | |
53 | + CircleAvatar( | |
54 | + radius: 22.5.r, | |
55 | + backgroundColor: Color(0xFF140C10), | |
56 | + child: CircleAvatar( | |
57 | + radius: 21.r, | |
58 | + backgroundImage: ImageUtil.getImageProviderOnDefault(user.avatarUrl), | |
59 | + ), | |
60 | + /*child: ClipOval( | |
61 | + child: OwImageWidget(name: user.avatarUrl ?? AssetsConst.wowLogo, fit: BoxFit.contain,), | |
62 | + )*/ | |
63 | + )), | |
64 | + 11.verticalSpace, | |
65 | + buildContentRow( | |
66 | + '名字', | |
67 | + Text( | |
68 | + user.name, | |
69 | + style: TextStyle( | |
70 | + fontWeight: FontWeight.w500, | |
71 | + color: const Color(0xFF333333), | |
72 | + fontSize: 21.sp, | |
73 | + ), | |
74 | + )), | |
75 | + 11.verticalSpace, | |
76 | + buildContentRow( | |
77 | + '年龄', | |
78 | + Text( | |
79 | + user.age.toString(), | |
80 | + style: TextStyle( | |
81 | + fontWeight: FontWeight.w500, | |
82 | + color: const Color(0xFF333333), | |
83 | + fontSize: 21.sp, | |
84 | + ), | |
85 | + )), | |
86 | + 11.verticalSpace, | |
87 | + buildContentRow( | |
88 | + '性别', | |
89 | + Text( | |
90 | + user.getGenderString(), | |
91 | + style: TextStyle( | |
92 | + fontWeight: FontWeight.w500, | |
93 | + color: const Color(0xFF333333), | |
94 | + fontSize: 21.sp, | |
95 | + ), | |
96 | + )), | |
97 | + 11.verticalSpace, | |
98 | + buildContentRow( | |
99 | + '账号', | |
100 | + Text( | |
101 | + user.phoneNum, | |
102 | + style: TextStyle( | |
103 | + fontWeight: FontWeight.w500, | |
104 | + color: const Color(0xFF999999), | |
105 | + fontSize: 21.sp, | |
106 | + ), | |
107 | + ), | |
108 | + isHideEndIcon: true, | |
109 | + ), | |
110 | + ], | |
111 | + ), | |
112 | + ), | |
113 | + ); | |
114 | + } | |
115 | + | |
116 | + Widget buildContentRow(String filedName, Widget contentWidget, {bool isHideEndIcon = false, Function()? onTap}) { | |
117 | + return GestureDetector( | |
118 | + onTap: onTap, | |
119 | + child: Container( | |
120 | + padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 18.h, bottom: 18.h), | |
121 | + decoration: BoxDecoration( | |
122 | + image: DecorationImage( | |
123 | + image: ImageUtil.getImageProviderOnDefault(AssetsConst.bgUserInformationText), fit: BoxFit.fill)), | |
124 | + child: Row(children: [ | |
125 | + Text( | |
126 | + filedName, | |
127 | + style: TextStyle( | |
128 | + fontWeight: FontWeight.w700, | |
129 | + color: const Color(0xFF999999), | |
130 | + fontSize: 21.sp, | |
131 | + ), | |
132 | + ), | |
133 | + 32.horizontalSpace, | |
134 | + Expanded( | |
135 | + child: Container( | |
136 | + alignment: Alignment.centerLeft, | |
137 | + child: contentWidget, | |
138 | + )), | |
139 | + Offstage( | |
140 | + offstage: isHideEndIcon, | |
141 | + child: Image.asset(AssetsConst.icNext, width: 20.w, height: 25.h), | |
142 | + ) | |
143 | + ]), | |
144 | + )); | |
145 | + } | |
146 | +} | ... | ... |
lib/pages/user/information/user_information_state.dart
0 → 100644
lib/pages/user/user_page.dart
... | ... | @@ -6,7 +6,6 @@ import 'package:wow_english/common/core/assets_const.dart'; |
6 | 6 | import 'package:wow_english/common/core/user_util.dart'; |
7 | 7 | import 'package:wow_english/common/widgets/we_app_bar.dart'; |
8 | 8 | import 'package:wow_english/models/user_entity.dart'; |
9 | -import 'package:wow_english/pages/login/setpwd/set_pwd_page.dart'; | |
10 | 9 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; |
11 | 10 | import 'package:wow_english/route/route.dart'; |
12 | 11 | import 'package:wow_english/utils/image_util.dart'; |
... | ... | @@ -55,7 +54,7 @@ class _UserView extends StatelessWidget { |
55 | 54 | ); |
56 | 55 | |
57 | 56 | return Scaffold( |
58 | - backgroundColor: Colors.white, | |
57 | + //backgroundColor: Colors.white, | |
59 | 58 | appBar: const WEAppBar(), |
60 | 59 | body: SingleChildScrollView( |
61 | 60 | padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 10.h, bottom: 22.h), |
... | ... | @@ -130,13 +129,15 @@ class _UserView extends StatelessWidget { |
130 | 129 | "修改个人信息>", |
131 | 130 | style: textStyle21sp, |
132 | 131 | ), |
133 | - onPressed: () {}, | |
132 | + onPressed: () { | |
133 | + Navigator.of(AppRouter.context).pushNamed(AppRouteName.userInformation); | |
134 | + }, | |
134 | 135 | ) |
135 | 136 | ], |
136 | 137 | ), |
137 | 138 | 30.verticalSpace, |
138 | 139 | OutlinedButton( |
139 | - onPressed: () => SetPassWordPage.push(context, SetPwdPageType.changePwd), | |
140 | + onPressed: () => Navigator.of(context).pushNamed(AppRouteName.fogPwd), | |
140 | 141 | style: normalButtonStyle, |
141 | 142 | child: Text( |
142 | 143 | "修改密码", | ... | ... |
lib/route/route.dart
... | ... | @@ -14,6 +14,7 @@ import 'package:wow_english/pages/shop/exchane/exchange_lesson_page.dart'; |
14 | 14 | import 'package:wow_english/pages/shop/exchangelist/exchange_lesson_list_page.dart'; |
15 | 15 | import 'package:wow_english/pages/shop/home/shop_home_page.dart'; |
16 | 16 | import 'package:wow_english/pages/tab/tab_page.dart'; |
17 | +import 'package:wow_english/pages/user/information/user_information_page.dart'; | |
17 | 18 | import 'package:wow_english/pages/user/user_page.dart'; |
18 | 19 | import 'package:wow_english/pages/video/lookvideo/look_video_page.dart'; |
19 | 20 | |
... | ... | @@ -39,7 +40,12 @@ class AppRouteName { |
39 | 40 | static const String voicePic = 'voicePic'; |
40 | 41 | static const String voiceWord = 'voiceWord'; |
41 | 42 | static const String voiceAnswer = 'voiceAnswer'; |
43 | + | |
44 | + /// 用户个人主页 | |
42 | 45 | static const String user = 'user'; |
46 | + | |
47 | + /// 用户详细信息页 | |
48 | + static const String userInformation = 'userInformation'; | |
43 | 49 | static const String lookVideo = 'lookVideo'; |
44 | 50 | static const String reading = 'reading'; |
45 | 51 | |
... | ... | @@ -88,6 +94,8 @@ class AppRouter { |
88 | 94 | return CupertinoPageRoute(builder: (_) => const RepeatAfterPage()); |
89 | 95 | case AppRouteName.user: |
90 | 96 | return CupertinoPageRoute(builder: (_) => const UserPage()); |
97 | + case AppRouteName.userInformation: | |
98 | + return CupertinoPageRoute(builder: (_) => const UserInformationPage()); | |
91 | 99 | case AppRouteName.topicPic: |
92 | 100 | return CupertinoPageRoute(builder: (_) => const TopicPicturePage()); |
93 | 101 | case AppRouteName.lookVideo: | ... | ... |