UserChange.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. import 'package:flutter/material.dart';
  2. import 'package:file_picker/file_picker.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter_screenutil/flutter_screenutil.dart';
  5. import 'package:dio/dio.dart';
  6. import 'package:intl/intl.dart';
  7. import 'package:jpush_flutter/jpush_flutter.dart';
  8. import 'package:package_info/package_info.dart';
  9. import 'package:shared_preferences/shared_preferences.dart';
  10. import './loginFirst.dart';
  11. import '../styles/colors.dart';
  12. import 'dart:io';
  13. import 'dart:async';
  14. import 'dart:ui';
  15. import '../styles/totast.dart';
  16. import 'ChangeUserInfo.dart';
  17. import 'package:redux/redux.dart';
  18. import 'package:flutter_redux/flutter_redux.dart';
  19. import '../redux/AppState.dart';
  20. import '../model/UserInfo.dart';
  21. import '../net/HttpManager.dart';
  22. import '../net/Result.dart';
  23. import '../redux/UserRedux.dart';
  24. import 'package:image_cropper/image_cropper.dart';
  25. class UserChange extends StatefulWidget {
  26. @override
  27. UserChangeState createState() => UserChangeState();
  28. }
  29. class UserChangeState extends State<UserChange> {
  30. String version = '';
  31. bool receiveMsg = false;
  32. @override
  33. void initState() {
  34. super.initState();
  35. PackageInfo.fromPlatform().then((packageInfo) {
  36. setState(() {
  37. version = packageInfo.version;
  38. });
  39. });
  40. }
  41. @override
  42. Widget build(BuildContext context) {
  43. ScreenUtil.instance = ScreenUtil(width: 375, height: 667)..init(context);
  44. return StoreConnector<AppState, UserInfo>(
  45. converter: (Store store) => store.state.userInfo,
  46. builder: (context, userInfo) {
  47. return WillPopScope(
  48. key: Key('UserChangesPage'),
  49. child: Scaffold(
  50. backgroundColor: PAGE_BACKGROUND_COLOR,
  51. appBar: AppBar(
  52. backgroundColor: PRIMARY_COLOR,
  53. title: Text('系统设置'),
  54. centerTitle: true,
  55. elevation: 0,
  56. ),
  57. body: Stack(
  58. children: <Widget>[
  59. RefreshIndicator(
  60. color: PRIMARY_COLOR,
  61. backgroundColor: Colors.white,
  62. displacement: 10,
  63. onRefresh: () async {
  64. await Future.delayed(const Duration(seconds: 1));
  65. getUserInfo();
  66. },
  67. child: SizedBox.expand(
  68. child: SingleChildScrollView(
  69. physics: AlwaysScrollableScrollPhysics(),
  70. child: Column(
  71. children: <Widget>[
  72. _sectionDivier(),
  73. _section([
  74. _cell(
  75. '头像',
  76. ClipOval(
  77. child: Image.network(userInfo.icon, width: 36, height: 36),
  78. ),
  79. onTap: () {
  80. _chooseImage();
  81. },
  82. ),
  83. _cell(
  84. '昵称',
  85. userInfo.nickname,
  86. placeholder: '请填写昵称',
  87. onTap: () {
  88. Navigator.push(
  89. context, CupertinoPageRoute(builder: (context) => ChangeUserInfo(title: '昵称', val: userInfo.nickname)));
  90. },
  91. ),
  92. _cell(
  93. '性别',
  94. userInfo.sex,
  95. placeholder: '请添加性别信息',
  96. onTap: () {
  97. _chooseSex(context);
  98. },
  99. ),
  100. _cell(
  101. '生日',
  102. DateFormat('yyyy-MM-dd').format(
  103. DateTime.fromMillisecondsSinceEpoch(userInfo.birthday),
  104. ),
  105. placeholder: '选择生日',
  106. onTap: () {
  107. _chooseBirthday(context);
  108. },
  109. ),
  110. _cell('手机', userInfo.phone, showBorder: false, onTap: () {
  111. Navigator.push(context, CupertinoPageRoute(builder: (context) => ChangeUserInfo(title: '手机号', val: userInfo.phone)));
  112. })
  113. ]),
  114. ],
  115. ),
  116. ),
  117. ),
  118. ),
  119. Positioned(
  120. bottom: 10,
  121. right: 15,
  122. left: 15,
  123. height: 48,
  124. child: FlatButton(
  125. textColor: Colors.white,
  126. color: PRIMARY_COLOR,
  127. highlightColor: Color(0xFF763434),
  128. child: Text(
  129. '退出登录',
  130. style: TextStyle(fontSize: 16, fontWeight: FontWeight.w700),
  131. ),
  132. onPressed: () async {
  133. Toast.show(context, '退出成功', 1500, 'success');
  134. Navigator.push(context, MaterialPageRoute(builder: (context) => LoginFirst()));
  135. final prefs = await SharedPreferences.getInstance();
  136. prefs.remove('token');
  137. JPush jpush = JPush();
  138. jpush.deleteAlias();
  139. // Future.delayed(const Duration(seconds: 1), () {
  140. // StoreProvider.of<AppState>(context).dispatch(UpdateUserAction(null));
  141. // });
  142. }),
  143. )
  144. ],
  145. ),
  146. ),
  147. onWillPop: () {
  148. Toast.hide();
  149. Navigator.pop(context);
  150. return Future.value(false);
  151. });
  152. });
  153. }
  154. Future<void> updateUserInfo(userInfo, value, key) async {
  155. if (Toast.preToast == null) {
  156. Toast.show(context, '加载中', -1, 'loading');
  157. }
  158. final Result res = await HttpManager.post('userInfo/update', data: {'id': userInfo.id, key: value});
  159. Toast.hide();
  160. if (res.success) {
  161. Toast.show(context, '修改成功', 1500, 'success');
  162. getUserInfo();
  163. } else {
  164. Toast.show(context, res.error, 1500, 'info');
  165. }
  166. }
  167. Future<void> getUserInfo() async {
  168. Result res = await HttpManager.get('userInfo/getUserInfo');
  169. if (res.success) {
  170. StoreProvider.of<AppState>(context).dispatch(UpdateUserAction(UserInfo.fromJson(res.data)));
  171. } else {}
  172. }
  173. Future<void> _chooseSex(BuildContext context) async {
  174. String sex = await showCupertinoModalPopup(
  175. context: context,
  176. builder: (BuildContext context) {
  177. return CupertinoActionSheet(
  178. title: Text('选择性别'),
  179. actions: <Widget>[
  180. CupertinoActionSheetAction(
  181. child: Text('男'),
  182. onPressed: () {
  183. Navigator.pop(context, '男');
  184. },
  185. ),
  186. CupertinoActionSheetAction(
  187. child: Text('女'),
  188. onPressed: () {
  189. Navigator.pop(context, '女');
  190. },
  191. )
  192. ],
  193. cancelButton: CupertinoDialogAction(
  194. child: const Text('取消'),
  195. onPressed: () {
  196. Navigator.pop(context);
  197. },
  198. ),
  199. );
  200. });
  201. if (sex != null) {
  202. updateUserInfo(StoreProvider.of<AppState>(context).state.userInfo, sex, 'sex');
  203. }
  204. }
  205. Future<void> _chooseBirthday(BuildContext context) async {
  206. UserInfo userInfo = StoreProvider.of<AppState>(context).state.userInfo;
  207. DateTime date = userInfo.birthday > 0 ? DateTime.fromMillisecondsSinceEpoch(userInfo.birthday) : DateTime.now();
  208. DateTime res = await showCupertinoModalPopup<DateTime>(
  209. context: context,
  210. builder: (BuildContext context) {
  211. return Container(
  212. height: 216,
  213. color: CupertinoColors.white,
  214. child: Column(
  215. children: <Widget>[
  216. SizedBox(
  217. height: 44,
  218. child: Stack(
  219. children: <Widget>[
  220. Positioned(
  221. left: 0,
  222. top: 0,
  223. bottom: 0,
  224. child: CupertinoButton(
  225. child: Text(
  226. '取消',
  227. style: TextStyle(color: PRIMARY_COLOR),
  228. ),
  229. onPressed: () {
  230. Navigator.of(context).pop();
  231. },
  232. ),
  233. ),
  234. Positioned(
  235. right: 0,
  236. top: 0,
  237. bottom: 0,
  238. child: CupertinoButton(
  239. child: Text(
  240. '确定',
  241. style: TextStyle(color: PRIMARY_COLOR),
  242. ),
  243. onPressed: () {
  244. Navigator.of(context).pop(date);
  245. },
  246. ),
  247. )
  248. ],
  249. ),
  250. ),
  251. Expanded(
  252. flex: 1,
  253. child: DefaultTextStyle(
  254. style: const TextStyle(
  255. color: CupertinoColors.black,
  256. fontSize: 22.0,
  257. ),
  258. child: GestureDetector(
  259. // Blocks taps from propagating to the modal sheet and popping.
  260. onTap: () {},
  261. child: SafeArea(
  262. top: false,
  263. child: CupertinoDatePicker(
  264. mode: CupertinoDatePickerMode.date,
  265. initialDateTime: date,
  266. onDateTimeChanged: (DateTime newDateTime) {
  267. date = newDateTime;
  268. },
  269. ),
  270. ),
  271. ),
  272. ),
  273. )
  274. ],
  275. ),
  276. );
  277. },
  278. );
  279. if (res != null) {
  280. updateUserInfo(userInfo, res.millisecondsSinceEpoch, 'birthday');
  281. }
  282. }
  283. Future<void> _chooseImage() async {
  284. String path = await FilePicker.getFilePath(type: FileType.IMAGE);
  285. if (path == null) {
  286. return;
  287. }
  288. File croppedFile = await ImageCropper.cropImage(
  289. sourcePath: path,
  290. ratioX: 1.0,
  291. ratioY: 1.0,
  292. maxWidth: 512,
  293. maxHeight: 512,
  294. toolbarColor: PRIMARY_COLOR,
  295. );
  296. if (croppedFile == null) {
  297. return;
  298. }
  299. Toast.show(context, '加载中', -1, 'loading');
  300. Result res = await HttpManager.post('assets/uploadFile', data: {
  301. 'file': UploadFileInfo(croppedFile, croppedFile.path),
  302. });
  303. Toast.hide();
  304. if (res.success) {
  305. updateUserInfo(StoreProvider.of<AppState>(context).state.userInfo, res.data[0], 'icon');
  306. }
  307. }
  308. Widget _sectionDivier() {
  309. return SizedBox(height: 10);
  310. }
  311. Widget _section(List<Widget> children) {
  312. return Container(
  313. color: CELL_COLOR,
  314. child: Column(
  315. children: children,
  316. ),
  317. );
  318. }
  319. Widget _cell(String title, dynamic child, {String placeholder, void Function() onTap, bool showBorder = true}) {
  320. Widget secondChild;
  321. if (child == null || (child is String && child.isEmpty)) {
  322. secondChild = Text(
  323. placeholder ?? '',
  324. style: TextStyle(color: PLACEHOLDER_COLOR, fontSize: 13),
  325. );
  326. } else if (child is String) {
  327. secondChild = Text(
  328. child ?? '',
  329. style: TextStyle(color: Colors.white, fontSize: 15),
  330. );
  331. } else {
  332. secondChild = child;
  333. }
  334. return Container(
  335. height: 60,
  336. padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
  337. child: GestureDetector(
  338. onTap: onTap,
  339. child: Container(
  340. decoration: BoxDecoration(
  341. border: Border(
  342. bottom: BorderSide(
  343. color: Color(0x2E000000),
  344. width: showBorder ? 1 : 0,
  345. ),
  346. ),
  347. ),
  348. child: Row(
  349. mainAxisAlignment: MainAxisAlignment.center,
  350. children: <Widget>[
  351. Expanded(
  352. child: Text(
  353. title ?? '',
  354. style: TextStyle(color: Colors.white, fontSize: 14),
  355. ),
  356. ),
  357. secondChild,
  358. Padding(
  359. padding: EdgeInsets.only(left: 2),
  360. child: Image.asset(
  361. 'images/icon_inter.png',
  362. width: 24,
  363. height: 24,
  364. ),
  365. )
  366. ],
  367. ),
  368. ),
  369. ),
  370. );
  371. }
  372. }