edit_info.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. import 'dart:typed_data';
  2. import 'package:dio/dio.dart';
  3. import 'package:file_picker/file_picker.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_svg/svg.dart';
  6. import 'package:get/get.dart';
  7. import 'package:dio/dio.dart' as adio;
  8. // import 'package:image_cropper/image_cropper.dart';
  9. import 'package:link/view/edit_avatar.dart';
  10. import '../constants.dart';
  11. import '../utils/api.dart';
  12. import '../utils/http_utils.dart';
  13. import '../utils/size_fit.dart';
  14. import '../utils/util.dart';
  15. import 'component/link_btn.dart';
  16. import 'component/toast.dart';
  17. import 'component/top_container.dart';
  18. import 'component/upload_file.dart';
  19. class EditInfo extends StatefulWidget {
  20. const EditInfo({Key? key}) : super(key: key);
  21. @override
  22. State<EditInfo> createState() => _EditInfoState();
  23. }
  24. class _EditInfoState extends State<EditInfo> {
  25. TextEditingController controller = TextEditingController();
  26. TextEditingController introController = TextEditingController();
  27. FocusNode focusNode = FocusNode();
  28. bool isFocus = false;
  29. String nickname = '';
  30. String avatar = '';
  31. String location = '';
  32. Uint8List? chooseImage;
  33. bool isBoy = true;
  34. String intro = '';
  35. Map<String, dynamic>? userData;
  36. @override
  37. void initState() {
  38. // TODO: implement initState
  39. getUserInfo();
  40. Util().setPageTitle('基本信息');
  41. focusNode.addListener(() {
  42. setState(() {
  43. isFocus = focusNode.hasFocus;
  44. });
  45. });
  46. super.initState();
  47. }
  48. Future getUserInfo() async {
  49. var data = await HttpUtils.get(Api.userInfo);
  50. setState(() {
  51. userData = data;
  52. avatar = data['avatar'];
  53. nickname = data['nickname'];
  54. intro = data['signature'];
  55. isBoy = data['sex'] == 'MALE';
  56. location = data['country'] + ' ' + data['city'];
  57. controller.text = nickname;
  58. introController.text = intro;
  59. });
  60. }
  61. @override
  62. void dispose() {
  63. // TODO: implement dispose
  64. focusNode.dispose();
  65. super.dispose();
  66. }
  67. Future commit() async {
  68. if (chooseImage == null && avatar.isEmpty) {
  69. Toast().showInfoText('请上传头像', context: context);
  70. return;
  71. }
  72. if (nickname.isEmpty) {
  73. Toast().showInfoText('请输入昵称', context: context);
  74. return;
  75. }
  76. Toast().showHud(context: context);
  77. var data2 = await HttpUtils.post(Api.userInfo, data: {
  78. 'nickname': nickname,
  79. 'sex': isBoy ? 'MALE' : 'FEMALE',
  80. 'signature': intro,
  81. 'area': '北京',
  82. 'city': '北京',
  83. 'province': '北京',
  84. 'country': '中国'
  85. });
  86. if (data2 != null) {
  87. print(data2.toString());
  88. }
  89. Toast().hideHud();
  90. Get.back();
  91. // Get.toNamed('/edit_base_info');
  92. }
  93. Future chooseFile() async {
  94. FilePickerResult? result =
  95. await FilePicker.platform.pickFiles(type: FileType.image);
  96. if (result != null) {
  97. // setState(() {
  98. // chooseImage = result.files.single.bytes;
  99. // });
  100. Uint8List? temp = result.files.single.bytes;
  101. showDialog(
  102. context: context,
  103. barrierDismissible: false,
  104. barrierColor: Colors.transparent,
  105. useSafeArea: false,
  106. builder: (BuildContext context) {
  107. return EditAvatar(
  108. image: temp!,
  109. callback: (Uint8List img) {
  110. setState(() {
  111. chooseImage = img;
  112. });
  113. uploadImage(img);
  114. },
  115. );
  116. });
  117. // uploadImage(result.files.single.bytes);
  118. // print(result.files.single.path);
  119. }
  120. }
  121. Future uploadImage(Uint8List? imgData) async {
  122. // Toast().showHud(context: context);
  123. Map<String, dynamic> data = await HttpUtils.get(Api.ossFormUpload,
  124. params: {'type': 'AVATAR', 'file_ext': 'png'});
  125. Dio dio = Dio();
  126. Map<String, dynamic> map = data['fields'];
  127. map['file'] =
  128. await adio.MultipartFile.fromBytes(imgData!, filename: 'avatar.png');
  129. adio.FormData formData = adio.FormData.fromMap(map);
  130. adio.Response response = await dio.post(data['upload_url'], data: formData);
  131. var data2 =
  132. await HttpUtils.post(Api.userInfo, data: {'avatar': data['view_url']});
  133. if (data2 != null) {
  134. print(data['view_url']);
  135. // getUserInfo();
  136. }
  137. // Toast().hideHud();
  138. }
  139. @override
  140. Widget build(BuildContext context) {
  141. SizeFit.initialize(context);
  142. TextStyle style = TextStyle(
  143. color: kThemeColor, fontSize: 16.px, fontWeight: FontWeight.bold);
  144. if (userData == null) {
  145. return const Material(color: kBgColor);
  146. }
  147. return Material(
  148. color: kBgColor,
  149. child: TopContainer(
  150. child: Stack(children: [
  151. Positioned(
  152. left: 0,
  153. top: 0,
  154. right: 0,
  155. bottom: 0,
  156. child: Padding(
  157. padding: EdgeInsets.only(
  158. bottom: MediaQuery.of(context).viewInsets.bottom),
  159. child: SingleChildScrollView(
  160. child: Column(children: [
  161. SizedBox(
  162. height: 32.px,
  163. ),
  164. UploadFile(
  165. child: ClipRRect(
  166. borderRadius: BorderRadius.circular(70.px),
  167. child: Container(
  168. width: 140.px,
  169. height: 140.px,
  170. alignment: Alignment.bottomCenter,
  171. decoration: BoxDecoration(
  172. image: chooseImage != null
  173. ? DecorationImage(
  174. image: MemoryImage(chooseImage!),
  175. fit: BoxFit.cover)
  176. : avatar.isNotEmpty
  177. ? DecorationImage(
  178. image: NetworkImage(avatar),
  179. fit: BoxFit.cover)
  180. : const DecorationImage(
  181. image: AssetImage(
  182. 'assets/images/default_avatar.png'))),
  183. child: Container(
  184. height: 28.px,
  185. color: kThemeColor,
  186. alignment: Alignment.center,
  187. child: SvgPicture.asset(
  188. 'assets/icons/edit.svg',
  189. width: 24.px,
  190. height: 24.px,
  191. color: Colors.black,
  192. ),
  193. ),
  194. )),
  195. callback: (Uint8List file) {
  196. showDialog(
  197. context: context,
  198. barrierDismissible: false,
  199. barrierColor: Colors.transparent,
  200. useSafeArea: false,
  201. builder: (BuildContext context) {
  202. return EditAvatar(
  203. image: file,
  204. callback: (Uint8List img) {
  205. setState(() {
  206. chooseImage = img;
  207. });
  208. uploadImage(img);
  209. },
  210. );
  211. });
  212. // setState(() {
  213. // chooseImage = file;
  214. // });
  215. // showDialog(
  216. // context: context,
  217. // barrierDismissible: false,
  218. // barrierColor: Colors.transparent,
  219. // useSafeArea: false,
  220. // builder: (BuildContext context) {
  221. // return EditAvatar(
  222. // image: chooseImage!,
  223. // );
  224. // });
  225. // uploadImage(file);
  226. },
  227. ),
  228. SizedBox(
  229. height: 24.px,
  230. ),
  231. Container(
  232. width: 315.px,
  233. height: 68.px,
  234. alignment: Alignment.centerLeft,
  235. padding: EdgeInsets.only(left: 16.px, right: 16.px),
  236. decoration: BoxDecoration(
  237. borderRadius: BorderRadius.circular(16.px),
  238. color: const Color(0xFF2C2C2E)),
  239. child: TextField(
  240. // autofocus: true,
  241. controller: controller,
  242. focusNode: focusNode,
  243. maxLength: 50,
  244. cursorColor: kBtnColor,
  245. onChanged: (value) {
  246. setState(() {
  247. nickname = value;
  248. });
  249. },
  250. textAlign: TextAlign.center,
  251. style: TextStyle(
  252. color: Colors.white,
  253. fontSize: 28.px),
  254. decoration: InputDecoration(
  255. border: InputBorder.none,
  256. hintText: isFocus ? '' : '请输入您的昵称',
  257. hintStyle: TextStyle(
  258. fontSize: 20.px,
  259. color: const Color(0xFF74747A)),
  260. counterText: "",
  261. ),
  262. )),
  263. SizedBox(
  264. height: 40.px,
  265. ),
  266. Container(
  267. width: 343.px,
  268. padding:
  269. EdgeInsets.fromLTRB(20.px, 18.px, 20.px, 18.px),
  270. decoration: BoxDecoration(
  271. color: const Color(0xFF2C2C2E),
  272. borderRadius: BorderRadius.circular(24.px)),
  273. child: Column(
  274. mainAxisAlignment: MainAxisAlignment.start,
  275. crossAxisAlignment: CrossAxisAlignment.start,
  276. children: [
  277. Row(
  278. children: [
  279. Text(
  280. '性别',
  281. style: style,
  282. ),
  283. Expanded(child: Container()),
  284. GestureDetector(
  285. onTap: () {
  286. setState(() {
  287. isBoy = true;
  288. });
  289. },
  290. child: Container(
  291. alignment: Alignment.center,
  292. width: 40.px,
  293. height: 40.px,
  294. decoration: BoxDecoration(
  295. borderRadius:
  296. BorderRadius.circular(20.px),
  297. color: isBoy
  298. ? const Color(0xFF00FFFF)
  299. : const Color(0xFF444447)),
  300. child: SvgPicture.asset(
  301. 'assets/icons/gender_male.svg',
  302. width: 24.px,
  303. height: 24.px,
  304. ),
  305. ),
  306. ),
  307. SizedBox(
  308. width: 16.px,
  309. ),
  310. GestureDetector(
  311. onTap: () {
  312. setState(() {
  313. isBoy = false;
  314. });
  315. },
  316. child: Container(
  317. alignment: Alignment.center,
  318. width: 40.px,
  319. height: 40.px,
  320. decoration: BoxDecoration(
  321. borderRadius:
  322. BorderRadius.circular(20.px),
  323. color: !isBoy
  324. ? const Color(0xFFFF00AA)
  325. : const Color(0xFF444447)),
  326. child: SvgPicture.asset(
  327. 'assets/icons/gender_female.svg',
  328. width: 24.px,
  329. height: 24.px,
  330. ),
  331. ),
  332. )
  333. ],
  334. ),
  335. Container(
  336. margin:
  337. EdgeInsets.only(top: 18.px, bottom: 18.px),
  338. height: 1.px,
  339. color: const Color(0xFF404040),
  340. ),
  341. GestureDetector(
  342. child: Row(
  343. children: [
  344. Text('地区', style: style),
  345. Expanded(child: Container()),
  346. Text(
  347. '中国 北京',
  348. style: TextStyle(
  349. color: Colors.white, fontSize: 14.px),
  350. ),
  351. Image.asset(
  352. 'assets/images/arrow_right.png',
  353. width: 20.px,
  354. height: 20.px,
  355. )
  356. // SvgPicture.asset(
  357. // 'assets/icons/arrow_right.svg',
  358. // color: const Color(0xFF444447),
  359. // width: 20.px,
  360. // height: 20.px,
  361. // )
  362. ],
  363. ),
  364. ),
  365. Container(
  366. margin:
  367. EdgeInsets.only(top: 18.px, bottom: 18.px),
  368. height: 1.px,
  369. color: const Color(0xFF404040),
  370. ),
  371. Text('简介', style: style),
  372. TextField(
  373. maxLength: 1000,
  374. maxLines: 1000,
  375. minLines: 1,
  376. controller: introController,
  377. cursorColor: kBtnColor,
  378. style: TextStyle(
  379. color: Colors.white,
  380. fontSize: 14.px,
  381. ),
  382. onChanged: (e) {
  383. setState(() {
  384. intro = e;
  385. });
  386. },
  387. decoration: InputDecoration(
  388. border: InputBorder.none,
  389. hintText: '请填写您的简介(选填)',
  390. hintStyle: TextStyle(
  391. fontSize: 14.px,
  392. color: const Color(0xFF74747A)),
  393. counterText: "",
  394. )),
  395. ])),
  396. SizedBox(
  397. height: 30.px,
  398. ),
  399. LinkButton(
  400. title: '提交',
  401. disable: false,
  402. isBlack: false,
  403. callback: () {
  404. commit();
  405. })
  406. ]))))
  407. ])));
  408. }
  409. }