message_page.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. import 'dart:async';
  2. import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' as extended;
  3. import 'package:flutter/material.dart';
  4. import 'package:get_it/get_it.dart';
  5. import 'package:provider/provider.dart';
  6. import 'package:sport/bean/notice.dart';
  7. import 'package:sport/pages/social/message_list_subpage.dart';
  8. import 'package:sport/pages/social/message_notice_detail_page.dart';
  9. import 'package:sport/provider/message_model.dart';
  10. import 'package:sport/router/navigator_util.dart';
  11. import 'package:sport/router/routes.dart';
  12. import 'package:sport/services/api/inject_api.dart';
  13. import 'package:sport/services/userid.dart';
  14. import 'package:sport/widgets/appbar.dart';
  15. import 'package:sport/widgets/image.dart';
  16. import 'package:sport/widgets/loading.dart';
  17. import 'package:sport/widgets/misc.dart';
  18. import 'package:sport/widgets/persistent_header.dart';
  19. import 'package:sport/widgets/round_tab_indicator.dart';
  20. class MessagePage extends StatefulWidget {
  21. @override
  22. State<StatefulWidget> createState() => _PageState();
  23. }
  24. class _PageState extends State<MessagePage> with TickerProviderStateMixin, InjectApi, UserId {
  25. late TabController _controller;
  26. late Future<List<Notice>> _future;
  27. @override
  28. void initState() {
  29. super.initState();
  30. _controller = TabController(length: 3, vsync: this);
  31. _future = _getNotice();
  32. }
  33. Future<List<Notice>> _getNotice() async {
  34. List<Notice> items = [];
  35. var resp = await api.getInformList().catchError((onError) {});
  36. items.addAll(resp.pageResult.results ?? []);
  37. resp = await api.getNoticeList(isMsg: "0", markread: null);
  38. items.addAll(resp.pageResult.results ?? []);
  39. return items;
  40. }
  41. @override
  42. void dispose() {
  43. _controller.dispose();
  44. super.dispose();
  45. }
  46. @override
  47. Widget build(BuildContext context) {
  48. final double tabHeader = 50;
  49. final double statusBarHeight = MediaQuery.of(context).padding.top;
  50. final double pinnedHeaderHeight =
  51. //statusBar height
  52. statusBarHeight +
  53. //pinned SliverAppBar height in header
  54. kToolbarHeight +
  55. tabHeader;
  56. return Scaffold(
  57. backgroundColor: Colors.white,
  58. body: extended.ExtendedNestedScrollView(
  59. pinnedHeaderSliverHeightBuilder: () {
  60. return pinnedHeaderHeight;
  61. },
  62. headerSliverBuilder: (context, innerBoxIsScrolled) {
  63. return <Widget>[
  64. buildSliverAppBar(context, "社区消息", innerBoxIsScrolled: innerBoxIsScrolled),
  65. SliverPersistentHeader(
  66. delegate: PersistentHeader(
  67. min: tabHeader,
  68. max: tabHeader,
  69. child: Container(
  70. color: Colors.white,
  71. child: Column(
  72. children: <Widget>[
  73. Expanded(
  74. child: Center(
  75. child: Container(
  76. height: 35,
  77. child: TabBar(
  78. controller: _controller,
  79. isScrollable: true,
  80. labelPadding: EdgeInsets.symmetric(horizontal: 32),
  81. indicatorWeight: 3,
  82. indicatorPadding: EdgeInsets.symmetric(horizontal: 6),
  83. indicator: RoundUnderlineTabIndicator(borderSide: BorderSide(color: const Color(0xffFFC400), width: 3)),
  84. tabs: <Widget>[
  85. Tab(
  86. text: '聊天',
  87. ),
  88. Tab(
  89. child: Stack(
  90. clipBehavior: Clip.none,
  91. children: [
  92. Center(
  93. child: Text("消息"),
  94. ),
  95. ValueListenableBuilder(
  96. valueListenable: GetIt.I<MessageModel>().notifierSocial,
  97. builder: (BuildContext context, int value, Widget? child) {
  98. int v = value - GetIt.I<MessageModel>().notifierMessage.value;
  99. if (v == 0) return Container();
  100. return Positioned(
  101. right: -4,
  102. top: 4,
  103. child: Container(
  104. width: 8,
  105. height: 8,
  106. decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.red),
  107. ),
  108. );
  109. },
  110. )
  111. ],
  112. ),
  113. ),
  114. Tab(
  115. text: '通知',
  116. ),
  117. ],
  118. ),
  119. ),
  120. ),
  121. ),
  122. Divider(
  123. height: 1,
  124. indent: 12.0,
  125. endIndent: 12.0,
  126. )
  127. ],
  128. ),
  129. )),
  130. pinned: true,
  131. ),
  132. ];
  133. },
  134. body: TabBarView(controller: _controller, children: [
  135. Container(key: const PageStorageKey<String>('Tab1'), child: MessageListSubPage()),
  136. ListView.separated(
  137. key: const PageStorageKey<String>('Tab2'),
  138. padding: EdgeInsets.symmetric(horizontal: 12.0),
  139. itemBuilder: (context, index) => index == 0
  140. ? InkWell(
  141. onTap: () async {
  142. await NavigatorUtil.go(context, "${Routes.socialMessageDetail}?data=comment");
  143. GetIt.I<MessageModel>().getCount();
  144. },
  145. child: Padding(
  146. padding: const EdgeInsets.symmetric(vertical: 12.0),
  147. child: Row(children: <Widget>[
  148. Image.asset(
  149. "lib/assets/img/bbsmessage_icon_color_reply.png",
  150. width: 44.0,
  151. height: 44.0,
  152. ),
  153. SizedBox(
  154. width: 16.0,
  155. ),
  156. Expanded(
  157. child: Text(
  158. "回复我的",
  159. style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16),
  160. strutStyle: fixedLine,
  161. ),
  162. ),
  163. ValueListenableBuilder(
  164. valueListenable: GetIt.I<MessageModel>().notifierComment,
  165. builder: (BuildContext context, int value, Widget? child) => value == 0
  166. ? Container()
  167. : Container(
  168. width: 20,
  169. height: 20,
  170. decoration: BoxDecoration(shape: BoxShape.circle, color: Theme.of(context).accentColor),
  171. child: Center(
  172. child: Text(
  173. value > 99 ? "99+" : "$value",
  174. maxLines: 1,
  175. style: TextStyle(fontSize: 10, color: Colors.white),
  176. ),
  177. ),
  178. )),
  179. SizedBox(
  180. width: 8.0,
  181. ),
  182. arrowRight()
  183. ]),
  184. ))
  185. : index == 1
  186. ? InkWell(
  187. onTap: () async {
  188. await NavigatorUtil.go(context, "${Routes.socialMessageDetail}?data=like");
  189. GetIt.I<MessageModel>().getCount();
  190. },
  191. child: Padding(
  192. padding: const EdgeInsets.symmetric(vertical: 12.0),
  193. child: Row(children: <Widget>[
  194. Image.asset(
  195. "lib/assets/img/bbsmessage_icon_color_like.png",
  196. width: 44.0,
  197. height: 44.0,
  198. ),
  199. SizedBox(
  200. width: 16.0,
  201. ),
  202. Expanded(
  203. child: Text(
  204. "点赞",
  205. style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16),
  206. strutStyle: fixedLine,
  207. ),
  208. ),
  209. ValueListenableBuilder(
  210. valueListenable: GetIt.I<MessageModel>().notifierLike,
  211. builder: (BuildContext context, int value, Widget? child) => value == 0
  212. ? Container()
  213. : Container(
  214. width: 20,
  215. height: 20,
  216. decoration: BoxDecoration(shape: BoxShape.circle, color: Theme.of(context).accentColor),
  217. child: Center(
  218. child: Text(
  219. value > 99 ? "99+" : "$value",
  220. maxLines: 1,
  221. style: TextStyle(fontSize: 10, color: Colors.white),
  222. ),
  223. ),
  224. )),
  225. SizedBox(
  226. width: 8.0,
  227. ),
  228. arrowRight()
  229. ]),
  230. ))
  231. : Container(),
  232. separatorBuilder: (context, index) => Divider(
  233. height: 1,
  234. ),
  235. itemCount: 3,
  236. ),
  237. Container(
  238. key: const PageStorageKey<String>('Tab3'),
  239. child: FutureBuilder(
  240. future: _future,
  241. builder: (_, AsyncSnapshot<List<Notice>> snapshot) {
  242. if (snapshot.data == null) return RequestLoadingWidget();
  243. return ListView.separated(
  244. padding: EdgeInsets.symmetric(horizontal: 12.0),
  245. itemBuilder: (context, index) {
  246. if (index >= (snapshot.data?.length ?? 0)) return Container();
  247. var item = snapshot.data![index];
  248. return InkWell(
  249. onTap: () async {
  250. bool result = await NavigatorUtil.goPage(context, (context) => MessageNoticeDetailPage(item));
  251. if (result == true) {
  252. item.isRead = 1;
  253. }
  254. },
  255. child: Padding(
  256. padding: const EdgeInsets.symmetric(vertical: 12.0),
  257. child: Row(children: <Widget>[
  258. Image.asset(
  259. "lib/assets/img/bbsmessage_icon_color_${(item.type == "rank" || item.type == "receive") ? 'rank' : 'notice'}.png",
  260. width: 44.0,
  261. height: 44.0,
  262. ),
  263. SizedBox(
  264. width: 8.0,
  265. ),
  266. Expanded(
  267. child: Column(
  268. crossAxisAlignment: CrossAxisAlignment.start,
  269. children: <Widget>[
  270. Container(
  271. height: 18.0,
  272. child: Text(
  273. "${item.title}",
  274. style: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: 16),
  275. strutStyle: fixedLine,
  276. overflow: TextOverflow.ellipsis,
  277. ),
  278. ),
  279. SizedBox(
  280. height: 4,
  281. ),
  282. Text(
  283. "${item.content}",
  284. maxLines: 1,
  285. overflow: TextOverflow.ellipsis,
  286. style: Theme.of(context).textTheme.bodyText1!,
  287. )
  288. ],
  289. ),
  290. ),
  291. SizedBox(
  292. width: 8.0,
  293. ),
  294. arrowRight()
  295. ]),
  296. ),
  297. );
  298. },
  299. separatorBuilder: (context, index) => Divider(
  300. height: 1,
  301. ),
  302. itemCount: snapshot.data?.length ?? 0 + 1,
  303. );
  304. },
  305. ),
  306. )
  307. ])),
  308. );
  309. }
  310. }