message_list_subpage.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. import 'dart:async';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:provider/provider.dart';
  5. import 'package:sport/bean/message.dart';
  6. import 'package:sport/bean/user_info.dart';
  7. import 'package:sport/db/message_db.dart';
  8. import 'package:sport/pages/social/chat_page.dart';
  9. import 'package:sport/provider/message_model.dart';
  10. import 'package:sport/router/navigator_util.dart';
  11. import 'package:sport/services/api/inject_api.dart';
  12. import 'package:sport/services/userid.dart';
  13. import 'package:sport/utils/DateFormat.dart';
  14. import 'package:sport/utils/toast.dart';
  15. import 'package:sport/widgets/dialog/alert_dialog.dart';
  16. import 'package:sport/widgets/dialog/popupmenu.dart' as menu;
  17. import 'package:sport/widgets/error.dart';
  18. import 'package:sport/widgets/image.dart';
  19. import 'package:sport/widgets/loading.dart';
  20. class MessageListSubPage extends StatefulWidget {
  21. @override
  22. State<StatefulWidget> createState() {
  23. // TODO: implement createState
  24. return _MessageListSubPageState();
  25. }
  26. }
  27. class _MessageListSubPageState extends State<MessageListSubPage>
  28. with InjectApi, UserId, AutomaticKeepAliveClientMixin {
  29. List<MessageItem> messageList;
  30. StreamSubscription _streamSubscription;
  31. bool isLoading = true;
  32. @override
  33. // TODO: implement wantKeepAlive
  34. bool get wantKeepAlive => true;
  35. @override
  36. void initState() {
  37. // TODO: implement initState
  38. super.initState();
  39. getChatIndex().then((value) {
  40. setState(() {
  41. isLoading = false;
  42. messageList = value;
  43. });
  44. });
  45. initListen();
  46. }
  47. // MessageInstance 类型是 服务器请求回来的类型 MessageItem 是本地 存储后的类型...
  48. Future<List<MessageItem>> getChatIndex() async {
  49. // List<ChatMessageInstance> list = (await api.getChatIndex()).results;
  50. // var list = await MessageDB().getMessageList();
  51. messageList = [];
  52. var unReadList = await MessageDB().getMessageUnRead();
  53. // print("[unReadList]:$unReadList---------------------------------------");
  54. if (unReadList != null && unReadList.length > 0) {
  55. List<int> ids = [];
  56. for (var item in unReadList) {
  57. ids.add(MessageItem.fromJson(item).userId);
  58. }
  59. List<ChatOnlineInfo> chatInfo = (await api.getChatUserInfo(ids)).results;
  60. // 这不是是个骚的?
  61. for (int i = 0; i < unReadList.length; i++) {
  62. MessageItem item = MessageItem.fromJson(unReadList[i]);
  63. for (int j = 0; j < chatInfo.length; j++) {
  64. if (item.userId == chatInfo[j].userId) {
  65. if (item.message.fromUser.id == int.parse(selfId)) {
  66. item.message.toUser.online = chatInfo[i].online;
  67. } else {
  68. item.message.fromUser.online = chatInfo[i].online;
  69. }
  70. // print("[online:]${chatInfo[i].online}------------------------");
  71. item.message.relate = chatInfo[i].relate;
  72. item.unReadCount = unReadList[i]['cout'];
  73. item.isTop = unReadList[i]['isTop'];
  74. }
  75. }
  76. messageList.add(item);
  77. }
  78. }
  79. return messageList;
  80. }
  81. // 在本页中如果收到了就 ...
  82. initListen() {
  83. Stream<List<MessageInstance>> queryStream =
  84. Provider.of<MessageModel>(context, listen: false).queryStream;
  85. _streamSubscription = queryStream.listen((List<MessageInstance> list) {
  86. print("[receive:message]:$list-----------------------------");
  87. getChatIndex();
  88. });
  89. }
  90. void dispose() {
  91. super.dispose();
  92. _streamSubscription?.cancel();
  93. }
  94. Widget messageWidget(
  95. BuildContext context, api, id, online, avatar, name, messageList, index) {
  96. GlobalKey messageKey = new GlobalKey();
  97. return GestureDetector(
  98. behavior: HitTestBehavior.opaque,
  99. key: messageKey,
  100. onTap: () async {
  101. UserInfo info = (await api.getUserInfo("$id")).data;
  102. await NavigatorUtil.goPage(context, (context) => ChatPage(info));
  103. getChatIndex().then((value) {
  104. setState(() {
  105. isLoading = false;
  106. messageList = messageList;
  107. });
  108. }); // 原来是为了更新那个红点的...
  109. },
  110. onLongPressStart: (e) async {
  111. RenderBox renderBox = messageKey.currentContext.findRenderObject();
  112. var offset =
  113. renderBox.localToGlobal(Offset(0.0, renderBox.size.height));
  114. final RelativeRect position = RelativeRect.fromLTRB(
  115. e.globalPosition.dx, //取点击位置坐弹出x坐标
  116. offset.dy, //取text高度做弹出y坐标(这样弹出就不会遮挡文本)
  117. e.globalPosition.dx,
  118. offset.dy);
  119. PopupMenuEntry menuItem(
  120. {String imgUrl, String text, dynamic callBack}) =>
  121. menu.PopupMenuItem(
  122. value: callBack,
  123. child: Row(
  124. mainAxisSize: MainAxisSize.min,
  125. children: <Widget>[
  126. if (imgUrl != null)
  127. Image.asset(
  128. "lib/assets/img/$imgUrl",
  129. width: 24,
  130. ),
  131. SizedBox(
  132. width: 4,
  133. ),
  134. Text(
  135. text,
  136. )
  137. ],
  138. ),
  139. );
  140. var d = await showMenu(
  141. context: context,
  142. position: position,
  143. items: <PopupMenuEntry>[
  144. PopupMenuItem(
  145. child: Container(
  146. child: Column(
  147. children: <Widget>[
  148. menuItem(
  149. text: messageList[index].isTop == 1 ? "取消置顶" : "置顶",
  150. callBack: 1),
  151. menuItem(text: "删除聊天", callBack: 2)
  152. ],
  153. ),
  154. ))
  155. ],
  156. );
  157. if (d == 1) {
  158. // Navigator.of(context).pop(1);
  159. await MessageDB()
  160. .updateIsTop(id, messageList[index].isTop == 1 ? 0 : 1);
  161. ToastUtil.show("${messageList[index].isTop}");
  162. } else if (d == 2) {
  163. bool flag = await showDialog(
  164. context: context,
  165. builder: (context) => CustomAlertDialog(
  166. title: '是否删除聊天记录',
  167. ok: () => Navigator.of(context).pop(true)));
  168. if (flag) {
  169. await MessageDB().deleteUserIdMessage(id);
  170. getChatIndex();
  171. ToastUtil.show("删除成功");
  172. }
  173. }
  174. },
  175. child: Column(
  176. children: <Widget>[
  177. Padding(
  178. padding: const EdgeInsets.only(top: 12.0, bottom: 12.0),
  179. child: Row(
  180. children: <Widget>[
  181. !online
  182. ? ColorFiltered(
  183. colorFilter:
  184. ColorFilter.mode(Colors.white, BlendMode.color),
  185. child: CircleAvatar(
  186. backgroundImage: userAvatarProvider(avatar),
  187. radius: 22,
  188. ),
  189. )
  190. : CircleAvatar(
  191. backgroundImage: userAvatarProvider(avatar),
  192. radius: 22,
  193. ),
  194. SizedBox(
  195. width: 8,
  196. ),
  197. Expanded(
  198. flex: 3,
  199. child: Column(
  200. crossAxisAlignment: CrossAxisAlignment.start,
  201. mainAxisAlignment:MainAxisAlignment.center,
  202. children: <Widget>[
  203. Row(
  204. mainAxisAlignment: MainAxisAlignment.start,
  205. children: <Widget>[
  206. Flexible(
  207. child: Text(
  208. "$name",
  209. style: Theme.of(context)
  210. .textTheme
  211. .headline3
  212. .copyWith(fontWeight: FontWeight.normal),
  213. maxLines: 1,
  214. overflow: TextOverflow.ellipsis,
  215. strutStyle: StrutStyle(forceStrutHeight: true),
  216. ),
  217. ),
  218. SizedBox(
  219. width: 4.0,
  220. ),
  221. messageList[index].message.relate != 'friends'
  222. ?
  223. // Container(
  224. // padding:
  225. // EdgeInsets.symmetric(horizontal: 5.0),
  226. // decoration: BoxDecoration(
  227. // border: Border.all(
  228. // color: Color(0xffffc400)),
  229. // borderRadius: BorderRadius.all(
  230. // Radius.circular(8.0))),
  231. // child: Text(
  232. // "未关注",
  233. // style: Theme.of(context)
  234. // .textTheme
  235. // .bodyText1
  236. // .copyWith(color: Color(0xffffc400),fontSize: 11.0),
  237. // ))
  238. Image.asset("lib/assets/img/untrace.png",width: 44.0,height: 22.0,)
  239. : Container()
  240. ],
  241. ),
  242. SizedBox(
  243. height: 4,
  244. ),
  245. if (messageList[index].message.type == "text")
  246. Text(
  247. "${messageList[index].message.data.text}",
  248. style: Theme.of(context).textTheme.bodyText1,
  249. maxLines: 1,
  250. overflow: TextOverflow.ellipsis,
  251. ),
  252. if (messageList[index].message.type ==
  253. "forum-forward")
  254. Text(
  255. "${messageList[index].message.data.subject.content}",
  256. style: Theme.of(context).textTheme.bodyText1,
  257. maxLines: 1,
  258. overflow: TextOverflow.ellipsis,
  259. ),
  260. if (messageList[index].message.type == "image")
  261. Text(
  262. "分享图片",
  263. style: Theme.of(context).textTheme.bodyText1,
  264. maxLines: 1,
  265. overflow: TextOverflow.ellipsis,
  266. ),
  267. if (messageList[index].message.type == "share")
  268. Text(
  269. "分享链接",
  270. style: Theme.of(context).textTheme.bodyText1,
  271. maxLines: 1,
  272. overflow: TextOverflow.ellipsis,
  273. )
  274. ],
  275. ),
  276. ),
  277. SizedBox(
  278. width: 8,
  279. ),
  280. Expanded(
  281. flex: 1,
  282. child: Column(
  283. crossAxisAlignment: CrossAxisAlignment.end,
  284. mainAxisAlignment: MainAxisAlignment.center,
  285. children: <Widget>[
  286. Text(
  287. "${DateFormat.format(DateTime.parse(messageList[index].message.createdAt))}",
  288. style: Theme.of(context).textTheme.bodyText1,
  289. ),
  290. SizedBox(
  291. height: 3,
  292. ),
  293. if (messageList[index].unReadCount > 0)
  294. ClipOval(
  295. child: Container(
  296. width: 21.0,
  297. height: 21.0,
  298. color: Color(0xffff5B1D),
  299. child: Center(
  300. child: Text(
  301. '${messageList[index].unReadCount}',
  302. style: TextStyle(
  303. color: Colors.white, fontSize: 12.0),
  304. ),
  305. ),
  306. ))
  307. ],
  308. ),
  309. )
  310. ],
  311. )),
  312. Divider(height: 1,)
  313. ],
  314. ),
  315. );
  316. }
  317. @override
  318. Widget build(BuildContext context) {
  319. super.build(context);
  320. if (isLoading)
  321. return LoadingWidget(
  322. child: Text("loading"),
  323. );
  324. // TODO: implement build
  325. return messageList.length <= 0
  326. ? Center(
  327. child: RequestErrorWidget(
  328. null,
  329. msg: "暂无消息",
  330. assets: RequestErrorWidget.ASSETS_NO_COMMENT,
  331. ),
  332. )
  333. : ListView.builder(
  334. padding: EdgeInsets.symmetric(horizontal: 12.0),
  335. // separatorBuilder: (context, index) => Divider(
  336. // height: 1,
  337. // ),
  338. itemCount: messageList?.length ?? 0,
  339. itemBuilder: (context, index) {
  340. // 这里可能有得后续看看怎么写比较好 ... 判断是否是自己 ...
  341. // 这里拿的时候得判断一手 是自己还是别人发的...
  342. int id;
  343. String name;
  344. String avatar;
  345. bool online;
  346. if (messageList[index].message.fromUser.id == int.parse(selfId)) {
  347. id = messageList[index].message.toUser.id;
  348. name = messageList[index].message.toUser.name;
  349. avatar = messageList[index].message.toUser.avatar;
  350. online = messageList[index].message.toUser.online;
  351. } else {
  352. id = messageList[index].message.fromUser.id;
  353. name = messageList[index].message.fromUser.name;
  354. avatar = messageList[index].message.fromUser.avatar;
  355. online = messageList[index].message.fromUser.online;
  356. }
  357. return messageWidget(
  358. context, api, id, online, avatar, name, messageList, index);
  359. });
  360. }
  361. }