add_link.dart 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  1. import 'dart:convert';
  2. import 'dart:html';
  3. import 'dart:typed_data';
  4. import 'package:avoid_keyboard/avoid_keyboard.dart';
  5. import 'package:dotted_border/dotted_border.dart';
  6. import 'package:file_picker/file_picker.dart';
  7. import 'package:flutter/material.dart';
  8. import 'package:flutter/services.dart';
  9. import 'package:flutter_svg/svg.dart';
  10. import 'package:get/get.dart';
  11. import 'package:link/view/component/link_btn.dart';
  12. import 'package:link/view/component/toast.dart';
  13. import 'package:link/view/component/web_image.dart';
  14. import 'package:link/view/preview.dart';
  15. import 'package:web_smooth_scroll/web_smooth_scroll.dart';
  16. import '../constants.dart';
  17. import '../utils/api.dart';
  18. import '../utils/http_utils.dart';
  19. import '../utils/size_fit.dart';
  20. import '../utils/storage.dart';
  21. import 'component/link_step.dart';
  22. import 'component/top_container.dart';
  23. import 'package:dio/dio.dart' as adio;
  24. import 'package:dio/dio.dart';
  25. import 'component/upload_file.dart';
  26. class AddLink extends StatelessWidget {
  27. const AddLink({Key? key}) : super(key: key);
  28. @override
  29. Widget build(BuildContext context) {
  30. return Material(
  31. color: kBgColor, child: TopContainer(child: AddLinkContent()));
  32. }
  33. }
  34. class AddLinkContent extends StatefulWidget {
  35. const AddLinkContent({Key? key}) : super(key: key);
  36. @override
  37. State<AddLinkContent> createState() => _AddLinkContentState();
  38. }
  39. class _AddLinkContentState extends State<AddLinkContent> {
  40. TextEditingController controller = TextEditingController();
  41. TextEditingController titleController = TextEditingController();
  42. TextEditingController descController = TextEditingController();
  43. FileUploadInputElement uploadInput = FileUploadInputElement();
  44. bool isLink = true;
  45. bool showError = false;
  46. Uint8List? chooseImage;
  47. String strPicUrl = '';
  48. bool isFirstEnter = true;
  49. var social;
  50. late List types;
  51. late ScrollController scrollController;
  52. @override
  53. void initState() {
  54. scrollController = ScrollController();
  55. Map<String, dynamic> data = Get.parameters;
  56. social = jsonDecode(data['social']);
  57. types = social['types'];
  58. if (types[0] == 'LINK') {
  59. isLink = true;
  60. } else {
  61. isLink = false;
  62. }
  63. isFirstEnter = data['add_more'] != '1';
  64. loadCache();
  65. saveCache();
  66. super.initState();
  67. }
  68. @override
  69. dispose() {
  70. clearCache();
  71. controller.dispose();
  72. titleController.dispose();
  73. descController.dispose();
  74. super.dispose();
  75. }
  76. loadCache() {
  77. var json = isFirstEnter
  78. ? StorageUtil().getJSON('tempGuideLink1')
  79. : StorageUtil().getJSON('tempLink');
  80. if (json != null) {
  81. setState(() {
  82. isLink = json['type'] == 'LINK';
  83. controller.text = json['link'].toString();
  84. titleController.text = json['title'].toString();
  85. descController.text = json['desc'].toString();
  86. });
  87. }
  88. }
  89. Future chooseFile() async {
  90. uploadInput.accept = '.png,.jpg,.jpeg';
  91. uploadInput.multiple = false;
  92. uploadInput.click();
  93. uploadInput.onChange.listen((e) {
  94. final files = uploadInput.files;
  95. if (files?.length == 1) {
  96. FileReader reader = FileReader();
  97. reader.onLoadEnd.listen((event) {
  98. setState(() {
  99. chooseImage = reader.result as Uint8List;
  100. });
  101. uploadImg();
  102. });
  103. reader.readAsArrayBuffer(files![0]);
  104. }
  105. });
  106. }
  107. Future uploadImg() async {
  108. // qrCode.scanRgbaBytes(chooseImage!, 3000, 3000);
  109. // if (qrCode.location == null){
  110. // print('aaaa');
  111. // }
  112. // else {
  113. // print('bbb');
  114. // }
  115. // final emvdecode = EMVMPM
  116. Map<String, dynamic> data = await HttpUtils.get(Api.ossFormUpload,
  117. params: {'type': 'QRCODE', 'file_ext': 'png'});
  118. Dio dio = Dio();
  119. Map<String, dynamic> map = data['fields'];
  120. map['file'] = await adio.MultipartFile.fromBytes(chooseImage!,
  121. filename: 'avatar.png');
  122. adio.FormData formData = adio.FormData.fromMap(map);
  123. adio.Response response = await dio.post(data['upload_url'], data: formData);
  124. setState(() {
  125. strPicUrl = data['view_url'];
  126. });
  127. saveCache();
  128. }
  129. checkData() {
  130. if (isLink && controller.text.isEmpty) {
  131. Toast().showInfoText('请粘贴链接地址后再提交\n或选择“稍后添加”', context: context);
  132. setState(() {
  133. showError = true;
  134. });
  135. return;
  136. }
  137. if (!isLink && chooseImage == null) {
  138. Toast().showInfoText('请上传二维码后再提交\n或选择“稍后添加”', context: context);
  139. setState(() {
  140. showError = true;
  141. });
  142. return;
  143. }
  144. if (isLink) {
  145. List rules = [];
  146. if (social['url_rules'] != null) {
  147. rules = social['url_rules'];
  148. }
  149. bool isFind = false;
  150. for (int i = 0; i < rules.length; i++) {
  151. var rule = rules[i];
  152. if (rule['type'] == 'CONTAIN' &&
  153. controller.text.contains(rule['rule'])) {
  154. isFind = true;
  155. }
  156. }
  157. if (rules.isEmpty) {
  158. isFind = true;
  159. }
  160. if (isFind == false) {
  161. Toast().showCustomHud(commitAlert(), context: context);
  162. return;
  163. }
  164. }
  165. commit();
  166. }
  167. commitAlert() {
  168. return Container(
  169. alignment: Alignment.center,
  170. padding: EdgeInsets.only(top: 32.px, bottom: 32.px),
  171. child: Column(
  172. children: [
  173. Image.asset(
  174. 'assets/images/toast_tip.png',
  175. width: 48.px,
  176. height: 48.px,
  177. ),
  178. SizedBox(
  179. height: 12.px,
  180. ),
  181. Text(
  182. '粘贴的链接地址\n与所选平台不匹配!\n建议返回修改',
  183. textAlign: TextAlign.center,
  184. style: TextStyle(
  185. color: Colors.white,
  186. fontSize: 16.px,
  187. fontWeight: FontWeight.bold),
  188. ),
  189. SizedBox(
  190. height: 16.px,
  191. ),
  192. AlertButton(
  193. title: '返回修改',
  194. isCancel: false,
  195. width: 220.px,
  196. height: 40.px,
  197. callback: () {
  198. Toast().hideHud();
  199. }),
  200. SizedBox(
  201. height: 24.px,
  202. ),
  203. AlertButton(
  204. title: '忽略并提交',
  205. isCancel: true,
  206. width: 220.px,
  207. height: 40.px,
  208. callback: () {
  209. Toast().hideHud();
  210. commit();
  211. }),
  212. ],
  213. ),
  214. );
  215. }
  216. Future commit() async {
  217. Toast().showHud(context: context);
  218. if (isLink) {
  219. var data2 = await HttpUtils.post(Api.userSocials, data: {
  220. 'user_url': controller.text,
  221. 'description': descController.text,
  222. 'social_id': social['id'],
  223. 'social_name': social['id'].length == 0 ? social['name'] : '',
  224. 'type': 'LINK',
  225. 'user_nick': titleController.text
  226. });
  227. } else {
  228. var data2 = await HttpUtils.post(Api.userSocials, data: {
  229. 'user_url': strPicUrl,
  230. 'description': descController.text,
  231. 'social_id': social['id'],
  232. 'social_name': social['id'].length == 0 ? social['name'] : '',
  233. 'type': 'QR',
  234. 'user_nick': titleController.text
  235. });
  236. }
  237. Toast().hideHud();
  238. clearCache();
  239. var user = StorageUtil().getJSON('userInfo');
  240. Get.offAllNamed('/', parameters: {'u': user['id']});
  241. // Get.toNamed('/', parameters: {'u': user['id']});
  242. }
  243. saveCache() {
  244. var data = {
  245. "social": social,
  246. "type": isLink ? 'LINK' : 'QR',
  247. "link": controller.text,
  248. "title": titleController.text,
  249. "desc": descController.text
  250. };
  251. StorageUtil().setJSON(isFirstEnter ? 'tempGuideLink1' : 'tempLink', data);
  252. }
  253. clearCache() {
  254. StorageUtil().remove('tempLink');
  255. StorageUtil().remove('tempGuideLink1');
  256. }
  257. intro() {
  258. Color tapColor = kBtnColor;
  259. if (isLink) {
  260. if (controller.text.isNotEmpty) {
  261. tapColor = const Color(0xFFA5A5AD);
  262. }
  263. } else {
  264. if (chooseImage != null) {
  265. tapColor = const Color(0xFFA5A5AD);
  266. }
  267. }
  268. return Container(
  269. color: showError ? const Color(0xFF002FFF) : Colors.transparent,
  270. padding: EdgeInsets.only(
  271. left: 20.px,
  272. right: 20.px,
  273. top: showError ? 12.px : 0,
  274. bottom: showError ? 12.px : 0),
  275. child: Column(
  276. children: [
  277. Row(
  278. children: [
  279. Container(
  280. width: 12.px,
  281. height: 12.px,
  282. alignment: Alignment.center,
  283. decoration: BoxDecoration(
  284. borderRadius: BorderRadius.circular(6.px),
  285. border: Border.all(color: kThemeColor, width: 1.px)),
  286. child: Text(
  287. '1',
  288. style: TextStyle(
  289. color: kThemeColor,
  290. fontFamily: 'Link1',
  291. fontWeight: FontWeight.w800,
  292. fontSize: 8.px),
  293. ),
  294. ),
  295. SizedBox(
  296. width: 3.px,
  297. ),
  298. Text(
  299. '去『已选平台-我』找到「',
  300. style:
  301. TextStyle(color: const Color(0xFFA5A5AD), fontSize: 12.px),
  302. ),
  303. Text(
  304. isLink ? '分享-复制链接' : '我的二维码',
  305. style: TextStyle(
  306. color: const Color(0xFFA5A5AD),
  307. fontSize: 12.px,
  308. fontWeight: FontWeight.bold),
  309. ),
  310. Text(
  311. isLink ? '」' : '」保存',
  312. style:
  313. TextStyle(color: const Color(0xFFA5A5AD), fontSize: 12.px),
  314. ),
  315. ],
  316. ),
  317. SizedBox(
  318. height: 5.px,
  319. ),
  320. Row(
  321. children: [
  322. Container(
  323. width: 12.px,
  324. height: 12.px,
  325. alignment: Alignment.center,
  326. decoration: BoxDecoration(
  327. borderRadius: BorderRadius.circular(6.px),
  328. border: Border.all(color: kThemeColor, width: 1.px)),
  329. child: Text(
  330. '2',
  331. style: TextStyle(
  332. color: kThemeColor,
  333. fontFamily: 'Link1',
  334. fontWeight: FontWeight.w800,
  335. fontSize: 8.px),
  336. ),
  337. ),
  338. SizedBox(
  339. width: 3.px,
  340. ),
  341. Text(
  342. '回到此处',
  343. style:
  344. TextStyle(color: const Color(0xFFA5A5AD), fontSize: 12.px),
  345. ),
  346. SizedBox(
  347. width: 3.px,
  348. ),
  349. if (!isLink && chooseImage == null)
  350. UploadFile(
  351. child: Text(
  352. '上传二维码',
  353. style: TextStyle(
  354. color: tapColor,
  355. fontSize: 12.px,
  356. fontWeight: FontWeight.bold),
  357. ),
  358. callback: (Uint8List file) {
  359. setState(() {
  360. chooseImage = file;
  361. showError = false;
  362. });
  363. uploadImg();
  364. },
  365. ),
  366. if (isLink || (chooseImage != null))
  367. GestureDetector(
  368. onTap: () {
  369. if (isLink) {
  370. if (controller.text.isEmpty) {
  371. getClipData();
  372. }
  373. } else {
  374. if (chooseImage == null) {
  375. chooseFile();
  376. }
  377. }
  378. },
  379. child: Text(
  380. isLink ? '粘贴链接' : '上传二维码',
  381. style: TextStyle(
  382. color: tapColor,
  383. fontSize: 12.px,
  384. fontWeight: FontWeight.bold),
  385. ),
  386. )
  387. ],
  388. ),
  389. ],
  390. ),
  391. );
  392. }
  393. switchWarn() {
  394. return Container(
  395. alignment: Alignment.center,
  396. padding: EdgeInsets.only(top: 32.px, bottom: 32.px),
  397. child: Column(
  398. children: [
  399. SvgPicture.asset(
  400. 'assets/icons/question.svg',
  401. width: 48.px,
  402. height: 48.px,
  403. ),
  404. SizedBox(
  405. height: 12.px,
  406. ),
  407. Text(
  408. isLink
  409. ? '切换选择「二维码」\n将使现有「链接」不被展示\n确定要切换吗?'
  410. : '切换选择「链接」\n将使现有「二维码」不被展示\n确定要切换吗?',
  411. textAlign: TextAlign.center,
  412. style: TextStyle(
  413. color: Colors.white,
  414. fontSize: 16.px,
  415. fontWeight: FontWeight.bold),
  416. ),
  417. SizedBox(
  418. height: 16.px,
  419. ),
  420. AlertButton(
  421. title: '确定',
  422. isCancel: false,
  423. width: 220.px,
  424. height: 40.px,
  425. callback: () {
  426. Toast().hideHud();
  427. setState(() {
  428. showError = false;
  429. if (isLink) {
  430. // strLink = '';
  431. isLink = false;
  432. } else {
  433. // chooseImage = null;
  434. isLink = true;
  435. }
  436. });
  437. }),
  438. SizedBox(
  439. height: 24.px,
  440. ),
  441. AlertButton(
  442. title: '再想想',
  443. isCancel: true,
  444. width: 220.px,
  445. height: 40.px,
  446. callback: () {
  447. Toast().hideHud();
  448. }),
  449. ],
  450. ),
  451. );
  452. }
  453. switchType() {
  454. if (isLink && controller.text.isNotEmpty) {
  455. Toast().showCustomHud(switchWarn(), context: context);
  456. return;
  457. }
  458. if (!isLink && chooseImage != null) {
  459. Toast().showCustomHud(switchWarn(), context: context);
  460. return;
  461. }
  462. setState(() {
  463. showError = false;
  464. isLink = !isLink;
  465. });
  466. // clearCache();
  467. }
  468. preview() {
  469. Toast().showText('长按图片识别或保存', context: context);
  470. showDialog(
  471. context: context,
  472. barrierDismissible: false,
  473. barrierColor: Colors.transparent,
  474. useSafeArea: false,
  475. builder: (BuildContext context) {
  476. return Preview(
  477. memory: chooseImage,
  478. );
  479. });
  480. }
  481. Future getClipData() async {
  482. await Clipboard.getData(Clipboard.kTextPlain).then((value) {
  483. if (value != null && value.text != null) {
  484. setState(() {
  485. controller.text = value.text!;
  486. // strLink = value.text!;
  487. // controller.text = strLink;
  488. });
  489. }
  490. });
  491. }
  492. content() {
  493. return Column(
  494. children: [
  495. SizedBox(
  496. height: 32.px,
  497. ),
  498. if (isFirstEnter)
  499. Row(mainAxisAlignment: MainAxisAlignment.center, children: [
  500. LinkStep(step: -1, content: '', hasShadow: false),
  501. Container(
  502. width: 60.px,
  503. height: 8.px,
  504. transform: Matrix4.translationValues(-1, 0, 0),
  505. decoration: const BoxDecoration(
  506. gradient: LinearGradient(
  507. begin: Alignment.centerLeft,
  508. end: Alignment.centerRight,
  509. colors: [
  510. Color(0xFF74747A),
  511. Color(0xFF74747A),
  512. kThemeColor
  513. ])),
  514. ),
  515. Container(
  516. transform: Matrix4.translationValues(-2, 0, 0),
  517. child: LinkStep(step: 2, content: '添加我的第 1 个链接', hasShadow: true),
  518. )
  519. ]),
  520. if (isFirstEnter)
  521. SizedBox(
  522. height: 36.px,
  523. ),
  524. Container(
  525. width: 343.px,
  526. padding: EdgeInsets.all(20.px),
  527. margin: EdgeInsets.only(bottom: 20.px),
  528. decoration: BoxDecoration(
  529. color: const Color(0xFF2C2C2E),
  530. borderRadius: BorderRadius.circular(24.px)),
  531. child: GestureDetector(
  532. onTap: () {
  533. Get.toNamed('/choose_social', parameters: {'update': '1'})
  534. ?.then((value) {
  535. if (value == null) {
  536. return;
  537. }
  538. setState(() {
  539. social = value;
  540. types = value['types'];
  541. if (types[0] == 'LINK') {
  542. isLink = true;
  543. } else {
  544. isLink = false;
  545. }
  546. });
  547. });
  548. },
  549. child: Row(
  550. children: [
  551. Expanded(
  552. child: Text(
  553. '已选平台',
  554. style: TextStyle(
  555. color: kThemeColor,
  556. fontSize: 16.px,
  557. fontWeight: FontWeight.bold),
  558. )),
  559. social['logo'].length == 0
  560. ? ClipRRect(
  561. borderRadius: BorderRadius.circular(6.px),
  562. child: SvgPicture.asset(
  563. 'assets/icons/other_link.svg',
  564. width: 24.px,
  565. height: 24.px,
  566. ))
  567. : WebImage(
  568. url: social['logo'],
  569. width: 24.px,
  570. height: 24.px,
  571. borderRadius: 6.px,
  572. ),
  573. SizedBox(
  574. width: 8.px,
  575. ),
  576. Text(
  577. social['name'],
  578. style: TextStyle(
  579. color: const Color(0xFFA5A5AD), fontSize: 14.px),
  580. ),
  581. Image.asset(
  582. 'assets/images/arrow_right.png',
  583. width: 20.px,
  584. height: 20.px,
  585. )
  586. ],
  587. ),
  588. )),
  589. Container(
  590. width: 343.px,
  591. padding: EdgeInsets.only(top: 20.px, bottom: 20.px),
  592. margin: EdgeInsets.only(bottom: 20.px),
  593. decoration: BoxDecoration(
  594. color: const Color(0xFF2C2C2E),
  595. borderRadius: BorderRadius.circular(24.px)),
  596. child: Column(
  597. children: [
  598. Row(
  599. children: [
  600. SizedBox(
  601. width: 20.px,
  602. ),
  603. Expanded(
  604. child: Text(
  605. '链接方式',
  606. style: TextStyle(
  607. color: kThemeColor,
  608. fontSize: 16.px,
  609. fontWeight: FontWeight.bold),
  610. )),
  611. Container(
  612. height: 28.px,
  613. // width: 98.px,
  614. decoration: BoxDecoration(
  615. color: const Color(0xFF131314),
  616. borderRadius: BorderRadius.circular(14.px)),
  617. child: Row(
  618. children: [
  619. Container(
  620. padding: EdgeInsets.only(left: 10.px, right: 10.px),
  621. height: 28.px,
  622. decoration: BoxDecoration(
  623. color: kThemeColor,
  624. borderRadius: BorderRadius.circular(14.px)),
  625. child: Row(
  626. children: [
  627. SvgPicture.asset(
  628. isLink
  629. ? 'assets/icons/link.svg'
  630. : 'assets/icons/qrcode.svg',
  631. width: 16.px,
  632. height: 16.px,
  633. color: const Color(0xFF131314),
  634. ),
  635. SizedBox(
  636. width: 2.px,
  637. ),
  638. Text(
  639. isLink ? '链接' : '二维码',
  640. style: TextStyle(
  641. color: const Color(0xFF131314),
  642. fontSize: 12.px),
  643. )
  644. ],
  645. ),
  646. ),
  647. if (types.length > 1)
  648. GestureDetector(
  649. onTap: () {
  650. switchType();
  651. },
  652. child: Container(
  653. alignment: Alignment.center,
  654. width: 36.px,
  655. height: 28.px,
  656. child: SvgPicture.asset(
  657. isLink
  658. ? 'assets/icons/qrcode.svg'
  659. : 'assets/icons/link.svg',
  660. width: 16.px,
  661. height: 16.px,
  662. color: const Color(0xFF74747A),
  663. ),
  664. ),
  665. )
  666. ],
  667. ),
  668. ),
  669. SizedBox(
  670. width: 20.px,
  671. )
  672. ],
  673. ),
  674. SizedBox(
  675. height: 8.px,
  676. ),
  677. intro(),
  678. // SizedBox(
  679. // height: 28.px,
  680. // ),
  681. SizedBox(
  682. height: 16.px,
  683. ),
  684. if (isLink)
  685. Row(
  686. children: [
  687. SizedBox(
  688. width: 20.px,
  689. ),
  690. Expanded(
  691. child: TextField(
  692. controller: controller,
  693. cursorColor: kBtnColor,
  694. onChanged: (value) {
  695. // setState(() {
  696. // strLink = value;
  697. // showError = false;
  698. // // keyword = value;
  699. // });
  700. saveCache();
  701. },
  702. style: TextStyle(
  703. color: Colors.white,
  704. fontSize: 14.px,
  705. fontFamily: 'Link1'),
  706. decoration: InputDecoration(
  707. border: InputBorder.none,
  708. hintText: '请输入链接',
  709. hintStyle: TextStyle(
  710. fontSize: 14.px, color: const Color(0xFF444447)),
  711. counterText: "",
  712. ),
  713. ),
  714. ),
  715. if (controller.text.isEmpty)
  716. GestureDetector(
  717. onTap: () {
  718. getClipData();
  719. },
  720. child: SvgPicture.asset(
  721. 'assets/icons/copy_link.svg',
  722. width: 24.px,
  723. height: 24.px,
  724. color: kBtnColor,
  725. ),
  726. ),
  727. SizedBox(
  728. width: 20.px,
  729. ),
  730. ],
  731. ),
  732. if (!isLink)
  733. Stack(
  734. children: [
  735. DottedBorder(
  736. color: const Color(0xFF444447),
  737. borderType: BorderType.RRect,
  738. radius: Radius.circular(16.px),
  739. child: ClipRRect(
  740. borderRadius: BorderRadius.circular(16.px),
  741. child: Container(
  742. width: 303.px,
  743. alignment: Alignment.center,
  744. padding: EdgeInsets.only(top: 12.px, bottom: 12.px),
  745. child: chooseImage != null
  746. ? GestureDetector(
  747. onTap: () {
  748. preview();
  749. },
  750. child: Image.memory(
  751. chooseImage!,
  752. height: 120.px,
  753. ),
  754. )
  755. : UploadFile(
  756. // width: 120.px,
  757. // height: 120.px,
  758. child: SvgPicture.asset(
  759. 'assets/icons/upload_qrcode.svg',
  760. width: 120.px,
  761. height: 120.px,
  762. ),
  763. callback: (Uint8List file) {
  764. setState(() {
  765. chooseImage = file;
  766. showError = false;
  767. });
  768. uploadImg();
  769. },
  770. ),
  771. ),
  772. )),
  773. if (chooseImage != null)
  774. Positioned(
  775. right: 12.px,
  776. top: 12.px,
  777. child: UploadFile(
  778. // width: 68.px,
  779. // height: 28.px,
  780. child: Container(
  781. width: 68.px,
  782. height: 28.px,
  783. alignment: Alignment.center,
  784. decoration: BoxDecoration(
  785. borderRadius: BorderRadius.circular(14.px),
  786. color: const Color(0xBF131314)),
  787. child: Text(
  788. '重新上传',
  789. style: TextStyle(
  790. color: kBtnColor, fontSize: 12.px),
  791. )),
  792. callback: (Uint8List file) {
  793. setState(() {
  794. chooseImage = file;
  795. showError = false;
  796. });
  797. uploadImg();
  798. },
  799. ))
  800. // GestureDetector(
  801. // onTap: () {
  802. // chooseFile();
  803. // },
  804. // child: Container(
  805. // width: 68.px,
  806. // height: 28.px,
  807. // alignment: Alignment.center,
  808. // decoration: BoxDecoration(
  809. // borderRadius: BorderRadius.circular(14.px),
  810. // color: const Color(0xBF131314)),
  811. // child: Text(
  812. // '重新上传',
  813. // style: TextStyle(
  814. // color: kBtnColor, fontSize: 12.px),
  815. // )),
  816. // ))
  817. ],
  818. ),
  819. ],
  820. ),
  821. ),
  822. if ((isLink && controller.text.isNotEmpty) ||
  823. (!isLink && chooseImage != null))
  824. Container(
  825. width: 343.px,
  826. padding: EdgeInsets.all(20.px),
  827. margin: EdgeInsets.only(bottom: 20.px),
  828. decoration: BoxDecoration(
  829. color: const Color(0xFF2C2C2E),
  830. borderRadius: BorderRadius.circular(24.px)),
  831. child: Column(
  832. mainAxisAlignment: MainAxisAlignment.start,
  833. crossAxisAlignment: CrossAxisAlignment.start,
  834. children: [
  835. Text(
  836. '标题',
  837. style: TextStyle(
  838. color: kThemeColor,
  839. fontWeight: FontWeight.bold,
  840. fontSize: 16.px,
  841. height: 1.75),
  842. ),
  843. SizedBox(
  844. height: 8.px,
  845. ),
  846. SelectableText(
  847. '填写在我该平台上的用户名,不填将展示平台名称,如:',
  848. style: TextStyle(
  849. color: const Color(0xFFA5A5AD),
  850. fontSize: 12.px,
  851. height: 1.5),
  852. ),
  853. SizedBox(
  854. height: 16.px,
  855. ),
  856. TextField(
  857. cursorColor: kBtnColor,
  858. controller: titleController,
  859. onChanged: (value) {
  860. saveCache();
  861. },
  862. style: TextStyle(color: Colors.white, fontSize: 14.px),
  863. decoration: InputDecoration(
  864. border: InputBorder.none,
  865. hintText: social['url_example'],
  866. hintStyle: TextStyle(
  867. fontSize: 14.px, color: const Color(0xFF444447)),
  868. counterText: "",
  869. ),
  870. ),
  871. Container(
  872. height: 1.px,
  873. color: const Color(0xFF444447),
  874. margin: EdgeInsets.only(top: 18.px, bottom: 18.px),
  875. ),
  876. Text(
  877. '描述',
  878. style: TextStyle(
  879. color: kThemeColor,
  880. fontWeight: FontWeight.bold,
  881. fontSize: 16.px,
  882. height: 1.75),
  883. ),
  884. SizedBox(
  885. height: 8.px,
  886. ),
  887. Text(
  888. '对以上内容的补充描述,如:',
  889. style: TextStyle(
  890. color: const Color(0xFFA5A5AD),
  891. fontSize: 12.px,
  892. height: 1.5),
  893. ),
  894. SizedBox(
  895. height: 16.px,
  896. ),
  897. TextField(
  898. cursorColor: kBtnColor,
  899. controller: descController,
  900. onChanged: (value) {
  901. saveCache();
  902. },
  903. style: TextStyle(color: Colors.white, fontSize: 14.px),
  904. decoration: InputDecoration(
  905. border: InputBorder.none,
  906. hintText: social['description_example'],
  907. hintStyle: TextStyle(
  908. fontSize: 14.px, color: const Color(0xFF444447)),
  909. counterText: "",
  910. ),
  911. ),
  912. ],
  913. )),
  914. SizedBox(
  915. height: 162.px,
  916. )
  917. ],
  918. );
  919. }
  920. @override
  921. Widget build(BuildContext context) {
  922. SizeFit.initialize(context);
  923. return Stack(children: [
  924. Positioned(
  925. left: 0,
  926. top: 0,
  927. right: 0,
  928. height: MediaQuery.of(context).size.height,
  929. // bottom: 0,
  930. child: Padding(
  931. padding: EdgeInsets.only(
  932. bottom: MediaQuery.of(context).viewInsets.bottom),
  933. child: SingleChildScrollView(
  934. // physics: const NeverScrollableScrollPhysics(),
  935. controller: scrollController,
  936. child: AvoidKeyboard(child: content()),
  937. ))),
  938. Positioned(
  939. left: 0,
  940. right: 0,
  941. bottom: 0,
  942. child: Container(
  943. height: isFirstEnter ? 162.px : 140.px,
  944. decoration: const BoxDecoration(
  945. gradient: LinearGradient(
  946. begin: Alignment.topCenter,
  947. end: Alignment.bottomCenter,
  948. colors: [
  949. Color(0x00131314),
  950. Color(0xFF131314),
  951. Color(0xFF131314),
  952. ])),
  953. child: Column(
  954. children: [
  955. SizedBox(
  956. height: 36.px,
  957. ),
  958. LinkButton(
  959. title: '完成',
  960. disable: false,
  961. isBlack: false,
  962. callback: () {
  963. checkData();
  964. }),
  965. SizedBox(
  966. height: 30.px,
  967. ),
  968. if (isFirstEnter)
  969. GestureDetector(
  970. child: Text(
  971. '稍后添加',
  972. style: TextStyle(
  973. color: const Color(0xFF74747A), fontSize: 14.px),
  974. ),
  975. )
  976. ],
  977. ),
  978. ))
  979. ]);
  980. }
  981. }