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

1382 рядки
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: TextStyle(fontSize: 12, height: 1.15),
  804. border: InputBorder.none,
  805. ),
  806. style: TextStyle(
  807. fontSize: 13, textBaseline: TextBaseline.alphabetic),
  808. maxLines: 6,
  809. // inputFormatters: [LengthLimitingTextInputFormatter(100)],
  810. onChanged: (str) {
  811. if (str.length > 100) {
  812. print('超过100了');
  813. _textCtrl.text = _textCtrl.value.text.substring(0, 100);
  814. int length = _textCtrl.text.length;
  815. Future.delayed(Duration(milliseconds: 100), () {
  816. _textCtrl.selection = TextSelection(
  817. baseOffset: length, extentOffset: length);
  818. });
  819. }
  820. },
  821. )),
  822. ],
  823. ),
  824. );
  825. List<Widget> imgList = imgUrlList.map((f) {
  826. return _buildImg(f);
  827. }).toList();
  828. if (imgList.length < Max_Img_Num) {
  829. imgList.add(_buildUpButton());
  830. }
  831. Widget picture = Container(
  832. alignment: Alignment.topCenter,
  833. child: Row(
  834. children: <Widget>[
  835. Container(
  836. alignment: Alignment.centerLeft,
  837. width: LEFT_WIDTH,
  838. margin: EdgeInsets.only(left: 15),
  839. child: fixedText(I18n.of(context).image,
  840. fontSize: 14, fontWeight: FontWeight.w600)),
  841. Expanded(
  842. child: Container(
  843. margin: EdgeInsets.only(top: 10, bottom: 10),
  844. child:
  845. Wrap(alignment: WrapAlignment.start, children: imgList))),
  846. ],
  847. ),
  848. );
  849. List<Widget> list = [
  850. _bottomBorderBox(
  851. I18n.of(context).expect_lover,
  852. lovePeople == '' ? I18n.of(context).choose : lovePeople,
  853. false,
  854. null,
  855. selectLovePeople,
  856. rightTextGrey: lovePeople == ''),
  857. _buildDivider(),
  858. // _bottomBorderBox(
  859. // I18n.of(context).city,
  860. // dateRange == '' ? I18n.of(context).choose : dateRange,
  861. // false,
  862. // null,
  863. // selectDateRange,
  864. // rightTextGrey: dateRange == ''),
  865. // _buildDivider(),
  866. _bottomBorderBox(
  867. I18n.of(context).time,
  868. beginTime == '' ? I18n.of(context).choose : beginTime,
  869. false,
  870. null,
  871. selectBegin,
  872. rightTextGrey: beginTime == ''),
  873. _buildDivider(),
  874. _bottomBorderBox('', endTime == '' ? I18n.of(context).choose : endTime,
  875. false, null, selectEnd,
  876. rightTextGrey: endTime == ''),
  877. _buildDivider(),
  878. moreInfo,
  879. _buildDivider(),
  880. picture
  881. ];
  882. return new Container(
  883. margin: EdgeInsets.only(top: 15),
  884. decoration: _getCardDecoration(),
  885. child: Column(
  886. children: list,
  887. ),
  888. );
  889. }
  890. //下划线
  891. Widget _buildDivider() {
  892. return new Container(
  893. margin: EdgeInsets.zero,
  894. padding: EdgeInsets.zero,
  895. decoration: BoxDecoration(border: Border(top: Constants.GreyBorderSide)),
  896. height: 1,
  897. width: MediaQuery.of(context).size.width * 0.9,
  898. );
  899. }
  900. Widget _buildImg(f) {
  901. return Stack(
  902. children: <Widget>[
  903. InkWell(
  904. onTap: () {
  905. Navigator.of(context).push(
  906. new MaterialPageRoute(
  907. builder: (context) {
  908. return PicSwiper(
  909. id: imgUrlList.indexOf(f),
  910. pics: imgUrlList
  911. .map((f) => PicSwiperItem(
  912. f,
  913. id: imgUrlList.indexOf(f),
  914. ))
  915. .toList(),
  916. );
  917. },
  918. ),
  919. );
  920. },
  921. child: Container(
  922. height: 75,
  923. width: 75,
  924. margin: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5),
  925. decoration: BoxDecoration(
  926. borderRadius: BorderRadius.circular(10.0),
  927. border: Border.all(color: Colors.grey[300], width: 1),
  928. ),
  929. child: ClipRRect(
  930. borderRadius: BorderRadius.circular(10),
  931. child: f == null
  932. ? Container()
  933. : CachedNetworkImage(
  934. imageUrl: f,
  935. fit: BoxFit.cover,
  936. ),
  937. ))),
  938. Positioned(
  939. right: 0,
  940. child: InkWell(
  941. onTap: () {
  942. imgUrlList.remove(f);
  943. setState(() {});
  944. },
  945. child: Image.asset(
  946. 'assets/images/login/delete.png',
  947. height: 20,
  948. )),
  949. )
  950. ],
  951. );
  952. }
  953. //自定义item
  954. Widget _bottomBorderBox(
  955. String textLeft, String textRight, bool flag, controller, callback,
  956. {bool rightTextGrey = true}) {
  957. Widget left = new Container(
  958. width: LEFT_WIDTH,
  959. child: new Text(
  960. textLeft,
  961. textScaleFactor: 1.0,
  962. style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
  963. ));
  964. Widget right = flag
  965. ? new Expanded(
  966. child: new TextField(
  967. keyboardAppearance: Brightness.light,
  968. controller: controller,
  969. decoration: new InputDecoration(
  970. hintText: textRight,
  971. hintStyle: TextStyle(fontSize: 14),
  972. border: InputBorder.none,
  973. ),
  974. style: TextStyle(textBaseline: TextBaseline.alphabetic),
  975. maxLines: 1,
  976. onChanged: (str) {
  977. if (flag && callback != null) callback(str);
  978. },
  979. ),
  980. )
  981. : new Expanded(
  982. child: GestureDetector(
  983. onTap: () {
  984. if (!flag && callback != null) callback();
  985. },
  986. child: Container(
  987. color: Colors.transparent,
  988. height: 53,
  989. width: MediaQuery.of(context).size.width,
  990. alignment: Alignment.centerLeft,
  991. padding: EdgeInsets.only(left: 5),
  992. child: Text(
  993. textRight,
  994. textScaleFactor: 1.0,
  995. style: TextStyle(
  996. fontSize: 14,
  997. color: rightTextGrey
  998. ? Constants.GreyTextColor
  999. : Constants.BlackTextColor),
  1000. ),
  1001. ),
  1002. ),
  1003. );
  1004. return new Container(
  1005. height: 53,
  1006. margin: EdgeInsets.only(left: 15, bottom: 0),
  1007. child: new Row(
  1008. children: <Widget>[left, right],
  1009. ),
  1010. );
  1011. }
  1012. Widget _buildSwitch(str, value, callback) {
  1013. Widget left = new Text(
  1014. str,
  1015. textScaleFactor: 1.0,
  1016. style: TextStyle(
  1017. fontSize: 14,
  1018. fontWeight: widget.isProgram ? FontWeight.w600 : FontWeight.normal),
  1019. );
  1020. Widget right = new Expanded(
  1021. child: new Align(
  1022. alignment: Alignment.centerRight,
  1023. child: new Switch(
  1024. activeTrackColor: Constants.ConfrimButtonColor.withOpacity(0.3),
  1025. value: value,
  1026. onChanged: (bool val) {
  1027. callback();
  1028. },
  1029. )));
  1030. return new Container(
  1031. padding: EdgeInsets.only(left: 15),
  1032. height: 53,
  1033. child: new Row(
  1034. children: <Widget>[left, right],
  1035. ),
  1036. );
  1037. }
  1038. Widget _buildSelct() {
  1039. return new Container(
  1040. decoration: _getCardDecoration(),
  1041. //margin: EdgeInsets.only(top: , bottom: 0),
  1042. child: Column(
  1043. children: <Widget>[
  1044. _buildSwitch(I18n.of(context).prohibit_comments, isCanContent, () {
  1045. setState(() {
  1046. isCanContent = !isCanContent;
  1047. });
  1048. }),
  1049. _buildDivider(),
  1050. _buildSwitch(I18n.of(context).same_sex, isHidden, () {
  1051. setState(() {
  1052. isHidden = !isHidden;
  1053. });
  1054. }),
  1055. ],
  1056. ));
  1057. }
  1058. Widget _buildTip() {
  1059. return Container(
  1060. alignment: Alignment.centerLeft,
  1061. margin: EdgeInsets.only(top: 10, bottom: 10, left: 10),
  1062. child: Text(
  1063. I18n.of(context).dont,
  1064. textScaleFactor: 1.0,
  1065. style: TextStyle(fontSize: 12, color: Constants.GreyTextColor),
  1066. ),
  1067. );
  1068. }
  1069. Widget _buildTips() {
  1070. String str = '';
  1071. if (UserData().isMan()) {
  1072. str = I18n.of(context)
  1073. .member_free
  1074. .replaceFirst('/s1', UserData().addProgramPrice.toString());
  1075. } else {
  1076. str = I18n.of(context)
  1077. .certified_free
  1078. .replaceFirst('/s1', UserData().addProgramPrice.toString());
  1079. }
  1080. return Container(
  1081. padding: EdgeInsets.only(bottom: 100, left: 20, right: 20),
  1082. child: Text(
  1083. str,
  1084. textScaleFactor: 1.0,
  1085. style: TextStyle(fontSize: 12, color: Constants.GreyTextColor),
  1086. ),
  1087. );
  1088. }
  1089. Widget _buildBody() {
  1090. List<Widget> program = [
  1091. _buildProgramCat(),
  1092. _buildProgramContent(),
  1093. _buildTip(),
  1094. _buildSelct(),
  1095. _buildLoginButton(),
  1096. _buildTips()
  1097. ];
  1098. List<Widget> dynamics = [
  1099. _buildDynicContent(),
  1100. _buildTip(),
  1101. _buildSelct(),
  1102. _buildLoginButton(),
  1103. _buildTips()
  1104. ];
  1105. return Column(
  1106. children: widget.isProgram ? program : dynamics,
  1107. );
  1108. }
  1109. //构建登陆按钮
  1110. Widget _buildLoginButton() {
  1111. Text text = new Text(I18n.of(context).release,
  1112. textScaleFactor: 1.0,
  1113. style: TextStyle(fontSize: 15, color: Colors.white));
  1114. LinearGradient gradientColor = new LinearGradient(colors: <Color>[
  1115. Constants.ConfrimButtonColor,
  1116. Constants.ConfrimButtonColor
  1117. ]);
  1118. callback() async {
  1119. closeEmojiAction();
  1120. if (widget.isProgram) {
  1121. if (programId == -1) {
  1122. showToast(I18n.of(context).please_choose);
  1123. return;
  1124. }
  1125. if (lovePeopleId.length == 0) {
  1126. showToast(I18n.of(context).please_choose2);
  1127. return;
  1128. }
  1129. // if (dateRangeId.length == 0) {
  1130. // showToast(I18n.of(context).please_choose3);
  1131. // return;
  1132. // }
  1133. if (beginTimeId == '') {
  1134. showToast(I18n.of(context).please_choose4);
  1135. return;
  1136. }
  1137. if (endTimeId == -1) {
  1138. showToast(I18n.of(context).please_choose5);
  1139. return;
  1140. }
  1141. } else {
  1142. if (_textCtrl.value.text.trim().length == 0 && imgUrlList.length == 0) {
  1143. showToast(I18n.of(context).enter_something);
  1144. return;
  1145. }
  1146. }
  1147. payCallback() {
  1148. if (Provider.of<MoneyChangeProvider>(context).money <
  1149. UserData().addProgramPrice) {
  1150. CustomUI.buildOneConfirm(
  1151. context,
  1152. I18n.of(context).balance_insufficien,
  1153. I18n.of(context).recharge, () {
  1154. Navigator.of(context).pop();
  1155. ChargeMoney.showChargeSheet(context, () {
  1156. setState(() {});
  1157. });
  1158. });
  1159. return;
  1160. }
  1161. Navigator.of(context).pop();
  1162. postAddProgram(UserData().addProgramPrice);
  1163. }
  1164. String title = widget.isProgram
  1165. ? I18n.of(context).release_program
  1166. : I18n.of(context).release_dynamics;
  1167. //非会员男士提示付费
  1168. if (!UserData().isVip && UserData().isMan()) {
  1169. bool isMan = UserData().isMan();
  1170. CustomUI.buildTowConfirm(
  1171. context,
  1172. title,
  1173. isMan
  1174. ? I18n.of(context).become_member2
  1175. : I18n.of(context).now_certification,
  1176. () {
  1177. Navigator.of(context).push(
  1178. new MaterialPageRoute(
  1179. builder: (context) {
  1180. return isMan ? VipPage() : VerificationCenterPage();
  1181. },
  1182. ),
  1183. );
  1184. },
  1185. I18n.of(context)
  1186. .raid_release
  1187. .replaceFirst('/s1', UserData().addProgramPrice.toString()),
  1188. payCallback,
  1189. );
  1190. return;
  1191. }
  1192. //免费次数用完提示付费
  1193. if (UserData().basicInfo.usedPublishNum >=
  1194. UserData().basicInfo.publishNum) {
  1195. CustomUI.buildOneConfirm(
  1196. context,
  1197. title,
  1198. I18n.of(context)
  1199. .pay_unlock
  1200. .replaceFirst('/s1', UserData().addProgramPrice.toString()),
  1201. payCallback);
  1202. return;
  1203. }
  1204. HttpUtil().userFreeTime(context, UserData().basicInfo.userId, 3, () {
  1205. UserData().basicInfo.usedPublishNum++;
  1206. postAddProgram(0);
  1207. });
  1208. }
  1209. return new Container(
  1210. margin: EdgeInsets.only(top: 30, bottom: 10),
  1211. height: 44,
  1212. width: MediaQuery.of(context).size.width * 0.8,
  1213. child: ShadowButton().builder(gradientColor, text, callback),
  1214. );
  1215. }
  1216. postAddProgram(price) async {
  1217. var dateRangeStr = '';
  1218. dateRangeId.forEach((f) => dateRangeStr += dateRangeStr == '' ? f : ',$f');
  1219. var hopeObject = '';
  1220. lovePeopleId.forEach((f) => hopeObject += hopeObject == '' ? f : ',$f');
  1221. String temp = '';
  1222. String postTemp = '';
  1223. imgUrlList.forEach((str) {
  1224. temp += (temp == "" ? str : '|$str');
  1225. postTemp += (postTemp == ""
  1226. ? WebData().deleteDemain(str)
  1227. : '|${WebData().deleteDemain(str)}');
  1228. });
  1229. var type = widget.isProgram ? 0 : 1;
  1230. Map data = {
  1231. "userId": UserData().basicInfo.userId,
  1232. "type": type,
  1233. "price": price,
  1234. };
  1235. data['sign'] = TokenMgr().getSign(data);
  1236. //data['city'] = dateRangeStr;
  1237. data['programType'] = programId;
  1238. data['hopeObject'] = hopeObject;
  1239. data['aboutTime'] = beginTimeId;
  1240. data['content'] = _textCtrl.text;
  1241. data['imgUrl'] = postTemp;
  1242. data['evaluateStatus'] = isCanContent;
  1243. data['sexStatus'] = isHidden;
  1244. data['timeQuantum'] = endTimeId;
  1245. Response res = await HttpUtil()
  1246. .post('station/publish/program', data: data, isShowLoading: true);
  1247. var resData = res.data;
  1248. if (resData['code'] == 0) {
  1249. if (widget.isProgram) {
  1250. UserData().isCanProgram = false;
  1251. }
  1252. MessageMgr().emit('Add_program', {
  1253. 'Id': resData['data'],
  1254. 'UserId': UserData().basicInfo.userId,
  1255. 'NickName': UserData().basicInfo.nickName,
  1256. 'HeadimgUrl': UserData().basicInfo.headimgurl,
  1257. 'Type': type,
  1258. 'Sex': UserData().basicInfo.sex,
  1259. 'IsMember': UserData().basicInfo.isMember,
  1260. 'ProgramType': programId,
  1261. 'HopeObject': hopeObject,
  1262. 'City': dateRangeStr,
  1263. 'AboutTime': beginTimeId,
  1264. 'timeQuantum': endTimeId,
  1265. 'Content': _textCtrl.text,
  1266. 'ImgUrl': temp,
  1267. 'EvaluateStatus': isCanContent ? 1 : 0,
  1268. 'SexStatus': isHidden,
  1269. 'Status': 0,
  1270. 'CreateTime': DateTime.now().toIso8601String(),
  1271. 'FabulousNum': 0,
  1272. 'EvaluateNum': 0,
  1273. 'EnrollNum': 0,
  1274. 'IsAttestation': UserData().basicInfo.isAttestation ? 1 : 0,
  1275. 'IsFabulous': 0,
  1276. 'IsEnroll': 0,
  1277. 'EvaluateList': null,
  1278. "FabulousList": []
  1279. });
  1280. Navigator.of(context).pop();
  1281. focusNode.removeListener(_focusNodeListener);
  1282. } else {
  1283. showToast(resData['msg']);
  1284. }
  1285. }
  1286. }