Hibok
您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 
 
 
 

1423 行
45 KiB

  1. import 'dart:io';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:chat/chat/emoji_text.dart';
  4. import 'package:chat/chat/input_bar.dart';
  5. import 'package:chat/chat/my_special_text_span_builder.dart';
  6. import 'package:chat/data/UserData.dart';
  7. import 'package:chat/data/constants.dart';
  8. import 'package:chat/generated/i18n.dart';
  9. import 'package:chat/home/MyDialogContent.dart';
  10. import 'package:chat/home/SelectPage.dart';
  11. import 'package:chat/home/VerificationCenter.dart';
  12. import 'package:chat/home/VipPage.dart';
  13. import 'package:chat/models/money_change.dart';
  14. import 'package:chat/utils/ChargeMoney.dart';
  15. import 'package:chat/utils/CustomUI.dart';
  16. import 'package:chat/utils/HttpUtil.dart';
  17. import 'package:chat/utils/MessageMgr.dart';
  18. import 'package:chat/utils/PicSwiper.dart';
  19. import 'package:chat/utils/file_cache_mgr.dart';
  20. import 'package:chat/utils/keyboard/bottom_area_avoider.dart';
  21. import 'package:chat/utils/keyboard_utils.dart';
  22. import 'package:chat/utils/screen.dart';
  23. import 'package:dio/dio.dart';
  24. import 'package:extended_text_field/extended_text_field.dart';
  25. import 'package:flutter/material.dart';
  26. import 'package:flutter/services.dart';
  27. import 'package:flutter_screenutil/flutter_screenutil.dart';
  28. import 'package:multi_image_picker/multi_image_picker.dart';
  29. import 'package:oktoast/oktoast.dart';
  30. import 'package:provider/provider.dart';
  31. import 'package:shared_preferences/shared_preferences.dart';
  32. import '../utils/ShadowButton.dart';
  33. import '../data/UserData.dart';
  34. import '../utils/TokenMgr.dart';
  35. import '../data/WebData.dart';
  36. class AddProgram extends StatefulWidget {
  37. @required
  38. final bool isProgram;
  39. AddProgram({Key key, this.isProgram = true}) : super(key: key);
  40. _AddProgramState createState() => _AddProgramState();
  41. }
  42. const double LEFT_WIDTH = 80;
  43. const int Max_Img_Num = 4;
  44. class _AddProgramState extends State<AddProgram> {
  45. //期待对象
  46. String lovePeople = "";
  47. Set<String> lovePeopleId = new Set();
  48. //约会范围
  49. String dateRange = "";
  50. Set<String> dateRangeId = new Set();
  51. //开始时间
  52. String beginTime = '';
  53. String beginTimeId = '';
  54. //结束时间
  55. String endTime = '';
  56. var endTimeId = -1;
  57. //List<File> imgFileList = [];
  58. //上传图片地址
  59. List<String> imgUrlList = [];
  60. //禁止评论
  61. bool isCanContent = false;
  62. bool isHidden = false;
  63. int programId = -1;
  64. String programCat = '';
  65. // String content = '';
  66. @override
  67. void initState() {
  68. super.initState();
  69. print('AddProgram initState');
  70. _bloc.start();
  71. getKeyboardHeight();
  72. focusNode.addListener(_focusNodeListener);
  73. msgMgr.on('Keyboard Hide', dealWithKeyboardHide);
  74. }
  75. @override
  76. void dispose() {
  77. focusNode.removeListener(_focusNodeListener);
  78. _bloc.dispose();
  79. msgMgr.off('Keyboard Hide', dealWithKeyboardHide);
  80. super.dispose();
  81. }
  82. ///keyboard相关-----------------------------------------------------------------------------------------------
  83. KeyboardBloc _bloc = KeyboardBloc();
  84. MessageMgr msgMgr = MessageMgr();
  85. double keyboardHeight;
  86. final _keyParent = GlobalKey();
  87. double _offset = 0;
  88. Duration _timeToDismiss = Duration(milliseconds: 120);
  89. OverlayEntry _overlayEntry;
  90. FocusNode focusNode = new FocusNode();
  91. bool get _isShowing {
  92. return _overlayEntry != null;
  93. }
  94. bool isShowEmoji = false;
  95. bool _dismissAnimationNeeded = true;
  96. double _kBarSize = 45.0;
  97. bool isActionFromButton = false;
  98. dealWithKeyboardHide(args) {
  99. if (!isActionFromButton) {
  100. closeEmojiAction();
  101. }
  102. }
  103. TextEditingController _textCtrl = TextEditingController();
  104. final ValueNotifier<bool> _counter = ValueNotifier<bool>(false);
  105. void _insertOverlay() {
  106. print('插入界面');
  107. OverlayState os = Overlay.of(context);
  108. _overlayEntry = OverlayEntry(builder: (context) {
  109. // Update and build footer, if any
  110. final queryData = MediaQuery.of(context);
  111. return Positioned(
  112. bottom: queryData.viewInsets.bottom,
  113. left: 0,
  114. right: 0,
  115. child: SafeArea(
  116. child: Container(
  117. height: _kBarSize,
  118. child: Column(
  119. mainAxisSize: MainAxisSize.min,
  120. children: [
  121. Material(
  122. color: Colors.grey[200],
  123. child: Column(
  124. mainAxisSize: MainAxisSize.min,
  125. children: <Widget>[
  126. Divider(
  127. height: 1,
  128. color: Color(0xffb0b0b0),
  129. ),
  130. InkWell(
  131. child: Container(
  132. padding: EdgeInsets.only(left: 15),
  133. height: 43,
  134. color: Colors.white,
  135. alignment: Alignment.centerLeft,
  136. child: Icon(
  137. IconData(isShowEmoji ? 0xe655 : 0xe651,
  138. fontFamily: Constants.IconFontFamily),
  139. size: 27,
  140. color: Color(0xffb0b0b0)),
  141. ),
  142. onTap: () {
  143. setState(() {
  144. isActionFromButton = true;
  145. isShowEmoji = !isShowEmoji;
  146. _kBarSize = isShowEmoji ? keyboardHeight : 45;
  147. if (isShowEmoji) {
  148. SystemChannels.textInput
  149. .invokeMethod('TextInput.hide');
  150. } else {
  151. SystemChannels.textInput
  152. .invokeMethod('TextInput.show');
  153. }
  154. if (isShowEmoji) {
  155. Future.delayed(Duration(milliseconds: 200), () {
  156. ///150延迟防止界面越界
  157. _counter.value = isShowEmoji;
  158. });
  159. Future.delayed(Duration(milliseconds: 1000), () {
  160. ///缩下键盘的时候-防止表情被关闭
  161. isActionFromButton = false;
  162. });
  163. } else {
  164. _counter.value = isShowEmoji;
  165. Future.delayed(Duration(milliseconds: 360), () {
  166. ///150延迟防止界面越界
  167. isActionFromButton = false;
  168. });
  169. }
  170. });
  171. },
  172. ),
  173. ValueListenableBuilder(
  174. builder:
  175. (BuildContext context, bool value, Widget child) {
  176. return value
  177. ? Container(
  178. width: MediaQuery.of(context).size.width,
  179. child: buildEmojiGird(),
  180. )
  181. : SizedBox(
  182. height: 1,
  183. );
  184. },
  185. valueListenable: _counter,
  186. ),
  187. ],
  188. ),
  189. ),
  190. ],
  191. ),
  192. ),
  193. ),
  194. );
  195. });
  196. os.insert(_overlayEntry);
  197. }
  198. getKeyboardHeight() async {
  199. var sp = await SharedPreferences.getInstance();
  200. keyboardHeight = sp.getDouble(Constants.KeyboardHeight);
  201. print('keyboardHeight : $keyboardHeight');
  202. }
  203. Future<Null> _focusNodeListener() async {
  204. print('监听');
  205. if (isShowEmoji) {
  206. return;
  207. }
  208. _focusChanged(focusNode.hasFocus);
  209. }
  210. _focusChanged(bool showBar) {
  211. print('showBar $showBar _isShowing:$_isShowing');
  212. if (showBar && !_isShowing) {
  213. _insertOverlay();
  214. } else if (!showBar && _isShowing) {
  215. _removeOverlay();
  216. } else if (showBar && _isShowing) {
  217. _overlayEntry.markNeedsBuild();
  218. }
  219. }
  220. /// Remove the overlay bar. Call when losing focus or being dismissed.
  221. void _removeOverlay({bool fromDispose = false}) async {
  222. if (_dismissAnimationNeeded) {
  223. if (mounted && !fromDispose) {
  224. _overlayEntry?.markNeedsBuild();
  225. await Future.delayed(_timeToDismiss);
  226. }
  227. }
  228. _overlayEntry?.remove();
  229. _overlayEntry = null;
  230. if (!fromDispose && _dismissAnimationNeeded) _updateOffset();
  231. _dismissAnimationNeeded = true;
  232. }
  233. void _updateOffset() {
  234. if (!mounted) {
  235. return;
  236. }
  237. if (!_isShowing) {
  238. setState(() {
  239. _offset = 0.0;
  240. });
  241. return;
  242. }
  243. double newOffset = _kBarSize; // offset for the actions bar
  244. newOffset += MediaQuery.of(context)
  245. .viewInsets
  246. .bottom; // + offset for the system keyboard
  247. if (newOffset < 0) newOffset = 0;
  248. // Update state if changed
  249. if (_offset != newOffset) {
  250. setState(() {
  251. _offset = newOffset;
  252. });
  253. }
  254. }
  255. Widget buildEmojiGird() {
  256. return Container(
  257. height: keyboardHeight - 44,
  258. child: Stack(
  259. children: <Widget>[
  260. Padding(
  261. padding: EdgeInsets.fromLTRB(5, 8, 50, 0),
  262. child: GridView.builder(
  263. controller: new ScrollController(keepScrollOffset: false),
  264. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  265. crossAxisCount: 7, crossAxisSpacing: 0, mainAxisSpacing: 0),
  266. itemBuilder: (context, index) {
  267. return GestureDetector(
  268. child: Container(
  269. padding: EdgeInsets.all(7),
  270. child: Image.asset(EmojiUitl
  271. .instance.emojiMap[EmojiText.flag + "${index + 1}]"]),
  272. ),
  273. behavior: HitTestBehavior.translucent,
  274. onTap: () {
  275. if (_textCtrl.value.text.length < 94) {
  276. InputBarState.insertText(
  277. EmojiText.flag + "${index + 1}]", _textCtrl);
  278. }
  279. // setState(() {
  280. // _isComposingMessage = _textCtrl.text.length > 0;
  281. // });
  282. },
  283. );
  284. },
  285. itemCount: EmojiUitl.instance.emojiMap.length,
  286. padding: EdgeInsets.all(5.0),
  287. ),
  288. ),
  289. Positioned.fill(
  290. child: Container(
  291. padding: EdgeInsets.fromLTRB(0, 0, 0, 14),
  292. alignment: Alignment(1, 1),
  293. child: InkWell(
  294. onTap: () {
  295. InputBarState.deleteText(_textCtrl);
  296. },
  297. child: Container(
  298. decoration: BoxDecoration(
  299. color: Color(0x4d0E0E10),
  300. borderRadius: BorderRadius.only(
  301. topLeft: Radius.circular(4.0),
  302. bottomLeft: Radius.circular(4))),
  303. width: 37,
  304. height: 28,
  305. child: Icon(
  306. IconData(
  307. 0xe679,
  308. fontFamily: 'iconfont',
  309. ),
  310. size: 16,
  311. color: Colors.white,
  312. ),
  313. ),
  314. ),
  315. )),
  316. ],
  317. ),
  318. );
  319. }
  320. ///keyboard相关------------------------------------------------------------------------------------------------------------
  321. void closeEmojiAction() {
  322. print('### closeEmojiAction');
  323. FocusScope.of(context).requestFocus(FocusNode());
  324. isShowEmoji = false;
  325. _counter.value = isShowEmoji;
  326. _removeOverlay();
  327. _offset = 0;
  328. _kBarSize = isShowEmoji ? keyboardHeight : 45;
  329. }
  330. ScrollController _scrollController = new ScrollController();
  331. @override
  332. Widget build(BuildContext context) {
  333. Widget appBar = new AppBar(
  334. backgroundColor: AppColors.NewAppbarBgColor,
  335. title: Text(
  336. widget.isProgram
  337. ? I18n.of(context).release_program
  338. : I18n.of(context).release_dynamics,
  339. style: TextStyle(color: AppColors.NewAppbarTextColor),
  340. ),
  341. elevation: 0,
  342. leading: CustomUI.buildCustomLeading(context, onTap: () {
  343. closeEmojiAction();
  344. Navigator.of(context).pop();
  345. }),
  346. centerTitle: true,
  347. );
  348. return WillPopScope(
  349. child: Scaffold(
  350. appBar: appBar,
  351. body: SafeArea(
  352. child: Center(
  353. child: Container(
  354. height: MediaQuery.of(context).size.height,
  355. width: MediaQuery.of(context).size.width,
  356. child: GestureDetector(
  357. onTap: () {
  358. closeEmojiAction();
  359. },
  360. child: Material(
  361. color: Colors.transparent,
  362. child: SizedBox(
  363. width: double.maxFinite,
  364. key: _keyParent,
  365. child: BottomAreaAvoider(
  366. scrollTo: _scrollController,
  367. areaToAvoid: _offset,
  368. duration: Duration(
  369. milliseconds:
  370. (_timeToDismiss.inMilliseconds * 1.8).toInt()),
  371. autoScroll: true,
  372. child: Container(
  373. child: Column(
  374. children: <Widget>[_buildBody()],
  375. ),
  376. ),
  377. ),
  378. ),
  379. ),
  380. ),
  381. ),
  382. )),
  383. ),
  384. onWillPop: () {
  385. closeEmojiAction();
  386. return Future.value(true);
  387. });
  388. }
  389. // Future<bool> _willPop() {
  390. // print('###### willpop');
  391. //// tempDispose=true;
  392. //// closeEmojiAction();
  393. //// print('isshowemoji:$isShowEmoji');
  394. //// _counter.value = false;
  395. //// print('关闭emoji');
  396. //// FocusScope.of(context).requestFocus(FocusNode());
  397. // Navigator.pop(context);
  398. // return new Future.value(false);
  399. // }
  400. BoxDecoration _getCardDecoration() {
  401. return new BoxDecoration(
  402. color: Colors.white,
  403. boxShadow: [
  404. BoxShadow(
  405. color: Color.fromRGBO(230, 230, 230, 1),
  406. offset: Offset(0, 10),
  407. blurRadius: 8,
  408. )
  409. ],
  410. );
  411. }
  412. //节目主题
  413. Widget _buildProgramCat() {
  414. return new Container(
  415. margin: EdgeInsets.only(top: 15),
  416. decoration: _getCardDecoration(),
  417. child: _bottomBorderBox(
  418. I18n.of(context).program_theme,
  419. programCat == '' ? I18n.of(context).choose : programCat,
  420. false,
  421. null, () {
  422. CustomUI.buildTip(
  423. context, I18n.of(context).please_choose, _buildCategoryButton());
  424. }, rightTextGrey: programCat == ''),
  425. );
  426. }
  427. //选择期待对象
  428. void selectLovePeople() {
  429. var tempSet = lovePeopleId.toSet();
  430. List<Widget> actions = [
  431. FlatButton(
  432. child: fixedText(I18n.of(context).close),
  433. onPressed: () {
  434. tempSet.clear();
  435. Navigator.of(context).pop();
  436. },
  437. ),
  438. FlatButton(
  439. child: fixedText(I18n.of(context).determine),
  440. onPressed: () {
  441. Navigator.of(context).pop();
  442. setState(() {
  443. lovePeopleId = tempSet.toSet();
  444. lovePeople = '';
  445. lovePeopleId.forEach((k) {
  446. lovePeople += (lovePeople == '')
  447. ? WebData().loverPeopleMap[k]
  448. : ('/' + WebData().loverPeopleMap[k]);
  449. });
  450. });
  451. },
  452. ),
  453. ];
  454. //约会节目
  455. showDialog(
  456. context: context,
  457. builder: (BuildContext context) {
  458. return AlertDialog(
  459. title: new Align(
  460. alignment: Alignment.center,
  461. child: Text(I18n.of(context).expect_lover, textScaleFactor: 1.0),
  462. ),
  463. content: new MyDialogContent(
  464. mostNum: 4,
  465. dataMap: WebData().loverPeopleMap,
  466. keyList: tempSet,
  467. ),
  468. contentPadding: EdgeInsets.only(top: 10),
  469. actions: actions,
  470. );
  471. });
  472. }
  473. //选择约会地区
  474. void selectDateRange() async {
  475. Navigator.of(context).push(
  476. new MaterialPageRoute(
  477. builder: (context) {
  478. return SelectPage(
  479. mostNum: 4,
  480. dataId: dateRangeId,
  481. title: I18n.of(context).select_city,
  482. provinces: {'VietNam': WebData().provinces['VietNam']},
  483. cities: WebData().cities,
  484. isSingle: true,
  485. callback: (tempRankId) {
  486. dateRangeId = tempRankId.toSet();
  487. dateRange = '';
  488. dateRangeId.forEach((item) {
  489. var city = item.split('-');
  490. dateRange += dateRange == ''
  491. ? WebData().cities[city[0]][city[1]]
  492. : '/${WebData().cities[city[0]][city[1]]}';
  493. });
  494. Navigator.of(context).pop();
  495. },
  496. );
  497. },
  498. ),
  499. );
  500. }
  501. //选择开始时间
  502. void selectBegin() async {
  503. DateTime _date = DateTime.now();
  504. final DateTime picked = await showDatePicker(
  505. context: context,
  506. initialDate: _date,
  507. firstDate: DateTime(_date.year, _date.month, _date.day),
  508. locale: WebData().locale,
  509. lastDate: DateTime(_date.year, _date.month, _date.day + 7));
  510. setState(() {
  511. if (picked != null) {
  512. beginTime = '${picked.year}-${picked.month}-${picked.day}';
  513. beginTimeId = '${picked.year}-${picked.month}-${picked.day}';
  514. }
  515. });
  516. if (picked == null) _date = DateTime.now();
  517. }
  518. //分类按钮
  519. Widget _buildCategoryButton() {
  520. return Container(
  521. padding: EdgeInsets.only(top: 10),
  522. child: Column(
  523. children: <Widget>[
  524. Container(
  525. child: Row(
  526. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  527. children: <Widget>[
  528. _buildIconButton(1, WebData().getProgramName(context, 0),
  529. Constants.Category1Color, 0),
  530. _buildIconButton(2, WebData().getProgramName(context, 1),
  531. Constants.Category2Color, 1),
  532. _buildIconButton(3, WebData().getProgramName(context, 2),
  533. Constants.Category3Color, 2),
  534. _buildIconButton(4, WebData().getProgramName(context, 3),
  535. Constants.Category4Color, 3),
  536. ],
  537. ),
  538. ),
  539. Container(
  540. child: Row(
  541. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  542. children: <Widget>[
  543. _buildIconButton(5, WebData().getProgramName(context, 4),
  544. Constants.Category5Color, 4),
  545. _buildIconButton(6, WebData().getProgramName(context, 5),
  546. Constants.Category6Color, 5),
  547. _buildIconButton(7, WebData().getProgramName(context, 6),
  548. Constants.Category7Color, 6),
  549. _buildIconButton(8, WebData().getProgramName(context, 7),
  550. Constants.Category8Color, 7),
  551. ],
  552. ),
  553. ),
  554. ],
  555. ));
  556. }
  557. Widget _buildIconButton(iconNum, str, strColor, value) {
  558. Widget icon = Container(
  559. padding: EdgeInsets.only(bottom: 10),
  560. child: Image.asset(
  561. 'assets/images/park/qz_icon$iconNum.png',
  562. height: 60,
  563. ));
  564. Widget text = Positioned(
  565. bottom: 0,
  566. child: Container(
  567. child: new Text(str,
  568. textScaleFactor: 1.0,
  569. style: TextStyle(
  570. color: strColor, fontWeight: FontWeight.w700, fontSize: 13)),
  571. ));
  572. return InkWell(
  573. onTap: () {
  574. setState(() {
  575. programId = value;
  576. programCat = WebData().getProgramName(context, value);
  577. Navigator.of(context).pop();
  578. });
  579. },
  580. highlightColor: Colors.transparent,
  581. radius: 0,
  582. child: Container(
  583. width: (MediaQuery.of(context).size.width * 0.9) / 4,
  584. margin: EdgeInsets.only(top: 10),
  585. child: Stack(
  586. alignment: Alignment.center,
  587. children: <Widget>[
  588. icon,
  589. text,
  590. ],
  591. ),
  592. ));
  593. }
  594. Widget _buildTimeSelect(str, value) {
  595. return InkWell(
  596. child: Container(
  597. margin: EdgeInsets.only(top: 5, bottom: 5),
  598. height: 20,
  599. alignment: Alignment.center,
  600. child: Text(
  601. str,
  602. textScaleFactor: 1.0,
  603. style: TextStyle(fontSize: 15, color: Constants.BlackTextColor),
  604. ),
  605. ),
  606. onTap: () async {
  607. if (WebData().testTimeOver(value, beginTimeId)) {
  608. showToast(I18n.of(context).outTime);
  609. return;
  610. }
  611. setState(() {
  612. endTimeId = value;
  613. endTime = str;
  614. Navigator.of(context).pop();
  615. });
  616. },
  617. );
  618. }
  619. //选择结束时间
  620. void selectEnd() async {
  621. Widget title = Container(
  622. margin: EdgeInsets.only(top: 15, bottom: 10),
  623. alignment: Alignment.center,
  624. child: Text(
  625. I18n.of(context).select_time,
  626. textScaleFactor: 1.0,
  627. style: TextStyle(fontSize: 19, color: Constants.BlackTextColor),
  628. ),
  629. );
  630. List<Widget> list = [title];
  631. WebData().getDateTime(context).forEach((k, v) {
  632. list.add(Divider());
  633. list.add(_buildTimeSelect(v, k));
  634. });
  635. if (beginTimeId == '') {
  636. showToast(I18n.of(context).please_choose4);
  637. return;
  638. }
  639. showModalBottomSheet(
  640. context: context,
  641. builder: (BuildContext context) {
  642. return SafeArea(
  643. child: Container(
  644. height: 345,
  645. child: Column(children: list),
  646. ));
  647. },
  648. ).then((val) {});
  649. }
  650. void _sendPicture() async {
  651. closeEmojiAction();
  652. List<Asset> resultList = List<Asset>();
  653. resultList = await MultiImagePicker.pickImages(
  654. maxImages: Max_Img_Num - imgUrlList.length,
  655. enableCamera: false,
  656. selectedAssets: [],
  657. cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
  658. materialOptions: MaterialOptions(
  659. actionBarColor: "#50A7F9",
  660. actionBarTitle: "Hibok",
  661. allViewTitle: "",
  662. useDetailsView: true,
  663. selectCircleStrokeColor: "#000000",
  664. ),
  665. );
  666. if (resultList != null && resultList.length > 0) {
  667. List<File> fileList = [];
  668. for (var i = 0; i < resultList.length; i++) {
  669. Asset photoEntity = resultList[i];
  670. print('名字:${photoEntity.name}');
  671. ByteData byteData = await photoEntity.getByteData();
  672. File file = await FileCacheMgr().writeFile('temp-photo-${DateTime.now().millisecondsSinceEpoch}.png', byteData.buffer.asInt8List(0));
  673. fileList.add(file);
  674. }
  675. print('文件列表${fileList.length}');
  676. Map data = {"type": 3, "userId": UserData().basicInfo.userId};
  677. data['sign'] = TokenMgr().getSign(data);
  678. Response res = await HttpUtil().uploadFiles(
  679. fileList, data, 'upload/post/postfiles', 'image',
  680. isShowLoading: true);
  681. var resData = res.data;
  682. if (resData['code'] == 0 && resData['msg'] != null) {
  683. imgUrlList.addAll(resData['msg'].split("|"));
  684. setState(() {});
  685. }
  686. }
  687. // var photos = await PhotoPicker.pickAsset(
  688. // context: context,
  689. // themeColor: Color(0xFFF0F0F0),
  690. // maxSelected: Max_Img_Num - imgUrlList.length,
  691. // textColor: Color(0xFF3F3F3F),
  692. // pickType: PickType.onlyImage);
  693. //
  694. // if (photos != null && photos.length > 0) {
  695. // List<File> fileList = [];
  696. // for (var i = 0; i < photos.length; i++) {
  697. // AssetEntity photoEntity = photos[i];
  698. // fileList.add(await photoEntity.file);
  699. // }
  700. // Map data = {"type": 3, "userId": UserData().basicInfo.userId};
  701. // data['sign'] = TokenMgr().getSign(data);
  702. // Response res = await HttpUtil().uploadFiles(
  703. // fileList, data, 'upload/post/postfiles', 'image',
  704. // isShowLoading: true);
  705. // var resData = res.data;
  706. // if (resData['code'] == 0 && resData['msg'] != null) {
  707. // imgUrlList.addAll(resData['msg'].split("|"));
  708. // setState(() {});
  709. // }
  710. // }
  711. }
  712. Widget _buildDynicContent() {
  713. Widget moreInfo = Container(
  714. alignment: Alignment.topCenter,
  715. padding: EdgeInsets.only(left: 15, right: 15),
  716. child: ExtendedTextField(
  717. keyboardAppearance: Brightness.light,
  718. onTap: () {
  719. // if(!isActionFromButton){
  720. isShowEmoji = false;
  721. _counter.value = isShowEmoji;
  722. _kBarSize = isShowEmoji ? keyboardHeight : 45;
  723. // }
  724. },
  725. focusNode: focusNode,
  726. specialTextSpanBuilder:
  727. MySpecialTextSpanBuilder(showAtBackground: true, emojiSize: 17.0),
  728. decoration: new InputDecoration(
  729. hintText: I18n.of(context).please_civilization,
  730. hintStyle: TextStyle(fontSize: 13, height: 1.25),
  731. border: InputBorder.none,
  732. ),
  733. maxLines: 6,
  734. controller: _textCtrl,
  735. style: TextStyle(
  736. fontSize: ScreenUtil().setSp(14),
  737. textBaseline: TextBaseline.alphabetic),
  738. inputFormatters: [LengthLimitingTextInputFormatter(100)],
  739. onChanged: (str) {
  740. if (str.length > 100) {
  741. print('超过100了');
  742. _textCtrl.text = _textCtrl.value.text.substring(0, 100);
  743. int length = _textCtrl.text.length;
  744. Future.delayed(Duration(milliseconds: 100), () {
  745. _textCtrl.selection =
  746. TextSelection(baseOffset: length, extentOffset: length);
  747. });
  748. }
  749. },
  750. ));
  751. List<Widget> imgList = imgUrlList.map((f) {
  752. return _buildImg(f);
  753. }).toList();
  754. if (imgList.length < Max_Img_Num) {
  755. imgList.add(_buildUpButton());
  756. }
  757. Widget picture = Container(
  758. alignment: Alignment.centerLeft,
  759. padding: EdgeInsets.only(left: 15, bottom: 15),
  760. child: Wrap(alignment: WrapAlignment.start, children: imgList));
  761. List<Widget> list = [moreInfo, picture];
  762. return new Container(
  763. margin: EdgeInsets.only(top: 15),
  764. decoration: _getCardDecoration(),
  765. child: Column(
  766. children: list,
  767. ),
  768. );
  769. }
  770. Widget _buildUpButton() {
  771. var color = Colors.grey[350];
  772. return Container(
  773. child: InkWell(
  774. onTap: _sendPicture,
  775. child: Container(
  776. margin: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5),
  777. decoration: BoxDecoration(
  778. borderRadius: BorderRadius.circular(10.0),
  779. border: Border.all(color: color)),
  780. width: 75,
  781. height: 75,
  782. child: ClipRRect(
  783. borderRadius: BorderRadius.circular(10),
  784. child: Icon(
  785. IconData(
  786. 0xe616,
  787. fontFamily: 'iconfont',
  788. ),
  789. color: color),
  790. ))));
  791. }
  792. //节目内容
  793. Widget _buildProgramContent() {
  794. Widget moreInfo = Container(
  795. child: Column(
  796. crossAxisAlignment: CrossAxisAlignment.start,
  797. mainAxisAlignment: MainAxisAlignment.start,
  798. children: <Widget>[
  799. Container(
  800. width: Screen.width,
  801. padding: EdgeInsets.only(
  802. top: 15,
  803. ),
  804. margin: EdgeInsets.only(left: 15),
  805. child: Text(
  806. I18n.of(context).describe_details,
  807. textScaleFactor: 1.0,
  808. style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
  809. )),
  810. Container(
  811. padding: EdgeInsets.only(right: 5),
  812. margin: EdgeInsets.only(left: 15),
  813. child: ExtendedTextField(
  814. keyboardAppearance: Brightness.light,
  815. focusNode: focusNode,
  816. onTap: () {
  817. // if(!isActionFromButton){
  818. isShowEmoji = false;
  819. _counter.value = isShowEmoji;
  820. _kBarSize = isShowEmoji ? keyboardHeight : 45;
  821. // }
  822. if (_scrollController != null) {
  823. ///解决键盘遮挡输入框
  824. _scrollController.position.moveTo(
  825. 200,
  826. duration: Duration(milliseconds: 100),
  827. curve: Curves.easeIn,
  828. );
  829. }
  830. },
  831. controller: _textCtrl,
  832. specialTextSpanBuilder: MySpecialTextSpanBuilder(
  833. showAtBackground: true, emojiSize: 17.0),
  834. decoration: new InputDecoration(
  835. contentPadding:
  836. EdgeInsets.only(top: 6, bottom: 10, right: 10),
  837. hintText: I18n.of(context).please_civilization,
  838. hintStyle:
  839. TextStyle(fontSize: 12, height: 1.15),
  840. border: InputBorder.none,
  841. ),
  842. style: TextStyle(
  843. fontSize: 13, textBaseline: TextBaseline.alphabetic),
  844. maxLines: 6,
  845. // inputFormatters: [LengthLimitingTextInputFormatter(100)],
  846. onChanged: (str) {
  847. if (str.length > 100) {
  848. print('超过100了');
  849. _textCtrl.text = _textCtrl.value.text.substring(0, 100);
  850. int length = _textCtrl.text.length;
  851. Future.delayed(Duration(milliseconds: 100), () {
  852. _textCtrl.selection = TextSelection(
  853. baseOffset: length, extentOffset: length);
  854. });
  855. }
  856. },
  857. )),
  858. ],
  859. ),
  860. );
  861. List<Widget> imgList = imgUrlList.map((f) {
  862. return _buildImg(f);
  863. }).toList();
  864. if (imgList.length < Max_Img_Num) {
  865. imgList.add(_buildUpButton());
  866. }
  867. Widget picture = Container(
  868. alignment: Alignment.topCenter,
  869. child: Row(
  870. children: <Widget>[
  871. Container(
  872. alignment: Alignment.centerLeft,
  873. width: LEFT_WIDTH,
  874. margin: EdgeInsets.only(left: 15),
  875. child: fixedText(I18n.of(context).image,
  876. fontSize: 14, fontWeight: FontWeight.w600)),
  877. Expanded(
  878. child: Container(
  879. margin: EdgeInsets.only(top: 10, bottom: 10),
  880. child:
  881. Wrap(alignment: WrapAlignment.start, children: imgList))),
  882. ],
  883. ),
  884. );
  885. List<Widget> list = [
  886. _bottomBorderBox(
  887. I18n.of(context).expect_lover,
  888. lovePeople == '' ? I18n.of(context).choose : lovePeople,
  889. false,
  890. null,
  891. selectLovePeople,
  892. rightTextGrey: lovePeople == ''),
  893. _buildDivider(),
  894. // _bottomBorderBox(
  895. // I18n.of(context).city,
  896. // dateRange == '' ? I18n.of(context).choose : dateRange,
  897. // false,
  898. // null,
  899. // selectDateRange,
  900. // rightTextGrey: dateRange == ''),
  901. // _buildDivider(),
  902. _bottomBorderBox(
  903. I18n.of(context).time,
  904. beginTime == '' ? I18n.of(context).choose : beginTime,
  905. false,
  906. null,
  907. selectBegin,
  908. rightTextGrey: beginTime == ''),
  909. _buildDivider(),
  910. _bottomBorderBox('', endTime == '' ? I18n.of(context).choose : endTime,
  911. false, null, selectEnd,
  912. rightTextGrey: endTime == ''),
  913. _buildDivider(),
  914. moreInfo,
  915. _buildDivider(),
  916. picture
  917. ];
  918. return new Container(
  919. margin: EdgeInsets.only(top: 15),
  920. decoration: _getCardDecoration(),
  921. child: Column(
  922. children: list,
  923. ),
  924. );
  925. }
  926. //下划线
  927. Widget _buildDivider() {
  928. return new Container(
  929. margin: EdgeInsets.zero,
  930. padding: EdgeInsets.zero,
  931. decoration: BoxDecoration(border: Border(top: Constants.GreyBorderSide)),
  932. height: 1,
  933. width: MediaQuery.of(context).size.width * 0.9,
  934. );
  935. }
  936. Widget _buildImg(f) {
  937. return Stack(
  938. children: <Widget>[
  939. InkWell(
  940. onTap: () {
  941. Navigator.of(context).push(
  942. new MaterialPageRoute(
  943. builder: (context) {
  944. return PicSwiper(
  945. id: imgUrlList.indexOf(f),
  946. pics: imgUrlList
  947. .map((f) => PicSwiperItem(
  948. f,
  949. id: imgUrlList.indexOf(f),
  950. ))
  951. .toList(),
  952. );
  953. },
  954. ),
  955. );
  956. },
  957. child: Container(
  958. height: 75,
  959. width: 75,
  960. margin: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5),
  961. decoration: BoxDecoration(
  962. borderRadius: BorderRadius.circular(10.0),
  963. border: Border.all(color: Colors.grey[300], width: 1),
  964. ),
  965. child: ClipRRect(
  966. borderRadius: BorderRadius.circular(10),
  967. child: f == null
  968. ? Container()
  969. : CachedNetworkImage(
  970. imageUrl: f,
  971. fit: BoxFit.cover,
  972. ),
  973. ))),
  974. Positioned(
  975. right: 0,
  976. child: InkWell(
  977. onTap: () {
  978. imgUrlList.remove(f);
  979. setState(() {});
  980. },
  981. child: Image.asset(
  982. 'assets/images/login/delete.png',
  983. height: 20,
  984. )),
  985. )
  986. ],
  987. );
  988. }
  989. //自定义item
  990. Widget _bottomBorderBox(
  991. String textLeft, String textRight, bool flag, controller, callback,
  992. {bool rightTextGrey = true}) {
  993. Widget left = new Container(
  994. width: LEFT_WIDTH,
  995. child: new Text(
  996. textLeft,
  997. textScaleFactor: 1.0,
  998. style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
  999. ));
  1000. Widget right = flag
  1001. ? new Expanded(
  1002. child: new TextField(
  1003. keyboardAppearance: Brightness.light,
  1004. controller: controller,
  1005. decoration: new InputDecoration(
  1006. hintText: textRight,
  1007. hintStyle: TextStyle(fontSize: 14),
  1008. border: InputBorder.none,
  1009. ),
  1010. style: TextStyle(textBaseline: TextBaseline.alphabetic),
  1011. maxLines: 1,
  1012. onChanged: (str) {
  1013. if (flag && callback != null) callback(str);
  1014. },
  1015. ),
  1016. )
  1017. : new Expanded(
  1018. child: GestureDetector(
  1019. onTap: () {
  1020. if (!flag && callback != null) callback();
  1021. },
  1022. child: Container(
  1023. color: Colors.transparent,
  1024. height: 53,
  1025. width: MediaQuery.of(context).size.width,
  1026. alignment: Alignment.centerLeft,
  1027. padding: EdgeInsets.only(left: 5),
  1028. child: Text(
  1029. textRight,
  1030. textScaleFactor: 1.0,
  1031. style: TextStyle(
  1032. fontSize: 14,
  1033. color: rightTextGrey
  1034. ? Constants.GreyTextColor
  1035. : Constants.BlackTextColor),
  1036. ),
  1037. ),
  1038. ),
  1039. );
  1040. return new Container(
  1041. height: 53,
  1042. margin: EdgeInsets.only(left: 15, bottom: 0),
  1043. child: new Row(
  1044. children: <Widget>[left, right],
  1045. ),
  1046. );
  1047. }
  1048. Widget _buildSwitch(str, value, callback) {
  1049. Widget left = new Text(
  1050. str,
  1051. textScaleFactor: 1.0,
  1052. style: TextStyle(
  1053. fontSize: 14,
  1054. fontWeight: widget.isProgram ? FontWeight.w600 : FontWeight.normal),
  1055. );
  1056. Widget right = new Expanded(
  1057. child: new Align(
  1058. alignment: Alignment.centerRight,
  1059. child: new Switch(
  1060. activeTrackColor: Constants.ConfrimButtonColor.withOpacity(0.3),
  1061. value: value,
  1062. onChanged: (bool val) {
  1063. callback();
  1064. },
  1065. )));
  1066. return new Container(
  1067. padding: EdgeInsets.only(left: 15),
  1068. height: 53,
  1069. child: new Row(
  1070. children: <Widget>[left, right],
  1071. ),
  1072. );
  1073. }
  1074. Widget _buildSelct() {
  1075. return new Container(
  1076. decoration: _getCardDecoration(),
  1077. //margin: EdgeInsets.only(top: , bottom: 0),
  1078. child: Column(
  1079. children: <Widget>[
  1080. _buildSwitch(I18n.of(context).prohibit_comments, isCanContent, () {
  1081. setState(() {
  1082. isCanContent = !isCanContent;
  1083. });
  1084. }),
  1085. _buildDivider(),
  1086. _buildSwitch(I18n.of(context).same_sex, isHidden, () {
  1087. setState(() {
  1088. isHidden = !isHidden;
  1089. });
  1090. }),
  1091. ],
  1092. ));
  1093. }
  1094. Widget _buildTip() {
  1095. return Container(
  1096. alignment: Alignment.centerLeft,
  1097. margin: EdgeInsets.only(top: 10, bottom: 10, left: 10),
  1098. child: Text(
  1099. I18n.of(context).dont,
  1100. textScaleFactor: 1.0,
  1101. style: TextStyle(fontSize: 12, color: Constants.GreyTextColor),
  1102. ),
  1103. );
  1104. }
  1105. Widget _buildTips() {
  1106. String str = '';
  1107. if (UserData().isMan()) {
  1108. str = I18n.of(context)
  1109. .member_free
  1110. .replaceFirst('/s1', UserData().addProgramPrice.toString());
  1111. } else {
  1112. str = I18n.of(context)
  1113. .certified_free
  1114. .replaceFirst('/s1', UserData().addProgramPrice.toString());
  1115. }
  1116. return Container(
  1117. padding: EdgeInsets.only(bottom: 100, left: 20, right: 20),
  1118. child: Text(
  1119. str,
  1120. textScaleFactor: 1.0,
  1121. style: TextStyle(fontSize: 12, color: Constants.GreyTextColor),
  1122. ),
  1123. );
  1124. }
  1125. Widget _buildBody() {
  1126. List<Widget> program = [
  1127. _buildProgramCat(),
  1128. _buildProgramContent(),
  1129. _buildTip(),
  1130. _buildSelct(),
  1131. _buildLoginButton(),
  1132. _buildTips()
  1133. ];
  1134. List<Widget> dynamics = [
  1135. _buildDynicContent(),
  1136. _buildTip(),
  1137. _buildSelct(),
  1138. _buildLoginButton(),
  1139. _buildTips()
  1140. ];
  1141. return Column(
  1142. children: widget.isProgram ? program : dynamics,
  1143. );
  1144. }
  1145. //构建登陆按钮
  1146. Widget _buildLoginButton() {
  1147. Text text = new Text(I18n.of(context).release,
  1148. textScaleFactor: 1.0,
  1149. style: TextStyle(fontSize: 15, color: Colors.white));
  1150. LinearGradient gradientColor = new LinearGradient(colors: <Color>[
  1151. Constants.ConfrimButtonColor,
  1152. Constants.ConfrimButtonColor
  1153. ]);
  1154. callback() async {
  1155. closeEmojiAction();
  1156. if (widget.isProgram) {
  1157. if (programId == -1) {
  1158. showToast(I18n.of(context).please_choose);
  1159. return;
  1160. }
  1161. if (lovePeopleId.length == 0) {
  1162. showToast(I18n.of(context).please_choose2);
  1163. return;
  1164. }
  1165. // if (dateRangeId.length == 0) {
  1166. // showToast(I18n.of(context).please_choose3);
  1167. // return;
  1168. // }
  1169. if (beginTimeId == '') {
  1170. showToast(I18n.of(context).please_choose4);
  1171. return;
  1172. }
  1173. if (endTimeId == -1) {
  1174. showToast(I18n.of(context).please_choose5);
  1175. return;
  1176. }
  1177. } else {
  1178. if (_textCtrl.value.text.trim().length == 0 && imgUrlList.length == 0) {
  1179. showToast(I18n.of(context).enter_something);
  1180. return;
  1181. }
  1182. }
  1183. payCallback() {
  1184. if (Provider.of<MoneyChangeProvider>(context).money <
  1185. UserData().addProgramPrice) {
  1186. CustomUI.buildOneConfirm(
  1187. context,
  1188. I18n.of(context).balance_insufficien,
  1189. I18n.of(context).recharge, () {
  1190. Navigator.of(context).pop();
  1191. ChargeMoney.showChargeSheet(context, () {
  1192. setState(() {});
  1193. });
  1194. });
  1195. return;
  1196. }
  1197. Navigator.of(context).pop();
  1198. postAddProgram(UserData().addProgramPrice);
  1199. }
  1200. String title = widget.isProgram
  1201. ? I18n.of(context).release_program
  1202. : I18n.of(context).release_dynamics;
  1203. //非会员男士提示付费
  1204. if (!UserData().isVip && UserData().isMan()) {
  1205. bool isMan = UserData().isMan();
  1206. CustomUI.buildTowConfirm(
  1207. context,
  1208. title,
  1209. isMan
  1210. ? I18n.of(context).become_member2
  1211. : I18n.of(context).now_certification,
  1212. () {
  1213. Navigator.of(context).push(
  1214. new MaterialPageRoute(
  1215. builder: (context) {
  1216. return isMan ? VipPage() : VerificationCenterPage();
  1217. },
  1218. ),
  1219. );
  1220. },
  1221. I18n.of(context)
  1222. .raid_release
  1223. .replaceFirst('/s1', UserData().addProgramPrice.toString()),
  1224. payCallback,
  1225. );
  1226. return;
  1227. }
  1228. //免费次数用完提示付费
  1229. if (UserData().basicInfo.usedPublishNum >=
  1230. UserData().basicInfo.publishNum) {
  1231. CustomUI.buildOneConfirm(
  1232. context,
  1233. title,
  1234. I18n.of(context)
  1235. .pay_unlock
  1236. .replaceFirst('/s1', UserData().addProgramPrice.toString()),
  1237. payCallback);
  1238. return;
  1239. }
  1240. HttpUtil().userFreeTime(context, UserData().basicInfo.userId, 3, () {
  1241. UserData().basicInfo.usedPublishNum++;
  1242. postAddProgram(0);
  1243. });
  1244. }
  1245. return new Container(
  1246. margin: EdgeInsets.only(top: 30, bottom: 10),
  1247. height: 44,
  1248. width: MediaQuery.of(context).size.width * 0.8,
  1249. child: ShadowButton().builder(gradientColor, text, callback),
  1250. );
  1251. }
  1252. postAddProgram(price) async {
  1253. var dateRangeStr = '';
  1254. dateRangeId.forEach((f) => dateRangeStr += dateRangeStr == '' ? f : ',$f');
  1255. var hopeObject = '';
  1256. lovePeopleId.forEach((f) => hopeObject += hopeObject == '' ? f : ',$f');
  1257. String temp='';
  1258. String postTemp='';
  1259. imgUrlList.forEach((str) {
  1260. temp += (temp == "" ? str : '|$str');
  1261. postTemp += (postTemp == ""
  1262. ? WebData().deleteDemain(str)
  1263. : '|${WebData().deleteDemain(str)}');
  1264. });
  1265. var type = widget.isProgram ? 0 : 1;
  1266. Map data = {
  1267. "userId": UserData().basicInfo.userId,
  1268. "type": type,
  1269. "price": price,
  1270. };
  1271. data['sign'] = TokenMgr().getSign(data);
  1272. //data['city'] = dateRangeStr;
  1273. data['programType'] = programId;
  1274. data['hopeObject'] = hopeObject;
  1275. data['aboutTime'] = beginTimeId;
  1276. data['content'] = _textCtrl.text;
  1277. data['imgUrl'] = postTemp;
  1278. data['evaluateStatus'] = isCanContent;
  1279. data['sexStatus'] = isHidden;
  1280. data['timeQuantum'] = endTimeId;
  1281. Response res = await HttpUtil()
  1282. .post('station/publish/program', data: data, isShowLoading: true);
  1283. var resData = res.data;
  1284. if (resData['code'] == 0) {
  1285. if (widget.isProgram) {
  1286. UserData().isCanProgram = false;
  1287. }
  1288. MessageMgr().emit('Add_program', {
  1289. 'Id': resData['data'],
  1290. 'UserId': UserData().basicInfo.userId,
  1291. 'NickName': UserData().basicInfo.nickName,
  1292. 'HeadimgUrl': UserData().basicInfo.headimgurl,
  1293. 'Type': type,
  1294. 'Sex': UserData().basicInfo.sex,
  1295. 'IsMember': UserData().basicInfo.isMember,
  1296. 'ProgramType': programId,
  1297. 'HopeObject': hopeObject,
  1298. 'City': dateRangeStr,
  1299. 'AboutTime': beginTimeId,
  1300. 'timeQuantum': endTimeId,
  1301. 'Content': _textCtrl.text,
  1302. 'ImgUrl': temp,
  1303. 'EvaluateStatus': isCanContent ? 1 : 0,
  1304. 'SexStatus': isHidden,
  1305. 'Status': 0,
  1306. 'CreateTime': DateTime.now().toIso8601String(),
  1307. 'FabulousNum': 0,
  1308. 'EvaluateNum': 0,
  1309. 'EnrollNum': 0,
  1310. 'IsAttestation': UserData().basicInfo.isAttestation ? 1 : 0,
  1311. 'IsFabulous': 0,
  1312. 'IsEnroll': 0,
  1313. 'EvaluateList': null,
  1314. "FabulousList": []
  1315. });
  1316. Navigator.of(context).pop();
  1317. focusNode.removeListener(_focusNodeListener);
  1318. } else {
  1319. showToast(resData['msg']);
  1320. }
  1321. }
  1322. }