Commit c948a9eac63212b287c5ece7f034e0fe877932eb

Authored by liangchengyou
1 parent 67d028e7

feat:个人信息更改模块功能

assets/images/alter.png 0 → 100644

40.7 KB

assets/images/intowow.png 0 → 100644

26.9 KB

assets/images/oninto.png 0 → 100644

25.6 KB

ios/Podfile
... ... @@ -43,5 +43,52 @@ end
43 43 post_install do |installer|
44 44 installer.pods_project.targets.each do |target|
45 45 flutter_additional_ios_build_settings(target)
  46 + target.build_configurations.each do |config|
  47 + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
  48 + '$(inherited)',
  49 +
  50 + ## dart: PermissionGroup.calendar
  51 + # 'PERMISSION_EVENTS=1',
  52 +
  53 + ## dart: PermissionGroup.reminders
  54 + # 'PERMISSION_REMINDERS=1',
  55 +
  56 + ## dart: PermissionGroup.contacts
  57 + # 'PERMISSION_CONTACTS=1',
  58 +
  59 + ## dart: PermissionGroup.camera
  60 + 'PERMISSION_CAMERA=1',
  61 +
  62 + ## dart: PermissionGroup.microphone
  63 + 'PERMISSION_MICROPHONE=1',
  64 +
  65 + ## dart: PermissionGroup.speech
  66 + # 'PERMISSION_SPEECH_RECOGNIZER=1',
  67 +
  68 + ## dart: PermissionGroup.photos
  69 + 'PERMISSION_PHOTOS=1',
  70 +
  71 + ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
  72 + # 'PERMISSION_LOCATION=1',
  73 +
  74 + ## dart: PermissionGroup.notification
  75 + # 'PERMISSION_NOTIFICATIONS=1',
  76 +
  77 + ## dart: PermissionGroup.mediaLibrary
  78 + # 'PERMISSION_MEDIA_LIBRARY=1',
  79 +
  80 + ## dart: PermissionGroup.sensors
  81 + # 'PERMISSION_SENSORS=1',
  82 +
  83 + ## dart: PermissionGroup.bluetooth
  84 + # 'PERMISSION_BLUETOOTH=1',
  85 +
  86 + ## dart: PermissionGroup.appTrackingTransparency
  87 + # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1',
  88 +
  89 + ## dart: PermissionGroup.criticalAlerts
  90 + # 'PERMISSION_CRITICAL_ALERTS=1'
  91 + ]
  92 + end
46 93 end
47 94 end
... ...
ios/Runner/Info.plist
... ... @@ -24,6 +24,8 @@
24 24 <string>????</string>
25 25 <key>CFBundleVersion</key>
26 26 <string>$(FLUTTER_BUILD_NUMBER)</string>
  27 + <key>LSApplicationCategoryType</key>
  28 + <string></string>
27 29 <key>LSRequiresIPhoneOS</key>
28 30 <true/>
29 31 <key>NSAppTransportSecurity</key>
... ... @@ -31,6 +33,8 @@
31 33 <key>NSAllowsArbitraryLoads</key>
32 34 <true/>
33 35 </dict>
  36 + <key>NSCameraUsageDescription</key>
  37 + <string>需要访问相机完成拍照</string>
34 38 <key>NSMicrophoneUsageDescription</key>
35 39 <string>需要获取录音完成后续功能</string>
36 40 <key>NSPhotoLibraryUsageDescription</key>
... ...
lib/app/app.dart
... ... @@ -7,6 +7,7 @@ import &#39;package:responsive_framework/responsive_breakpoints.dart&#39;;
7 7 import 'package:wow_english/common/blocs/cachebloc/cache_bloc.dart';
8 8 import 'package:wow_english/common/widgets/hide_keyboard_widget.dart';
9 9 import 'package:wow_english/pages/tab/blocs/tab_bloc.dart';
  10 +import 'package:wow_english/pages/user/bloc/user_bloc.dart';
10 11 import 'package:wow_english/route/route.dart';
11 12  
12 13 class App extends StatelessWidget {
... ... @@ -20,6 +21,7 @@ class App extends StatelessWidget {
20 21 providers: [
21 22 BlocProvider<TabBloc>(create: (_) => TabBloc()),
22 23 BlocProvider<CacheBloc>(create: (_) => CacheBloc()),
  24 + BlocProvider<UserBloc>(create: (_) => UserBloc()),
23 25 ],
24 26 child: HideKeyboard(
25 27 child: MaterialApp(
... ...
lib/pages/home/widgets/home_tab_header_widget.dart
1 1 import 'package:flutter/material.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
2 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
3 4 import 'package:wow_english/common/core/user_util.dart';
4 5 import 'package:wow_english/common/extension/string_extension.dart';
  6 +import 'package:wow_english/pages/user/bloc/user_bloc.dart';
5 7 import 'package:wow_english/utils/color_util.dart';
6 8 import 'package:wow_english/utils/image_util.dart';
7 9  
... ... @@ -26,89 +28,93 @@ class HomeTabHeaderWidget extends StatelessWidget {
26 28  
27 29 @override
28 30 Widget build(BuildContext context) {
29   - return Container(
30   - height: 45,
31   - width: double.infinity,
32   - color: HexColor(themColor??''),
33   - padding: EdgeInsets.symmetric(horizontal: 9.5.w),
34   - child: Row(
35   - children: [
36   - ScreenUtil().bottomBarHeight.horizontalSpace,
37   - GestureDetector(
38   - onTap: () => actionTap?.call(HeaderActionType.user),
39   - child: Container(
40   - decoration: BoxDecoration(
41   - border: Border.all(
42   - width: 1.0,
43   - color: const Color(0xFF140C10),
  31 + return BlocBuilder<UserBloc,UserState>(
  32 + builder: (context,state) {
  33 + return Container(
  34 + height: 45,
  35 + width: double.infinity,
  36 + color: HexColor(themColor??''),
  37 + padding: EdgeInsets.symmetric(horizontal: 9.5.w),
  38 + child: Row(
  39 + children: [
  40 + ScreenUtil().bottomBarHeight.horizontalSpace,
  41 + GestureDetector(
  42 + onTap: () => actionTap?.call(HeaderActionType.user),
  43 + child: Container(
  44 + decoration: BoxDecoration(
  45 + border: Border.all(
  46 + width: 1.0,
  47 + color: const Color(0xFF140C10),
  48 + ),
  49 + borderRadius: BorderRadius.circular(21),
  50 + ),
  51 + child: CircleAvatar(
  52 + radius: 21,
  53 + backgroundImage: ImageUtil.getImageProviderOnDefault(UserUtil.getUser()?.avatarUrl),
  54 + ),
  55 + ),
44 56 ),
45   - borderRadius: BorderRadius.circular(21),
46   - ),
47   - child: CircleAvatar(
48   - radius: 21,
49   - backgroundImage: ImageUtil.getImageProviderOnDefault(UserUtil.getUser()?.avatarUrl),
50   - ),
51   - ),
52   - ),
53   - GestureDetector(
54   - onTap: () {
55   - if (actionTap != null) {
56   - actionTap!(HeaderActionType.user);
57   - }
58   - },
59   - child: Container(
60   - margin: const EdgeInsets.only(left: 7),
61   - padding: const EdgeInsets.all(4.0),
62   - decoration: BoxDecoration(
63   - color: Colors.white,
64   - borderRadius: BorderRadius.circular(2),
65   - border: Border.all(width: 1.0, color: const Color(0xFF140C10), style: BorderStyle.solid),
66   - ),
67   - child: Text(
68   - UserUtil.getUser()?.name ?? '未登录',
69   - style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp),
70   - ),
71   - ),
72   - ),
73   - 20.horizontalSpace,
74   - const Expanded(
75   - child: Text(
76   - 'learn wow',
77   - textAlign: TextAlign.left,
78   - style: TextStyle(color: Colors.white, fontSize: 30.0),
79   - )),
80   - IconButton(
81   - onPressed: () {
82   - if (actionTap != null) {
83   - actionTap!(HeaderActionType.video);
84   - }
85   - },
86   - icon: Image.asset('video'.assetPng)),
87   - IconButton(
88   - onPressed: () {
89   - if (actionTap != null) {
90   - actionTap!(HeaderActionType.phase);
91   - }
92   - },
93   - icon: Image.asset('home'.assetPng)),
94   - IconButton(
95   - onPressed: () {
96   - if (actionTap != null) {
97   - actionTap!(HeaderActionType.listen);
98   - }
99   - },
100   - icon: Image.asset('listen'.assetPng)),
101   - // IconButton(
102   - // onPressed: (){
103   - // if(actionTap != null) {
104   - // actionTap!(HeaderActionType.shop);
105   - // }
106   - // },
107   - // icon: Image.asset('shop'.assetPng)
108   - // ),
109   - ScreenUtil().bottomBarHeight.horizontalSpace,
110   - ],
111   - )
  57 + GestureDetector(
  58 + onTap: () {
  59 + if (actionTap != null) {
  60 + actionTap!(HeaderActionType.user);
  61 + }
  62 + },
  63 + child: Container(
  64 + margin: const EdgeInsets.only(left: 7),
  65 + padding: const EdgeInsets.all(4.0),
  66 + decoration: BoxDecoration(
  67 + color: Colors.white,
  68 + borderRadius: BorderRadius.circular(2),
  69 + border: Border.all(width: 1.0, color: const Color(0xFF140C10), style: BorderStyle.solid),
  70 + ),
  71 + child: Text(
  72 + UserUtil.getUser()?.name ?? '未登录',
  73 + style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp),
  74 + ),
  75 + ),
  76 + ),
  77 + 20.horizontalSpace,
  78 + const Expanded(
  79 + child: Text(
  80 + 'learn wow',
  81 + textAlign: TextAlign.left,
  82 + style: TextStyle(color: Colors.white, fontSize: 30.0),
  83 + )),
  84 + IconButton(
  85 + onPressed: () {
  86 + if (actionTap != null) {
  87 + actionTap!(HeaderActionType.video);
  88 + }
  89 + },
  90 + icon: Image.asset('video'.assetPng)),
  91 + IconButton(
  92 + onPressed: () {
  93 + if (actionTap != null) {
  94 + actionTap!(HeaderActionType.phase);
  95 + }
  96 + },
  97 + icon: Image.asset('home'.assetPng)),
  98 + IconButton(
  99 + onPressed: () {
  100 + if (actionTap != null) {
  101 + actionTap!(HeaderActionType.listen);
  102 + }
  103 + },
  104 + icon: Image.asset('listen'.assetPng)),
  105 + // IconButton(
  106 + // onPressed: (){
  107 + // if(actionTap != null) {
  108 + // actionTap!(HeaderActionType.shop);
  109 + // }
  110 + // },
  111 + // icon: Image.asset('shop'.assetPng)
  112 + // ),
  113 + ScreenUtil().bottomBarHeight.horizontalSpace,
  114 + ],
  115 + )
  116 + );
  117 + },
112 118 );
113 119 }
114 120 }
... ...
lib/pages/user/bloc/user_bloc.dart
... ... @@ -33,13 +33,13 @@ class UserBloc extends Bloc&lt;UserEvent, UserState&gt; {
33 33 }
34 34  
35 35 void _updateUser(UserUpdate event, Emitter<UserState> emitter) async {
36   - Log.d('_updateUser, event: ${event.type}, emitter.isDone: ${emitter.isDone}, text=${modifyTextController.text}');
  36 + Log.d('_updateUser, event: ${event.type}, emitter.isDone: ${emitter.isDone}, text=${event.content}');
37 37 UserEntity user = UserUtil.getUser()!;
38 38 switch (event.type) {
39 39 case ModifyUserInformationType.avatar:
40 40 break;
41 41 case ModifyUserInformationType.name:
42   - String name = modifyTextController.text;
  42 + String name = event.content;
43 43 try {
44 44 await UserDao.updateUserInfoField(name: name);
45 45 // 修改成功,更新本地缓存及UI
... ... @@ -54,7 +54,7 @@ class UserBloc extends Bloc&lt;UserEvent, UserState&gt; {
54 54 try {
55 55 int age;
56 56 try {
57   - age = modifyTextController.text as int;
  57 + age = int.parse(event.content);
58 58 } catch (e) {
59 59 Log.w(e.toString());
60 60 throw '年龄格式错误';
... ... @@ -69,8 +69,9 @@ class UserBloc extends Bloc&lt;UserEvent, UserState&gt; {
69 69 break;
70 70 case ModifyUserInformationType.gender:
71 71 try {
72   - await UserDao.updateUserInfoField(gender: tempGender);
73   - user.gender = tempGender;
  72 + var gender = int.parse(event.content);
  73 + await UserDao.updateUserInfoField(gender: gender);
  74 + user.gender = gender;
74 75 emitter(UserInfoUpdated());
75 76 } catch (e) {
76 77 Log.e('_updateUser gender, e: $e');
... ...
lib/pages/user/bloc/user_event.dart
... ... @@ -12,8 +12,9 @@ class UserDelete extends UserEvent {}
12 12  
13 13 class UserUpdate extends UserEvent {
14 14 final ModifyUserInformationType type;
  15 + final String content;
15 16  
16   - UserUpdate(this.type);
  17 + UserUpdate(this.type,this.content);
17 18 }
18 19  
19 20 class UserUIUpdate extends UserEvent {
... ...
lib/pages/user/information/user_information_page.dart
... ... @@ -6,6 +6,7 @@ import &#39;package:wow_english/common/core/user_util.dart&#39;;
6 6 import 'package:wow_english/common/widgets/we_app_bar.dart';
7 7 import 'package:wow_english/models/user_entity.dart';
8 8 import 'package:wow_english/pages/user/bloc/user_bloc.dart';
  9 +import 'package:wow_english/route/route.dart';
9 10 import 'package:wow_english/utils/image_util.dart';
10 11 import 'package:wow_english/utils/log_util.dart';
11 12  
... ... @@ -16,35 +17,19 @@ class UserInformationPage extends StatelessWidget {
16 17  
17 18 @override
18 19 Widget build(BuildContext context) {
19   - return BlocProvider(
20   - create: (context) => UserBloc(),
21   - child: const _UserInformationView(),
22   - );
  20 + return BlocBuilder<UserBloc, UserState>(
  21 + builder: (context,state){
  22 + return _UserInformationContentView();
  23 + });
23 24 }
24 25 }
25 26  
26   -class _UserInformationView extends StatelessWidget {
27   - const _UserInformationView({super.key});
28   -
29   - @override
30   - Widget build(BuildContext context) {
31   - return BlocListener<UserBloc, UserState>(
32   - listener: (context, state) {
33   - Log.d('UserInformationPage: $state');
34   - },
35   - child: BlocBuilder<UserBloc, UserState>(builder: (context, state) {
36   - return _UserInformationContentView();
37   - }),
38   - );
39   - }
40   -}
41 27  
42 28 class _UserInformationContentView extends StatelessWidget {
43 29  
44 30 void _openModifyPage(BuildContext context, ModifyUserInformationType type) {
45 31 Log.d('_openModifyPage($type)');
46   - // 暂时关闭修改,修复后打开
47   - // ModifyUserInformationPage.push(context, type);
  32 + ModifyUserInformationPage.push(context, type);
48 33 }
49 34  
50 35 @override
... ... @@ -68,7 +53,9 @@ class _UserInformationContentView extends StatelessWidget {
68 53 radius: 21.r,
69 54 backgroundImage: ImageUtil.getImageProviderOnDefault(user.avatarUrl),
70 55 ),
71   - )),
  56 + ),
  57 + onTap: () => pushNamed(AppRouteName.userAvatar)
  58 + ),
72 59 11.verticalSpace,
73 60 _buildContentRow(
74 61 '名字',
... ... @@ -144,9 +131,9 @@ class _UserInformationContentView extends StatelessWidget {
144 131 32.horizontalSpace,
145 132 Expanded(
146 133 child: Container(
147   - alignment: Alignment.centerLeft,
148   - child: contentWidget,
149   - )),
  134 + alignment: Alignment.centerLeft,
  135 + child: contentWidget,
  136 + )),
150 137 Offstage(
151 138 offstage: isHideEndIcon,
152 139 child: Image.asset(AssetsConst.icNext, width: 20.w, height: 25.h),
... ...
lib/pages/user/modify/modify_user_avatar_page.dart
  1 +import 'dart:io';
  2 +
  3 +import 'package:flutter/material.dart';
  4 +import 'package:flutter_bloc/flutter_bloc.dart';
  5 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  6 +import 'package:wow_english/common/extension/string_extension.dart';
  7 +import 'package:wow_english/common/widgets/ow_image_widget.dart';
  8 +import 'package:wow_english/common/widgets/we_app_bar.dart';
  9 +import 'package:wow_english/pages/user/bloc/user_bloc.dart';
  10 +import 'package:wow_english/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart';
  11 +import 'package:wow_english/utils/toast_util.dart';
  12 +
  13 +class ModifyUserAvatarPage extends StatelessWidget {
  14 + const ModifyUserAvatarPage({super.key, required this.pageType});
  15 +
  16 + /// 0 新用户设置头像 1 修改头像
  17 + final int pageType;
  18 +
  19 + @override
  20 + Widget build(BuildContext context) {
  21 + return BlocProvider(
  22 + create: (context) => UserAvatarBloc(),
  23 + child: _ModifyUserAvatarPage(pageType: pageType),
  24 + );
  25 + }
  26 +}
  27 +
  28 +class _ModifyUserAvatarPage extends StatelessWidget {
  29 + const _ModifyUserAvatarPage({required this.pageType});
  30 + final int pageType;
  31 +
  32 + @override
  33 + Widget build(BuildContext context) {
  34 + return MultiBlocListener(
  35 + listeners: [
  36 + BlocListener<UserBloc,UserState>(
  37 + listener: (context, state){
  38 + if (state is UserInfoUpdated) {
  39 + showToast('修改成功');
  40 + }
  41 + }),
  42 + BlocListener(
  43 + listener: (context,state){
  44 + if (state is ChangeImageState) {
  45 + showToast('上传图片');
  46 + }
  47 + },)
  48 + ],
  49 + child: pageType == 0 ? _setUserAvatarView():_modifyUserAvatarPageView(),
  50 + );
  51 + }
  52 +
  53 + ///个人信息修改头像
  54 + Widget _modifyUserAvatarPageView() => BlocBuilder<UserAvatarBloc,UserAvatarState>(
  55 + builder: (context,state){
  56 + return Scaffold(
  57 + appBar:const WEAppBar(
  58 + titleText: '头像修改',
  59 + ),
  60 + body: SafeArea(
  61 + child: Column(
  62 + children: [
  63 + 20.verticalSpace,
  64 + _avatarImageWidget(),
  65 + ],
  66 + ),
  67 + ),
  68 + );
  69 + });
  70 +
  71 + ///新用户设置头像
  72 + Widget _setUserAvatarView() => BlocBuilder<UserAvatarBloc,UserAvatarState>(
  73 + builder: (context, state) {
  74 + final bloc = BlocProvider.of<UserAvatarBloc>(context);
  75 + return Container(
  76 + color: Colors.white,
  77 + child: SafeArea(
  78 + child: Column(
  79 + children: [
  80 + 20.verticalSpace,
  81 + Row(
  82 + children: [
  83 + Image.asset(
  84 + 'wow_logo'.assetPng,
  85 + height: 49.h,
  86 + width: 84.w,
  87 + ),
  88 + Text(
  89 + '欢迎登录wow english\n接下来请填写一下您的个人信息吧',
  90 + textAlign: TextAlign.left,
  91 + style: TextStyle(
  92 + fontSize: 17.sp,
  93 + color: const Color(0xFF666666)
  94 + ),
  95 + )
  96 + ],
  97 + ),
  98 + 15.verticalSpace,
  99 + _avatarImageWidget(),
  100 + 10.verticalSpace,
  101 + Container(
  102 + width: 176.w,
  103 + height: 52.h,
  104 + padding: const EdgeInsets.all(5),
  105 + decoration: BoxDecoration(
  106 + image: DecorationImage(
  107 + image: AssetImage(bloc.canInsertApp?'oninto'.assetPng:'intowow'.assetPng),
  108 + fit: BoxFit.fill
  109 + )
  110 + ),
  111 + alignment: Alignment.center,
  112 + child: Text(
  113 + '进入wow english',
  114 + textAlign: TextAlign.center,
  115 + style: TextStyle(
  116 + fontSize: 12.sp,
  117 + color: Colors.white
  118 + ),
  119 + ),
  120 + )
  121 + ],
  122 + ),
  123 + ),
  124 + );
  125 + }
  126 + );
  127 +
  128 + Widget _avatarImageWidget() => BlocBuilder<UserAvatarBloc,UserAvatarState>(
  129 + builder: (context, state){
  130 + final bloc = BlocProvider.of<UserAvatarBloc>(context);
  131 + return Row(
  132 + mainAxisAlignment: MainAxisAlignment.center,
  133 + children: [
  134 + Container(
  135 + width: 205.w,
  136 + height: 197.h,
  137 + padding: const EdgeInsets.all(5),
  138 + decoration: BoxDecoration(
  139 + image: DecorationImage(
  140 + image: AssetImage('video_background'.assetPng),
  141 + fit: BoxFit.fill
  142 + )
  143 + ),
  144 + child: bloc.file == null ?
  145 + OwImageWidget(name: bloc.imageUrl):
  146 + Image.file(
  147 + File(bloc.file!.path),
  148 + fit: BoxFit.fill,
  149 + ),
  150 + ),
  151 + 54.horizontalSpace,
  152 + Column(
  153 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  154 + children: [
  155 + GestureDetector(
  156 + onTap: () => bloc.add(GetImageFromCameraEvent()),
  157 + child: Container(
  158 + width: 222.w,
  159 + height: 65.h,
  160 + alignment: Alignment.center,
  161 + decoration: BoxDecoration(
  162 + image: DecorationImage(
  163 + image: AssetImage('alter'.assetPng),
  164 + fit: BoxFit.fill
  165 + )
  166 + ),
  167 + child: Text(
  168 + '拍照修改头像',
  169 + textAlign: TextAlign.center,
  170 + style: TextStyle(
  171 + color: Colors.white,
  172 + fontSize: 20.sp
  173 + ),
  174 + ),
  175 + ),
  176 + ),
  177 + 20.verticalSpace,
  178 + GestureDetector(
  179 + onTap: () => bloc.add(GetImageFromPhotoEvent()),
  180 + child: Container(
  181 + width: 222.w,
  182 + height: 65.h,
  183 + alignment: Alignment.center,
  184 + decoration: BoxDecoration(
  185 + image: DecorationImage(
  186 + image: AssetImage('alter'.assetPng),
  187 + fit: BoxFit.fill
  188 + )
  189 + ),
  190 + child: Text(
  191 + '从相册选择',
  192 + textAlign: TextAlign.center,
  193 + style: TextStyle(
  194 + color: Colors.white,
  195 + fontSize: 20.sp
  196 + ),
  197 + ),
  198 + ),
  199 + )
  200 + ],
  201 + )
  202 + ],
  203 + );
  204 + });
  205 +}
0 206 \ No newline at end of file
... ...
lib/pages/user/modify/modify_user_information_page.dart
... ... @@ -8,7 +8,9 @@ import &#39;package:wow_english/common/core/user_util.dart&#39;;
8 8 import 'package:wow_english/common/widgets/textfield_customer_widget.dart';
9 9 import 'package:wow_english/common/widgets/we_app_bar.dart';
10 10 import 'package:wow_english/pages/user/bloc/user_bloc.dart';
11   -import 'package:wow_english/utils/log_util.dart';
  11 +import 'package:wow_english/pages/user/modify/user_info_bloc/user_info_bloc.dart';
  12 +import 'package:wow_english/route/route.dart';
  13 +import 'package:wow_english/utils/toast_util.dart';
12 14  
13 15 enum ModifyUserInformationType {
14 16 avatar('头像'),
... ... @@ -34,97 +36,127 @@ class ModifyUserInformationPage extends StatelessWidget {
34 36  
35 37 @override
36 38 Widget build(BuildContext context) {
  39 + String text = '';
  40 + if (type == ModifyUserInformationType.age) {
  41 + text = UserUtil.getUser()!.age.toString();
  42 + } else if (type == ModifyUserInformationType.name) {
  43 + text = UserUtil.getUser()!.name;
  44 + }
37 45 return BlocProvider(
38   - create: (context) => UserBloc(),
39   - child: Scaffold(
40   - backgroundColor: Colors.white,
41   - appBar: WEAppBar(
42   - titleText: '修改${type.title}',
43   - ),
44   - body: BlocListener<UserBloc, UserState>(
45   - listener: (context, state) {},
46   - child: BlocBuilder<UserBloc, UserState>(builder: (context, state) {
47   - //final bloc = context.read<UserBloc>();
48   - // 区别是什么?
49   - //BlocProvider.of<UserBloc>(context);
50   - return SingleChildScrollView(
51   - child: Column(
52   - children: [
53   - Padding(
54   - padding: EdgeInsets.only(left: 65.w, right: 55.w, top: 38.h),
55   - child: Row(
  46 + create: (context) => UserInfoBloc()..add(InitControllerTextEvent(text)),
  47 + child: MultiBlocListener(
  48 + listeners: [
  49 + BlocListener<UserBloc,UserState>(listener: (context, state){
  50 + if (state is UserInfoUpdated) {
  51 + showToast('修改成功');
  52 + popPage();
  53 + }
  54 + })
  55 + ],
  56 + child: Scaffold(
  57 + backgroundColor: Colors.white,
  58 + appBar: WEAppBar(
  59 + titleText: '修改${type.title}',
  60 + ),
  61 + body: BlocBuilder<UserInfoBloc, UserInfoState>(
  62 + builder: (context, state) {
  63 + final bloc = BlocProvider.of<UserInfoBloc>(context);
  64 + return SingleChildScrollView(
  65 + child: Column(
56 66 children: [
57   - Text(
58   - type.title,
59   - style: TextStyle(
60   - fontWeight: FontWeight.w700,
61   - color: const Color(0xFF333333),
62   - fontSize: 21.sp,
63   - ),
64   - ),
65   - 20.horizontalSpace,
66   - // 输入框 or 选择框
67   - _buildTextFieldWidget(context),
68   - // 占位
69   - Expanded(
70   - child: Container(),
71   - ),
72   - // 按钮
73   - GestureDetector(
74   - onTap: () {
75   - // 更新type类型的字段
76   - context.read<UserBloc>().add(UserUpdate(type));
77   - },
78   - child: Container(
79   - alignment: Alignment.center,
80   - width: 90.w,
81   - height: 44.h,
82   - decoration: const BoxDecoration(
83   - image: DecorationImage(image: AssetImage(AssetsConst.bgButtonBlue), fit: BoxFit.fill),
  67 + Padding(
  68 + padding: EdgeInsets.only(left: 65.w, right: 55.w, top: 38.h),
  69 + child: Row(
  70 + children: [
  71 + Text(
  72 + type.title,
  73 + style: TextStyle(
  74 + fontWeight: FontWeight.w700,
  75 + color: const Color(0xFF333333),
  76 + fontSize: 21.sp,
  77 + ),
  78 + ),
  79 + 20.horizontalSpace,
  80 + // 输入框 or 选择框
  81 + _buildTextFieldWidget(context),
  82 + // 占位
  83 + Expanded(
  84 + child: Container(),
  85 + ),
  86 + // 按钮
  87 + GestureDetector(
  88 + onTap: () {
  89 + var text = '';
  90 + if (type == ModifyUserInformationType.name || type == ModifyUserInformationType.age){
  91 + if(bloc.modifyTextController.text.isEmpty) {
  92 + showToast('内容不能为空');
  93 + return;
  94 + }
  95 + text = bloc.modifyTextController.text;
  96 + }
  97 +
  98 + if (type == ModifyUserInformationType.gender) {
  99 + text = bloc.gender.toString();
  100 + }
  101 + // 更新type类型的字段
  102 + context.read<UserBloc>().add(UserUpdate(type,text));
  103 + },
  104 + child: Container(
  105 + alignment: Alignment.center,
  106 + width: 90.w,
  107 + height: 44.h,
  108 + decoration: const BoxDecoration(
  109 + image: DecorationImage(image: AssetImage(AssetsConst.bgButtonBlue), fit: BoxFit.fill),
  110 + ),
  111 + child: Text(
  112 + '确定',
  113 + style: TextStyle(fontSize: 17.sp, color: Colors.white),
  114 + ),
  115 + ),
  116 + )
  117 + ],
  118 + )),
  119 + Stack(
  120 + alignment: Alignment.topRight,
  121 + children: [
  122 + Image.asset(
  123 + AssetsConst.bgEditUserInformation,
  124 + width: double.infinity,
84 125 ),
85   - child: Text(
86   - '确定',
87   - style: TextStyle(fontSize: 17.sp, color: Colors.white),
  126 + Positioned(
  127 + right: 125.w,
  128 + top: 10.h,
  129 + child: Image.asset(AssetsConst.bgIcSteveWrite, width: 161.w, height: 249.w),
88 130 ),
89   - ),
90   - )
  131 + ],
  132 + ),
91 133 ],
92   - )),
93   - Stack(
94   - alignment: Alignment.topRight,
95   - children: [
96   - Image.asset(
97   - AssetsConst.bgEditUserInformation,
98   - width: double.infinity,
99   - ),
100   - Positioned(
101   - right: 125.w,
102   - top: 10.h,
103   - child: Image.asset(AssetsConst.bgIcSteveWrite, width: 161.w, height: 249.w),
104   - ),
105   - ],
106   - ),
107   - ],
108   - ));
109   - }),
  134 + ));
  135 + }),
110 136 ),
111 137 ),
112 138 );
113 139 }
114 140  
115 141 Widget _buildTextFieldWidget(BuildContext context) {
116   - var userBloc = context.read<UserBloc>();
117   - var user = UserUtil.getUser()!;
118   - userBloc.tempGender = user.gender ?? 0;
119   - Log.d('user = $user');
120 142 if (type == ModifyUserInformationType.gender) {
121   - return Row(
122   - children: <Widget>[
123   - _buildSexWidget('男', true),
124   - 70.horizontalSpace,
125   - _buildSexWidget('女', false)
126   - ],
127   - );
  143 + return BlocBuilder<UserInfoBloc, UserInfoState>(
  144 + builder: (context,state){
  145 + final bloc = BlocProvider.of<UserInfoBloc>(context);
  146 + return Row(
  147 + children: <Widget>[
  148 + GestureDetector(
  149 + onTap: () => bloc.add(ChangeGenderEvent(0)),
  150 + child: _buildSexWidget('男', bloc.gender == 0),
  151 + ),
  152 + 70.horizontalSpace,
  153 + GestureDetector(
  154 + onTap: () => bloc.add(ChangeGenderEvent(1)),
  155 + child: _buildSexWidget('女', bloc.gender == 1),
  156 + )
  157 + ],
  158 + );
  159 + });
128 160 }
129 161  
130 162 var formatters = [
... ... @@ -141,22 +173,26 @@ class ModifyUserInformationPage extends StatelessWidget {
141 173 inputType = TextInputType.number;
142 174 }
143 175  
144   - return TextFieldCustomerWidget(
145   - height: 65.h,
146   - width: 222.w,
147   - textStyle: TextStyle(
148   - fontWeight: FontWeight.w700,
149   - color: const Color(0xFF333333),
150   - fontSize: 21.sp,
151   - ),
152   - bgImageName: 'Input_layer_up',
153   - textInputType: inputType,
154   - inputFormatters: formatters,
155   - controller: userBloc.modifyTextController,
156   - /*onChangeValue: (String value) {
  176 + return BlocBuilder<UserInfoBloc, UserInfoState>(
  177 + builder: (context,state){
  178 + final bloc = BlocProvider.of<UserInfoBloc>(context);
  179 + return TextFieldCustomerWidget(
  180 + height: 65.h,
  181 + width: 222.w,
  182 + textStyle: TextStyle(
  183 + fontWeight: FontWeight.w700,
  184 + color: const Color(0xFF333333),
  185 + fontSize: 21.sp,
  186 + ),
  187 + bgImageName: 'Input_layer_up',
  188 + textInputType: inputType,
  189 + inputFormatters: formatters,
  190 + controller: bloc.modifyTextController,
  191 + /*onChangeValue: (String value) {
157 192 bloc.add(CodeNumberChangeEvent());
158 193 },*/
159   - );
  194 + );
  195 + });
160 196 }
161 197  
162 198 Widget _buildSexWidget(String title,bool isSelect) {
... ...
lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart 0 → 100644
  1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:image_picker/image_picker.dart';
  4 +import 'package:permission_handler/permission_handler.dart';
  5 +import 'package:wow_english/common/core/assets_const.dart';
  6 +import 'package:wow_english/common/core/user_util.dart';
  7 +
  8 +part 'user_avatar_event.dart';
  9 +part 'user_avatar_state.dart';
  10 +
  11 +class UserAvatarBloc extends Bloc<UserAvatarEvent, UserAvatarState> {
  12 +
  13 + String _imageUrl = UserUtil.getUser()!.avatarUrl??AssetsConst.wowLogo;
  14 +
  15 + String get imageUrl => _imageUrl;
  16 +
  17 + XFile? _file;
  18 +
  19 + XFile? get file => _file;
  20 +
  21 + bool _canInsertApp =false;
  22 +
  23 + bool get canInsertApp => _canInsertApp;
  24 +
  25 + final ImagePicker picker = ImagePicker();
  26 +
  27 +
  28 + UserAvatarBloc() : super(UserAvatarInitial()) {
  29 + on<ChangeImageEvent>(_changeImage);
  30 + on<GetImageFromPhotoEvent>(_getImageFromPhoto);
  31 + on<GetImageFromCameraEvent>(_getImageFromCamera);
  32 + }
  33 +
  34 + void _changeImage(ChangeImageEvent event,Emitter<UserAvatarState> emitter) async {
  35 + _imageUrl = event.imagePath;
  36 + emitter(ChangeImageState());
  37 + }
  38 +
  39 + void _getImageFromPhoto(GetImageFromPhotoEvent event,Emitter<UserAvatarState> emitter) async {
  40 + await getPhotoPermissionStatus().then((value) async {
  41 + if (!value){
  42 + debugPrint('失败$value');
  43 + return;
  44 + }
  45 + _file = await picker.pickImage(source: ImageSource.gallery);
  46 + emitter(ChangeImageState());
  47 + });
  48 + }
  49 +
  50 + void _getImageFromCamera(GetImageFromCameraEvent event,Emitter<UserAvatarState> emitter) async {
  51 + await getCameraPermissionStatus().then((value) async {
  52 + if (!value){
  53 + debugPrint('失败$value');
  54 + return;
  55 + }
  56 + _file = await picker.pickImage(source: ImageSource.camera);
  57 + emitter(ChangeImageState());
  58 + });
  59 + }
  60 +
  61 + ///获取相机权限
  62 + Future<bool> getCameraPermissionStatus() async {
  63 + Permission permission = Permission.camera;
  64 + //granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示
  65 + PermissionStatus status = await permission.status;
  66 + if (status.isGranted) {
  67 + return true;
  68 + } else if (status.isDenied) {
  69 + _requestPermission(permission);
  70 + } else if (status.isPermanentlyDenied) {
  71 + openAppSettings();
  72 + } else if (status.isRestricted) {
  73 + _requestPermission(permission);
  74 + } else {
  75 +
  76 + }
  77 + return false;
  78 + }
  79 +
  80 + ///获取相册权限
  81 + Future<bool> getPhotoPermissionStatus() async {
  82 + Permission permission = Permission.photos;
  83 + PermissionStatus status = await permission.status;
  84 + if (status.isGranted) {
  85 + return true;
  86 + } else if (status.isDenied) {
  87 + _requestPermission(permission);
  88 + } else if (status.isPermanentlyDenied) {
  89 + openAppSettings();
  90 + } else if (status.isRestricted) {
  91 + _requestPermission(permission);
  92 + } else {
  93 +
  94 + }
  95 + return false;
  96 + }
  97 +
  98 + /// 获取权限
  99 + void _requestPermission(Permission permission) async {
  100 + PermissionStatus status = await permission.request();
  101 + if (status.isPermanentlyDenied) {
  102 + openAppSettings();
  103 + }
  104 + }
  105 +}
... ...
lib/pages/user/modify/user_avatar_bloc/user_avatar_event.dart 0 → 100644
  1 +part of 'user_avatar_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class UserAvatarEvent {}
  5 +
  6 +class GetImageFromPhotoEvent extends UserAvatarEvent {}
  7 +
  8 +class GetImageFromCameraEvent extends UserAvatarEvent {}
  9 +
  10 +class ChangeImageEvent extends UserAvatarEvent {
  11 + final String imagePath;
  12 + ChangeImageEvent(this.imagePath);
  13 +}
... ...
lib/pages/user/modify/user_avatar_bloc/user_avatar_state.dart 0 → 100644
  1 +part of 'user_avatar_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class UserAvatarState {}
  5 +
  6 +class UserAvatarInitial extends UserAvatarState {}
  7 +
  8 +class ChangeImageState extends UserAvatarState {}
... ...
lib/pages/user/modify/user_info_bloc/user_info_bloc.dart 0 → 100644
  1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:wow_english/common/core/user_util.dart';
  4 +
  5 +part 'user_info_event.dart';
  6 +part 'user_info_state.dart';
  7 +
  8 +class UserInfoBloc extends Bloc<UserInfoEvent, UserInfoState> {
  9 + final TextEditingController modifyTextController = TextEditingController();
  10 +
  11 + int _gender = UserUtil.getUser()!.gender??0;
  12 +
  13 + int get gender => _gender;
  14 +
  15 + UserInfoBloc() : super(UserInfoInitial()) {
  16 + on<ChangeGenderEvent>(_changeGender);
  17 + on<InitControllerTextEvent>(_initControllerText);
  18 + }
  19 +
  20 + _initControllerText(InitControllerTextEvent event,Emitter<UserInfoState> emitter) async {
  21 + modifyTextController.text = event.text;
  22 + }
  23 +
  24 + _changeGender(ChangeGenderEvent event,Emitter<UserInfoState> emitter) async {
  25 + _gender = event.gender;
  26 + emitter(ChangeGenderState());
  27 + }
  28 +}
... ...
lib/pages/user/modify/user_info_bloc/user_info_event.dart 0 → 100644
  1 +part of 'user_info_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class UserInfoEvent {}
  5 +
  6 +class InitControllerTextEvent extends UserInfoEvent {
  7 + final String text;
  8 + InitControllerTextEvent(this.text);
  9 +}
  10 +
  11 +class ChangeGenderEvent extends UserInfoEvent {
  12 + final int gender;
  13 + ChangeGenderEvent(this.gender);
  14 +}
... ...
lib/pages/user/modify/user_info_bloc/user_info_state.dart 0 → 100644
  1 +part of 'user_info_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class UserInfoState {}
  5 +
  6 +class UserInfoInitial extends UserInfoState {}
  7 +
  8 +class ChangeGenderState extends UserInfoState {}
... ...
lib/pages/user/user_page.dart
... ... @@ -16,10 +16,7 @@ class UserPage extends StatelessWidget {
16 16  
17 17 @override
18 18 Widget build(BuildContext context) {
19   - return BlocProvider(
20   - create: (context) => UserBloc(),
21   - child: _UserView(),
22   - );
  19 + return _UserView();
23 20 }
24 21 }
25 22  
... ... @@ -32,38 +29,37 @@ class _UserView extends StatelessWidget {
32 29 }
33 30  
34 31 Widget _pageWidget() => BlocBuilder<UserBloc, UserState>(
35   - /*buildWhen: (previous, current) {
  32 + /*buildWhen: (previous, current) {
36 33 return current != previous;
37 34 },*/
38   - builder: (context, state) {
39   - UserEntity user = UserUtil.getUser()!;
40   - final userBloc = BlocProvider.of<UserBloc>(context);
  35 + builder: (context, state) {
  36 + UserEntity user = UserUtil.getUser()!;
  37 + final userBloc = BlocProvider.of<UserBloc>(context);
41 38  
42   - // 常规按钮的字体样式
43   - final textStyle21sp = TextStyle(
44   - //fontWeight: FontWeight.w600,
45   - color: const Color(0xFF333333),
46   - fontSize: 21.sp,
47   - );
  39 + // 常规按钮的字体样式
  40 + final textStyle21sp = TextStyle(
  41 + //fontWeight: FontWeight.w600,
  42 + color: const Color(0xFF333333),
  43 + fontSize: 21.sp,
  44 + );
48 45  
49   - // 常规按钮的样式
50   - var normalButtonStyle = ButtonStyle(
51   - side: MaterialStateProperty.all(BorderSide(color: const Color(0xFF140C10), width: 1.5.w)),
52   - shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
53   - minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)),
54   - backgroundColor: MaterialStateProperty.all(Colors.white),
55   - );
  46 + // 常规按钮的样式
  47 + var normalButtonStyle = ButtonStyle(
  48 + side: MaterialStateProperty.all(BorderSide(color: const Color(0xFF140C10), width: 1.5.w)),
  49 + shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
  50 + minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)),
  51 + backgroundColor: MaterialStateProperty.all(Colors.white),
  52 + );
56 53  
57   - return Scaffold(
58   - //backgroundColor: Colors.white,
59   - appBar: const WEAppBar(),
60   - body: SingleChildScrollView(
61   - padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 10.h, bottom: 22.h),
62   - child: Column(
63   - mainAxisAlignment: MainAxisAlignment.center,
64   - children: <Widget>[
65   - // todo banner,暂时没有接口获取banner URL
66   - /*Offstage(
  54 + return Scaffold(
  55 + appBar: const WEAppBar(),
  56 + body: SingleChildScrollView(
  57 + padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 10.h, bottom: 22.h),
  58 + child: Column(
  59 + mainAxisAlignment: MainAxisAlignment.center,
  60 + children: <Widget>[
  61 + // todo banner,暂时没有接口获取banner URL
  62 + /*Offstage(
67 63 child: Column(
68 64 children: [
69 65 Container(child: Image.asset(bannerUrl), constraints: BoxConstraints(maxHeight: 196.h)),
... ... @@ -71,23 +67,23 @@ class _UserView extends StatelessWidget {
71 67 ],
72 68 ),
73 69 ),*/
74   - Row(
75   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
76   - children: [
77   - CircleAvatar(
78   - radius: 40.r,
79   - backgroundColor: const Color(0xFF140C10),
80   - child: CircleAvatar(
81   - radius: 38.5.r,
82   - backgroundImage: ImageUtil.getImageProviderOnDefault(user.avatarUrl),
83   - ),
84   - /*child: ClipOval(
  70 + Row(
  71 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  72 + children: [
  73 + CircleAvatar(
  74 + radius: 40.r,
  75 + backgroundColor: const Color(0xFF140C10),
  76 + child: CircleAvatar(
  77 + radius: 38.5.r,
  78 + backgroundImage: ImageUtil.getImageProviderOnDefault(user.avatarUrl),
  79 + ),
  80 + /*child: ClipOval(
85 81 child: OwImageWidget(name: user.avatarUrl ?? AssetsConst.wowLogo, fit: BoxFit.contain,),
86 82 )*/
87   - ),
88   - 32.horizontalSpace,
89   - Expanded(
90   - child: Column(
  83 + ),
  84 + 32.horizontalSpace,
  85 + Expanded(
  86 + child: Column(
91 87 children: [
92 88 Row(
93 89 children: [
... ... @@ -131,94 +127,94 @@ class _UserView extends StatelessWidget {
131 127 )
132 128 ],
133 129 )),
134   - Offstage(
135   - offstage: UserUtil.getUser()?.phoneNum == '17730280759',
136   - child: TextButton(
137   - child: Text(
138   - "修改个人信息>",
139   - style: textStyle21sp,
140   - ),
141   - onPressed: () {
142   - pushNamed(AppRouteName.userInformation);
143   - },
144   - ),
145   - )
146   - ],
147   - ),
148   - 30.verticalSpace,
149   - OutlinedButton(
150   - onPressed: () => pushNamed(AppRouteName.fogPwd),
151   - style: normalButtonStyle,
152   - child: Text(
153   - "修改密码",
154   - style: textStyle21sp,
155   - ),
156   - ),
157   - 12.verticalSpace,
158   - // todo 为了过审,把测试账号兑换功能下掉
159   - Offstage(
160   - offstage: UserUtil.getUser()?.phoneNum == '17730280759',
161   - child: OutlinedButton(
162   - onPressed: () => pushNamed(AppRouteName.exLesson),
163   - style: normalButtonStyle,
164   - child: Text(
165   - "兑换课程",
166   - style: textStyle21sp,
167   - )),
168   - ),
169 130 Offstage(
170 131 offstage: UserUtil.getUser()?.phoneNum == '17730280759',
171   - child: 12.verticalSpace,
172   - ),
173   - OutlinedButton(
174   - onPressed: () {
175   - pushNamed(AppRouteName.webView,arguments: {'urlStr': AppConsts.userPrivacyPolicyUrl, 'webViewTitle': '隐私协议'});
176   - },
177   - style: normalButtonStyle,
  132 + child: TextButton(
178 133 child: Text(
179   - "隐私协议",
  134 + "修改个人信息>",
180 135 style: textStyle21sp,
181   - )),
182   - 30.verticalSpace,
183   - OutlinedButton(
184   - onPressed: () => userBloc.add(UserLogout()),
185   - style: ButtonStyle(
186   - side: MaterialStateProperty.all(const BorderSide(color: Color(0xFF140C10), width: 1.5)),
187   - shape: MaterialStateProperty.all(
188   - RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
189   - minimumSize: MaterialStateProperty.all(Size(295.w, 40.h)),
190   - backgroundColor: MaterialStateProperty.all(Color(0xFFFBB621)),
191 136 ),
192   - child: Text(
193   - "退出登录",
194   - style: TextStyle(
195   - //fontWeight: FontWeight.w600,
196   - color: Colors.white,
197   - fontSize: 17.sp,
198   - ),
199   - )),
200   - 30.verticalSpace,
201   - TextButton(
202 137 onPressed: () {
203   - //userBloc.add(UserDelete())
204   - showTwoActionDialog('注销账号', '取消', '注销', '请谨慎操作!\n注销后不可恢复哦!', () {
205   - popPage();
206   - }, () {
207   - userBloc.add(UserDelete());
208   - popPage();
209   - });
  138 + pushNamed(AppRouteName.userInformation);
210 139 },
211   - child: Text(
212   - "注销账号",
213   - style: TextStyle(
214   - //fontWeight: FontWeight.w600,
215   - color: Colors.red,
216   - fontSize: 15.sp,
217   - ),
218   - )),
  140 + ),
  141 + )
219 142 ],
220 143 ),
221   - ));
222   - },
223   - );
  144 + 30.verticalSpace,
  145 + OutlinedButton(
  146 + onPressed: () => pushNamed(AppRouteName.fogPwd),
  147 + style: normalButtonStyle,
  148 + child: Text(
  149 + "修改密码",
  150 + style: textStyle21sp,
  151 + ),
  152 + ),
  153 + 12.verticalSpace,
  154 + // todo 为了过审,把测试账号兑换功能下掉
  155 + Offstage(
  156 + offstage: UserUtil.getUser()?.phoneNum == '17730280759',
  157 + child: OutlinedButton(
  158 + onPressed: () => pushNamed(AppRouteName.exLesson),
  159 + style: normalButtonStyle,
  160 + child: Text(
  161 + "兑换课程",
  162 + style: textStyle21sp,
  163 + )),
  164 + ),
  165 + Offstage(
  166 + offstage: UserUtil.getUser()?.phoneNum == '17730280759',
  167 + child: 12.verticalSpace,
  168 + ),
  169 + OutlinedButton(
  170 + onPressed: () {
  171 + pushNamed(AppRouteName.webView,arguments: {'urlStr': AppConsts.userPrivacyPolicyUrl, 'webViewTitle': '隐私协议'});
  172 + },
  173 + style: normalButtonStyle,
  174 + child: Text(
  175 + "隐私协议",
  176 + style: textStyle21sp,
  177 + )),
  178 + 30.verticalSpace,
  179 + OutlinedButton(
  180 + onPressed: () => userBloc.add(UserLogout()),
  181 + style: ButtonStyle(
  182 + side: MaterialStateProperty.all(const BorderSide(color: Color(0xFF140C10), width: 1.5)),
  183 + shape: MaterialStateProperty.all(
  184 + RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))),
  185 + minimumSize: MaterialStateProperty.all(Size(295.w, 40.h)),
  186 + backgroundColor: MaterialStateProperty.all(Color(0xFFFBB621)),
  187 + ),
  188 + child: Text(
  189 + "退出登录",
  190 + style: TextStyle(
  191 + //fontWeight: FontWeight.w600,
  192 + color: Colors.white,
  193 + fontSize: 17.sp,
  194 + ),
  195 + )),
  196 + 30.verticalSpace,
  197 + TextButton(
  198 + onPressed: () {
  199 + //userBloc.add(UserDelete())
  200 + showTwoActionDialog('注销账号', '取消', '注销', '请谨慎操作!\n注销后不可恢复哦!', () {
  201 + popPage();
  202 + }, () {
  203 + userBloc.add(UserDelete());
  204 + popPage();
  205 + });
  206 + },
  207 + child: Text(
  208 + "注销账号",
  209 + style: TextStyle(
  210 + //fontWeight: FontWeight.w600,
  211 + color: Colors.red,
  212 + fontSize: 15.sp,
  213 + ),
  214 + )),
  215 + ],
  216 + ),
  217 + ));
  218 + },
  219 + );
224 220 }
... ...
lib/route/route.dart
... ... @@ -16,6 +16,7 @@ import &#39;package:wow_english/pages/shop/exchangelist/exchange_lesson_list_page.da
16 16 import 'package:wow_english/pages/shop/home/shop_home_page.dart';
17 17 import 'package:wow_english/pages/tab/tab_page.dart';
18 18 import 'package:wow_english/pages/user/information/user_information_page.dart';
  19 +import 'package:wow_english/pages/user/modify/modify_user_avatar_page.dart';
19 20 import 'package:wow_english/pages/user/modify/modify_user_information_page.dart';
20 21 import 'package:wow_english/pages/user/user_page.dart';
21 22 import 'package:wow_english/pages/video/lookvideo/look_video_page.dart';
... ... @@ -42,6 +43,8 @@ class AppRouteName {
42 43  
43 44 /// 用户详细信息页
44 45 static const String userInformation = 'userInformation';
  46 + /// 修改用户头像
  47 + static const String userAvatar = 'userAvatar';
45 48  
46 49 /// 用户修改信息页,不要自己调用,使用[ModifyUserInformationPage.push]方法,隐藏这种实现
47 50 //static const String userModifyInformation = 'userModifyInformation';
... ... @@ -99,6 +102,13 @@ class AppRouter {
99 102 return CupertinoPageRoute(builder: (_) => const UserPage());
100 103 case AppRouteName.userInformation:
101 104 return CupertinoPageRoute(builder: (_) => const UserInformationPage());
  105 + case AppRouteName.userAvatar:
  106 + var pageType = 0;
  107 + if (settings.arguments != null) {
  108 + final content = (settings.arguments as Map)['pageType'] as String??'0';
  109 + pageType = int.parse(content);
  110 + }
  111 + return CupertinoPageRoute(builder: (_) => ModifyUserAvatarPage(pageType: pageType,));
102 112 /*case AppRouteName.userModifyInformation:
103 113 return CupertinoPageRoute(builder: (_) {
104 114 ModifyUserInformationType argument = ModifyUserInformationType.name;
... ...
pubspec.yaml
... ... @@ -80,7 +80,7 @@ dependencies:
80 80 # 获取设备信息 https://pub.flutter-io.cn/packages/device_info_plus
81 81 device_info_plus: ^9.0.1
82 82 # 用户权限申请 https://pub.dev/packages/permission_handler
83   - permission_handler: ^10.2.0
  83 + permission_handler: ^10.4.1
84 84 # 网络状态监听 https://pub.dev/packages/connectivity_plus
85 85 connectivity_plus: ^4.0.1
86 86 # iOS设备方向控制 https://pub.dev/packages/limiting_direction_csx
... ...