Hibok
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

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