Hibok
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

918 righe
29 KiB

  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:chat/data/translate_hk_data_mgr.dart';
  4. import 'package:chat/home/audio_chat_view.dart';
  5. import 'package:chat/home/coin_anim.dart';
  6. import 'package:chat/utils/screen.dart';
  7. import 'package:chat/utils/upload_util.dart';
  8. import 'package:fixnum/fixnum.dart';
  9. import 'package:cached_network_image/cached_network_image.dart';
  10. import 'package:chat/chat/translate_state.dart';
  11. import 'package:chat/data/UserData.dart';
  12. import 'package:chat/data/chat_data_mgr.dart';
  13. import 'package:chat/data/constants.dart';
  14. import 'package:chat/generated/i18n.dart';
  15. import 'package:chat/home/add_friend.dart';
  16. import 'package:chat/models/ChatMsg.dart';
  17. import 'package:chat/models/UserInfo.dart';
  18. import 'package:chat/models/keyboard_provider.dart';
  19. import 'package:chat/models/ref_name_provider.dart';
  20. import 'package:chat/models/voucher_change.dart';
  21. import 'package:chat/proto/all.pbserver.dart';
  22. import 'package:chat/utils/CustomUI.dart';
  23. import 'package:chat/utils/HttpUtil.dart';
  24. import 'package:chat/utils/MessageMgr.dart';
  25. import 'package:chat/utils/TokenMgr.dart';
  26. import 'package:chat/utils/analyze_utils.dart';
  27. import 'package:chat/utils/app_navigator.dart';
  28. import 'package:chat/utils/blacklist_mgr.dart';
  29. import 'package:chat/utils/count_down_button.dart';
  30. import 'package:chat/utils/friend_list_mgr.dart';
  31. import 'package:chat/utils/msgHandler.dart';
  32. import 'package:chat/utils/net_state_widget.dart';
  33. import 'package:chat/utils/sound_util.dart';
  34. import 'package:chat/utils/sp_utils.dart';
  35. import 'package:chat/utils/sql_util.dart';
  36. import 'package:dio/dio.dart';
  37. import 'package:extended_text/extended_text.dart';
  38. import 'package:flutter/cupertino.dart';
  39. import 'package:flutter/material.dart';
  40. import 'package:oktoast/oktoast.dart';
  41. import 'package:permission_handler/permission_handler.dart';
  42. import 'package:provider/provider.dart';
  43. import 'package:scroll_to_index/scroll_to_index.dart';
  44. //import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
  45. import '../r.dart';
  46. import 'ChatPageItem.dart';
  47. import 'input_bar.dart';
  48. import 'package:chat/utils/PopUpMenu.dart' as myPop;
  49. import 'package:chat/models/money_change.dart';
  50. class ChatPage extends StatefulWidget {
  51. static bool isChatPageActive = false;
  52. final int friendId;
  53. final int enterType; // 0默认 1图片
  54. final dynamic enterContent;
  55. final bool isTranslateButler;
  56. ChatPage(
  57. {Key key,
  58. this.friendId,
  59. this.enterType = 0,
  60. this.enterContent,
  61. this.isTranslateButler = false})
  62. : super(key: key);
  63. _ChatPageState createState() => _ChatPageState();
  64. }
  65. class _ChatPageState extends State<ChatPage> {
  66. MessageMgr msgMgr = MessageMgr();
  67. UserInfo friendInfo;
  68. List<MsgModel> msgList;
  69. KeyboardIndexProvider _keyboardIndexProvider = KeyboardIndexProvider();
  70. TextEditingController nickNameController = new TextEditingController();
  71. //统计聊天时长
  72. int startTime;
  73. bool isTranslateButler;
  74. bool isTranslateButlerFinish = false;
  75. ///翻译管家是否已经结束
  76. int jumpTime;
  77. AutoScrollController controller;
  78. bool hasChatPermission = false;
  79. bool isPlayCoinAnim = false;
  80. @override
  81. void dispose() {
  82. var endTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
  83. AnalyzeUtils.commitChatDuration(startTime, endTime);
  84. MessageMgr().off('Send CoinBag', _sendCoin);
  85. msgMgr.off('New Chat Message', receiveMsg);
  86. msgMgr.off('Keyboard Hide', dealWithKeyboardHide);
  87. msgMgr.off('Delete Select Message', _deleteItem);
  88. msgMgr.off(MessageMgr.TRANSLATE_HK_END_CHAT, translateHKChatEnd);
  89. msgMgr.off('Jump to Msg', jumpToMsg);
  90. MsgHandler.curActiveSession = 0;
  91. SoundUtils().stop();
  92. nickNameController.dispose();
  93. super.dispose();
  94. ChatPage.isChatPageActive = false;
  95. }
  96. jumpToMsg(time) async {
  97. hideKeyBoard();
  98. int jumIndex = 0;
  99. jumpTime = time;
  100. for (int i = 0; i < msgList.length; i++) {
  101. if (time == msgList[i].time) {
  102. jumIndex = i;
  103. break;
  104. }
  105. }
  106. if (jumIndex < 0) {
  107. jumIndex = 0;
  108. }
  109. if (jumIndex > msgList.length - 1) {
  110. jumIndex = msgList.length - 1;
  111. }
  112. await controller.scrollToIndex(jumIndex,
  113. preferPosition: AutoScrollPosition.middle);
  114. controller.highlight(jumIndex,
  115. highlightDuration: new Duration(milliseconds: 100));
  116. }
  117. @override
  118. void initState() {
  119. super.initState();
  120. print('init chatpage');
  121. ChatPage.isChatPageActive = true;
  122. getDefaultSetting();
  123. getUserInfo();
  124. controller = AutoScrollController(
  125. viewportBoundaryGetter: () =>
  126. Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
  127. axis: Axis.vertical);
  128. isTranslateButler = widget.isTranslateButler;
  129. ///todo 这里再判断是否还在服务时间
  130. startTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
  131. msgList = ChatDataMgr().getRecord();
  132. msgMgr.on('New Chat Message', receiveMsg);
  133. msgMgr.on('Keyboard Hide', dealWithKeyboardHide);
  134. msgMgr.on('Send CoinBag', _sendCoin);
  135. msgMgr.on('Delete Select Message', _deleteItem);
  136. msgMgr.on(MessageMgr.TRANSLATE_HK_END_CHAT, translateHKChatEnd);
  137. msgMgr.on('Jump to Msg', jumpToMsg);
  138. WidgetsBinding.instance.addPostFrameCallback((_) {
  139. checkPermission();
  140. });
  141. }
  142. checkPermission() async {
  143. if (isTranslateButler) {
  144. if (await CustomUI.showPermissionSetting(context,
  145. PermissionGroup.microphone, I18n.of(context).video_permission)) {
  146. setState(() {
  147. hasChatPermission = true;
  148. dx = Screen.width - zoomButtonSizeWidth;
  149. dy = (Screen.height - zoomButtonSizeHeight) / 2;
  150. });
  151. } else {
  152. hasChatPermission = false;
  153. showToast(I18n.of(context).need_record);
  154. }
  155. }
  156. }
  157. translateHKChatEnd(args) {
  158. setState(() {
  159. isShowZoomButton = false;
  160. isTranslateButlerFinish = true;
  161. TranslateHKMgr().order = null;
  162. });
  163. if (!UserData().isTranslateUser) {
  164. var cancle = InkWell(
  165. onTap: () {
  166. Navigator.pop(context);
  167. },
  168. child: Container(
  169. decoration: BoxDecoration(
  170. color: const Color(0XFFC7E5FF),
  171. borderRadius: BorderRadius.all(
  172. Radius.circular(Constants.LittleButtonRadius))),
  173. margin: EdgeInsets.only(top: 0, bottom: 18.5),
  174. height: 37.5,
  175. width: 200,
  176. alignment: Alignment.center,
  177. child: CountDownButton(
  178. I18n.of(context).cancel,
  179. () {
  180. Navigator.of(context).pop();
  181. },
  182. isOnlyRichText: true,
  183. countDownTime: 10,
  184. )),
  185. );
  186. CustomUI.buildTowConfirmWithCountDown(context, '是否再来一单', '是的', () {
  187. MsgHandler.sendAnotherOrderReq();
  188. Navigator.of(context).pop();
  189. }, cancle);
  190. }
  191. }
  192. void _sendFile(File file) async {
  193. // File file = await FilePicker.getFile();
  194. int fileSize = file.lengthSync();
  195. print('选择的文件 ${file.path} 大小 $fileSize');
  196. if (fileSize > 33 * 1024 * 1024) {
  197. showToast(I18n.of(context).max_file.replaceFirst('/s1', 33.toString()));
  198. return;
  199. }
  200. var fileName = file.path.split('/').last;
  201. print('fileName $fileName');
  202. var ext = '';
  203. var extList = fileName.split('.');
  204. if (extList.length > 1) {
  205. ext = extList.last;
  206. }
  207. print('ext $ext');
  208. var fileMsg = FileChat.create();
  209. fileMsg.type = ext;
  210. fileMsg.size = fileSize;
  211. fileMsg.name = fileName;
  212. var msg = MsgHandler.createSendMsg(
  213. ChatType.FileChatType, fileMsg.writeToBuffer(),
  214. friendId: widget.friendId,
  215. localFile: file.path,
  216. channelType: ChatChannelType.Session);
  217. sendMsg(msg);
  218. }
  219. _sendCoin(args) async {
  220. var res = await _checkCoinBeforeSend(args['amount']);
  221. if (res != null) {
  222. args['redNo'] = res['redNo'];
  223. args['friendId'] = widget.friendId;
  224. var msg = MsgHandler.createCoinBagMsg(args);
  225. sendMsg(msg);
  226. }
  227. }
  228. //校验
  229. _checkCoinBeforeSend(int amount) async {
  230. Map data = {
  231. "userId": UserData().basicInfo.userId,
  232. "rUserId": friendInfo.userId,
  233. "price": amount,
  234. };
  235. data['sign'] = TokenMgr().getSign(data);
  236. Response res = await HttpUtil().post('red/packet/send', data: data);
  237. if (res == null) {
  238. return null;
  239. }
  240. Map resData = res.data;
  241. if (resData['code'] == 0) {
  242. print(resData['data']);
  243. return resData['data'];
  244. }
  245. return null;
  246. }
  247. void getDefaultSetting() async {
  248. bool soundPlayMode =
  249. (await SPUtils.getBool(Constants.SOUND_PLAY_MODE)) ?? false;
  250. _keyboardIndexProvider.init(soundPlayMode);
  251. }
  252. dealWithKeyboardHide(args) {
  253. if (_keyboardIndexProvider.curKeyboardIndex == 0) {
  254. hideKeyBoard();
  255. }
  256. }
  257. getUserInfo() async {
  258. //先从本地获取用户信息
  259. friendInfo = await HttpUtil().getFriendInfo(widget.friendId, true);
  260. //如果是新的聊天,向服务器发送创建会话消息
  261. if (msgList.length == 0) {
  262. MsgHandler.getActiveSesstion(
  263. [friendInfo.userId, UserData().basicInfo.userId]);
  264. }
  265. if (mounted) {
  266. setState(() {});
  267. }
  268. WidgetsBinding.instance.addPostFrameCallback((_) {
  269. if (widget.enterType == 1) {
  270. print('接收到的:${widget.enterContent}');
  271. _sendFile(File(widget.enterContent));
  272. } else if (widget.enterType == 2 || widget.enterType == 3) {
  273. //转发消息
  274. MsgModel originMsg = widget.enterContent;
  275. MsgModel msg = MsgHandler.createSendMsg(
  276. ChatType.valueOf(originMsg.msgType), originMsg.msgContent);
  277. msg.extraInfo = originMsg.extraInfo;
  278. if (originMsg.extraFile == null ||
  279. originMsg.extraFile.contains('http')) {
  280. msg.extraFile = originMsg.extraFile;
  281. } else {
  282. msg.extraFile = UploadUtil().getFullUrl(
  283. originMsg.extraFile, originMsg.sessionId, originMsg.channelType);
  284. }
  285. msg.localFile = originMsg.localFile;
  286. msg.friendId = widget.friendId;
  287. if (msg.localFile != null) {
  288. msg.state = MsgState.Uploaded;
  289. }
  290. sendMsg(msg);
  291. }
  292. });
  293. }
  294. @override
  295. Widget build(BuildContext context) {
  296. print('build chatpage');
  297. if (friendInfo == null) {
  298. return Scaffold(
  299. backgroundColor: const Color(0xFFE2E9F1),
  300. body: SafeArea(
  301. child: Center(
  302. child: CircularProgressIndicator(),
  303. ),
  304. ),
  305. );
  306. }
  307. List<Widget> actions = [];
  308. int voucher = Provider.of<VoucherChangeProvider>(context).voucher;
  309. actions.add(Row(
  310. children: <Widget>[
  311. CustomUI.buildImageLabel("assets/images/voucher.png", voucher,
  312. imgOpc: 0.5, imgHeight: 13),
  313. Stack(alignment: Alignment.centerLeft, children: <Widget>[
  314. CustomUI.buildImageLabel(R.assetsImagesCoin,
  315. Provider.of<MoneyChangeProvider>(context).money,
  316. isLeft: false, isPlayAnim: isPlayCoinAnim),
  317. isPlayCoinAnim
  318. ? CoinAnim(
  319. animFinishCallback: () {
  320. setState(() {
  321. isPlayCoinAnim = false;
  322. });
  323. },
  324. )
  325. : Text('')
  326. ]),
  327. ],
  328. ));
  329. //actions.add(TranslateSateWidget(friendId: friendInfo.userId));
  330. actions.add(Container(
  331. margin: EdgeInsets.only(top: 1),
  332. child: myPop.PopupMenuButton(
  333. icon: Icon(
  334. Icons.more_horiz,
  335. size: 24,
  336. ),
  337. offset: Offset(0, 100),
  338. onSelected: (int index) {
  339. if (index == 2) {
  340. AppNavigator.pushInformUserPage(
  341. context, friendInfo.sex == 1, friendInfo.userId);
  342. } else if (index == 1) {
  343. Navigator.of(context).push(
  344. new MaterialPageRoute(
  345. builder: (context) {
  346. return AddFriendPage(
  347. userId: friendInfo.userId,
  348. pageType: SendMessagePageType.Remark,
  349. originalName: Provider.of<RefNameProvider>(context)
  350. .getRefName(
  351. friendInfo.userId, friendInfo.nickName));
  352. },
  353. ),
  354. );
  355. }
  356. },
  357. itemBuilder: (BuildContext context) {
  358. return <myPop.PopupMenuItem<int>>[
  359. myPop.PopupMenuItem(
  360. child: Container(
  361. alignment: Alignment.center,
  362. color: Colors.white,
  363. padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
  364. child: Text(I18n.of(context).anonymous_report,
  365. textScaleFactor: 1.0,
  366. maxLines: 1,
  367. style: TextStyle(
  368. color: Color(AppColors.AppBarColor), fontSize: 12)),
  369. ),
  370. value: 2,
  371. ),
  372. myPop.PopupMenuItem(
  373. child: Container(
  374. decoration: BoxDecoration(
  375. border: Border(
  376. top: BorderSide(width: 1, color: Colors.grey[300])),
  377. color: Colors.white,
  378. ),
  379. alignment: Alignment.center,
  380. padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
  381. child: Text(I18n.of(context).Remark,
  382. textScaleFactor: 1.0,
  383. maxLines: 1,
  384. style: TextStyle(
  385. color: Color(AppColors.AppBarColor), fontSize: 12)),
  386. ),
  387. value: 1,
  388. ),
  389. ];
  390. })));
  391. var allItem = Stack(
  392. children: <Widget>[
  393. MultiProvider(
  394. providers: [
  395. ChangeNotifierProvider(create: (_) => _keyboardIndexProvider),
  396. Provider<bool>.value(value: false),
  397. Provider<int>.value(value: widget.friendId),
  398. ],
  399. child: GestureDetector(
  400. onTap: hideKeyBoard,
  401. child: ExtendedTextSelectionPointerHandler(
  402. ///选择文字,消除弹窗
  403. builder: (states) {
  404. return Listener(
  405. child: Scaffold(
  406. resizeToAvoidBottomInset: false,
  407. backgroundColor: const Color(0xFFE2E9F1),
  408. appBar: AppBar(
  409. title: Text(
  410. '${Provider.of<RefNameProvider>(context).getRefName(friendInfo.userId, friendInfo.nickName)}',
  411. textScaleFactor: 1.0,
  412. style: TextStyle(
  413. color: Constants.BlackTextColor,
  414. fontSize: 16.47),
  415. ),
  416. leading: CustomUI.buildCustomLeading(context,
  417. onTap: () {
  418. goBackCheck();
  419. }),
  420. titleSpacing: -10,
  421. centerTitle: false,
  422. elevation: 1,
  423. actions: actions),
  424. body: SafeArea(
  425. child: Column(
  426. children: <Widget>[
  427. NetStateWidget(),
  428. (isTranslateButler)
  429. ? _buildTranslationButler()
  430. : Container(),
  431. Expanded(child: _buildMessageList()),
  432. InputBar(
  433. sendMsg: sendMsg,
  434. isTranslateHK: isTranslateButler,
  435. ),
  436. ],
  437. ))),
  438. behavior: HitTestBehavior.translucent,
  439. onPointerDown: (value) {
  440. for (var state in states) {
  441. if (!state.containsPosition(value.position)) {
  442. //clear other selection
  443. state.clearSelection();
  444. }
  445. }
  446. },
  447. onPointerMove: (value) {
  448. //clear other selection
  449. for (var state in states) {
  450. if (!state.containsPosition(value.position)) {
  451. //clear other selection
  452. state.clearSelection();
  453. }
  454. }
  455. },
  456. );
  457. },
  458. ))),
  459. isTranslateButler ? getAudioChatView() : Container(),
  460. isTranslateButler ? zoomAudioButton() : Container()
  461. ],
  462. );
  463. return isTranslateButler
  464. ? WillPopScope(
  465. child: allItem,
  466. onWillPop: () {
  467. if (isTranslateButler && !isTranslateButlerFinish) {
  468. if (UserData().isTranslateUser) {
  469. showToast(
  470. I18n.of(context).translation_butler_order_close_tips);
  471. } else {
  472. CustomUI.buildTowConfirm(
  473. context,
  474. I18n.of(context).translation_butler_order_close_tips2,
  475. I18n.of(context).confirm,
  476. () {
  477. setState(() {
  478. isTranslateButlerFinish = true;
  479. });
  480. MsgHandler.sendEndTransHKOrderReq();
  481. Navigator.of(context).pop();
  482. },
  483. I18n.of(context).cancel,
  484. () {
  485. Navigator.of(context).pop();
  486. });
  487. }
  488. } else {
  489. Navigator.of(context).pop();
  490. }
  491. return Future.value(false);
  492. })
  493. : allItem;
  494. }
  495. addCoin() {
  496. setState(() {
  497. isPlayCoinAnim = true;
  498. });
  499. MessageMgr().emit('addCoin');
  500. }
  501. goBackCheck() {
  502. if (isTranslateButler && !isTranslateButlerFinish) {
  503. if (UserData().isTranslateUser) {
  504. showToast('翻译服务未结束不能主动结束');
  505. } else {
  506. CustomUI.buildTowConfirm(
  507. context,
  508. '是否提前结束翻译管家服务?',
  509. I18n.of(context).confirm,
  510. () {
  511. setState(() {
  512. isTranslateButlerFinish = true;
  513. });
  514. MsgHandler.sendEndTransHKOrderReq();
  515. Navigator.of(context).pop();
  516. },
  517. I18n.of(context).cancel,
  518. () {
  519. Navigator.of(context).pop();
  520. });
  521. }
  522. } else {
  523. Navigator.of(context).pop();
  524. }
  525. }
  526. Widget getAudioChatView() {
  527. if (friendInfo == null || isTranslateButlerFinish || !hasChatPermission) {
  528. return Container();
  529. }
  530. return isActive
  531. ? Offstage(
  532. offstage: !isShowAudio,
  533. child: AudioChatPage(
  534. userInfo: friendInfo,
  535. isTranslateButler: true,
  536. isReplay: !TranslateHKMgr().isUser,
  537. translateButlerCloseCallBack: audioChatPageCallBack,
  538. ),
  539. )
  540. : Container();
  541. }
  542. audioChatPageCallBack(int args) {
  543. switch (args) {
  544. case 1:
  545. setState(() {
  546. isShowAudio = !isShowAudio;
  547. isShowZoomButton = true;
  548. });
  549. break;
  550. case 2:
  551. setState(() {
  552. isActive = false;
  553. });
  554. break;
  555. }
  556. }
  557. bool isShowAudio = false;
  558. ///控住连麦窗口是否显示
  559. bool isActive = true;
  560. ///控制连麦是否关闭
  561. bool isShowZoomButton = true;
  562. GlobalKey mykey = GlobalKey();
  563. double dx = 0, dy = 0;
  564. double zoomButtonSizeWidth = 60;
  565. double zoomButtonSizeHeight = 74;
  566. void dragEvent(DragUpdateDetails details) {
  567. final RenderObject F = context.findRenderObject();
  568. // 获得自定义Widget的大小,用来计算Widget的中心锚点
  569. dx = details.globalPosition.dx - mykey.currentContext.size.width / 2;
  570. dy = details.globalPosition.dy - mykey.currentContext.size.height / 2;
  571. // print('dx $dx dy $dy screen width:${Screen.width}');
  572. if (dx > Screen.width - zoomButtonSizeWidth) {
  573. dx = Screen.width - zoomButtonSizeWidth;
  574. } else if (dx < 0) {
  575. dx = 0;
  576. }
  577. if (dy > Screen.height - zoomButtonSizeHeight) {
  578. dy = Screen.height - zoomButtonSizeHeight;
  579. } else if (dy < 0) {
  580. dy = 0;
  581. }
  582. setState(() {});
  583. }
  584. Widget zoomAudioButton() {
  585. if (friendInfo == null || !isShowZoomButton || !hasChatPermission) {
  586. return Container();
  587. }
  588. Widget button = Container(
  589. key: mykey,
  590. width: zoomButtonSizeWidth,
  591. height: zoomButtonSizeHeight,
  592. child: Card(
  593. child: Align(
  594. child: Icon(
  595. IconData(0xe67d, fontFamily: Constants.IconFontFamily),
  596. color: Color(0xFF008AFF),
  597. size: 35.0,
  598. ),
  599. alignment: Alignment.center,
  600. ),
  601. ),
  602. );
  603. return GestureDetector(
  604. onHorizontalDragUpdate: dragEvent,
  605. onVerticalDragUpdate: dragEvent,
  606. onTap: () {
  607. setState(() {
  608. isShowAudio = !isShowAudio;
  609. isShowZoomButton = !isShowZoomButton;
  610. });
  611. },
  612. child: Container(
  613. child: Transform.translate(
  614. offset: Offset(dx, dy),
  615. child: Align(
  616. alignment: Alignment.topLeft,
  617. child: button,
  618. ),
  619. ),
  620. ),
  621. );
  622. }
  623. Widget _buildTranslationButler() {
  624. bool hasHeadImg = true;
  625. if (friendInfo.headimgurl == null || friendInfo.headimgurl.length == 0) {
  626. hasHeadImg = false;
  627. }
  628. /// 5H币/1分钟
  629. String coinTIme = I18n.of(context).translation_butler_coin_time;
  630. coinTIme = coinTIme.replaceAll('/s1', '5');
  631. coinTIme = coinTIme.replaceAll('/s2', '1');
  632. return Container(
  633. padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
  634. decoration: BoxDecoration(
  635. color: Colors.white,
  636. border: Border(bottom: BorderSide(color: Colors.grey, width: .3))),
  637. child: Row(
  638. children: <Widget>[
  639. ClipRRect(
  640. borderRadius: BorderRadius.circular(8),
  641. child: hasHeadImg
  642. ? CachedNetworkImage(
  643. imageUrl: friendInfo.headimgurl,
  644. placeholder: (context, url) => Image.asset(
  645. Constants.DefaultHeadImgUrl,
  646. width: 54,
  647. height: 54,
  648. ),
  649. width: 54,
  650. height: 54,
  651. )
  652. : SizedBox(
  653. width: 54,
  654. height: 54,
  655. child: Image.asset(R.assetsImagesDefaultNorAvatar))),
  656. Padding(
  657. padding: EdgeInsets.only(left: 10),
  658. child: Container(
  659. child: Column(
  660. crossAxisAlignment: CrossAxisAlignment.start,
  661. children: <Widget>[
  662. Text(
  663. I18n.of(context).translation_butler,
  664. textScaleFactor: 1.0,
  665. overflow: TextOverflow.ellipsis,
  666. maxLines: 1,
  667. style: TextStyle(
  668. color: AppColors.NewAppbarTextColor, fontSize: 15),
  669. ),
  670. SizedBox(
  671. height: 5,
  672. ),
  673. Text(
  674. coinTIme,
  675. textScaleFactor: 1.0,
  676. maxLines: 1,
  677. style: TextStyle(color: Color(0xFF797979), fontSize: 13),
  678. )
  679. ],
  680. ),
  681. constraints: BoxConstraints(maxWidth: 135),
  682. ),
  683. ),
  684. (TranslateHKMgr().isUser && !isTranslateButlerFinish)
  685. ? Expanded(
  686. child: Container(
  687. constraints: BoxConstraints(maxWidth: 130),
  688. width: double.maxFinite,
  689. child: CountDownButton(
  690. I18n.of(context).translation_butler_end_service,
  691. () {
  692. // Navigator.of(context).pop();
  693. },
  694. countDownTime: 60 * 5,
  695. align: Alignment.centerRight,
  696. onPress: () {
  697. MsgHandler.sendEndTransHKOrderReq();
  698. // Navigator.of(context).pop();
  699. },
  700. ),
  701. // alignment: Alignment(1,0),
  702. ))
  703. : Container(),
  704. ],
  705. ),
  706. );
  707. }
  708. Widget _buildMessageList() {
  709. return Container(
  710. alignment: Alignment.topCenter,
  711. child: msgList.length == 0
  712. ? Padding(
  713. padding: EdgeInsets.all(8),
  714. child: Text(
  715. I18n.of(context).chat_tips,
  716. textAlign: TextAlign.center,
  717. textScaleFactor: 1.0,
  718. style: TextStyle(color: Colors.grey, fontSize: 12),
  719. ))
  720. : NotificationListener(
  721. child: Scrollbar(
  722. child: ListView.builder(
  723. controller: controller,
  724. physics: new ClampingScrollPhysics(),
  725. itemCount: msgList.length,
  726. itemBuilder: _buildItem,
  727. padding: EdgeInsets.symmetric(vertical: 8),
  728. reverse: true,
  729. shrinkWrap: true,
  730. )),
  731. onNotification: (notification) {
  732. if (notification is ScrollNotification) {}
  733. return true;
  734. },
  735. ),
  736. );
  737. }
  738. hideKeyBoard() {
  739. _keyboardIndexProvider.changeSelectIndex(-1);
  740. }
  741. readOnly() {
  742. _keyboardIndexProvider.changeReadOnlyKey(true);
  743. }
  744. sendMsg(MsgModel msg) async {
  745. // if(widget.isTranslateButler){ ///翻译管家聊天通道
  746. // msg.channelType = ChatChannelType.TransHK.value;
  747. // }
  748. print('对方是否拉黑你 ${friendInfo.isBlackened}');
  749. if (BlacklistMgr.isBlack(friendInfo.userId)) {
  750. return;
  751. }
  752. print('chat page session id:${msg.sessionId}');
  753. if (!friendInfo.isCanStrangerNews &&
  754. !FriendListMgr().isMyFriend(friendInfo.userId)) {
  755. showToast(I18n.of(context).stranger_close_tips);
  756. return;
  757. }
  758. MsgHandler.insertMsgToDB(msg);
  759. MsgHandler.sendChatMsg(msg);
  760. if (mounted) {
  761. setState(() {});
  762. await controller.scrollToIndex(0,
  763. preferPosition: AutoScrollPosition.begin);
  764. }
  765. }
  766. MsgModel msg;
  767. int count = 0;
  768. testBig(MsgModel msg) async {
  769. for (int k = 0; k < 100; k++) {
  770. msg.msgContent = utf8.encode('测试$count');
  771. Int64 time = Int64((DateTime.now()).millisecondsSinceEpoch);
  772. msg.time = time.toInt();
  773. MsgHandler.insertMsgToDB(msg);
  774. MsgHandler.sendChatMsg(msg);
  775. await Future.delayed(Duration(milliseconds: 500), () {});
  776. count++;
  777. }
  778. count = 0;
  779. print('发送完毕');
  780. showToast('发送完毕');
  781. }
  782. void receiveMsg(args) {
  783. if (mounted) {
  784. setState(() {});
  785. }
  786. }
  787. _deleteItem(msg) {
  788. if (msg.state == MsgState.Uploading) {
  789. print('取消上传');
  790. UploadUtil().cancelSendMsg(msg);
  791. }
  792. print('#### 开始删除--');
  793. msgList.remove(msg);
  794. setState(() {});
  795. SqlUtil().deleteSigleRecordWith(msg.sessionId, msg.time);
  796. }
  797. Widget _wrapScrollTag({int index, Widget child}) => AutoScrollTag(
  798. key: ValueKey(index),
  799. controller: controller,
  800. index: index,
  801. child: child,
  802. highlightColor: Colors.white.withOpacity(1),
  803. );
  804. Widget _buildItem(BuildContext context, int index) {
  805. var lastMsgTime;
  806. if (index < msgList.length - 1) {
  807. lastMsgTime = msgList[index + 1].time;
  808. }
  809. MsgModel msg = msgList[index];
  810. return _wrapScrollTag(
  811. index: index,
  812. child: ChatPageItem(
  813. key: Key(msg.time.toString()),
  814. msg: msg,
  815. hideKeyboard: readOnly,
  816. friendInfo: friendInfo,
  817. lastMsgTime: lastMsgTime));
  818. }
  819. }