Hibok
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

808 行
28 KiB

  1. import 'package:chat/data/UserData.dart';
  2. import 'package:chat/data/WebData.dart';
  3. import 'package:chat/generated/i18n.dart';
  4. import 'package:chat/home/ProfilePage.dart';
  5. import 'package:chat/home/rich_title.dart';
  6. import 'package:chat/utils/CustomUI.dart';
  7. import 'package:chat/utils/HttpUtil.dart';
  8. import 'package:chat/utils/MessageMgr.dart';
  9. import 'package:chat/utils/PicSwiper.dart';
  10. import 'package:chat/utils/TokenMgr.dart';
  11. import 'package:chat/utils/conversation_table.dart';
  12. import 'package:chat/utils/friend_list_mgr.dart';
  13. import 'package:chat/utils/screen.dart';
  14. import 'package:dio/dio.dart';
  15. import 'package:flutter/cupertino.dart';
  16. import 'package:flutter/material.dart';
  17. import 'package:flutter/services.dart';
  18. import 'package:oktoast/oktoast.dart';
  19. import 'package:pull_to_refresh/pull_to_refresh.dart';
  20. import 'package:url_launcher/url_launcher.dart';
  21. import '../data/constants.dart' show AppColors, Constants;
  22. import '../data/conversation.dart';
  23. import 'package:cached_network_image/cached_network_image.dart';
  24. import 'ProgramDetail.dart';
  25. class _ConversationItem extends StatelessWidget {
  26. const _ConversationItem(
  27. {Key key,
  28. this.conversation,
  29. this.callback,
  30. this.showRight = true,
  31. this.rightButton,
  32. this.applyInfo,
  33. this.bgColor,
  34. this.title})
  35. : assert(conversation != null),
  36. super(key: key);
  37. final Widget rightButton;
  38. final Conversation conversation;
  39. final callback;
  40. final bool showRight;
  41. final title;
  42. final applyInfo;
  43. final bgColor;
  44. @override
  45. Widget build(BuildContext context) {
  46. Widget avatar;
  47. double width = 53;
  48. if (conversation.isAvatarFromNet()) {
  49. avatar = ClipRRect(
  50. borderRadius: BorderRadius.circular(10),
  51. child: CachedNetworkImage(
  52. imageUrl: conversation.avatar,
  53. placeholder: (context, url) => Image.asset(
  54. Constants.DefaultHeadImgUrl,
  55. width: width,
  56. height: width,
  57. ),
  58. fit: BoxFit.cover,
  59. width: width,
  60. height: width,
  61. ));
  62. } else {
  63. avatar = ClipRRect(
  64. borderRadius: BorderRadius.circular(10),
  65. child: Container(
  66. width: width,
  67. height: width,
  68. alignment: Alignment.center,
  69. decoration: BoxDecoration(
  70. gradient: this.bgColor,
  71. borderRadius: BorderRadius.all(Radius.circular(50))),
  72. child: Image.asset(
  73. conversation.avatar,
  74. height: 27,
  75. )));
  76. }
  77. _buildBotton(str, callback) {
  78. return InkWell(
  79. onTap: callback,
  80. child: Container(
  81. padding: EdgeInsets.only(top: 5, left: 15, right: 15, bottom: 5),
  82. decoration: BoxDecoration(
  83. border:
  84. Border.all(color: Constants.ConfrimButtonColor, width: 1),
  85. color: Constants.ConfrimButtonColor,
  86. borderRadius: BorderRadius.all(Radius.circular(5))),
  87. child: fixedText(
  88. str,
  89. fontSize: 12,
  90. color: Colors.white,
  91. ),
  92. ));
  93. }
  94. void doApply(state, callback) async {
  95. Map data = {
  96. "id": applyInfo['applyId'],
  97. "userId": UserData().basicInfo.userId,
  98. "status": state,
  99. };
  100. data['sign'] = TokenMgr().getSign(data);
  101. Response res = await HttpUtil().post('user/handler/apply', data: data);
  102. if (res == null) {
  103. return;
  104. }
  105. var resData = res.data;
  106. if (resData['code'] == 0) {
  107. callback(resData['msg']);
  108. } else {}
  109. }
  110. void doFriendApply(state, callback) async {
  111. Map data = {
  112. "id": applyInfo['applyId'],
  113. "userId": UserData().basicInfo.userId,
  114. "status": state,
  115. };
  116. data['sign'] = TokenMgr().getSign(data);
  117. Response res =
  118. await HttpUtil().post('friendship/handler/apply', data: data);
  119. if (res == null) {
  120. return;
  121. }
  122. var resData = res.data;
  123. if (resData['code'] == 0) {
  124. callback(resData['msg']);
  125. } else {}
  126. }
  127. var bottomWiget = applyInfo == null
  128. ? Container()
  129. : Container(
  130. padding: EdgeInsets.only(left: 0, top: 10),
  131. decoration: BoxDecoration(
  132. color: Color(AppColors.ConversationItemBgColor),
  133. ),
  134. child: Row(
  135. crossAxisAlignment: CrossAxisAlignment.center,
  136. children: applyInfo['type'] == 0 || applyInfo['type'] == 6
  137. ? <Widget>[
  138. CustomUI.buildImgCover(
  139. applyInfo['imgId'],
  140. [
  141. PicSwiperItem(applyInfo['showUrl'],
  142. id: applyInfo['imgId'],
  143. type: applyInfo['type'] == 0
  144. ? PhotoType.destroy.index
  145. : PhotoType.free.index,
  146. isWatch: applyInfo['isWatch'],
  147. userId: applyInfo['userId'])
  148. ],
  149. applyInfo['showUrl'],
  150. 65,
  151. 10,
  152. applyInfo['isWatch'],
  153. context,
  154. applyInfo['type'] == 0
  155. ? PhotoType.destroy.index
  156. : PhotoType.free.index),
  157. Expanded(
  158. child: applyInfo['type'] == 0
  159. ? Container(
  160. alignment: Alignment.centerRight,
  161. padding: EdgeInsets.only(top: 40),
  162. child: applyInfo['state'] == 0
  163. ? Row(
  164. mainAxisAlignment:
  165. MainAxisAlignment.end,
  166. children: <Widget>[
  167. _buildBotton(I18n.of(context).aging,
  168. () {
  169. doApply(1, (msg) {
  170. showToast(msg);
  171. applyInfo['state'] = 1;
  172. MessageMgr()
  173. .emit('do_info_apply');
  174. });
  175. }),
  176. SizedBox(
  177. width: 10,
  178. ),
  179. _buildBotton(I18n.of(context).refuse,
  180. () {
  181. doApply(2, (msg) {
  182. showToast(msg);
  183. applyInfo['state'] = 2;
  184. MessageMgr()
  185. .emit('do_info_apply');
  186. });
  187. }),
  188. ],
  189. )
  190. : Padding(
  191. padding: EdgeInsets.only(right: 0),
  192. child: Text(
  193. applyInfo['state'] == 1
  194. ? I18n.of(context).passed
  195. : I18n.of(context).rejected,
  196. style: TextStyle(
  197. color: Constants.GreyTextColor,
  198. fontSize: 13),
  199. textScaleFactor: 1.0,
  200. ),
  201. ),
  202. )
  203. : Container(),
  204. )
  205. ]
  206. : [
  207. Expanded(child: Container()),
  208. Container(
  209. alignment: Alignment.centerRight,
  210. child: applyInfo['state'] == 0
  211. ? Row(
  212. mainAxisAlignment: MainAxisAlignment.end,
  213. children: <Widget>[
  214. _buildBotton(I18n.of(context).agree, () {
  215. doFriendApply(1, (msg) {
  216. showToast(msg);
  217. applyInfo['state'] = 1;
  218. var friendModel =
  219. FriendModel.fromServerJson({
  220. 'UserId': applyInfo['userId'],
  221. 'ImgUrl': applyInfo['imgUrl'],
  222. 'UserName': applyInfo['name']
  223. });
  224. FriendListMgr().addFriend(friendModel);
  225. MessageMgr().emit('do_info_apply');
  226. MessageMgr().emit('do_friend_apply', {
  227. 'userId': applyInfo['userId'],
  228. 'state': 1
  229. });
  230. MessageMgr().emit('Add friend');
  231. });
  232. }),
  233. SizedBox(
  234. width: 10,
  235. ),
  236. _buildBotton(I18n.of(context).refuse, () {
  237. doFriendApply(2, (msg) {
  238. showToast(msg);
  239. applyInfo['state'] = 2;
  240. MessageMgr().emit('do_info_apply');
  241. MessageMgr().emit('do_friend_apply', {
  242. 'userId': applyInfo['userId'],
  243. 'state': 2
  244. });
  245. });
  246. }),
  247. ],
  248. )
  249. : Padding(
  250. padding: EdgeInsets.only(right: 0),
  251. child: Text(
  252. applyInfo['state'] == 1
  253. ? I18n.of(context).passed
  254. : I18n.of(context).rejected,
  255. style: TextStyle(
  256. color: Constants.GreyTextColor,
  257. fontSize: 13),
  258. textScaleFactor: 1.0,
  259. ),
  260. ),
  261. ),
  262. ],
  263. ),
  264. );
  265. return InkWell(
  266. child: Container(
  267. padding:
  268. const EdgeInsets.only(left: 16.5, top: 11, bottom: 11, right: 14.5),
  269. decoration: BoxDecoration(
  270. color: Color(AppColors.ConversationItemBgColor),
  271. border: Border(
  272. bottom: BorderSide(
  273. color: AppColors.DividerColor,
  274. width: Constants.DividerWidth))),
  275. child: Column(
  276. children: <Widget>[
  277. Row(
  278. crossAxisAlignment: CrossAxisAlignment.start,
  279. children: <Widget>[
  280. avatar,
  281. Container(width: 19.0),
  282. Expanded(
  283. child: Container(
  284. child: Column(
  285. crossAxisAlignment: CrossAxisAlignment.start,
  286. children: <Widget>[
  287. Container(
  288. child: title == null
  289. ? Text(conversation.title,
  290. textScaleFactor: 1.0,
  291. style: TextStyle(
  292. fontSize: 12,
  293. color: Constants.LightGreyTextColor))
  294. : title),
  295. Container(
  296. padding: EdgeInsets.only(top: 5, bottom: 5),
  297. child: Row(
  298. children: <Widget>[
  299. Text(conversation.desc,
  300. textScaleFactor: 1.0,
  301. style: TextStyle(
  302. fontSize: 11,
  303. color: Constants.LightGreyTextColor)),
  304. showRight
  305. ? Expanded(
  306. child: Container(
  307. alignment: Alignment.centerRight,
  308. child: rightButton == null
  309. ? Text(
  310. '${I18n.of(context).go_see}>',
  311. textScaleFactor: 1.0,
  312. style: TextStyle(
  313. fontSize: 11,
  314. color: Constants
  315. .LightGreyTextColor))
  316. : rightButton,
  317. ),
  318. )
  319. : Container()
  320. ],
  321. )),
  322. applyInfo != null && applyInfo['content'] != null
  323. ? Container(
  324. child: Text(applyInfo['content'],
  325. textScaleFactor: 1.0,
  326. style: TextStyle(
  327. fontSize: 14,
  328. color: Constants.LightGreyTextColor)))
  329. : Container(),
  330. ],
  331. ),
  332. )),
  333. ],
  334. ),
  335. bottomWiget
  336. ],
  337. ),
  338. ),
  339. onTap: () {
  340. callback();
  341. },
  342. );
  343. }
  344. }
  345. class InfoListPage extends StatefulWidget {
  346. @required
  347. final String title;
  348. @required
  349. final int type;
  350. InfoListPage({Key key, this.title = "", this.type = 1}) : super(key: key);
  351. _InfoListPageState createState() => _InfoListPageState();
  352. }
  353. class _InfoListPageState extends State<InfoListPage>
  354. with SingleTickerProviderStateMixin {
  355. List list = new List(); //列表要展示的数据
  356. RefreshController _refreshController =
  357. RefreshController(initialRefresh: true);
  358. int _page = 1; //加载的页数
  359. int rows = 20;
  360. @override
  361. void initState() {
  362. super.initState();
  363. messageOn();
  364. }
  365. void initList(data) {
  366. list.clear();
  367. if (data != null) {
  368. list.addAll(data);
  369. }
  370. if (mounted) setState(() {});
  371. }
  372. void addList(data) {
  373. if (data == null || data.length == 0) {
  374. _page--;
  375. _refreshController.loadNoData();
  376. } else {
  377. list.addAll(data);
  378. _refreshController.loadComplete();
  379. }
  380. setState(() {});
  381. }
  382. messageApply(data) {
  383. _onRefresh();
  384. }
  385. msgPhoto(id) {
  386. for (int i = 0; i < list.length; i++) {
  387. if (list[i]['ApplyImg'] == id) {
  388. setState(() {
  389. list[i]['IsCheck'] = 1;
  390. });
  391. break;
  392. }
  393. }
  394. }
  395. void messageOn() {
  396. MessageMgr().on('do_info_apply', messageApply);
  397. MessageMgr().on('refresh_photo', msgPhoto);
  398. }
  399. void messageOff() {
  400. MessageMgr().off('do_info_apply', messageApply);
  401. MessageMgr().off('refresh_photo', msgPhoto);
  402. }
  403. getNewData(callback) {
  404. switch (widget.type) {
  405. case InfoType.Apply: //获取申请通知
  406. getData('user/check/realecords', callback);
  407. break;
  408. case InfoType.Evaluation: //获取评价通知
  409. getData('evaluate/user/realecordslist', callback);
  410. break;
  411. case InfoType.System: //获取系统通知
  412. getData('message/center/list', callback);
  413. break;
  414. case InfoType.Radio: //获取电台消息
  415. getData('message/center/cast', callback);
  416. break;
  417. case InfoType.Money: //获取钱包通知
  418. getData('message/wallet/message', callback);
  419. break;
  420. default:
  421. }
  422. }
  423. Future getData(url, callback) async {
  424. Map data = {
  425. "userId": UserData().basicInfo.userId,
  426. };
  427. if (widget.type == InfoType.System) {
  428. data['type'] = UserData().basicInfo.sex;
  429. }
  430. data['sign'] = TokenMgr().getSign(data);
  431. if (widget.type == InfoType.Money) {
  432. data['type'] = 1;
  433. }
  434. data["page"] = _page;
  435. data['rows'] = rows;
  436. Response res = await HttpUtil()
  437. .post(url, data: data, failback: () => Navigator.of(context).pop());
  438. _refreshController.refreshCompleted();
  439. var resData = res.data;
  440. print(resData);
  441. if (resData['code'] == 0) {
  442. callback(resData['data']);
  443. } else {
  444. showToast(resData['msg']);
  445. }
  446. }
  447. /*
  448. * 下拉刷新方法,为list重新赋值
  449. */
  450. Future<Null> _onRefresh() async {
  451. _page = 1;
  452. getNewData(initList);
  453. }
  454. @override
  455. void dispose() {
  456. _refreshController.dispose();
  457. messageOff();
  458. super.dispose();
  459. }
  460. //钱包通知
  461. Widget _buildMoneyInfo(data) {
  462. String imgUrl = data['HeadImg'] == null || data['HeadImg'] == ''
  463. ? 'assets/images/chat/icon4.png'
  464. : data['HeadImg'];
  465. bool showIndex = data['ChangeUserId'] != 0;
  466. return _ConversationItem(
  467. conversation: Conversation(
  468. avatar: imgUrl,
  469. title: '',
  470. desc: WebData().getLoginTime(context, data['CreateTime']),
  471. updateAt: '',
  472. ),
  473. bgColor: Constants.MoneyGradient,
  474. showRight: data['DetailType'] == 10,
  475. title: RichTitle.getRichTitleWidget(data, context, InfoType.Money),
  476. rightButton: Text(I18n.of(context).alreay_back,
  477. style: TextStyle(
  478. fontSize: 12,
  479. fontWeight: FontWeight.normal,
  480. color: Constants.BlackTextColor)),
  481. callback: () {
  482. if (showIndex) {
  483. Navigator.of(context).push(
  484. new MaterialPageRoute(
  485. builder: (context) {
  486. return ProfilePage(
  487. userId: data['UserId'] == UserData().basicInfo.userId
  488. ? data['ChangeUserId']
  489. : data['UserId'],
  490. );
  491. },
  492. ),
  493. );
  494. }
  495. },
  496. );
  497. }
  498. //申请列表
  499. Widget _buildApllayInfo(userInfo) {
  500. bool isMyself = userInfo['ApplyUserId'] == UserData().basicInfo.userId;
  501. String name = isMyself ? userInfo['UserName'] : userInfo['ApplyName'];
  502. String imgUrl = isMyself ? userInfo['UserUrl'] : userInfo['ApplyUrl'];
  503. var applyInfo = {
  504. 'applyId': userInfo['Id'],
  505. 'userId': userInfo['ApplyUserId'],
  506. 'name': name,
  507. 'type': userInfo['Type'],
  508. 'imgUrl': imgUrl,
  509. 'showUrl': userInfo['ImgUrl'],
  510. 'content': userInfo['Content'],
  511. 'imgId': userInfo['ApplyImg'],
  512. 'createTime': userInfo['CreatTime'],
  513. 'isWatch': userInfo['IsCheck'] == 1,
  514. 'state': userInfo['Status'],
  515. };
  516. return _ConversationItem(
  517. conversation: Conversation(
  518. avatar: imgUrl == null || imgUrl == ''
  519. ? Constants.DefaultHeadImgUrl
  520. : imgUrl,
  521. title: '',
  522. desc: WebData().getLoginTime(context, userInfo['CreatTime']),
  523. updateAt: '17:20',
  524. ),
  525. title: RichTitle.getRichTitleWidget(userInfo, context, InfoType.Apply),
  526. applyInfo: isMyself ? null : applyInfo,
  527. callback: () {
  528. Navigator.of(context).push(
  529. new MaterialPageRoute(
  530. builder: (context) {
  531. return ProfilePage(
  532. userId: isMyself ? userInfo['UserId'] : userInfo['ApplyUserId'],
  533. );
  534. },
  535. ),
  536. );
  537. },
  538. );
  539. }
  540. //评价列表
  541. Widget _buildContentInfo(userInfo) {
  542. Widget botton = InkWell(
  543. onTap: () async {
  544. var data = {
  545. "userid": UserData().basicInfo.userId,
  546. "evaluateuserid": userInfo['EvaluateUserId'],
  547. };
  548. data['sign'] = TokenMgr().getSign(data);
  549. Response res =
  550. await HttpUtil().post('evaluate/user/appeal', data: data);
  551. if (res == null) {
  552. return;
  553. }
  554. Map resData = res.data;
  555. if (resData['code'] == 0) {
  556. setState(() {
  557. userInfo['Status'] = 1;
  558. });
  559. }
  560. },
  561. child: Container(
  562. padding: EdgeInsets.only(top: 2, left: 5, right: 5, bottom: 2),
  563. decoration: BoxDecoration(
  564. border:
  565. Border.all(color: Constants.LightBlueButtonColor, width: 1),
  566. color: Constants.LightBlueButtonColor,
  567. borderRadius: BorderRadius.all(Radius.circular(5))),
  568. child: fixedText(
  569. I18n.of(context).appeal,
  570. fontSize: 9,
  571. color: Colors.white,
  572. ),
  573. ));
  574. return _ConversationItem(
  575. conversation: Conversation(
  576. avatar: 'assets/images/chat/icon6.png',
  577. title: '',
  578. desc: WebData().getLoginTime(context, userInfo['CreateTime']),
  579. updateAt: '17:20',
  580. ),
  581. bgColor: Constants.EvaGradient,
  582. rightButton: userInfo['Status'] == 0 || userInfo['Status'] == 3
  583. ? botton
  584. : Text(userInfo['Status'] == 1 ? I18n.of(context).appealed : "",
  585. style:
  586. TextStyle(fontSize: 11, color: Constants.LightGreyTextColor)),
  587. title:
  588. RichTitle.getRichTitleWidget(userInfo, context, InfoType.Evaluation),
  589. callback: () {},
  590. );
  591. }
  592. String getReportTilte(bool isMyself, data) {
  593. String res = '';
  594. switch (data['ReportType']) {
  595. //举报用户
  596. case 1:
  597. if (isMyself) {
  598. res = data['Status'] == 1
  599. ? I18n.of(context)
  600. .report_success
  601. .replaceFirst('/s1', data['ReportedUserName'])
  602. : I18n.of(context)
  603. .report_failure
  604. .replaceFirst('/s1', data['ReportedUserName']);
  605. } else {
  606. res = I18n.of(context).coin_returen;
  607. }
  608. break;
  609. //举报节目
  610. case 2:
  611. break;
  612. //举报动态
  613. case 3:
  614. break;
  615. //举报评论
  616. case 4:
  617. break;
  618. default:
  619. }
  620. return res;
  621. }
  622. //系统通知
  623. Widget _buildSystemInfo(data) {
  624. bool isMyself = data['UserId'] == UserData().basicInfo.userId;
  625. String imgUrl = data['Type'] == 3
  626. ? (isMyself ? data['HeadImg'] : 'assets/images/chat/icon5.png')
  627. : 'assets/images/chat/icon5.png';
  628. var applyInfo = {
  629. 'applyId': data['Id'],
  630. 'userId': data['ApplyUserId'],
  631. 'name': data['Theme'],
  632. 'type': data['Type'],
  633. 'imgUrl': imgUrl,
  634. 'showUrl': data['HeadImg'],
  635. 'content': data['Content'],
  636. 'imgId': data['ApplyImg'],
  637. 'createTime': data['CreatTime'],
  638. 'isWatch': data['IsCheck'] == 1,
  639. 'links': data['Links'],
  640. 'state': data['Status'],
  641. };
  642. return _ConversationItem(
  643. conversation: Conversation(
  644. avatar: imgUrl,
  645. title: '',
  646. desc: WebData().getLoginTime(context, data['CreateTime']),
  647. updateAt: '17:20',
  648. ),
  649. showRight: data['Type'] == 6,
  650. applyInfo: data['Type'] == 6 ? applyInfo : null, // applyInfo,
  651. bgColor: Constants.ParkGradient,
  652. title: data['Type'] == 6
  653. ? Text(data['Theme'])
  654. : RichTitle.getRichTitleWidget(data, context, InfoType.System),
  655. callback: () {
  656. if (data['Type'] == 4 && data['Status'] == 1) {
  657. ClipboardData clipboardData =
  658. new ClipboardData(text: data['Content']);
  659. Clipboard.setData(clipboardData);
  660. showToast(I18n.of(context).successful_copy);
  661. }
  662. if (data['Type'] == 3) {
  663. Navigator.of(context).push(
  664. new MaterialPageRoute(
  665. builder: (context) {
  666. return ProfilePage(
  667. userId: data['ReportedUserId'],
  668. );
  669. },
  670. ),
  671. );
  672. }
  673. if (data['Type'] == 6) {
  674. launch(applyInfo['links']);
  675. }
  676. },
  677. );
  678. }
  679. //电台消息
  680. Widget _buildRadioInfo(data) {
  681. String imgUrl = data['HeadImg'] == null || data['HeadImg'] == ''
  682. ? Constants.DefaultHeadImgUrl
  683. : data['HeadImg'];
  684. return _ConversationItem(
  685. conversation: Conversation(
  686. avatar: imgUrl,
  687. title: '',
  688. desc: WebData().getLoginTime(context, data['CreateTime']),
  689. updateAt: '17:20',
  690. ),
  691. title: RichTitle.getRichTitleWidget(data, context, InfoType.Radio),
  692. callback: () {
  693. Navigator.of(context).push(
  694. new MaterialPageRoute(
  695. builder: (context) {
  696. return ProgramDetailPage(
  697. programId: data['Id'],
  698. );
  699. },
  700. ),
  701. );
  702. },
  703. );
  704. }
  705. Widget _renderRow(BuildContext context, int index) {
  706. if (index < list.length) {
  707. var userInfo = list[index];
  708. Widget result = Container();
  709. switch (widget.type) {
  710. case InfoType.Apply:
  711. result = _buildApllayInfo(userInfo);
  712. break;
  713. case InfoType.Evaluation:
  714. result = _buildContentInfo(userInfo);
  715. break;
  716. case InfoType.System:
  717. result = _buildSystemInfo(userInfo);
  718. break;
  719. case InfoType.Radio:
  720. result = _buildRadioInfo(userInfo);
  721. break;
  722. case InfoType.Money:
  723. result = _buildMoneyInfo(userInfo);
  724. break;
  725. default:
  726. }
  727. if (index == 0) {
  728. result = Padding(padding: EdgeInsets.only(top: 10), child: result);
  729. }
  730. return result;
  731. }
  732. return Container();
  733. }
  734. void _onLoading() async {
  735. _page++;
  736. getNewData(addList);
  737. }
  738. @override
  739. Widget build(BuildContext context) {
  740. var content = Scaffold(
  741. appBar: AppBar(
  742. backgroundColor: AppColors.NewAppbarBgColor,
  743. title: Text(
  744. widget.title,
  745. style: TextStyle(color: AppColors.NewAppbarTextColor),
  746. ),
  747. leading: CustomUI.buildCustomLeading(context),
  748. centerTitle: true,
  749. ),
  750. body: SafeArea(
  751. child: SmartRefresher(
  752. enablePullDown: true,
  753. enablePullUp: true,
  754. header: MaterialClassicHeader(),
  755. footer: CustomUI.buildLoadingFooter(),
  756. controller: _refreshController,
  757. onRefresh: _onRefresh,
  758. onLoading: _onLoading,
  759. child: (_refreshController.headerStatus == RefreshStatus.completed &&
  760. list.length == 0)
  761. ? CustomUI.buildNoData(context)
  762. : ListView.builder(
  763. itemBuilder: _renderRow,
  764. itemCount: list.length,
  765. ),
  766. )));
  767. return content; // CustomUI.buildPageLoading(context, content, !isLoadingFish);
  768. }
  769. }