Commit da82bd70e6b3907583c46519e8e7c34aa8d15514

Authored by Key
1 parent b90a1518

feat: user_information_page.dart

fixed: appbar style
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
... ... @@ -4,5 +4,6 @@ part &#39;cache_event.dart&#39;;
4 4 part 'cache_state.dart';
5 5  
6 6 class CacheBloc extends Bloc<CacheEvent, CacheState> {
  7 + /// app配置信息
7 8 CacheBloc() : super(CacheInitial());
8 9 }
... ...
lib/common/blocs/cachebloc/cache_event.dart
1 1 part of 'cache_bloc.dart';
2 2  
3 3 sealed class CacheEvent {}
  4 +
  5 +class CacheUserInfoUpdate extends CacheEvent {}
... ...
lib/common/blocs/cachebloc/cache_state.dart
... ... @@ -3,3 +3,5 @@ part of &#39;cache_bloc.dart&#39;;
3 3 sealed class CacheState {}
4 4  
5 5 class CacheInitial extends CacheState {}
  6 +
  7 +class CacheUserInfoUpdated extends CacheState {}
... ...
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 &#39;package:wow_english/models/user_entity.dart&#39;;
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
... ... @@ -18,7 +18,7 @@ class UserEntity {
18 18 /// 性别:0, 1
19 19 int? gender;
20 20 String? avatarUrl;
21   - String? phoneNum;
  21 + late String phoneNum;
22 22  
23 23 /// 用户信息是否填写 0.未填写 1.已经填写
24 24 int? fillUserInfo;
... ...
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&lt;SetPwdEvent, SetPwdState&gt; {
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
... ... @@ -458,4 +458,4 @@ class _TopicPicturePage extends StatelessWidget {
458 458 ],
459 459 );
460 460 });
461   -}
462 461 \ No newline at end of file
  462 +}
... ...
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
  1 +part of 'user_information_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class UserInformationEvent {}
... ...
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
  1 +part of 'user_information_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class UserInformationState {}
  5 +
  6 +class UserInformationInitial extends UserInformationState {}
... ...
lib/pages/user/user_page.dart
... ... @@ -6,7 +6,6 @@ import &#39;package:wow_english/common/core/assets_const.dart&#39;;
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 &#39;package:wow_english/pages/shop/exchane/exchange_lesson_page.dart&#39;;
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:
... ...