post_widget.dart 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. import 'dart:convert';
  2. import 'dart:math';
  3. import 'package:cached_network_image/cached_network_image.dart';
  4. import 'package:flutter/cupertino.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter/services.dart';
  7. import 'package:sport/bean/achievement_info.dart';
  8. import 'package:sport/bean/post.dart';
  9. import 'package:sport/bean/post_user.dart';
  10. import 'package:sport/pages/social/gallery_photo_view.dart';
  11. import 'package:sport/pages/social/post_detail_page.dart';
  12. import 'package:sport/pages/social/share_webview.dart';
  13. import 'package:sport/provider/social_detail_model.dart';
  14. import 'package:sport/router/navigator_util.dart';
  15. import 'package:sport/services/api/inject_api.dart';
  16. import 'package:sport/utils/DateFormat.dart';
  17. import 'package:sport/utils/toast.dart';
  18. import 'package:sport/widgets/dialog/alert_dialog.dart';
  19. import 'package:sport/widgets/dialog/bindphone_dialog.dart';
  20. import 'package:sport/widgets/dialog/modal_bottom_action.dart';
  21. import 'package:sport/widgets/dialog/request_dialog.dart';
  22. import 'package:sport/widgets/image.dart';
  23. import 'package:sport/widgets/menu_share_bottom.dart';
  24. import 'package:sport/widgets/misc.dart';
  25. import 'package:sport/widgets/space.dart';
  26. import 'package:sport/widgets/user_widget.dart';
  27. class PostWidget extends StatefulWidget {
  28. final SocialDetailModel model;
  29. final Post post;
  30. final bool isSelf;
  31. final bool jump; // 头像是否可点击
  32. final String? keyword; // 头像是否可点击
  33. final bool highlight; // 头像是否可点击
  34. final bool showForum; // 头像是否可点击
  35. final bool showTopButton; // 头像是否可点击
  36. final Function? callback; // 头像是否可点击
  37. PostWidget(this.post, this.model, this.isSelf,
  38. {this.jump = true, this.highlight = false, this.keyword, this.showForum = false, this.showTopButton = false, this.callback});
  39. @override
  40. State<StatefulWidget> createState() => _PostWidgetState();
  41. }
  42. class _PostWidgetState extends State<PostWidget> with InjectApi {
  43. @override
  44. Widget build(BuildContext context) {
  45. return widget.post.isDelete == true ? Container() : _buildPostDetailWidget(context, widget.post, widget.isSelf);
  46. }
  47. void go(Post post, bool comment) async {
  48. // print("${post.toJson()}----------------------------------------");
  49. var result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
  50. return PostDetailPage(post, comment, widget.model.list);
  51. }));
  52. if (result == true) {
  53. _delete(widget.model, post);
  54. }
  55. }
  56. bool isExpansion(String text) {
  57. TextPainter _textPainter = TextPainter(maxLines: 3, text: TextSpan(text: text, style: TextStyle(fontSize: 16.0)), textDirection: TextDirection.ltr)
  58. ..layout(maxWidth: MediaQuery.of(context).size.width - 24);
  59. if (_textPainter.didExceedMaxLines) {
  60. return true;
  61. } else {
  62. return false;
  63. }
  64. }
  65. Widget _highlightName(String content) {
  66. String keyword = widget.keyword ?? "";
  67. var list = content.split(keyword);
  68. List<InlineSpan> texts = [];
  69. for (int i = 0; i < list.length; i++) {
  70. texts.add(TextSpan(text: list[i]));
  71. if (i < list.length - 1) texts.add(TextSpan(text: keyword, style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Theme.of(context).accentColor)));
  72. }
  73. return RichText(
  74. text: TextSpan(style: Theme.of(context).textTheme.subtitle1!, children: texts),
  75. );
  76. }
  77. Widget _highlightContent(String content, {int maxLines = 1}) {
  78. String keyword = widget.keyword ?? "";
  79. var list = content.split(keyword);
  80. List<InlineSpan> texts = [];
  81. for (int i = 0; i < list.length; i++) {
  82. texts.add(TextSpan(text: list[i]));
  83. if (i < list.length - 1)
  84. texts.add(TextSpan(text: keyword, style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16, color: Theme.of(context).accentColor)));
  85. }
  86. return RichText(
  87. maxLines: maxLines,
  88. text: TextSpan(style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16), children: texts),
  89. );
  90. }
  91. Widget _postWidget(Post post) {
  92. double width = MediaQuery.of(context).size.width - 24 - 22;
  93. // if(post.quoteData != null) print("[post:]${post.toJson()}-------------------------");
  94. // print("[post:]${post.toJson()}----------------------------------------");
  95. return Column(
  96. crossAxisAlignment: CrossAxisAlignment.start,
  97. children: <Widget>[
  98. RichText(
  99. maxLines: 3,
  100. overflow: TextOverflow.ellipsis,
  101. text: TextSpan(style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16), children: <InlineSpan>[
  102. TextSpan(text: '${post.nickname}:', style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Theme.of(context).accentColor)),
  103. TextSpan(text: '${post.content}', style: Theme.of(context).textTheme.subtitle1!),
  104. ]),
  105. ),
  106. if (post.images?.isNotEmpty == true)
  107. GridView.count(
  108. physics: new NeverScrollableScrollPhysics(),
  109. shrinkWrap: true,
  110. padding: EdgeInsets.only(top: 15),
  111. childAspectRatio: post.images!.length == 1 ? max(16 / 10, post.images![0].getImageAspectRatio()) : 1,
  112. crossAxisSpacing: 10.0,
  113. crossAxisCount: min(3, post.images!.length),
  114. children: post.images!
  115. .asMap()
  116. .keys
  117. .take(min(3, post.images!.length))
  118. .map((i) => GestureDetector(
  119. onTap: () => open(context, i, post.images!),
  120. child: i < 2
  121. ? post.images!.length == 1
  122. ? Row(
  123. mainAxisSize: MainAxisSize.min,
  124. children: <Widget>[
  125. ClipRRect(
  126. borderRadius: BorderRadius.circular(6),
  127. child: Stack(
  128. children: <Widget>[
  129. CachedNetworkImage(
  130. imageUrl: post.images![i].thumbnail ?? "",
  131. fit: BoxFit.cover,
  132. width: post.images![i].getWidth(width),
  133. ),
  134. if (post.images![i].isLongImage())
  135. Positioned(
  136. bottom: 4,
  137. right: 4,
  138. child: Container(
  139. padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
  140. decoration:
  141. BoxDecoration(color: Colors.black.withOpacity(.8), borderRadius: BorderRadius.all(Radius.circular(20))),
  142. child: Text(
  143. "长图",
  144. style: Theme.of(context).textTheme.bodyText1!.copyWith(color: Colors.white),
  145. ),
  146. ),
  147. )
  148. ],
  149. ))
  150. ],
  151. )
  152. : ClipRRect(
  153. borderRadius: BorderRadius.circular(6),
  154. child: CachedNetworkImage(imageUrl: post.images![i].thumbnail ?? "", fit: BoxFit.cover))
  155. : ClipRRect(
  156. borderRadius: BorderRadius.circular(6),
  157. child: Stack(
  158. fit: StackFit.expand,
  159. children: <Widget>[
  160. CachedNetworkImage(
  161. imageUrl: post.images![i].thumbnail ?? "",
  162. fit: BoxFit.cover,
  163. ),
  164. if (post.images!.length - 3 > 0)
  165. Container(
  166. color: Color(0x80000000),
  167. child: Center(
  168. child: Text(
  169. "+${post.images!.length - 3}",
  170. style: TextStyle(color: Colors.white, fontSize: 16),
  171. ),
  172. ),
  173. )
  174. ],
  175. ))))
  176. .toList()),
  177. if (post.quoteData != null) _postLink(post.quoteData!, color: Colors.white),
  178. ],
  179. );
  180. }
  181. Widget _postLink(String quote, {Color? color}) {
  182. var data = json.decode(quote);
  183. return Container(
  184. padding: EdgeInsets.all(8.0),
  185. color: color != null ? color : Color(0xfff5f5f5),
  186. child: Row(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: <Widget>[
  187. Icon(
  188. Icons.link,
  189. size: 60.0,
  190. ),
  191. Space(
  192. width: 5.0,
  193. ),
  194. Expanded(
  195. child: RichText(
  196. maxLines: 3,
  197. overflow: TextOverflow.ellipsis,
  198. text: TextSpan(style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16), children: <InlineSpan>[
  199. TextSpan(text: '${data["username"]["value"]}:', style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Theme.of(context).accentColor)),
  200. TextSpan(text: '分享了他的运动记录,快来围观吧~', style: Theme.of(context).textTheme.subtitle1!),
  201. ]),
  202. ),
  203. ),
  204. ]),
  205. );
  206. }
  207. _delete(SocialDetailModel model, Post post) {
  208. model.list.removeWhere((element) => element.id == post.id);
  209. setState(() {
  210. post.isDelete = true;
  211. });
  212. }
  213. _deleteF(SocialDetailModel model, Post post) async {
  214. if (await showDialog(
  215. context: context,
  216. builder: (context) => CustomAlertDialog(title: '确定删除帖子?', ok: () => Navigator.of(context).pop(true)),
  217. ) ==
  218. true) {
  219. await request(context, () async {
  220. await model.api.postDelSubject(post.id!);
  221. ToastUtil.show("删除成功");
  222. _delete(model, post);
  223. });
  224. }
  225. }
  226. Widget _buildPostDetailWidget(BuildContext context, Post post, bool isSelf) {
  227. SocialDetailModel model = widget.model;
  228. double width = MediaQuery.of(context).size.width - 24;
  229. return Column(
  230. children: <Widget>[
  231. GestureDetector(
  232. behavior: HitTestBehavior.opaque,
  233. onTap: () {
  234. go(post, false);
  235. // NavigatorUtil.goSocialPostDetail(context, post)
  236. },
  237. onLongPress: () async {
  238. await showActionDialog(context, {
  239. if (isSelf == false)
  240. "举报帖子": () async {
  241. await request(context, () async {
  242. await model.api.postForumReport(subjectId: post.id).catchError((onError) {});
  243. ToastUtil.show("举报成功");
  244. });
  245. },
  246. if (isSelf == false)
  247. "屏蔽此条": () async {
  248. await request(context, () async {
  249. await model.api.postForumBlockObject(post.id!, "subject").catchError((onError) {});
  250. ToastUtil.show("屏蔽成功");
  251. _delete(model, post);
  252. });
  253. },
  254. "复制文字": () {
  255. Clipboard.setData(ClipboardData(text: post.content));
  256. ToastUtil.show("已复制到粘贴板");
  257. }
  258. });
  259. },
  260. child: Padding(
  261. padding: const EdgeInsets.symmetric(vertical: 12.0),
  262. child: Column(
  263. crossAxisAlignment: CrossAxisAlignment.start,
  264. children: <Widget>[
  265. Row(
  266. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  267. children: <Widget>[
  268. GestureDetector(
  269. onTap: widget.jump
  270. ? () => NavigatorUtil.goSocialUserDetail(context, PostUser(id: post.userId, name: post.nickname, avatar: post.avatar))
  271. : null,
  272. child: Row(
  273. children: <Widget>[
  274. Space(
  275. width: 12,
  276. ),
  277. CircleAvatar(backgroundColor: Colors.black26,backgroundImage: userAvatarProvider(post.avatar), radius: 18),
  278. Space(
  279. width: 8,
  280. ),
  281. Column(
  282. crossAxisAlignment: CrossAxisAlignment.start,
  283. children: <Widget>[
  284. Row(
  285. children: <Widget>[
  286. widget.highlight
  287. ? _highlightName(post.nickname!)
  288. : Text(
  289. post.nickname!,
  290. style: Theme.of(context).textTheme.subtitle1!.copyWith(fontWeight: FontWeight.w600),
  291. ),
  292. UserLevelWidget(level :Level(level: post.userLevel, logo: post.userLevelLogo)),
  293. if (post.followStatus == "friends")
  294. Container(
  295. margin: EdgeInsets.only(left: 2.0),
  296. width: 27.0,
  297. height: 14.0,
  298. decoration: BoxDecoration(
  299. // color: Colors.white,
  300. // borderRadius: BorderRadius.all(Radius.circular(2)),
  301. // border: Border.all(
  302. // color: Theme.of(context).accentColor,
  303. // width: .5,
  304. // )
  305. image: DecorationImage(image: AssetImage("lib/assets/img/bbs_icon_friend.png")),
  306. ),
  307. // padding: EdgeInsets.fromLTRB(4, 0, 4, 2),
  308. // margin: EdgeInsets.fromLTRB(6.0, 0, 6, 0),
  309. // child: Text(
  310. // "好友",
  311. // style: Theme.of(context).textTheme.subtitle2.copyWith(color: Theme.of(context).accentColor, fontSize: 11),
  312. // )
  313. ),
  314. if (post.isOfficial == "1")
  315. Container(
  316. margin: EdgeInsets.only(left: 2.0),
  317. width: 27.0,
  318. height: 14.0,
  319. decoration: BoxDecoration(
  320. image: DecorationImage(image: AssetImage("lib/assets/img/bbs_icon_official.png")),
  321. ),
  322. ),
  323. ],
  324. ),
  325. Text(DateFormat.formatTime(post.createTime), style: Theme.of(context).textTheme.bodyText1!)
  326. ],
  327. ),
  328. ],
  329. )),
  330. widget.showForum && isSelf
  331. ? PopupMenuButton(
  332. icon: Image.asset(
  333. "lib/assets/img/bbs_btn_more.png",
  334. height: 12,
  335. fit: BoxFit.fitHeight,
  336. ),
  337. onSelected: (action) async {
  338. switch (action) {
  339. case "delete":
  340. if (await showDialog(
  341. context: context,
  342. builder: (context) => CustomAlertDialog(title: '确定删除此条?', ok: () => Navigator.of(context).pop(true)),
  343. ) ==
  344. true) {
  345. await request(context, () async {
  346. await model.api.postDelSubject(post.id!);
  347. ToastUtil.show("删除成功");
  348. _delete(model, post);
  349. });
  350. }
  351. break;
  352. case "top":
  353. await request(context, () async {
  354. if (post.isUserTop == "1") {
  355. var resp = await model.api.unsetUserTopSubjects(post.id!).catchError((onError) {});
  356. if (resp.code == 0) {
  357. ToastUtil.show("取消置顶成功");
  358. post.isUserTop = "0";
  359. }
  360. } else {
  361. var resp = await model.api.setUserTopSubjects(post.id!).catchError((onError) {});
  362. if (resp.code == 0) {
  363. ToastUtil.show("置顶成功");
  364. post.isUserTop = "1";
  365. }
  366. }
  367. widget.callback?.call();
  368. // setState(() {});
  369. });
  370. break;
  371. }
  372. },
  373. itemBuilder: (_) => divideMenus([
  374. menuItemCenter("delete", "删除此条"),
  375. if (widget.showTopButton == true) menuItemCenter("top", post.isUserTop == "1" ? "取消置顶" : "置顶帖子"),
  376. ]),
  377. )
  378. : IconButton(
  379. icon: Image.asset("lib/assets/img/btn_close_invitation.png"),
  380. onPressed: () async {
  381. if (isSelf == false) {
  382. if (await showDialog(
  383. context: context,
  384. builder: (context) => CustomAlertDialog(title: '是否屏蔽此条帖子', ok: () => Navigator.of(context).pop(true)),
  385. ) ==
  386. true) {
  387. await request(context, () async {
  388. await model.api.postForumBlockObject(post.id!, "subject").catchError((onError) {});
  389. ToastUtil.show("屏蔽成功");
  390. _delete(model, post);
  391. });
  392. }
  393. } else {
  394. _deleteF(model, post);
  395. }
  396. },
  397. )
  398. ],
  399. ),
  400. Padding(
  401. padding: const EdgeInsets.symmetric(horizontal: 12.0),
  402. child: Column(
  403. crossAxisAlignment: CrossAxisAlignment.start,
  404. children: <Widget>[
  405. Padding(
  406. padding: const EdgeInsets.only(top: 6.0),
  407. child: Column(
  408. crossAxisAlignment: CrossAxisAlignment.start,
  409. children: <Widget>[
  410. post.isExpansion ?? false == false
  411. ? widget.highlight
  412. ? _highlightContent(post.content!, maxLines: 3)
  413. : Text(post.content!,
  414. maxLines: 3, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16, height: 1.5))
  415. : widget.highlight
  416. ? _highlightContent(post.content!)
  417. : Text(post.content!, style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16, height: 1.5)),
  418. if (isExpansion(post.content!))
  419. GestureDetector(
  420. onTap: () {
  421. post.isExpansion = !(post.isExpansion ?? true);
  422. setState(() {});
  423. },
  424. child: Padding(
  425. padding: const EdgeInsets.only(top: 5.0),
  426. child: Row(
  427. children: <Widget>[
  428. Text(
  429. post.isExpansion ?? false == false ? "全部" : "收起",
  430. style: Theme.of(context).textTheme.bodyText1,
  431. strutStyle: fixedLine,
  432. ),
  433. SizedBox(
  434. width: 4,
  435. ),
  436. post.isExpansion ?? false == false ? arrowBottom() : arrowTop()
  437. ],
  438. ),
  439. )),
  440. ],
  441. ),
  442. ),
  443. if (post.images?.isNotEmpty == true)
  444. GridView.count(
  445. physics: new NeverScrollableScrollPhysics(),
  446. shrinkWrap: true,
  447. padding: const EdgeInsets.only(top: 12.0),
  448. childAspectRatio: post.images!.length == 1 ? max(16 / 10, post.images![0].getImageAspectRatio()) : 1,
  449. crossAxisSpacing: 10.0,
  450. crossAxisCount: min(3, post.images!.length),
  451. children: post.images!
  452. .asMap()
  453. .keys
  454. .take(min(3, post.images!.length))
  455. .map((i) => GestureDetector(
  456. onTap: () => i < 2 ? open(context, i, post.images ?? []) : go(post, false),
  457. child: i < 2
  458. ? post.images!.length == 1
  459. ? Row(
  460. mainAxisSize: MainAxisSize.min,
  461. children: <Widget>[
  462. ClipRRect(
  463. borderRadius: BorderRadius.circular(6),
  464. child: Stack(
  465. children: <Widget>[
  466. CachedNetworkImage(
  467. imageUrl: post.images![i].thumbnail ?? "",
  468. fit: BoxFit.cover,
  469. width: post.images![i].getWidth(width),
  470. ),
  471. if (post.images![i].isLongImage())
  472. Positioned(
  473. bottom: 4,
  474. right: 4,
  475. child: Container(
  476. padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
  477. decoration: BoxDecoration(
  478. color: Colors.black.withOpacity(.8), borderRadius: BorderRadius.all(Radius.circular(20))),
  479. child: Text(
  480. "长图",
  481. style: Theme.of(context).textTheme.bodyText1!.copyWith(color: Colors.white),
  482. ),
  483. ),
  484. )
  485. ],
  486. ))
  487. ],
  488. )
  489. : ClipRRect(
  490. borderRadius: BorderRadius.circular(6),
  491. child: CachedNetworkImage(imageUrl: post.images![i].thumbnail ?? "", fit: BoxFit.cover))
  492. : ClipRRect(
  493. borderRadius: BorderRadius.circular(6),
  494. child: Stack(
  495. fit: StackFit.expand,
  496. children: <Widget>[
  497. CachedNetworkImage(
  498. imageUrl: post.images![i].thumbnail ?? "",
  499. fit: BoxFit.cover,
  500. ),
  501. if (post.images!.length - 3 > 0)
  502. Container(
  503. color: Color(0x80000000),
  504. child: Center(
  505. child: Text(
  506. "+${post.images!.length - 3}",
  507. style: TextStyle(color: Colors.white, fontSize: 16),
  508. ),
  509. ),
  510. )
  511. ],
  512. ))))
  513. .toList()),
  514. ],
  515. ),
  516. ),
  517. if (post.quoteSubject != null)
  518. GestureDetector(
  519. behavior: HitTestBehavior.opaque,
  520. onTap: () {
  521. go(post.quoteSubject!, false);
  522. },
  523. child: Container(
  524. padding: EdgeInsets.all(11.0),
  525. margin: EdgeInsets.symmetric(horizontal: 12.0, vertical: 5.0),
  526. decoration: BoxDecoration(shape: BoxShape.rectangle, borderRadius: BorderRadius.all(Radius.circular(10)), color: Color(0xfff5f5f5)),
  527. child: _postWidget(post.quoteSubject!),
  528. ),
  529. ),
  530. Row(
  531. children: <Widget>[
  532. // Expanded(child:Text('${post.toJson()}')),
  533. if (post.gameName != null && post.gameName != "")
  534. Container(
  535. padding: EdgeInsets.fromLTRB(12.0, 12.0, 6.0, 0.0),
  536. alignment: Alignment.centerLeft,
  537. child: Container(
  538. padding: EdgeInsets.only(left: 6.0, right: 6.0, bottom: 2.0, top: 1.0),
  539. decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(4.0)), color: Color(0xffF1F1F1)),
  540. child: Text(
  541. post.gameName!,
  542. style: TextStyle(color: Color(0xff999999), fontSize: 12.0),
  543. strutStyle: StrutStyle(forceStrutHeight: true),
  544. ),
  545. ),
  546. ),
  547. if (widget.post.isUserTop == '1')
  548. Padding(
  549. padding: post.gameName != null && post.gameName != ""
  550. ? EdgeInsets.fromLTRB(0.0, 12.0, 12.0, 0.0)
  551. : EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 0.0),
  552. child: Container(
  553. child: Text(
  554. "已置顶",
  555. style: TextStyle(fontSize: 12, color: Color(0xff5498FF)),
  556. strutStyle: fixedLine,
  557. ),
  558. padding: EdgeInsets.only(left: 6.0, right: 6.0, bottom: 2.0, top: 1.0),
  559. decoration: BoxDecoration(
  560. borderRadius: BorderRadius.circular(2),
  561. border: Border.all(
  562. color: Color(0xff5498FF),
  563. width: .5,
  564. ),
  565. ),
  566. ),
  567. )
  568. ],
  569. ),
  570. if (post.quoteData != null)
  571. GestureDetector(
  572. behavior: HitTestBehavior.opaque,
  573. onTap: () {
  574. var data = json.decode(post.quoteData!);
  575. print("$data------------------------------");
  576. NavigatorUtil.goPage(
  577. context,
  578. (context) => WebViewSharePage(
  579. data['url']["value"],
  580. hash: data['hash']["value"],
  581. ));
  582. },
  583. child: Container(
  584. padding: EdgeInsets.all(11.0),
  585. margin: EdgeInsets.symmetric(horizontal: 12.0, vertical: 5.0),
  586. decoration: BoxDecoration(shape: BoxShape.rectangle, borderRadius: BorderRadius.all(Radius.circular(10)), color: Color(0xfff5f5f5)),
  587. child: _postLink(post.quoteData!),
  588. ),
  589. ),
  590. Space(
  591. height: 15,
  592. ),
  593. Row(
  594. children: <Widget>[
  595. Expanded(
  596. child: GestureDetector(
  597. behavior: HitTestBehavior.opaque,
  598. onTap: () {
  599. // NavigatorUtil.goPage(context, (context) => PostSharePage(post));
  600. menuShareBottom(context, "social", post: post);
  601. },
  602. child: Container(
  603. padding: const EdgeInsets.symmetric(horizontal: 5.0),
  604. child: Center(
  605. child: Row(
  606. mainAxisSize: MainAxisSize.min,
  607. children: <Widget>[
  608. Image.asset("lib/assets/img/bbslist_icon_share.png"),
  609. SizedBox(
  610. width: 5,
  611. ),
  612. Text(
  613. "转发",
  614. strutStyle: fixedLine,
  615. style: Theme.of(context).textTheme.bodyText1!,
  616. ),
  617. ],
  618. ),
  619. ),
  620. ),
  621. ),
  622. ),
  623. Expanded(
  624. child: GestureDetector(
  625. behavior: HitTestBehavior.opaque,
  626. onTap: () async {
  627. if (await showBindPhoneDialog(context) == true) {
  628. go(post, true);
  629. }
  630. },
  631. child: Container(
  632. padding: const EdgeInsets.symmetric(horizontal: 5.0),
  633. child: Center(
  634. child: Row(
  635. mainAxisSize: MainAxisSize.min,
  636. children: <Widget>[
  637. Image.asset("lib/assets/img/bbslist_icon_reply.png"),
  638. SizedBox(
  639. width: 5,
  640. ),
  641. Text(
  642. post.commentCount == 0 ? "回复" : "${post.commentCount}",
  643. strutStyle: fixedLine,
  644. style: Theme.of(context).textTheme.bodyText1!,
  645. ),
  646. ],
  647. ),
  648. ),
  649. ),
  650. ),
  651. ),
  652. Expanded(
  653. child: GestureDetector(
  654. behavior: HitTestBehavior.opaque,
  655. onTap: () async {
  656. await (post.isLiked == true ? model.api.postForumUnLike(post.id!, "subject_id") : model.api.postForumLike(post.id!, "subject_id"));
  657. setState(() {
  658. post.toggleLike();
  659. });
  660. },
  661. child: Container(
  662. padding: const EdgeInsets.symmetric(horizontal: 5.0),
  663. child: Center(
  664. child: SizedBox(
  665. height: 19,
  666. child: Row(
  667. crossAxisAlignment: CrossAxisAlignment.end,
  668. mainAxisSize: MainAxisSize.min,
  669. children: <Widget>[
  670. Image.asset(
  671. "lib/assets/img/bbslist_icon_like${post.isLiked == true ? 'd' : ''}.png",
  672. ),
  673. const SizedBox(
  674. width: 5,
  675. ),
  676. Text(
  677. post.likeCount == 0 ? "点赞" : "${post.likeCount}",
  678. strutStyle: fixedLine,
  679. style: Theme.of(context).textTheme.bodyText1!,
  680. ),
  681. ],
  682. ),
  683. ),
  684. ),
  685. ),
  686. ),
  687. ),
  688. ],
  689. ),
  690. ],
  691. ),
  692. ),
  693. ),
  694. // if (widget.showForum)
  695. // Padding(
  696. // padding: const EdgeInsets.only(bottom: 12.0, left: 12.0),
  697. // child: Row(
  698. // children: <Widget>[
  699. //// Container(
  700. //// child: Text("来自${widget.post.forumName}", style: Theme.of(context).textTheme.bodyText1!),
  701. //// padding: EdgeInsets.fromLTRB(8, 0, 8, 1),
  702. //// decoration: BoxDecoration(shape: BoxShape.rectangle, borderRadius: BorderRadius.all(Radius.circular(20)), color: Color(0xfff1f1f1)),
  703. //// ),
  704. //// Space(
  705. //// width: 10,
  706. //// ),
  707. // ],
  708. // ),
  709. // ),
  710. Divider(
  711. height: 1,
  712. ),
  713. ],
  714. );
  715. }
  716. }