UserSettingPage.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. import 'dart:io';
  2. import 'dart:typed_data';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_habit/common/BaseArchitectural.dart';
  5. import 'package:flutter_habit/common/I18N.dart';
  6. import 'package:flutter_habit/common/components/PopMenus.dart';
  7. import 'package:flutter_habit/provider/UserProvider.dart';
  8. import 'package:flutter_habit/common/utils/VerificationUtils.dart';
  9. import 'package:flutter_habit/network/Repository.dart';
  10. import 'package:flutter_habit/view/drawer/user/setting/CropImagePage.dart';
  11. import 'package:flutter_habit/view/drawer/user/sign/ModifyPwdPage.dart';
  12. import 'package:image_picker/image_picker.dart';
  13. import 'package:provider/provider.dart';
  14. class UserSettingPage extends StatelessWidget {
  15. @override
  16. Widget build(BuildContext context) {
  17. return MultiProvider(
  18. providers: [
  19. ChangeNotifierProvider<UserSettingPageService>(
  20. create: (_) => UserSettingPageService(context)),
  21. ChangeNotifierProvider<UserSettingPageModel>(
  22. create: (_) => UserSettingPageModel(context)),
  23. ],
  24. child: _UserSettingPageView(),
  25. );
  26. }
  27. }
  28. // model
  29. class UserSettingPageModel extends BaseModel {
  30. UserSettingPageModel(BuildContext context) : super(context);
  31. late bool isRequesting;
  32. @override
  33. void init(BuildContext context) {
  34. super.init(context);
  35. isRequesting = false;
  36. }
  37. }
  38. // service
  39. class UserSettingPageService extends BaseProvider {
  40. UserSettingPageService(BuildContext context) : super(context);
  41. Future<void> modifyAndUploadUserInfo(
  42. BuildContext context, {
  43. String? userName,
  44. String? gender,
  45. String? birthday,
  46. }) async {
  47. UserSettingPageModel model =
  48. Provider.of<UserSettingPageModel>(context, listen: false);
  49. model.isRequesting = true;
  50. model.refresh();
  51. UserProvider userProvider =
  52. Provider.of<UserProvider>(context, listen: false);
  53. bool isSuccess = await Repository.getInstance()!.modifyUserInfo(
  54. context,
  55. userProvider.token,
  56. userProvider.uid,
  57. userName,
  58. gender,
  59. birthday,
  60. );
  61. if (isSuccess) {
  62. userProvider.userName = userName ?? userProvider.userName;
  63. userProvider.gender = gender ?? userProvider.gender;
  64. userProvider.birthday = birthday ?? userProvider.birthday;
  65. userProvider.refresh();
  66. await PopMenus.attention(
  67. context: context, content: Text(I18N.of("修改成功")));
  68. }
  69. model.isRequesting = false;
  70. model.refresh();
  71. }
  72. Future<void> modifyAndUploadPhoto(
  73. BuildContext context, List<int> photo) async {
  74. UserSettingPageModel model =
  75. Provider.of<UserSettingPageModel>(context, listen: false);
  76. model.isRequesting = true;
  77. model.refresh();
  78. UserProvider userProvider =
  79. Provider.of<UserProvider>(context, listen: false);
  80. bool isSuccess = await Repository.getInstance()!
  81. .uploadPhoto(context, userProvider.token, userProvider.uid, photo);
  82. if (isSuccess) {
  83. userProvider.photo = Uint8List.fromList(photo);
  84. userProvider.store();
  85. userProvider.refresh();
  86. await PopMenus.attention(
  87. context: context, content: Text(I18N.of("修改成功")));
  88. }
  89. model.isRequesting = false;
  90. model.refresh();
  91. }
  92. Future<void> modifyUserPhoto(BuildContext context) async {
  93. List<int>? res = await PopMenus.baseMenu(
  94. context: context,
  95. title: Text(I18N.of("修改头像")),
  96. children: <Widget>[
  97. ListTile(
  98. leading: Icon(Icons.camera),
  99. title: Text(I18N.of("拍照")),
  100. trailing: Icon(Icons.chevron_right),
  101. onTap: () async =>
  102. Navigator.of(context).pop(await takePhoto(context)),
  103. ),
  104. ListTile(
  105. leading: Icon(Icons.photo),
  106. title: Text(I18N.of("从相册中选择")),
  107. trailing: Icon(Icons.chevron_right),
  108. onTap: () async =>
  109. Navigator.of(context).pop(await pickPhoto(context)),
  110. ),
  111. ],
  112. );
  113. if (res != null) {
  114. await modifyAndUploadPhoto(context, res);
  115. }
  116. }
  117. Future<List<int>?> takePhoto(BuildContext context) async {
  118. XFile? xfile = await ImagePicker().pickImage(source: ImageSource.camera);
  119. if (xfile != null) {
  120. List<int>? res = await Navigator.of(context).push(
  121. MaterialPageRoute(builder: (_) => CropImagePage(File(xfile.path))));
  122. if (res != null && res.isNotEmpty) {
  123. return res;
  124. }
  125. }
  126. return null;
  127. }
  128. Future<List<int>?> pickPhoto(BuildContext context) async {
  129. XFile? xfile = await ImagePicker().pickImage(source: ImageSource.gallery);
  130. if (xfile != null) {
  131. List<int>? res = await Navigator.of(context).push(
  132. MaterialPageRoute(builder: (_) => CropImagePage(File(xfile.path))));
  133. if (res != null && res.isNotEmpty) {
  134. return res;
  135. }
  136. }
  137. return null;
  138. }
  139. Future<void> modifyUserName(BuildContext context) async {
  140. UserProvider userProvider =
  141. Provider.of<UserProvider>(context, listen: false);
  142. TextEditingController controller = TextEditingController();
  143. controller.text = userProvider.userName!;
  144. String? res = await PopMenus.baseMenu<String>(
  145. context: context,
  146. title: Text(I18N.of("修改用户名")),
  147. children: <Widget>[
  148. TextFormField(
  149. autovalidateMode: AutovalidateMode.always,
  150. validator: (v) {
  151. if (VerifyUtils.isUserName(v)) {
  152. return null;
  153. }
  154. return I18N.of("长度为2-10个不包括任何符号的字符");
  155. },
  156. controller: controller,
  157. decoration: InputDecoration(
  158. labelText: I18N.of("用户名"),
  159. hintText: I18N.of("请输入新用户名"),
  160. ),
  161. ),
  162. TextButton(
  163. child: Text(I18N.of("确定")),
  164. onPressed: () {
  165. if (VerifyUtils.isUserName(controller.text)) {
  166. Navigator.of(context).pop(controller.text.trim());
  167. }
  168. },
  169. ),
  170. ],
  171. contentPadding: EdgeInsets.all(16),
  172. );
  173. if (res != null && res != userProvider.userName) {
  174. await modifyAndUploadUserInfo(context, userName: res);
  175. }
  176. }
  177. void signOut(BuildContext context) {
  178. UserProvider userProvider =
  179. Provider.of<UserProvider>(context, listen: false);
  180. PopMenus.confirm(
  181. context: context,
  182. function: () async {
  183. await userProvider.cleanDataAndBackToHome(context);
  184. },
  185. );
  186. }
  187. Future<void> modifyUserGender(BuildContext context) async {
  188. String? res = await PopMenus.baseMenu<String>(
  189. context: context,
  190. title: Text(I18N.of("修改用户名")),
  191. children: <Widget>[
  192. ListTile(
  193. leading: Icon(Icons.tag_faces),
  194. title: Text(I18N.of("男")),
  195. trailing: Icon(Icons.arrow_right),
  196. onTap: () => Navigator.of(context).pop("男"),
  197. ),
  198. ListTile(
  199. leading: Icon(Icons.face),
  200. title: Text(I18N.of("女")),
  201. trailing: Icon(Icons.arrow_right),
  202. onTap: () => Navigator.of(context).pop("女"),
  203. ),
  204. ],
  205. contentPadding: EdgeInsets.all(16),
  206. );
  207. if (res != null) {
  208. await modifyAndUploadUserInfo(context, gender: res);
  209. }
  210. }
  211. Future<void> modifyUserBirthday(BuildContext context) async {
  212. String res = await PopMenus.datePicker(context: context);
  213. if (res != null) {
  214. await modifyAndUploadUserInfo(context, birthday: res.substring(0, 10));
  215. }
  216. }
  217. void toModifyPwdPage(BuildContext context) {
  218. Navigator.of(context)
  219. .push(MaterialPageRoute(builder: (_) => ModifyPwdPage()));
  220. }
  221. }
  222. // view
  223. class _UserSettingPageView extends StatelessWidget {
  224. @override
  225. Widget build(BuildContext context) {
  226. UserSettingPageService service =
  227. Provider.of<UserSettingPageService>(context, listen: false);
  228. UserSettingPageModel model =
  229. Provider.of<UserSettingPageModel>(context, listen: true);
  230. return Scaffold(
  231. appBar: AppBar(
  232. title: Text(I18N.of("用户设置")),
  233. ),
  234. body: Padding(
  235. padding: EdgeInsets.all(16),
  236. child: ListView(
  237. children: <Widget>[
  238. model.isRequesting ? LinearProgressIndicator() : Container(),
  239. Icon(
  240. Icons.settings,
  241. size: 150,
  242. color: Theme.of(context).unselectedWidgetColor,
  243. ),
  244. Divider(),
  245. ListTile(
  246. leading: Icon(Icons.add_a_photo),
  247. title: Text(I18N.of("修改头像")),
  248. trailing: Icon(Icons.chevron_right),
  249. onTap: model.isRequesting
  250. ? null
  251. : () => service.modifyUserPhoto(context),
  252. ),
  253. ListTile(
  254. leading: Icon(Icons.account_box),
  255. title: Text(I18N.of("修改用户名")),
  256. trailing: Icon(Icons.chevron_right),
  257. onTap: model.isRequesting
  258. ? null
  259. : () => service.modifyUserName(context),
  260. ),
  261. ListTile(
  262. leading: Icon(Icons.supervisor_account),
  263. title: Text(I18N.of("修改性别")),
  264. trailing: Icon(Icons.chevron_right),
  265. onTap: model.isRequesting
  266. ? null
  267. : () => service.modifyUserGender(context),
  268. ),
  269. ListTile(
  270. leading: Icon(Icons.cake),
  271. title: Text(I18N.of("修改生日")),
  272. trailing: Icon(Icons.chevron_right),
  273. onTap: model.isRequesting
  274. ? null
  275. : () => service.modifyUserBirthday(context),
  276. ),
  277. ListTile(
  278. leading: Icon(Icons.lock),
  279. title: Text(I18N.of("重设密码")),
  280. trailing: Icon(Icons.chevron_right),
  281. onTap: model.isRequesting
  282. ? null
  283. : () => service.toModifyPwdPage(context),
  284. ),
  285. ListTile(
  286. leading: Icon(Icons.exit_to_app),
  287. title: Text(I18N.of("登出")),
  288. trailing: Icon(Icons.chevron_right),
  289. onTap: model.isRequesting ? null : () => service.signOut(context),
  290. ),
  291. ],
  292. ),
  293. ),
  294. );
  295. }
  296. }