msg_page.dart 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. import 'dart:convert';
  2. import 'package:bbyyy/beans/message_bean_entity.dart';
  3. import 'package:bbyyy/beans/my_shop_bean_entity.dart';
  4. import 'package:bbyyy/beans/system_information_bean_entity.dart';
  5. import 'package:bbyyy/beans/table_bean_entity.dart';
  6. import 'package:bbyyy/https/url.dart';
  7. import 'package:bbyyy/msgDB/my_msg_db.dart';
  8. import 'package:bbyyy/msgDB/sql_manager.dart';
  9. import 'package:bbyyy/my_tools/const.dart';
  10. import 'package:bbyyy/my_tools/event_bus.dart';
  11. import 'package:bbyyy/my_tools/my_colors.dart';
  12. import 'package:bbyyy/my_tools/my_cookie.dart';
  13. import 'package:bbyyy/my_tools/my_tools.dart';
  14. import 'package:bbyyy/my_tools/my_views.dart';
  15. import 'package:bbyyy/paegs/chat_page/chat_page.dart';
  16. import 'package:bbyyy/paegs/system_information_page/system_information_page.dart';
  17. import 'package:flutter/cupertino.dart';
  18. import 'package:flutter/material.dart';
  19. import 'package:flutter_slidable/flutter_slidable.dart';
  20. import 'package:flutter_svg/svg.dart';
  21. import 'package:pull_to_refresh/pull_to_refresh.dart';
  22. class MsgPage extends StatefulWidget {
  23. @override
  24. _MsgPageState createState() => _MsgPageState();
  25. }
  26. class _MsgPageState extends State<MsgPage> with AutomaticKeepAliveClientMixin {
  27. var types = ['商品', '对象'];
  28. List<DropdownMenuItem<String>> sortItems = [];
  29. int typeIndex = 0;
  30. bool showInput = false;
  31. TextEditingController _description = TextEditingController();
  32. FocusNode _descriptionFocus = FocusNode();
  33. RefreshController controller = RefreshController(initialRefresh: true);
  34. bool haveSysMsg = false;
  35. var sysMsgRead = false;
  36. String systemInformation;
  37. @override
  38. void initState() {
  39. // TODO: implement initState
  40. super.initState();
  41. types.forEach((element) {
  42. sortItems.add(DropdownMenuItem(
  43. child: Text(
  44. element,
  45. style: TextStyle(color: MyColors.c666666, fontSize: 14),
  46. ),
  47. value: element,
  48. ));
  49. });
  50. _descriptionFocus.addListener(() {
  51. if (_descriptionFocus.hasFocus) {
  52. } else {
  53. if (_description.text.isEmpty) {
  54. setState(() {
  55. showInput = false;
  56. });
  57. }
  58. }
  59. });
  60. EventBus().on('hasNewMsgInMsgPage', (arg) {
  61. queryChatRoom();
  62. });
  63. EventBus().on('haveSysMsg', (arg) {
  64. haveSysMsg = true;
  65. setState(() {});
  66. });
  67. }
  68. @override
  69. void dispose() {
  70. // TODO: implement dispose
  71. super.dispose();
  72. EventBus().off('hasNewMsgInMsgPage');
  73. EventBus().off('haveSysMsg');
  74. }
  75. @override
  76. Widget build(BuildContext context) {
  77. return GestureDetector(
  78. onTap: () {
  79. MyTools().hideKeyboard(context);
  80. },
  81. behavior: HitTestBehavior.translucent,
  82. child: Scaffold(
  83. body: Stack(
  84. children: [
  85. Container(
  86. decoration: BoxDecoration(
  87. gradient: LinearGradient(
  88. colors: MyColors.lg,
  89. ),
  90. ),
  91. height: 152,
  92. // child: SafeArea(
  93. // child: Container(
  94. // decoration: BoxDecoration(
  95. // color: Colors.white,
  96. // borderRadius: BorderRadius.all(
  97. // Radius.circular(17),
  98. // ),
  99. // ),
  100. // height: 34,
  101. // child: Row(
  102. // children: [
  103. // DropdownButtonHideUnderline(
  104. // child: DropdownButton(
  105. // items: sortItems,
  106. // onChanged: (v) {
  107. // setState(() {
  108. // typeIndex = types.indexOf(v);
  109. // });
  110. // },
  111. // value: types[typeIndex],
  112. // ),
  113. // ),
  114. // Container(
  115. // height: 13,
  116. // width: 1,
  117. // decoration: BoxDecoration(
  118. // borderRadius: BorderRadius.all(
  119. // Radius.circular(0.5),
  120. // ),
  121. // color: MyColors.c979797),
  122. // ),
  123. // Expanded(
  124. // child: showInput
  125. // ? TextField(
  126. // controller: _description,
  127. // focusNode: _descriptionFocus,
  128. // cursorColor: MyColors.cFF4233,
  129. // cursorWidth: 1.0,
  130. // decoration: InputDecoration(
  131. // border: InputBorder.none,
  132. // disabledBorder: InputBorder.none,
  133. // enabledBorder: InputBorder.none,
  134. // focusedBorder: InputBorder.none,
  135. // isDense: true,
  136. // hintText: '请输入描述',
  137. // hintStyle: TextStyle(
  138. // color: MyColors.c999999, fontSize: 14),
  139. // contentPadding: const EdgeInsets.fromLTRB(
  140. // 14, 4.5, 8, 4.5),
  141. // ),
  142. // maxLines: 1,
  143. // style: TextStyle(
  144. // color: MyColors.c333333,
  145. // fontSize: 14,
  146. // height: 1.3,
  147. // letterSpacing: 0.2),
  148. // keyboardType: TextInputType.text,
  149. // onChanged: (t) {},
  150. // )
  151. // : GestureDetector(
  152. // onTap: () {
  153. // setState(() {
  154. // showInput = true;
  155. // });
  156. // Timer(Duration(milliseconds: 100), () {
  157. // FocusScope.of(context)
  158. // .requestFocus(_descriptionFocus);
  159. // });
  160. // },
  161. // behavior: HitTestBehavior.translucent,
  162. // child: Row(
  163. // children: [
  164. // Container(
  165. // child:
  166. // SvgPicture.asset('images/svg/搜索.svg'),
  167. // margin: EdgeInsets.only(right: 5),
  168. // ),
  169. // Text(
  170. // '请输入',
  171. // style: TextStyle(
  172. // color: MyColors.cBFBFBF,
  173. // fontSize: 14),
  174. // )
  175. // ],
  176. // mainAxisAlignment: MainAxisAlignment.center,
  177. // ),
  178. // ),
  179. // ),
  180. // Container(
  181. // decoration: BoxDecoration(
  182. // color: MyColors.cFF4233,
  183. // borderRadius: BorderRadius.all(
  184. // Radius.circular(17),
  185. // ),
  186. // ),
  187. // height: 34,
  188. // width: 76,
  189. // child: Text(
  190. // '搜索',
  191. // style: TextStyle(color: Colors.white, fontSize: 14),
  192. // ),
  193. // alignment: Alignment.center,
  194. // padding: EdgeInsets.only(bottom: 2),
  195. // )
  196. // ],
  197. // ),
  198. // margin: EdgeInsets.only(
  199. // left: 15,
  200. // right: 15,
  201. // top: 72 - MediaQuery.of(context).padding.top),
  202. // padding: EdgeInsets.only(left: 16),
  203. // ),
  204. // ),
  205. child: SafeArea(
  206. bottom: false,
  207. child: Stack(
  208. children: [
  209. Container(
  210. height: 50,
  211. child: Text(
  212. '消息',
  213. style: TextStyle(color: Colors.white, fontSize: 16),
  214. ),
  215. alignment: Alignment.center,
  216. ),
  217. ],
  218. alignment: Alignment.topCenter,
  219. ),
  220. ),
  221. alignment: Alignment.topCenter,
  222. ),
  223. Container(
  224. decoration: BoxDecoration(
  225. color: Colors.white,
  226. borderRadius: BorderRadius.only(
  227. topLeft: Radius.circular(16),
  228. topRight: Radius.circular(16),
  229. ),
  230. ),
  231. margin:
  232. EdgeInsets.only(top: MediaQuery.of(context).padding.top + 50),
  233. child: SmartRefresher(
  234. onRefresh: onRefresh,
  235. controller: controller,
  236. child: lastMsg.length == 0 && !haveSysMsg
  237. ? SingleChildScrollView(child: noData())
  238. : ListView.builder(
  239. itemBuilder: (c, index) {
  240. // if (index == 0) {
  241. // return msgItems(null);
  242. // } else {
  243. return msgItems(lastMsg[index]);
  244. // }
  245. },
  246. itemCount: lastMsg.length,
  247. padding: EdgeInsets.only(bottom: 65),
  248. ),
  249. ),
  250. )
  251. ],
  252. ),
  253. ),
  254. );
  255. }
  256. @override
  257. // TODO: implement wantKeepAlive
  258. bool get wantKeepAlive => true;
  259. Widget msgItems(MessageBeanContent data) {
  260. String pic;
  261. String name;
  262. int uid;
  263. MyShopBeanDataData chatWith = MyShopBeanDataData();
  264. if (data.senderUid == MyCookie().getUID()) {
  265. pic = data.receiverPic;
  266. name = data.receiverName;
  267. uid = data.receiverUid;
  268. chatWith.userName = data.receiverName;
  269. chatWith.userUid = data.receiverUid;
  270. chatWith.userPic = data.receiverPic;
  271. } else {
  272. pic = data.senderPic;
  273. name = data.senderName;
  274. uid = data.senderUid;
  275. chatWith.userName = data.senderName;
  276. chatWith.userUid = data.senderUid;
  277. chatWith.userPic = data.senderPic;
  278. }
  279. if (data.senderUid == -1) {
  280. return Slidable(
  281. actionPane: SlidableDrawerActionPane(),
  282. actionExtentRatio: 0.25,
  283. child: GestureDetector(
  284. onTap: () {
  285. MyTools().toPage(context, SystemInformationPage(), (then) {});
  286. },
  287. behavior: HitTestBehavior.translucent,
  288. child: Container(
  289. height: 73,
  290. child: Column(
  291. children: [
  292. Expanded(
  293. child: Row(
  294. children: [
  295. Container(
  296. margin: EdgeInsets.only(left: 14, right: 14),
  297. child: ClipRRect(
  298. child: SvgPicture.asset(
  299. 'images/svg/平台助手.svg',
  300. height: 45,
  301. width: 45,
  302. ),
  303. borderRadius: BorderRadius.all(Radius.circular(4)),
  304. ),
  305. ),
  306. Expanded(
  307. child: Container(
  308. height: 45,
  309. padding: EdgeInsets.only(right: 14),
  310. child: Column(
  311. children: [
  312. Row(
  313. children: [
  314. Expanded(
  315. child: Text(
  316. '系统消息',
  317. style: TextStyle(
  318. color: MyColors.c333333,
  319. fontSize: 15),
  320. ),
  321. ),
  322. Text(
  323. '',
  324. style: TextStyle(
  325. color: MyColors.c888888, fontSize: 12),
  326. ),
  327. ],
  328. ),
  329. Row(
  330. children: [
  331. Expanded(
  332. child: Text(
  333. data.content,
  334. style: TextStyle(
  335. color: MyColors.c888888,
  336. fontSize: 12),
  337. maxLines: 1,
  338. overflow: TextOverflow.ellipsis,
  339. softWrap: true,
  340. ),
  341. ),
  342. ],
  343. )
  344. ],
  345. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  346. ),
  347. ),
  348. )
  349. ],
  350. ),
  351. ),
  352. Container(
  353. margin: EdgeInsets.only(left: 73, right: 14),
  354. height: 0.5,
  355. color: MyColors.cE7E7E7,
  356. )
  357. ],
  358. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  359. ),
  360. ),
  361. ),
  362. secondaryActions: <Widget>[
  363. SlideAction(
  364. child: Container(
  365. child: Container(
  366. decoration: BoxDecoration(
  367. borderRadius: BorderRadius.circular(30),
  368. color: MyColors.cFF4233,
  369. ),
  370. height: 40,
  371. width: 40,
  372. child: SvgPicture.asset(
  373. 'images/svg/del.svg',
  374. height: 25,
  375. width: 25,
  376. ),
  377. alignment: Alignment.center,
  378. ),
  379. ),
  380. onTap: () {
  381. showSimpleDialog('是否删除系统消息', context, () async {
  382. Navigator.pop(context);
  383. MyCookie().prefs.remove('${MyCookie().getUID()}系统消息');
  384. chatRoom.remove('系统消息');
  385. lastMsg.remove(data);
  386. setState(() {});
  387. queryChatRoom();
  388. });
  389. },
  390. )
  391. ],
  392. );
  393. } else {
  394. return Slidable(
  395. actionPane: SlidableDrawerActionPane(),
  396. actionExtentRatio: 0.25,
  397. child: GestureDetector(
  398. onTap: () {
  399. MyTools().toPage(context, ChatPage(chatWith, null), (then) {
  400. var now = new DateTime.now();
  401. MyCookie().prefs.setString(
  402. '${MyCookie().getUID()}_${chatWith.userUid}',
  403. now.toString().substring(0, 19));
  404. queryChatRoom();
  405. });
  406. },
  407. behavior: HitTestBehavior.translucent,
  408. child: Container(
  409. height: 73,
  410. child: Column(
  411. children: [
  412. Expanded(
  413. child: Row(
  414. children: [
  415. Container(
  416. margin: EdgeInsets.only(left: 14, right: 14),
  417. child: ClipRRect(
  418. child: uid == 0
  419. ? Image.asset(
  420. 'images/app_logo.png',
  421. height: 45,
  422. width: 45,
  423. )
  424. : MyViews().netImg(imgURL(pic), 45, 45,
  425. placeholder: 'images/svg/占位图.svg'),
  426. borderRadius: BorderRadius.all(Radius.circular(4)),
  427. ),
  428. ),
  429. Expanded(
  430. child: Container(
  431. height: 45,
  432. padding: EdgeInsets.only(right: 14),
  433. child: Column(
  434. children: [
  435. Row(
  436. children: [
  437. Expanded(
  438. child: Text(
  439. uid == 0 ? '客服' : name,
  440. style: TextStyle(
  441. color: MyColors.c333333, fontSize: 15),
  442. )),
  443. Text(
  444. data.sentAt,
  445. style: TextStyle(
  446. color: MyColors.c888888, fontSize: 12),
  447. ),
  448. ],
  449. ),
  450. Row(
  451. children: [
  452. Expanded(
  453. child: Text(
  454. data.type != chatMsgTypeText
  455. ? '[${data.type}]'
  456. : data.content,
  457. style: TextStyle(
  458. color: MyColors.c888888,
  459. fontSize: 12),
  460. maxLines: 1,
  461. overflow: TextOverflow.ellipsis,
  462. softWrap: true,
  463. ),
  464. ),
  465. Visibility(
  466. visible: showRedPoint(
  467. chatWith.userUid, data.sentAt),
  468. child: Container(
  469. decoration: BoxDecoration(
  470. color: MyColors.cFF4233,
  471. borderRadius: BorderRadius.all(
  472. Radius.circular(4))),
  473. height: 8,
  474. width: 8,
  475. padding:
  476. EdgeInsets.only(left: 5, right: 5),
  477. alignment: Alignment.center,
  478. ),
  479. )
  480. ],
  481. )
  482. ],
  483. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  484. ),
  485. ),
  486. )
  487. ],
  488. ),
  489. ),
  490. Container(
  491. margin: EdgeInsets.only(left: 73, right: 14),
  492. height: 0.5,
  493. color: MyColors.cE7E7E7,
  494. )
  495. ],
  496. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  497. ),
  498. ),
  499. ),
  500. secondaryActions: <Widget>[
  501. SlideAction(
  502. child: Container(
  503. child: Container(
  504. decoration: BoxDecoration(
  505. borderRadius: BorderRadius.circular(30),
  506. color: MyColors.cFF4233,
  507. ),
  508. height: 40,
  509. width: 40,
  510. child: SvgPicture.asset(
  511. 'images/svg/del.svg',
  512. height: 25,
  513. width: 25,
  514. ),
  515. alignment: Alignment.center,
  516. ),
  517. ),
  518. onTap: () {
  519. showSimpleDialog(
  520. '将删除与(${name.isEmpty ? '客服' : name})的聊天记录,确认删除?', context,
  521. () async {
  522. Navigator.pop(context);
  523. MsgDB msgDB = MsgDB('table${MyCookie().getUID()}_$uid');
  524. await msgDB.deleteTableData();
  525. chatRoom.remove(uid);
  526. lastMsg.remove(data);
  527. setState(() {});
  528. queryChatRoom();
  529. });
  530. },
  531. )
  532. ],
  533. );
  534. }
  535. // }
  536. }
  537. Map chatRoom = Map();
  538. List<MessageBeanContent> lastMsg = [];
  539. queryChatRoom() async {
  540. List<Map<String, dynamic>> map = await SqlManager.allTables();
  541. map.forEach((element) async {
  542. TableBeanEntity table =
  543. TableBeanEntity().fromJson(json.decode(json.encode(element)));
  544. if (table.name.contains('table${MyCookie().getUID()}_')) {
  545. MsgDB msgDB = MsgDB(table.name);
  546. List<Map<String, dynamic>> maps = await msgDB.queryTableData(1, 1);
  547. maps.forEach((element) {
  548. print(json.encode(element));
  549. MessageBeanContent msg =
  550. MessageBeanContent().fromJson(json.decode(json.encode(element)));
  551. if (msg.senderUid == MyCookie().getUID()) {
  552. print(msg.receiverUid);
  553. chatRoom[msg.receiverUid] = msg;
  554. } else {
  555. print(msg.senderUid);
  556. chatRoom[msg.senderUid] = msg;
  557. }
  558. lastMsg.clear();
  559. chatRoom.forEach((key, value) {
  560. lastMsg.add(value);
  561. });
  562. lastMsg.sort((left, right) {
  563. if (left.senderUid == -1) {
  564. return -1;
  565. } else if (right.senderUid == -1) {
  566. return 1;
  567. } else {
  568. return right.sentAt.compareTo(left.sentAt);
  569. }
  570. });
  571. setState(() {});
  572. });
  573. }
  574. });
  575. systemInformation =
  576. MyCookie().prefs.getString('${MyCookie().getUID()}系统消息');
  577. if (systemInformation != null) {
  578. print(systemInformation);
  579. List sList = json.decode(systemInformation);
  580. SystemInformationBeanEntity entity = SystemInformationBeanEntity().fromJson(json.decode(json.encode(sList[0])));
  581. MessageBeanContent sysMsg = MessageBeanContent();
  582. sysMsg.senderName = '系统消息';
  583. sysMsg.senderUid = -1;
  584. sysMsg.content = entity.content.content;
  585. chatRoom['系统消息'] = sysMsg;
  586. if (!lastMsg.any((element) => element.senderUid == -1)) {
  587. lastMsg.insert(0, chatRoom['系统消息']);
  588. }
  589. }
  590. setState(() {
  591. });
  592. endRe(controller);
  593. }
  594. void onRefresh() {
  595. queryChatRoom();
  596. }
  597. showRedPoint(int userUid, String sentAt) {
  598. try {
  599. String lastTime =
  600. MyCookie().prefs.getString('${MyCookie().getUID()}_$userUid');
  601. print('--------------');
  602. print(lastTime);
  603. print(sentAt);
  604. print('--------------');
  605. return lastTime.compareTo(sentAt) == -1;
  606. } catch (e) {
  607. return true;
  608. }
  609. }
  610. }