Hibok
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

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