detail_bottom.dart 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. import 'dart:math';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_easyrefresh/easy_refresh.dart';
  6. import 'package:fluttertoast/fluttertoast.dart';
  7. import 'package:photo_view/photo_view.dart';
  8. import 'package:photo_view/photo_view_gallery.dart';
  9. import 'package:provider/provider.dart';
  10. import 'package:sport/bean/comment.dart';
  11. import 'package:sport/bean/comment_post.dart';
  12. import 'package:sport/pages/social/post_comment.dart';
  13. import 'package:sport/provider/game_info_model.dart';
  14. import 'package:sport/provider/lib/provider_widget.dart';
  15. import 'package:sport/provider/user_model.dart';
  16. import 'package:sport/services/api/inject_api.dart';
  17. import 'package:sport/services/api/resp.dart';
  18. import 'package:sport/widgets/box.dart';
  19. import 'package:sport/widgets/decoration.dart';
  20. import 'package:sport/widgets/dialog/bindphone_dialog.dart';
  21. import 'package:sport/widgets/dialog/comment_dialog.dart';
  22. import 'package:sport/widgets/error.dart';
  23. import 'package:sport/widgets/loading.dart';
  24. import 'package:sport/widgets/misc.dart';
  25. import 'package:sport/widgets/persistent_header.dart';
  26. import 'package:sport/widgets/small_label.dart';
  27. import 'package:sport/widgets/text_input.dart';
  28. class DetailBottom extends StatelessWidget {
  29. TabController _controller;
  30. List<dynamic> _images;
  31. List<dynamic> _labels;
  32. dynamic _fileSize;
  33. dynamic _publishDate;
  34. dynamic _developCompany;
  35. int _subjectId;
  36. DetailBottom(this._controller, this._images, this._labels, this._fileSize, this._publishDate, this._developCompany, this._subjectId);
  37. @override
  38. Widget build(BuildContext context) {
  39. return TabBarView(
  40. controller: _controller,
  41. children: <Widget>[
  42. TabDetail(_images, _labels, _fileSize, _publishDate, _developCompany),
  43. TabComment(_subjectId),
  44. ],
  45. );
  46. }
  47. }
  48. // Tab 详情 左边的tab页
  49. class TabDetail extends StatelessWidget {
  50. List<dynamic> _images;
  51. List<dynamic> _labels;
  52. dynamic _fileSize;
  53. dynamic _publishDate;
  54. dynamic _developCompany;
  55. TabDetail(this._images, this._labels, this._fileSize, this._publishDate, this._developCompany);
  56. @override
  57. Widget build(BuildContext context) {
  58. return SingleChildScrollView(
  59. child: Column(
  60. mainAxisSize: MainAxisSize.min,
  61. crossAxisAlignment: CrossAxisAlignment.start,
  62. children: <Widget>[
  63. Padding(
  64. padding: const EdgeInsets.only(top: 12.0),
  65. child: SizedBox(
  66. height: 260,
  67. child: ListView.builder(
  68. scrollDirection: Axis.horizontal,
  69. shrinkWrap: true,
  70. itemBuilder: (context, index) {
  71. return GestureDetector(
  72. onTap: () => open(context, index),
  73. child: Padding(
  74. padding: EdgeInsets.only(left: (index == 0 ? 12.0 : 10.0), right: (index == _images.length - 1 ? 12.0 : 0.0)),
  75. child: ClipRRect(
  76. child: CachedNetworkImage(
  77. imageUrl: _images[index],
  78. width: 170,
  79. height: 226,
  80. fit: BoxFit.cover,
  81. ),
  82. borderRadius: BorderRadius.circular(10),
  83. ),
  84. ),
  85. );
  86. },
  87. itemCount: _images.length),
  88. ),
  89. ),
  90. SizedBox(height: 10,),
  91. Padding(
  92. padding: EdgeInsets.all(12.0),
  93. child: Column(
  94. crossAxisAlignment: CrossAxisAlignment.start,
  95. children: <Widget>[
  96. Padding(
  97. padding: EdgeInsets.only(bottom: 8.0),
  98. child: Row(
  99. children: <Widget>[
  100. Padding(
  101. padding: EdgeInsets.only(right: 2.0),
  102. child: Text(
  103. "运动标签:",
  104. style: TextStyle(color: Color.fromRGBO(102, 102, 102, 1)),
  105. ),
  106. ),
  107. if (_labels != null)
  108. Wrap(
  109. spacing: 4,
  110. runSpacing: 4,
  111. children: _labels.map((e) => gameTag(context, e)).toList(),
  112. ),
  113. ],
  114. ),
  115. ),
  116. Padding(
  117. padding: EdgeInsets.only(bottom: 8.0),
  118. child: Text("文件大小:${_fileSize}M", style: TextStyle(color: Color.fromRGBO(102, 102, 102, 1))),
  119. ),
  120. Padding(
  121. padding: EdgeInsets.only(bottom: 8.0),
  122. child: Text("发行时间:$_publishDate", style: TextStyle(color: Color.fromRGBO(102, 102, 102, 1))),
  123. ),
  124. Padding(
  125. padding: EdgeInsets.only(bottom: 8.0),
  126. child: Text("开发产商:$_developCompany", style: TextStyle(color: Color.fromRGBO(102, 102, 102, 1))),
  127. ),
  128. ],
  129. ),
  130. )
  131. // 第一个
  132. ],
  133. ),
  134. );
  135. }
  136. void open(BuildContext context, final int index) {
  137. Navigator.push(
  138. context,
  139. FadeRoute(
  140. page: GalleryPhotoViewWrapper(
  141. galleryItems: _images,
  142. backgroundDecoration: const BoxDecoration(
  143. color: Colors.black,
  144. ),
  145. initialIndex: index,
  146. scrollDirection: Axis.horizontal,
  147. ),
  148. ),
  149. );
  150. }
  151. }
  152. // 右边的tab
  153. class TabComment extends StatefulWidget {
  154. final int _subjectId;
  155. TabComment(this._subjectId);
  156. @override
  157. createState() => _TabCommentState();
  158. }
  159. class _TabCommentState extends State<TabComment> with InjectApi {
  160. FocusNode _comment = FocusNode();
  161. String _textFieldValue = "";
  162. CommentListModel _commentListModel;
  163. @override
  164. initState() {
  165. _commentListModel = new CommentListModel('${widget._subjectId}', by: 'created_at');
  166. super.initState();
  167. }
  168. Widget build(BuildContext context) {
  169. return ProviderWidget<CommentListModel>(
  170. model: _commentListModel,
  171. onModelReady: (model) => model.initData(),
  172. builder: (_, model, __) {
  173. return EasyRefresh.custom(
  174. controller: model.refreshController,
  175. enableControlFinishRefresh: true,
  176. enableControlFinishLoad: true,
  177. onRefresh: () => model.refresh(),
  178. onLoad: model.isIdle ? () => model.loadMore() : null,
  179. header: buildClassicalHeader(),
  180. footer: buildClassicalFooter(),
  181. slivers: [
  182. SliverPersistentHeader(
  183. delegate: PersistentHeader(
  184. min: 100,
  185. max: 100,
  186. child: Container(
  187. height: 100,
  188. margin: EdgeInsets.fromLTRB(12,12,12,24),
  189. padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12.0),
  190. decoration: card(),
  191. child: InkWell(
  192. child: Row(
  193. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  194. crossAxisAlignment: CrossAxisAlignment.center,
  195. children: <Widget>[
  196. Row(
  197. children: <Widget>[
  198. Consumer<UserModel>(
  199. builder: (_, model, __) {
  200. return model.user == null
  201. ? Container()
  202. : Row(
  203. children: <Widget>[
  204. CircleAvatar(radius: 15, backgroundImage: CachedNetworkImageProvider(model.user.avatar)),
  205. SizedBox(
  206. width: 12,
  207. ),
  208. Text(model.user.name, style: Theme.of(context).textTheme.subtitle1.copyWith(fontWeight: FontWeight.w600))
  209. ],
  210. );
  211. },
  212. ),
  213. ],
  214. ),
  215. Row(
  216. children: <Widget>[
  217. Padding(
  218. padding: EdgeInsets.only(right: 0.0),
  219. child: Text(
  220. "发表评论",
  221. style: TextStyle(color: Color.fromRGBO(51, 51, 51, 1)),
  222. ),
  223. ),
  224. Icon(Icons.keyboard_arrow_right)
  225. ],
  226. )
  227. ],
  228. ),
  229. onTap: ()async {
  230. if (await showBindPhoneDialog(context) != true) {
  231. return;
  232. }
  233. // 从下面弹出个框来 输入 评论
  234. showModalBottomSheet(
  235. context: context,
  236. isScrollControlled: true, // !important
  237. builder: (BuildContext context) {
  238. return SingleChildScrollView(
  239. // !important
  240. child: Container(
  241. padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), // !important
  242. child: TextInput(
  243. '${widget._subjectId}',
  244. focusNode: _comment,
  245. autoFocus: true,
  246. callback: () {
  247. model.refresh();
  248. Navigator.pop(context);
  249. },
  250. )),
  251. );
  252. },
  253. );
  254. },
  255. ),
  256. )),
  257. pinned: true,
  258. ),
  259. if (model.isBusy)
  260. SliverToBoxAdapter(
  261. child: RequestLoadingWidget(),
  262. ),
  263. if (model.isIdle && model.list.isNotEmpty)
  264. SliverList(
  265. delegate: SliverChildBuilderDelegate((context, index) {
  266. return PostCommentWidget(model.list[index]);
  267. // getComment(
  268. // 1,
  269. // model.list[index],
  270. // // initData: model.initData(),
  271. // );
  272. }, childCount: model.list.length)),
  273. if (model.isEmpty)
  274. SliverFillRemaining(
  275. child: Center(
  276. child: RequestErrorWidget(
  277. null,
  278. msg: "暂无评论~",
  279. assets: RequestErrorWidget.ASSETS_NO_COMMENT,
  280. ),
  281. ),
  282. ),
  283. ]);
  284. },
  285. );
  286. }
  287. }
  288. // type 1 bottom
  289. // type 2 head
  290. class getComment extends StatefulWidget {
  291. int type;
  292. String textType = "big";
  293. Function initData;
  294. Comment comment;
  295. getComment(this.type, this.comment, {this.initData});
  296. @override
  297. State<StatefulWidget> createState() {
  298. // TODO: implement createState
  299. return _getCommentState();
  300. }
  301. }
  302. class _getCommentState extends State<getComment> with InjectApi {
  303. FocusNode _comment = new FocusNode();
  304. String _textFieldValue = "";
  305. @override
  306. void initState() {
  307. // TODO: implement initState
  308. super.initState();
  309. }
  310. void handleLike({int type}) async {
  311. if (type == 1) {
  312. RespData<String> _data = await api.postForumLike(widget.comment.id, "comment_id");
  313. } else if (type == 2) {
  314. RespData<String> _data = await api.postForumUnLike(widget.comment.id, "comment_id");
  315. }
  316. }
  317. @override
  318. Widget build(BuildContext context) {
  319. // TODO: implement build
  320. return Container(
  321. padding: EdgeInsets.only(left: 12.0, right: 12.0, top: 16.0),
  322. child: Column(
  323. children: <Widget>[
  324. // avatar
  325. Padding(
  326. padding: EdgeInsets.only(bottom: 9.0),
  327. child: Row(
  328. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  329. children: <Widget>[
  330. ClipRRect(
  331. child: CachedNetworkImage(
  332. imageUrl: widget.comment.socialInfo.avatar == ""
  333. ? "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2661558467,1288211245&fm=26&gp=0.jpg"
  334. : widget.comment.socialInfo.avatar,
  335. width: 40.0,
  336. height: 40.0,
  337. fit: BoxFit.cover,
  338. ),
  339. borderRadius: BorderRadius.all(Radius.circular(50.0)),
  340. ),
  341. Expanded(
  342. child: Container(
  343. padding: EdgeInsets.only(left: 12.0),
  344. alignment: Alignment.centerLeft,
  345. child: Column(
  346. children: <Widget>[
  347. Container(
  348. width: double.infinity,
  349. alignment: Alignment.centerLeft,
  350. child: Text(
  351. "${widget.comment.socialInfo.name}",
  352. style: TextStyle(color: Color.fromRGBO(51, 51, 51, 1), fontWeight: FontWeight.bold),
  353. ),
  354. ),
  355. Container(
  356. padding: EdgeInsets.only(top: 5.0),
  357. width: double.infinity,
  358. alignment: Alignment.centerLeft,
  359. child: Text("${widget.comment.createdAt}", style: TextStyle(color: Color.fromRGBO(153, 153, 153, 1), fontSize: 12.0)),
  360. ),
  361. ],
  362. ),
  363. ),
  364. ),
  365. widget.type == 2
  366. ? Padding(
  367. padding: EdgeInsets.only(left: 12.0),
  368. child: Row(
  369. children: <Widget>[
  370. widget.comment.isLiked
  371. ? InkWell(
  372. child: Image.asset(
  373. "lib/assets/img/bbslist_icon_liked.png",
  374. width: 16.0,
  375. height: 16.0,
  376. ),
  377. onTap: () {
  378. handleLike(type: 2);
  379. widget.initData();
  380. },
  381. )
  382. : InkWell(
  383. child: Image.asset(
  384. "lib/assets/img/bbslist_icon_like.png",
  385. width: 16.0,
  386. height: 16.0,
  387. ),
  388. onTap: () {
  389. handleLike(type: 1);
  390. widget.initData();
  391. },
  392. ),
  393. Padding(
  394. padding: EdgeInsets.only(left: 5.0),
  395. child: Text(
  396. "${widget.comment.likeCount}",
  397. style: TextStyle(color: Color.fromRGBO(153, 153, 153, 1), fontSize: 12.0),
  398. ),
  399. )
  400. ],
  401. ),
  402. )
  403. : Container()
  404. ],
  405. )),
  406. // comment-content
  407. Container(
  408. width: double.infinity,
  409. alignment: Alignment.centerLeft,
  410. child: Text(
  411. "${widget.comment.content}",
  412. textAlign: TextAlign.left,
  413. style: TextStyle(fontSize: widget.textType == "big" ? 16.0 : 14.0, fontWeight: FontWeight.w400, height: 1.5, color: Colors.black),
  414. ),
  415. ),
  416. // comment-bottom
  417. widget.type == 1
  418. ? Padding(
  419. padding: EdgeInsets.only(top: 12.0),
  420. child: Row(
  421. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  422. children: <Widget>[
  423. widget.comment.subList.length != 0
  424. ? Row(
  425. children: <Widget>[
  426. InkWell(
  427. child: Text("查看${widget.comment.subList.length}条回复",
  428. style: TextStyle(fontSize: 12.0, fontWeight: FontWeight.w400, color: Color.fromRGBO(153, 153, 153, 1))),
  429. onTap: () async {
  430. _showCommentList(widget.comment, subjectId: widget.comment.id);
  431. // if (widget.comment.subList.length != 0) {
  432. // var data = await showModalBottomSheet(
  433. // context: context,
  434. // isScrollControlled: true,
  435. // shape: RoundedRectangleBorder(
  436. // borderRadius: BorderRadius.vertical(
  437. // top: Radius.circular(30))),
  438. // builder: (BuildContext context) {
  439. // return SingleChildScrollView(
  440. // child: Container(
  441. // height: MediaQuery.of(context)
  442. // .size
  443. // .height /
  444. // 3 *
  445. // 2,
  446. // padding: EdgeInsets.only(
  447. // bottom: MediaQuery.of(
  448. // context)
  449. // .viewInsets
  450. // .bottom), // !important
  451. // child: MaskComment(
  452. // widget.comment.id,
  453. // widget.comment.subjectId,
  454. // widget.comment.id,
  455. // widget.initData,
  456. // widget.comment,
  457. // )),
  458. // );
  459. // },
  460. // );
  461. // if (data == null) {
  462. // widget.initData();
  463. // }
  464. // }
  465. // else {
  466. // Fluttertoast.showToast(
  467. // msg: "没有可查看的回复",
  468. // toastLength: Toast.LENGTH_SHORT,
  469. // gravity: ToastGravity.CENTER,
  470. // timeInSecForIosWeb: 1,
  471. // backgroundColor: Colors.white,
  472. // textColor: Colors.black,
  473. // fontSize: 16.0);
  474. // }
  475. },
  476. ),
  477. Icon(
  478. Icons.chevron_right,
  479. color: Color.fromRGBO(153, 153, 153, 1),
  480. size: 16.0,
  481. )
  482. ],
  483. )
  484. : Container(),
  485. Row(
  486. children: <Widget>[
  487. Padding(
  488. padding: EdgeInsets.only(right: 25.0),
  489. child: Row(
  490. children: <Widget>[
  491. widget.comment.isLiked
  492. ? InkWell(
  493. child: Image.asset(
  494. "lib/assets/img/bbslist_icon_liked.png",
  495. width: 16.0,
  496. height: 16.0,
  497. ),
  498. onTap: () {
  499. handleLike(type: 2);
  500. widget.initData();
  501. },
  502. )
  503. : InkWell(
  504. child: Image.asset(
  505. "lib/assets/img/bbslist_icon_like.png",
  506. width: 16.0,
  507. height: 16.0,
  508. ),
  509. onTap: () {
  510. handleLike(type: 1);
  511. widget.initData();
  512. },
  513. ),
  514. Padding(
  515. padding: EdgeInsets.only(left: 5.0),
  516. child: Text(
  517. "${widget.comment.likeCount}",
  518. style: TextStyle(color: Color.fromRGBO(153, 153, 153, 1), fontSize: 12.0),
  519. ),
  520. )
  521. ],
  522. ),
  523. ),
  524. Row(
  525. children: <Widget>[
  526. Image.asset(
  527. "lib/assets/img/bbslist_icon_reply.png",
  528. width: 16.0,
  529. height: 16.0,
  530. ),
  531. InkWell(
  532. child: Padding(
  533. padding: EdgeInsets.only(left: 5.0),
  534. child: Text(
  535. "回复",
  536. style: TextStyle(color: Color.fromRGBO(153, 153, 153, 1), fontSize: 12.0),
  537. ),
  538. ),
  539. onTap: () {
  540. // showModalBottomSheet(
  541. // context: context,
  542. // isScrollControlled: true, // !important
  543. // builder: (BuildContext context) {
  544. // return SingleChildScrollView(
  545. // // !important
  546. // child: Container(
  547. // padding: EdgeInsets.only(
  548. // bottom: MediaQuery.of(context)
  549. // .viewInsets
  550. // .bottom), // !important
  551. // child: Container(
  552. // width: 351.0,
  553. // height: 44.0,
  554. // child: Padding(
  555. // padding: EdgeInsets.symmetric(
  556. // horizontal: 15.0),
  557. // child: Row(
  558. // mainAxisAlignment:
  559. // MainAxisAlignment
  560. // .spaceBetween,
  561. // crossAxisAlignment:
  562. // CrossAxisAlignment.center,
  563. // children: <Widget>[
  564. // Image.asset(
  565. // "lib/assets/img/bbs_icon_report.png",
  566. // width: 20.0,
  567. // height: 20.0,
  568. // ),
  569. // Expanded(
  570. // child: Container(
  571. // padding:
  572. // EdgeInsets.only(
  573. // left: 15.0),
  574. // alignment: Alignment
  575. // .centerLeft,
  576. // child: TextField(
  577. // focusNode: _comment,
  578. // autofocus: true,
  579. // style: TextStyle(
  580. // color: Color
  581. // .fromRGBO(
  582. // 153,
  583. // 153,
  584. // 153,
  585. // 1),
  586. // fontSize: 14.0),
  587. // onChanged: (value) {
  588. // setState(() {
  589. // _textFieldValue =
  590. // value;
  591. // });
  592. // },
  593. // decoration:
  594. // InputDecoration(
  595. // hintText:
  596. // '发表你的看法',
  597. // border:
  598. // InputBorder
  599. // .none),
  600. // )),
  601. // ),
  602. // InkWell(
  603. // child: Container(
  604. // width: 75.0,
  605. // height: 35.0,
  606. // alignment:
  607. // Alignment.center,
  608. // child: Text(
  609. // "发送",
  610. // style: TextStyle(
  611. // color:
  612. // Colors.white),
  613. // ),
  614. // decoration:
  615. // BoxDecoration(
  616. // borderRadius:
  617. // BorderRadius.all(
  618. // Radius
  619. // .circular(
  620. // 20.0)),
  621. // border: new Border
  622. // .all(
  623. // width: 1,
  624. // color: Theme.of(
  625. // context)
  626. // .accentColor),
  627. // gradient: LinearGradient(
  628. // begin: Alignment
  629. // .topCenter,
  630. // end: Alignment
  631. // .bottomCenter,
  632. // colors: [
  633. // Color.fromRGBO(
  634. // 255,
  635. // 196,
  636. // 0,
  637. // 1),
  638. // Color.fromRGBO(
  639. // 255,
  640. // 170,
  641. // 0,
  642. // 1),
  643. // ]),
  644. // ),
  645. // ),
  646. // onTap: () async {
  647. // RespData<CommentPost>
  648. // commentData =
  649. // await api.postForumComment(
  650. // "${widget.comment.subjectId}",
  651. // _textFieldValue,
  652. // toCommentId:
  653. // widget
  654. // .comment
  655. // .id,
  656. // parentCommentId:
  657. // widget
  658. // .comment
  659. // .id);
  660. // print(commentData);
  661. // print(commentData.code);
  662. // if (commentData.code !=
  663. // 0) {
  664. // Fluttertoast.showToast(
  665. // msg:
  666. // "${commentData.msg}",
  667. // toastLength: Toast
  668. // .LENGTH_SHORT,
  669. // gravity:
  670. // ToastGravity
  671. // .CENTER,
  672. // backgroundColor:
  673. // Colors.white,
  674. // textColor:
  675. // Colors.black,
  676. // fontSize: 13.0);
  677. // } else {
  678. // widget.initData();
  679. // Navigator.pop(
  680. // context);
  681. // }
  682. // },
  683. // )
  684. // ],
  685. // ),
  686. // ),
  687. // )),
  688. // );
  689. // },
  690. // );
  691. _showCommentList(widget.comment, subjectId: widget.comment.id);
  692. },
  693. ),
  694. ],
  695. ),
  696. ],
  697. ),
  698. ],
  699. ),
  700. )
  701. : Padding(
  702. padding: EdgeInsets.only(),
  703. ),
  704. Padding(
  705. padding: EdgeInsets.only(top: 17.0),
  706. child: Divider(),
  707. )
  708. ],
  709. ),
  710. );
  711. }
  712. void _showCommentList(Comment currentItem, {bool comment = false, String subjectId}) {
  713. showModalBottomSheet(
  714. context: context,
  715. isScrollControlled: true,
  716. shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(30))),
  717. builder: (BuildContext context) {
  718. return SingleChildScrollView(
  719. child: Container(
  720. height: max(520, MediaQuery.of(context).size.height / 3 * 2),
  721. padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), // !important
  722. child: CommentDialog(subjectId, currentItem, showInput: comment),
  723. ),
  724. );
  725. },
  726. ).then((val) {
  727. print(val);
  728. });
  729. }
  730. }
  731. class MaskComment extends StatefulWidget {
  732. String parentCommentId;
  733. String id;
  734. String subjectId;
  735. Function initData;
  736. Comment comment;
  737. MaskComment(this.parentCommentId, this.subjectId, this.id, this.initData, this.comment);
  738. @override
  739. State<StatefulWidget> createState() {
  740. // TODO: implement createState
  741. return _MaskCommentState();
  742. }
  743. }
  744. class _MaskCommentState extends State<MaskComment> with InjectApi {
  745. FocusNode _comment;
  746. RespPage<Comment> _data;
  747. var _textFieldValue = '';
  748. bool _isPopupText = false;
  749. @override
  750. void initState() {
  751. // TODO: implement initState
  752. super.initState();
  753. // _comment = FocusNode();
  754. // print(widget.parentCommentId);
  755. initData();
  756. }
  757. @override
  758. void dispose() {
  759. // TODO: implement dispose
  760. super.dispose();
  761. // _comment.dispose();
  762. }
  763. initData() async {
  764. RespPage<Comment> comment = await api.getPostCommentSubs(widget.parentCommentId, sortBy: "created_at");
  765. setState(() {
  766. _data = comment;
  767. print(_data);
  768. });
  769. }
  770. void handleLike({int type}) {
  771. print(type);
  772. }
  773. @override
  774. // void didChangeMetrics() {
  775. //// super.didChangeMetrics();
  776. // WidgetsBinding.instance.addPostFrameCallback((_) {
  777. // // 当前是安卓系统并且在焦点聚焦的情况下
  778. // if (Platform.isAndroid && _comment.hasFocus) {
  779. // if (_isPopupText) {
  780. // _isPopupText = false;
  781. // // 使输入框失去焦点
  782. // _comment.unfocus();
  783. // return;
  784. // }
  785. // _isPopupText = true;
  786. // }
  787. // });
  788. // }
  789. @override
  790. Widget build(BuildContext context) {
  791. // TODO: implement build
  792. return Container(
  793. width: MediaQuery.of(context).size.width,
  794. child: _data != null
  795. ? Column(
  796. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  797. children: <Widget>[
  798. // content
  799. Expanded(
  800. child: Column(
  801. children: <Widget>[
  802. // header
  803. Container(
  804. width: double.infinity,
  805. height: 50,
  806. child: Stack(
  807. alignment: Alignment.center,
  808. children: <Widget>[
  809. Text(
  810. "回复详情",
  811. style: TextStyle(color: Color.fromRGBO(153, 153, 153, 1), fontSize: 14.0),
  812. ),
  813. Positioned(
  814. left: 12.0,
  815. child: IconButton(
  816. icon: Icon(Icons.chevron_left),
  817. iconSize: 28.0,
  818. onPressed: () {
  819. Navigator.pop(context);
  820. },
  821. ))
  822. ],
  823. ),
  824. ),
  825. // Content
  826. getComment(1, widget.comment),
  827. Expanded(
  828. child: Padding(
  829. padding: EdgeInsets.only(left: 24.0),
  830. child: ListView.builder(
  831. itemBuilder: (context, index) {
  832. print(_data.pageResult.results[index].isLiked);
  833. return getComment(
  834. 2,
  835. _data.pageResult.results[index],
  836. initData: initData,
  837. );
  838. },
  839. itemCount: _data.pageResult.results.length,
  840. ),
  841. ),
  842. ),
  843. // listView
  844. ],
  845. ),
  846. ),
  847. // bottom
  848. Container(
  849. height: 50.0,
  850. decoration: new BoxDecoration(color: Colors.white, // 底色
  851. boxShadow: [BoxShadow(offset: Offset(0.0, 0), blurRadius: 5, spreadRadius: 0, color: Color.fromRGBO(0, 0, 0, 0.1))]),
  852. child: Padding(
  853. padding: EdgeInsets.symmetric(vertical: 7.0, horizontal: 22.0),
  854. child: Row(
  855. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  856. crossAxisAlignment: CrossAxisAlignment.center,
  857. children: <Widget>[
  858. Image.asset(
  859. "lib/assets/img/bbs_icon_report.png",
  860. width: 20.0,
  861. height: 20.0,
  862. ),
  863. Expanded(
  864. child: Container(
  865. padding: EdgeInsets.only(left: 15.0),
  866. alignment: Alignment.centerLeft,
  867. child: TextField(
  868. style: TextStyle(color: Color.fromRGBO(153, 153, 153, 1), fontSize: 14.0),
  869. onChanged: (value) {
  870. setState(() {
  871. _textFieldValue = value;
  872. });
  873. },
  874. decoration: InputDecoration(hintText: '发表你的看法', border: InputBorder.none),
  875. )),
  876. ),
  877. InkWell(
  878. child: Container(
  879. width: 75.0,
  880. height: 35.0,
  881. alignment: Alignment.center,
  882. child: Text(
  883. "发送",
  884. style: TextStyle(color: Colors.white),
  885. ),
  886. decoration: BoxDecoration(
  887. borderRadius: BorderRadius.all(Radius.circular(20.0)),
  888. border: new Border.all(width: 1, color: Theme.of(context).accentColor),
  889. gradient: LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [
  890. Color.fromRGBO(255, 196, 0, 1),
  891. Color.fromRGBO(255, 170, 0, 1),
  892. ]),
  893. ),
  894. ),
  895. onTap: () async {
  896. RespData<CommentPost> commentData;
  897. if (widget.parentCommentId != 0) {
  898. commentData = await api.postForumComment("${widget.subjectId}", _textFieldValue,
  899. toCommentId: widget.id, parentCommentId: widget.parentCommentId);
  900. } else {
  901. commentData = await api.postForumComment(
  902. "${widget.subjectId}",
  903. _textFieldValue,
  904. toCommentId: widget.id,
  905. );
  906. }
  907. if (commentData.code != 0) {
  908. Fluttertoast.showToast(
  909. msg: "${commentData.msg}",
  910. toastLength: Toast.LENGTH_SHORT,
  911. gravity: ToastGravity.CENTER,
  912. backgroundColor: Colors.white,
  913. textColor: Colors.black,
  914. fontSize: 13.0);
  915. } else {
  916. setState(() {
  917. _data = null;
  918. });
  919. initData();
  920. // Navigator.pop(context);
  921. }
  922. },
  923. )
  924. ],
  925. ),
  926. ),
  927. ),
  928. ],
  929. )
  930. : FadeingCircleLoading(context),
  931. );
  932. }
  933. }
  934. // 自定义PopRoute
  935. class PopRoute extends PopupRoute {
  936. final Duration _duration = Duration(milliseconds: 300);
  937. Widget child;
  938. PopRoute({@required this.child});
  939. @override
  940. Color get barrierColor => null;
  941. @override
  942. bool get barrierDismissible => true;
  943. @override
  944. String get barrierLabel => null;
  945. @override
  946. Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
  947. return child;
  948. }
  949. @override
  950. Duration get transitionDuration => _duration;
  951. }
  952. class FadeRoute extends PageRouteBuilder {
  953. final Widget page;
  954. FadeRoute({this.page})
  955. : super(
  956. pageBuilder: (
  957. BuildContext context,
  958. Animation<double> animation,
  959. Animation<double> secondaryAnimation,
  960. ) =>
  961. page,
  962. transitionsBuilder: (
  963. BuildContext context,
  964. Animation<double> animation,
  965. Animation<double> secondaryAnimation,
  966. Widget child,
  967. ) =>
  968. FadeTransition(
  969. opacity: animation,
  970. child: child,
  971. ),
  972. );
  973. }
  974. class GalleryPhotoViewWrapper extends StatefulWidget {
  975. GalleryPhotoViewWrapper({
  976. this.loadingBuilder,
  977. this.backgroundDecoration,
  978. this.minScale,
  979. this.maxScale,
  980. this.initialIndex,
  981. @required this.galleryItems,
  982. this.scrollDirection = Axis.horizontal,
  983. }) : pageController = PageController(initialPage: initialIndex);
  984. final LoadingBuilder loadingBuilder;
  985. final Decoration backgroundDecoration;
  986. final dynamic minScale;
  987. final dynamic maxScale;
  988. final int initialIndex;
  989. final PageController pageController;
  990. final List<String> galleryItems;
  991. final Axis scrollDirection;
  992. @override
  993. State<StatefulWidget> createState() {
  994. return _GalleryPhotoViewWrapperState();
  995. }
  996. }
  997. class _GalleryPhotoViewWrapperState extends State<GalleryPhotoViewWrapper> {
  998. int currentIndex;
  999. @override
  1000. void initState() {
  1001. currentIndex = widget.initialIndex;
  1002. super.initState();
  1003. }
  1004. void onPageChanged(int index) {
  1005. setState(() {
  1006. currentIndex = index;
  1007. });
  1008. }
  1009. @override
  1010. Widget build(BuildContext context) {
  1011. return Scaffold(
  1012. body: Container(
  1013. decoration: widget.backgroundDecoration,
  1014. constraints: BoxConstraints.expand(
  1015. height: MediaQuery.of(context).size.height,
  1016. ),
  1017. child: Stack(
  1018. alignment: Alignment.bottomRight,
  1019. children: <Widget>[
  1020. PhotoViewGallery.builder(
  1021. scrollPhysics: const BouncingScrollPhysics(),
  1022. builder: _buildItem,
  1023. itemCount: widget.galleryItems.length,
  1024. loadingBuilder: widget.loadingBuilder,
  1025. backgroundDecoration: widget.backgroundDecoration,
  1026. pageController: widget.pageController,
  1027. onPageChanged: onPageChanged,
  1028. scrollDirection: widget.scrollDirection,
  1029. ),
  1030. Container(
  1031. padding: const EdgeInsets.all(20.0),
  1032. child: Text(
  1033. "",
  1034. style: const TextStyle(
  1035. color: Colors.white,
  1036. fontSize: 17.0,
  1037. decoration: null,
  1038. ),
  1039. ),
  1040. )
  1041. ],
  1042. ),
  1043. ),
  1044. );
  1045. }
  1046. PhotoViewGalleryPageOptions _buildItem(BuildContext context, int index) {
  1047. final String item = widget.galleryItems[index];
  1048. return PhotoViewGalleryPageOptions(
  1049. imageProvider: CachedNetworkImageProvider(item),
  1050. initialScale: PhotoViewComputedScale.contained,
  1051. minScale: PhotoViewComputedScale.contained * (0.5 + index / 10),
  1052. maxScale: PhotoViewComputedScale.covered * 1.1,
  1053. heroAttributes: PhotoViewHeroAttributes(tag: item),
  1054. onTapUp: (
  1055. _,
  1056. __,
  1057. ___,
  1058. ) {
  1059. Navigator.of(context).pop();
  1060. });
  1061. }
  1062. }