Hibok
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1549 lines
50 KiB

  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'dart:math';
  4. import 'dart:typed_data';
  5. import 'package:cached_network_image/cached_network_image.dart';
  6. import 'package:chat/chat/download_item.dart';
  7. import 'package:chat/chat/file_msg_item.dart';
  8. import 'package:chat/chat/msg_state_widge.dart';
  9. import 'package:chat/chat/place_item.dart';
  10. import 'package:chat/chat/redbag_widget.dart';
  11. import 'package:chat/chat/upload_item.dart';
  12. import 'package:chat/chat/video_view.dart';
  13. import 'package:chat/data/UserData.dart';
  14. import 'package:chat/data/constants.dart';
  15. import 'package:chat/utils/friend_list_mgr.dart';
  16. import 'package:chat/utils/sql_util.dart';
  17. import 'package:chat/utils/wpop/w_popup_menu.dart';
  18. import 'package:flutter/services.dart';
  19. import 'package:chat/generated/i18n.dart';
  20. import 'package:chat/home/invite_detail_page.dart';
  21. import 'package:chat/models/ChatMsg.dart';
  22. import 'package:chat/models/group_info_model.dart';
  23. import 'package:chat/models/keyboard_provider.dart';
  24. import 'package:chat/proto/chat.pbenum.dart';
  25. import 'package:chat/proto/chat.pbserver.dart';
  26. import 'package:chat/utils/CustomUI.dart';
  27. import 'package:chat/utils/MessageMgr.dart';
  28. import 'package:chat/utils/app_navigator.dart';
  29. import 'package:chat/utils/date_utils.dart';
  30. import 'package:chat/utils/group_member_model.dart';
  31. import 'package:chat/utils/msgHandler.dart';
  32. import 'package:chat/utils/screen.dart';
  33. import 'package:chat/utils/sound_util.dart';
  34. import 'package:chat/utils/upload_util.dart';
  35. import 'package:chat/utils/video_anim.dart';
  36. import 'package:dio/dio.dart';
  37. import 'package:flutter/cupertino.dart';
  38. import 'package:flutter/material.dart';
  39. import 'package:provider/provider.dart';
  40. import 'package:oktoast/oktoast.dart';
  41. import 'package:chat/utils/HttpUtil.dart';
  42. import 'package:share_extend/share_extend.dart';
  43. import 'package:url_launcher/url_launcher.dart';
  44. import '../r.dart';
  45. import '../utils/file_cache_mgr.dart';
  46. import 'full_img_view.dart';
  47. import 'upload_item.dart';
  48. import 'package:chat/models/ref_name_provider.dart';
  49. import 'package:chat/models/money_change.dart';
  50. import 'package:chat/models/voucher_change.dart';
  51. const double ChatRadius = 7.5;
  52. const Color SendMsgBg = Color(0xFFD4F0FF);
  53. const Color SendMsgText = Colors.black;
  54. const double TextHeight = 1.2;
  55. const double PaddingLeft = 9.5;
  56. const Color ReciveBorderColor = Color(0xFFDCDCDC);
  57. const double FontSize = 15;
  58. class GroupChatPageItem extends StatefulWidget {
  59. final MsgModel msg;
  60. final int lastMsgTime;
  61. final GroupMemberModel memberModel;
  62. final Function hideKeyboard;
  63. const GroupChatPageItem(
  64. {Key key,
  65. this.msg,
  66. this.lastMsgTime,
  67. this.hideKeyboard,
  68. this.memberModel})
  69. : assert(msg != null),
  70. super(key: key);
  71. @override
  72. _GroupChatPageItemState createState() => _GroupChatPageItemState();
  73. }
  74. class _GroupChatPageItemState extends State<GroupChatPageItem>
  75. with SingleTickerProviderStateMixin {
  76. int curTextType = 0; //文字、译文切换索引
  77. List<String> textList = [];
  78. String curSoundUrl;
  79. bool isLongPressed = false;
  80. double maxWidth = Screen.width - 140;
  81. @override
  82. void initState() {
  83. super.initState();
  84. if (widget.msg.from == UserData().basicInfo.userId &&
  85. widget.msg.state == MsgState.None) {
  86. print('重新发送消息');
  87. MsgHandler.sendChatMsg(widget.msg);
  88. }
  89. textList = widget.msg.getTransTextList();
  90. MessageMgr().on('Update Translate Message', updateTranslateMsg);
  91. }
  92. @override
  93. void dispose() {
  94. MessageMgr().off('Update Translate Message', updateTranslateMsg);
  95. super.dispose();
  96. }
  97. updateTextList() {
  98. textList.clear();
  99. curTextType = 0;
  100. textList = widget.msg.getTransTextList();
  101. }
  102. updateTranslateMsg(msg) {
  103. if (msg.time == widget.msg.time) {
  104. if (mounted) {
  105. updateTextList();
  106. if (msg.transTag == 5 || msg.transTag == 6) {
  107. print('人工翻译失败');
  108. //更新最新的金额
  109. HttpUtil().getWealth(context, (data) {
  110. if (mounted) {
  111. Provider.of<MoneyChangeProvider>(context)
  112. .initMoney(data['CoinValue']);
  113. Provider.of<VoucherChangeProvider>(context)
  114. .initVoucher(data['Voucher']);
  115. }
  116. });
  117. }
  118. setState(() {
  119. print('更新翻译文字');
  120. });
  121. }
  122. }
  123. }
  124. getTodayTime(msgDate, {var sendTime}) {
  125. String showTimeStr;
  126. sendTime = sendTime ?? widget.msg.time;
  127. var today = DateTime.now();
  128. //今天
  129. if (msgDate.year == today.year &&
  130. msgDate.month == today.month &&
  131. msgDate.day == today.day) {
  132. showTimeStr =
  133. DateUtils().getFormartData(timeSamp: sendTime, format: 'HH:mm');
  134. } else {
  135. showTimeStr =
  136. DateUtils().getFormartData(timeSamp: sendTime, format: 'MM/dd HH:mm');
  137. }
  138. return showTimeStr;
  139. }
  140. String getMsgTime() {
  141. String showTimeStr;
  142. var sendTime = widget.msg.time;
  143. var msgDate = DateTime.fromMillisecondsSinceEpoch(sendTime);
  144. if (widget.lastMsgTime == null) {
  145. showTimeStr = getTodayTime(msgDate);
  146. } else {
  147. if (sendTime - widget.lastMsgTime > 3 * 60 * 1000) {
  148. showTimeStr = getTodayTime(msgDate);
  149. }
  150. }
  151. return showTimeStr;
  152. }
  153. @override
  154. Widget build(BuildContext context) {
  155. var showTime = getMsgTime();
  156. return Container(
  157. width: Screen.width,
  158. color: Colors.white.withOpacity(0),
  159. margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 4),
  160. child: Column(
  161. children: <Widget>[
  162. showTime == null
  163. ? SizedBox()
  164. : Container(
  165. decoration: BoxDecoration(
  166. color: Color(0xFF2C2F36).withOpacity(0.25),
  167. borderRadius: BorderRadius.all(Radius.circular(9.5))),
  168. padding:
  169. EdgeInsets.only(left: 7, right: 7, top: 3, bottom: 2),
  170. child: Text(showTime,
  171. textScaleFactor: 1.0,
  172. style: TextStyle(fontSize: 10.0, color: Colors.white)),
  173. ),
  174. SizedBox(height: 10),
  175. _msgWidget()
  176. ],
  177. ),
  178. );
  179. }
  180. _msgWidget() {
  181. if (widget.msg.from == 0) {
  182. return _serverNotifyMsg();
  183. } else {
  184. if (widget.msg.from == UserData().basicInfo.userId) {
  185. return _getSentMessageLayout(context);
  186. } else {
  187. return _getReceivedMessageLayout(context);
  188. }
  189. }
  190. }
  191. _serverNotifyMsg() {
  192. var type = widget.msg.msgType;
  193. if (type == ChatType.GroupChatNoticeType.value) {
  194. var res = GroupChatNotice.fromBuffer(widget.msg.msgContent);
  195. var groupInfoModel = Provider.of<GroupInfoModel>(context);
  196. var optId = res.operatuId;
  197. var showStr = MsgHandler.getGroupNoticeMsg(res, groupInfoModel);
  198. return Container(
  199. alignment: Alignment.center,
  200. constraints: BoxConstraints(maxWidth: Screen.width - 120),
  201. child: extendedText(showStr,
  202. color: Constants.GreyTextColor,
  203. fontSize: 12, onSpecialTextTap: (dynamic parameter) {
  204. // print('点击事件 $parameter');
  205. if (parameter.startsWith("\$")) {
  206. // showToast('点击: ${res.operateduId[0]}');
  207. List<GroupMemberModel> list = [];
  208. for (int k = 0; k < res.operateduId.length; k++) {
  209. list.add(GroupMemberModel.fromBaseInfo(res.operateduId[k]));
  210. }
  211. AppNavigator.push(
  212. context,
  213. InviteDetailPage(
  214. originalList: list,
  215. opt: GroupMemberModel.fromBaseInfo(optId),
  216. groupId: groupInfoModel.sessionId,
  217. ));
  218. }
  219. }),
  220. );
  221. }
  222. return Container();
  223. }
  224. _textGif(List<int> msgContent) {
  225. var msg = utf8.decode(msgContent);
  226. return Container(
  227. constraints: BoxConstraints(maxWidth: Screen.width - 120),
  228. child: extendedText(
  229. msg,
  230. selectionEnabled: false,
  231. hideKeyboard: widget.hideKeyboard,
  232. fontSize: FontSize,
  233. color: Colors.black,
  234. ),
  235. );
  236. }
  237. double getQuoteContentWidth(QuoteMsg quoteMsg, String refName,
  238. String showTimeStr, String quoteContent) {
  239. double width;
  240. var timetWidth = CustomUI.getRealTextWidht(showTimeStr, 13);
  241. var nameWidhth = CustomUI.getRealTextWidht(refName, 13);
  242. width = timetWidth + (nameWidhth > 70 ? 70 : nameWidhth) + 59;
  243. var contentWidht = _getTextWidth(quoteContent, fontSize: 13);
  244. return min(max(width, contentWidht), maxWidth);
  245. }
  246. Widget getQuoteContent(QuoteMsg quoteMsg, String refName, String showTimeStr,
  247. String quoteContent, bool isSend) {
  248. var strColor;
  249. var bgColor;
  250. if (isSend) {
  251. strColor = const Color(0xFF24343C);
  252. bgColor = const Color(0xFFC4E0F5);
  253. } else {
  254. strColor = const Color(0xFF515151);
  255. bgColor = const Color(0xFFEBEBEC);
  256. }
  257. return Container(
  258. padding: EdgeInsets.only(left: 8, bottom: 8),
  259. margin: EdgeInsets.only(bottom: 5, top: 2),
  260. decoration:
  261. BoxDecoration(color: bgColor, borderRadius: BorderRadius.circular(7)),
  262. child: Column(
  263. crossAxisAlignment: CrossAxisAlignment.start,
  264. children: <Widget>[
  265. Row(children: <Widget>[
  266. Container(
  267. constraints: BoxConstraints(maxWidth: 70),
  268. child: Text(
  269. refName,
  270. style: TextStyle(fontSize: 13, color: strColor),
  271. overflow: TextOverflow.ellipsis,
  272. )),
  273. SizedBox(width: 10),
  274. Text(
  275. showTimeStr,
  276. style: TextStyle(fontSize: 13, color: strColor),
  277. ),
  278. Expanded(child: SizedBox()),
  279. InkWell(
  280. onTap: () {
  281. MessageMgr().emit('Jump to Msg', quoteMsg.sendTime.toInt());
  282. },
  283. child: Container(
  284. alignment: Alignment.center,
  285. height: 27,
  286. padding: EdgeInsets.only(
  287. left: 10,
  288. right: 10,
  289. ),
  290. child: Icon(
  291. IconData(0xe67e, fontFamily: Constants.IconFontFamily),
  292. size: 13,
  293. color: strColor,
  294. )))
  295. ]),
  296. Padding(
  297. padding: EdgeInsets.only(right: 8),
  298. child: Text(
  299. quoteContent,
  300. style: TextStyle(fontSize: 13, color: strColor),
  301. ),
  302. ),
  303. ],
  304. ),
  305. );
  306. }
  307. Map getQuoteItem(MsgModel msgModel) {
  308. QuoteMsg quoteMsg = QuoteMsg.fromBuffer(widget.msg.refMsgContent);
  309. var refName = Provider.of<RefNameProvider>(context)
  310. .getGroupRefName(msgModel.sessionId, quoteMsg.sendUserId);
  311. var msgDate =
  312. DateTime.fromMillisecondsSinceEpoch(quoteMsg.sendTime.toInt());
  313. var showTimeStr =
  314. getTodayTime(msgDate, sendTime: quoteMsg.sendTime.toInt());
  315. var tempIndex = quoteMsg.content.indexOf(':');
  316. var quoteContent = tempIndex == -1
  317. ? quoteMsg.content
  318. : quoteMsg.content.substring(quoteMsg.content.indexOf(':') + 2);
  319. return {
  320. "quoteMsg": quoteMsg,
  321. "refName": refName,
  322. "showTimeStr": showTimeStr,
  323. "quoteContent": quoteContent,
  324. };
  325. }
  326. _textMsg(MsgModel msgModel) {
  327. List<Widget> showMsg = [];
  328. var width = 0.0;
  329. var msg = utf8.decode(msgModel.msgContent);
  330. if (msg.contains('[ ')) {
  331. msg = msg.replaceAll('[ ', '[');
  332. }
  333. if (msg.contains(' ]')) {
  334. msg = msg.replaceAll(' ]', ']');
  335. }
  336. bool isUrl = false;
  337. if (textList[curTextType].contains('http')) {
  338. isUrl = true;
  339. }
  340. if (msgModel.refMsgContent != null && msgModel.refMsgContent.length > 0) {
  341. var quoteItem = getQuoteItem(msgModel);
  342. width = getQuoteContentWidth(quoteItem['quoteMsg'], quoteItem['refName'],
  343. quoteItem['showTimeStr'], quoteItem['quoteContent']);
  344. showMsg.add(getQuoteContent(quoteItem['quoteMsg'], quoteItem['refName'],
  345. quoteItem['showTimeStr'], quoteItem['quoteContent'], true));
  346. }
  347. var contentWidth = _getTextWidth(textList[curTextType]);
  348. width = min(max(contentWidth, width), maxWidth);
  349. showMsg.add(Container(
  350. constraints: BoxConstraints(maxWidth: maxWidth, minHeight: 22),
  351. alignment: Alignment.centerLeft,
  352. child: extendedText(
  353. textList[curTextType],
  354. color: isUrl ? Colors.blue : Constants.BlackTextColor,
  355. hideKeyboard: widget.hideKeyboard,
  356. fontSize: FontSize,
  357. )));
  358. return Container(
  359. constraints: BoxConstraints(maxWidth: Screen.width - 120),
  360. width: width + 20,
  361. child: Column(
  362. crossAxisAlignment: CrossAxisAlignment.start, children: showMsg),
  363. padding: EdgeInsets.symmetric(horizontal: 9, vertical: 10.5),
  364. decoration: BoxDecoration(
  365. color: isLongPressed ? Colors.grey[300] : SendMsgBg,
  366. border: Border.all(color: Color(0xFFB9CBD7), width: 0.6),
  367. borderRadius: BorderRadius.all(Radius.circular(ChatRadius))),
  368. );
  369. }
  370. _soundMsg() {
  371. double time = widget.msg.extraInfo / 1000;
  372. if (time > 60) {
  373. time = 60.0;
  374. }
  375. bool isPlaying = false;
  376. var soundPath = widget.msg.localFile;
  377. isPlaying = SoundUtils().isPlaying(soundPath);
  378. var soundWidget = GestureDetector(
  379. child: Container(
  380. width: 120,
  381. child: Row(
  382. mainAxisAlignment: MainAxisAlignment.end,
  383. children: <Widget>[
  384. Container(
  385. alignment: Alignment.center,
  386. padding: EdgeInsets.only(bottom: 2),
  387. margin: EdgeInsets.only(right: 10),
  388. width: 25.5,
  389. height: 25.5,
  390. decoration: BoxDecoration(
  391. border:
  392. Border.all(color: const Color(0xFF1B92C7), width: 0.5),
  393. color: const Color(0xFF04A4FE),
  394. shape: BoxShape.circle),
  395. child: Icon(
  396. IconData(isPlaying ? 0xe652 : 0xe653,
  397. fontFamily: Constants.IconFontFamily),
  398. size: isPlaying ? 15 : 18,
  399. color: Colors.white,
  400. ),
  401. ),
  402. isPlaying
  403. ? Stack(
  404. children: <Widget>[
  405. Container(
  406. height: 18,
  407. width: 19,
  408. ),
  409. Positioned(
  410. bottom: 0,
  411. child: VideoAnim(
  412. begin: 18,
  413. start: 0.444,
  414. end: 4.5,
  415. )),
  416. Positioned(
  417. left: 7,
  418. bottom: 0,
  419. child: VideoAnim(
  420. begin: 4.5,
  421. end: 18,
  422. )),
  423. Positioned(
  424. left: 14,
  425. bottom: 0,
  426. child: VideoAnim(
  427. begin: 18,
  428. end: 4.5,
  429. ))
  430. ],
  431. )
  432. : Stack(
  433. children: <Widget>[
  434. Container(
  435. height: 18,
  436. width: 19,
  437. ),
  438. Positioned(
  439. bottom: 0, child: CustomUI.buildAudioContaniner(12)),
  440. Positioned(
  441. left: 7,
  442. bottom: 0,
  443. child: CustomUI.buildAudioContaniner(4.5)),
  444. Positioned(
  445. left: 14,
  446. bottom: 0,
  447. child: CustomUI.buildAudioContaniner(18))
  448. ],
  449. ),
  450. Expanded(child: SizedBox()),
  451. fixedText(time.toStringAsFixed(0), color: SendMsgText, fontSize: 16)
  452. ],
  453. ),
  454. padding: EdgeInsets.symmetric(horizontal: 15, vertical: 12),
  455. decoration: BoxDecoration(
  456. color: SendMsgBg,
  457. border: Border.all(color: Color(0xFFB9CBD7), width: 0.6),
  458. borderRadius: BorderRadius.all(Radius.circular(ChatRadius))),
  459. ),
  460. onTap: () async {
  461. print('播放状态 : $isPlaying');
  462. print('当前文件$soundPath ');
  463. if (isPlaying) {
  464. SoundUtils().pause();
  465. } else {
  466. SoundUtils().play(soundPath, onPlayed: () {
  467. if (mounted) {
  468. setState(() {});
  469. }
  470. }, complete: () {
  471. if (mounted) {
  472. setState(() {});
  473. }
  474. });
  475. }
  476. },
  477. );
  478. return UploadImgItem(
  479. msg: widget.msg,
  480. child: soundWidget,
  481. isShowProgress: false,
  482. );
  483. }
  484. Size _getImgSize() {
  485. double aspectRatio = widget.msg.extraInfo / 100;
  486. var maxWidth = Screen.width * 0.65;
  487. var maxHeight = Screen.height / 4;
  488. var width, height;
  489. if (maxWidth / maxHeight > aspectRatio) {
  490. height = maxHeight;
  491. width = maxHeight * aspectRatio;
  492. } else {
  493. width = maxWidth;
  494. height = maxWidth / aspectRatio;
  495. }
  496. return Size(width, height);
  497. }
  498. _imgMsg(List<int> imgData) {
  499. var imgSize = _getImgSize();
  500. ImageProvider provider = MemoryImage(widget.msg.localFile == null
  501. ? Uint8List.fromList(imgData)
  502. : File(widget.msg.localFile).readAsBytesSync());
  503. return GestureDetector(
  504. child: ClipRRect(
  505. child: UploadImgItem(
  506. msg: widget.msg,
  507. child: Container(
  508. height: imgSize.height,
  509. width: imgSize.width,
  510. child: Image(
  511. fit: BoxFit.contain,
  512. image: provider,
  513. ),
  514. )),
  515. borderRadius: BorderRadius.circular(5),
  516. ),
  517. onTap: () async {
  518. showFullImg(context, widget.msg);
  519. });
  520. }
  521. _videoMsg(BuildContext context, List<int> thumbnail) {
  522. var imgSize = _getImgSize();
  523. return InkWell(
  524. child: ClipRRect(
  525. child: Stack(
  526. alignment: Alignment.center,
  527. children: <Widget>[
  528. UploadImgItem(
  529. msg: widget.msg,
  530. child: Container(
  531. width: imgSize.width,
  532. height: imgSize.height,
  533. child: Image(
  534. fit: BoxFit.contain,
  535. image: MemoryImage(Uint8List.fromList(thumbnail)),
  536. ),
  537. ))
  538. ],
  539. ),
  540. borderRadius: BorderRadius.circular(5),
  541. ),
  542. onTap: () {
  543. showVideoPage(context, widget.msg.localFile);
  544. },
  545. );
  546. }
  547. _msgLayout(BuildContext context, MsgModel msg) {
  548. Widget item;
  549. switch (ChatType.valueOf(msg.msgType)) {
  550. case ChatType.TextChatType:
  551. item = _textMsg(msg);
  552. break;
  553. case ChatType.EmoticonType:
  554. item = _textGif(msg.msgContent);
  555. break;
  556. case ChatType.ImageChatType:
  557. item = _imgMsg(msg.msgContent);
  558. break;
  559. case ChatType.ShortVideoChatType:
  560. item = _videoMsg(context, msg.msgContent);
  561. break;
  562. case ChatType.ShortVoiceChatType:
  563. item = _soundMsg();
  564. break;
  565. case ChatType.RedWalletChatType:
  566. item = RedBagItem(
  567. Key(msg.time.toString()), UserData().basicInfo.userId, msg);
  568. break;
  569. case ChatType.PlaceChatType:
  570. item = PlaceItem(isMe: true, placeContent: msg.msgContent);
  571. break;
  572. case ChatType.FileChatType:
  573. item = _fileMsgItem();
  574. break;
  575. default:
  576. }
  577. return wrapItemWithMenu(item);
  578. }
  579. Widget _fileMsgItem() {
  580. return UploadImgItem(
  581. msg: widget.msg,
  582. child: Container(
  583. height: 100,
  584. constraints: BoxConstraints(maxWidth: Screen.width - 120),
  585. padding: EdgeInsets.symmetric(horizontal: 9, vertical: 10.5),
  586. decoration: BoxDecoration(
  587. color: isLongPressed ? Colors.grey[300] : SendMsgBg,
  588. borderRadius: BorderRadius.all(Radius.circular(ChatRadius))),
  589. child: FileMsgItem(widget.msg)));
  590. }
  591. Widget wrapItemWithMenu(item) {
  592. List<Function> actionsFunc = [];
  593. List<String> actions = [
  594. I18n.of(context).reply,
  595. I18n.of(context).delete,
  596. ];
  597. actionsFunc.add(() {
  598. print('发送引用的消息');
  599. MessageMgr().emit('Reply Select Message', widget.msg);
  600. });
  601. actionsFunc.add(() {
  602. MessageMgr().emit('Delete Select Message', widget.msg);
  603. });
  604. ///转发
  605. if (widget.msg.msgType == ChatType.TextChatType.value ||
  606. widget.msg.msgType == ChatType.ImageChatType.value ||
  607. widget.msg.msgType == ChatType.ShortVideoChatType.value ||
  608. widget.msg.msgType == ChatType.PlaceChatType.value ||
  609. widget.msg.msgType == ChatType.EmoticonType.value ||
  610. widget.msg.msgType == ChatType.FileChatType.value) {
  611. actions.add(I18n.of(context).forward);
  612. actionsFunc.add(() {
  613. print('转发消息');
  614. if (widget.msg.msgType == ChatType.FileChatType.value &&
  615. widget.msg.localFile == null) {
  616. showToast('请先下载文件');
  617. return;
  618. }
  619. AppNavigator.pushForwardPage(context, widget.msg);
  620. });
  621. }
  622. if (widget.msg.msgType == ChatType.FileChatType.value &&
  623. widget.msg.localFile != null) {
  624. //分享文件
  625. actions.add(I18n.of(context).copy_download_url);
  626. actionsFunc.add(() async {
  627. //如果是文件增加复制下载地址
  628. String path = widget.msg.localFile;
  629. UploadUtil().copyFileUrl(widget.msg, context);
  630. String type = 'file';
  631. if (path.contains('mp4') || path.contains('mp3')) {
  632. type = 'video';
  633. } else if (path.contains('png') ||
  634. path.contains('jpg') ||
  635. path.contains('jpeg') ||
  636. path.contains('JPG') ||
  637. path.contains('PNG')) {
  638. type = 'image';
  639. }
  640. ShareExtend.share(FileCacheMgr.replacePath(path), type);
  641. });
  642. }
  643. if (widget.msg.msgType == ChatType.TextChatType.value) {
  644. actions.insert(0, I18n.of(context).copy);
  645. actionsFunc.insert(0, () {
  646. //复制当前的文字
  647. print('复制文字 ${textList[curTextType]}');
  648. ClipboardData clipboardData =
  649. ClipboardData(text: textList[curTextType]);
  650. Clipboard.setData(clipboardData);
  651. });
  652. }
  653. if (widget.msg.msgType == ChatType.ShortVoiceChatType.value) {
  654. var soundPlayMode =
  655. Provider.of<KeyboardIndexProvider>(context).soundPlayMode;
  656. actions.add(soundPlayMode
  657. ? I18n.of(context).handset_playback
  658. : I18n.of(context).speaker_play);
  659. actionsFunc.add(() {
  660. Provider.of<KeyboardIndexProvider>(context)
  661. .changeSoundPlayMode(!soundPlayMode);
  662. SoundUtils.instance.savePlayModeConfig(soundPlayMode);
  663. });
  664. }
  665. // String date2 = DateTime.fromMillisecondsSinceEpoch(widget.msg.time).toString();
  666. bool isUrl = false;
  667. if (widget.msg.msgType == ChatType.TextChatType.value) {
  668. if (textList[curTextType].contains('http')) {
  669. isUrl = true;
  670. }
  671. }
  672. return WPopupMenu(
  673. child: item,
  674. actions: actions,
  675. onTap: () async {
  676. MessageMgr().emit('Keyboard Hide');
  677. if (isUrl) {
  678. if (await canLaunch(textList[curTextType])) {
  679. launch(textList[curTextType]);
  680. }
  681. }
  682. },
  683. onLongPressStart: () {
  684. isLongPressed = true;
  685. setState(() {});
  686. },
  687. onLongPressEnd: () {
  688. isLongPressed = false;
  689. setState(() {});
  690. },
  691. onValueChanged: (int value) {
  692. print('选择的是$value个菜单');
  693. if (value >= 0 && value < actionsFunc.length) {
  694. actionsFunc[value]();
  695. }
  696. },
  697. );
  698. }
  699. Widget _getSentMessageLayout(BuildContext context) {
  700. bool hasHeadImg = true;
  701. if (UserData().basicInfo.headimgurl == null ||
  702. UserData().basicInfo.headimgurl.length == 0) {
  703. hasHeadImg = false;
  704. }
  705. return Row(
  706. crossAxisAlignment: CrossAxisAlignment.start,
  707. mainAxisAlignment: MainAxisAlignment.end,
  708. children: <Widget>[
  709. MsgStateWidget(widget.msg),
  710. SizedBox(width: 3),
  711. _msgLayout(context, widget.msg),
  712. SizedBox(width: 10),
  713. Column(
  714. crossAxisAlignment: CrossAxisAlignment.end,
  715. children: <Widget>[
  716. ClipRRect(
  717. borderRadius: BorderRadius.circular(8),
  718. child: hasHeadImg
  719. ? CachedNetworkImage(
  720. imageUrl: UserData().basicInfo.headimgurl,
  721. placeholder: (context, url) => Image.asset(
  722. Constants.DefaultHeadImgUrl,
  723. width: 40,
  724. height: 40,
  725. ),
  726. width: 40,
  727. height: 40,
  728. )
  729. : SizedBox(
  730. width: 40,
  731. height: 40,
  732. child: Image.asset(R.assetsImagesDefaultNorAvatar))),
  733. ],
  734. )
  735. ]);
  736. }
  737. _receiveJIF(MsgModel msg) {
  738. var text = utf8.decode(msg.msgContent);
  739. return Container(
  740. constraints: BoxConstraints(maxWidth: Screen.width - 120),
  741. child: extendedText(text,
  742. selectionEnabled: false, hideKeyboard: widget.hideKeyboard));
  743. }
  744. double _getTextWidth(String text, {double fontSize: FontSize}) {
  745. var tp = TextPainter(
  746. text: TextSpan(style: TextStyle(fontSize: fontSize), text: text),
  747. textAlign: TextAlign.left,
  748. textDirection: TextDirection.ltr,
  749. textScaleFactor: 1,
  750. );
  751. tp.layout(maxWidth: Screen.width - 140);
  752. RegExp alterStr = RegExp(r'\[([0-9]+)\]');
  753. Iterable<Match> matches = alterStr.allMatches(text);
  754. // print('~~~~~~~~~~~~~~${matches.length}~~~~~~~~~~~~~~~');
  755. double delta = 0;
  756. for (Match m in matches) {
  757. // print('~~~~~~~~~~~~~~${m.group(1)}~~~~~~~~~~~~~~~');
  758. if (int.parse(m.group(1)) > 10) {
  759. delta += 20 + 4 - 25;
  760. } else {
  761. delta += 20 + 4 - 16.8;
  762. }
  763. }
  764. return tp.width + delta;
  765. }
  766. blueDot(bool isShow) {
  767. return Container(
  768. margin: EdgeInsets.only(right: 5),
  769. decoration: BoxDecoration(
  770. shape: BoxShape.circle,
  771. color: isShow ? Color(0xFFFF7E00) : Color(0xFFCFCFCF),
  772. ),
  773. width: 4,
  774. height: 4,
  775. );
  776. }
  777. _receiveText(MsgModel msg) {
  778. List<Widget> showMsg = [];
  779. double width = 0.0;
  780. if (textList.length > 0) {
  781. bool isUrl = false;
  782. if (textList[curTextType].contains('http')) {
  783. isUrl = true;
  784. }
  785. if (msg.refMsgContent != null && msg.refMsgContent.length > 0) {
  786. var quoteItem = getQuoteItem(msg);
  787. width = getQuoteContentWidth(
  788. quoteItem['quoteMsg'],
  789. quoteItem['refName'],
  790. quoteItem['showTimeStr'],
  791. quoteItem['quoteContent']);
  792. showMsg.add(getQuoteContent(quoteItem['quoteMsg'], quoteItem['refName'],
  793. quoteItem['showTimeStr'], quoteItem['quoteContent'], false));
  794. }
  795. var contentWidth = _getTextWidth(textList[curTextType]);
  796. width = min(max(contentWidth, width), maxWidth);
  797. showMsg.add(Container(
  798. constraints: BoxConstraints(maxWidth: maxWidth, minHeight: 22),
  799. alignment: Alignment.centerLeft,
  800. child: extendedText(
  801. textList[curTextType],
  802. color: isUrl ? Colors.blue : Constants.BlackTextColor,
  803. hideKeyboard: widget.hideKeyboard,
  804. fontSize: FontSize,
  805. )));
  806. }
  807. var minWidth = width + 20;
  808. if (msg.transTag != 0) {
  809. minWidth = 200;
  810. showMsg.add(Padding(
  811. padding: EdgeInsets.symmetric(vertical: 5),
  812. child: Divider(color: Color(0xFFECECEC), height: 1)));
  813. Widget tranWidget = _transProcessWidget(msg.transTag);
  814. showMsg.add(tranWidget);
  815. }
  816. Widget text = Stack(children: <Widget>[
  817. Container(
  818. width: width + 20,
  819. constraints:
  820. BoxConstraints(maxWidth: Screen.width - 120, minWidth: minWidth),
  821. padding: EdgeInsets.symmetric(horizontal: 9, vertical: 10.5),
  822. child: Column(
  823. crossAxisAlignment: CrossAxisAlignment.start, children: showMsg),
  824. decoration: BoxDecoration(
  825. border: Border.all(color: ReciveBorderColor, width: 0.5),
  826. color: isLongPressed ? Colors.grey[300] : Colors.white,
  827. borderRadius: BorderRadius.all(Radius.circular(ChatRadius))),
  828. ),
  829. msg.transTag != 1 && msg.transTag != 0
  830. ? Positioned(
  831. right: 5,
  832. top: 5,
  833. child: Container(
  834. child: Row(children: <Widget>[
  835. blueDot(curTextType == 0),
  836. blueDot(curTextType == 1),
  837. blueDot(curTextType == 2),
  838. //blueDot(true),
  839. ])))
  840. : Container()
  841. ]);
  842. return InkWell(
  843. child: text,
  844. onTap: () {
  845. MessageMgr().emit('Keyboard Hide');
  846. if (msg.transTag == 1) {
  847. return;
  848. }
  849. if (msg.transTag == 2 || msg.transTag == 3) {
  850. setState(() {
  851. curTextType += 1;
  852. curTextType %= textList.length;
  853. });
  854. return;
  855. }
  856. },
  857. );
  858. }
  859. //用户评价人工翻译,差评
  860. rateTranslateResult() async {
  861. return await HttpUtil().rateTranslateResult(widget.msg, () {
  862. if (mounted) {
  863. setState(() {});
  864. }
  865. });
  866. }
  867. _translateItemWidget(int code, String title, Function onTap) {
  868. Color color = onTap == null ? Color(0xFFC5C5C5) : Color(0xFF6A6A6A);
  869. return InkWell(
  870. onTap: onTap,
  871. splashColor: Colors.red,
  872. child: Container(
  873. width: 80,
  874. child: Row(
  875. children: <Widget>[
  876. Icon(
  877. IconData(code, fontFamily: Constants.IconFontFamily),
  878. color: color,
  879. size: 20,
  880. ),
  881. SizedBox(width: 5),
  882. Expanded(
  883. child: SizedBox(
  884. child: Text(
  885. title,
  886. style: TextStyle(color: color, fontSize: 10),
  887. textScaleFactor: 1.0,
  888. maxLines: 1,
  889. overflow: TextOverflow.ellipsis,
  890. ),
  891. ))
  892. ],
  893. )));
  894. }
  895. bool isTranslating = false;
  896. _transProcessWidget(int transTag) {
  897. double width = 160;
  898. Widget userTranslateWidget;
  899. Widget machineTranslateWidget;
  900. if (transTag == 1) {
  901. //机器翻译中
  902. userTranslateWidget =
  903. _translateItemWidget(0xe670, I18n.of(context).man_retranslate, null);
  904. machineTranslateWidget =
  905. _translateItemWidget(0xe671, I18n.of(context).robotTranslate, null);
  906. } else if (transTag == 2) {
  907. //人工翻译中
  908. userTranslateWidget =
  909. _translateItemWidget(0xe670, I18n.of(context).ManTranslate, null);
  910. machineTranslateWidget = _translateItemWidget(
  911. 0xe671,
  912. I18n.of(context).robot_retranslate,
  913. textList.length <= 1
  914. ? null
  915. : () {
  916. setState(() {
  917. curTextType += 1;
  918. curTextType %= textList.length;
  919. });
  920. });
  921. } else if (transTag == 3) {
  922. //机器翻译完成
  923. userTranslateWidget = _translateItemWidget(
  924. 0xe670,
  925. I18n.of(context).man_retranslate,
  926. isTranslating
  927. ? null
  928. : () async {
  929. isTranslating = true;
  930. int money =
  931. Provider.of<MoneyChangeProvider>(context, listen: false)
  932. .money;
  933. int voucher =
  934. Provider.of<VoucherChangeProvider>(context, listen: false)
  935. .voucher;
  936. int needMoney = widget.msg.getNeedMoney();
  937. if (needMoney > voucher + money) {
  938. showToast('翻译券和H币不足');
  939. return;
  940. }
  941. setState(() { // 把这条放提前放这的原因是 有记录的翻译的话 推送会比post请求先到达
  942. widget.msg.transTag = 2;
  943. });
  944. var res = await HttpUtil().getPersonalTranslate(widget.msg);
  945. if (res) {
  946. print('请求人工翻译成功,进行扣费');
  947. setState(() {
  948. SqlUtil().updateUserTranslateState(widget.msg.sessionId,
  949. widget.msg.time, widget.msg.transTag);
  950. //优先扣券
  951. if (voucher > 0) {
  952. int costQuan = min(voucher, needMoney);
  953. Provider.of<VoucherChangeProvider>(context,
  954. listen: false)
  955. .subVoucher(costQuan);
  956. }
  957. //不足的话再扣H币
  958. if (needMoney > voucher) {
  959. Provider.of<MoneyChangeProvider>(context, listen: false)
  960. .subMoney(needMoney - voucher);
  961. }
  962. });
  963. }
  964. });
  965. machineTranslateWidget = _translateItemWidget(
  966. 0xe671,
  967. I18n.of(context).robot_retranslate,
  968. textList.length <= 1
  969. ? null
  970. : () {
  971. setState(() {
  972. curTextType += 1;
  973. curTextType %= textList.length;
  974. });
  975. });
  976. } else if (transTag == 5 ) {
  977. //人工翻译失败
  978. userTranslateWidget = _translateItemWidget(0xe670, '人工翻译失败', null);
  979. machineTranslateWidget =
  980. _translateItemWidget(0xe671, I18n.of(context).robot_retranslate, () {
  981. setState(() {
  982. curTextType += 1;
  983. curTextType %= textList.length;
  984. });
  985. });
  986. } else if (transTag == 4 || transTag == 10 || transTag == 6) {
  987. //4人工翻译完成,未评论 10人工翻译完成已评论 6翻译点跳过相当于翻译完成
  988. userTranslateWidget = InkWell(
  989. onTap: () {
  990. setState(() {
  991. curTextType = 0;
  992. });
  993. },
  994. child: Container(
  995. width: width / 2,
  996. child: Row(
  997. children: <Widget>[
  998. InkWell(
  999. child: Icon(
  1000. IconData(0xe641, fontFamily: Constants.IconFontFamily),
  1001. size: 18,
  1002. color:
  1003. transTag == 10 ? Colors.grey : Color(0xFF087FF3)),
  1004. onTap: transTag == 10
  1005. ? null
  1006. : () {
  1007. CustomUI.showIosDialog(
  1008. context, I18n.of(context).bad_ev, () async {
  1009. bool isSuccess = await rateTranslateResult();
  1010. if (isSuccess) {
  1011. Navigator.of(context).pop(true);
  1012. showToast(I18n.of(context).success);
  1013. } else {
  1014. showToast(I18n.of(context).fail);
  1015. Navigator.of(context).pop();
  1016. }
  1017. }, () {
  1018. Navigator.of(context).pop();
  1019. });
  1020. },
  1021. ),
  1022. SizedBox(width: 5),
  1023. Expanded(
  1024. child: SizedBox(
  1025. child: Text(
  1026. I18n.of(context).over,
  1027. style: TextStyle(color: Color(0xFF087FF3), fontSize: 10),
  1028. textScaleFactor: 1.0,
  1029. maxLines: 1,
  1030. overflow: TextOverflow.ellipsis,
  1031. ),
  1032. ))
  1033. ],
  1034. )));
  1035. machineTranslateWidget =
  1036. _translateItemWidget(0xe675, I18n.of(context).see_original, () {
  1037. setState(() {
  1038. curTextType = textList.length - 1;
  1039. });
  1040. });
  1041. }
  1042. return Container(
  1043. height: 26,
  1044. alignment: Alignment.center,
  1045. child: Row(
  1046. children: <Widget>[
  1047. userTranslateWidget,
  1048. Expanded(
  1049. child: SizedBox(child: VerticalDivider(), height: 20, width: 2)),
  1050. machineTranslateWidget
  1051. ],
  1052. ),
  1053. );
  1054. }
  1055. _receiveImg(BuildContext context, List<int> imgData, {String downloadData}) {
  1056. // ImageProvider provider = MemoryImage(Uint8List.fromList(imgData));
  1057. ImageProvider provider = MemoryImage(widget.msg.localFile == null
  1058. ? Uint8List.fromList(imgData)
  1059. : File(widget.msg.localFile).readAsBytesSync());
  1060. var imgSize = _getImgSize();
  1061. return DownloadItem(
  1062. isAutoDown: false,
  1063. msg: widget.msg,
  1064. onFinishTap: () {
  1065. widget.hideKeyboard();
  1066. showFullImg(context, widget.msg);
  1067. },
  1068. child: Container(
  1069. alignment: Alignment.centerLeft,
  1070. width: imgSize.width,
  1071. height: imgSize.height,
  1072. child: ClipRRect(
  1073. child: Image(
  1074. image: provider ?? AssetImage(R.assetsImagesIcAlbum),
  1075. ),
  1076. borderRadius: BorderRadius.circular(5),
  1077. ),
  1078. ),
  1079. );
  1080. }
  1081. _receiveVideo(BuildContext context, List<int> imgData,
  1082. {String downloadData}) {
  1083. ImageProvider provider = MemoryImage(Uint8List.fromList(imgData));
  1084. var imgSize = _getImgSize();
  1085. return InkWell(
  1086. onTap: () {
  1087. if (widget.msg.localFile != null) {
  1088. showVideoPage(context, widget.msg.localFile);
  1089. }
  1090. },
  1091. child: DownloadItem(
  1092. isAutoDown: false,
  1093. msg: widget.msg,
  1094. child: Container(
  1095. width: imgSize.width,
  1096. height: imgSize.height,
  1097. child: ClipRRect(
  1098. child: Image(
  1099. image: provider ?? AssetImage(R.assetsImagesIcAlbum),
  1100. ),
  1101. borderRadius: BorderRadius.circular(5),
  1102. ),
  1103. ),
  1104. ));
  1105. }
  1106. showVideoPage(BuildContext context, String filePath) {
  1107. widget.hideKeyboard();
  1108. Navigator.push(context,
  1109. MaterialPageRoute<void>(builder: (BuildContext context) {
  1110. return VideoPage(videoPath: filePath);
  1111. }));
  1112. }
  1113. _receiveSound(BuildContext context, List<int> soundData) {
  1114. print(' build 收到的语音消息');
  1115. MsgModel msg = widget.msg;
  1116. var time = widget.msg.extraInfo / 1000;
  1117. if (time > 60) {
  1118. time = 60.0;
  1119. }
  1120. bool isPlaying = false;
  1121. if (curSoundUrl != null) {
  1122. isPlaying = SoundUtils().isPlaying(curSoundUrl);
  1123. }
  1124. var soundWidget = InkWell(
  1125. onTap: () async {
  1126. bool isLocal = true;
  1127. if (msg.localFile != null) {
  1128. isLocal = true;
  1129. curSoundUrl = msg.localFile;
  1130. } else {
  1131. isLocal = false;
  1132. var sessionId = msg.sessionId;
  1133. curSoundUrl = UploadUtil()
  1134. .getFullUrl(msg.extraFile, sessionId, msg.channelType);
  1135. }
  1136. print('当前文件$curSoundUrl 本地?$isLocal');
  1137. if (isPlaying) {
  1138. await SoundUtils().pause();
  1139. } else {
  1140. print('开始播放');
  1141. if (widget.msg.soundListened == 0) {
  1142. widget.msg.updateSoundListened();
  1143. }
  1144. await SoundUtils().play(curSoundUrl, isLocal: isLocal, onPlayed: () {
  1145. if (mounted) {
  1146. this.setState(() {});
  1147. }
  1148. }, complete: () {
  1149. if (mounted) {
  1150. this.setState(() {});
  1151. }
  1152. });
  1153. }
  1154. },
  1155. child: Container(
  1156. width: 130,
  1157. child: Row(children: <Widget>[
  1158. Container(
  1159. alignment: Alignment.center,
  1160. padding: EdgeInsets.only(bottom: 2),
  1161. margin: EdgeInsets.only(right: 10),
  1162. width: 25.5,
  1163. height: 25.5,
  1164. decoration: BoxDecoration(
  1165. border:
  1166. Border.all(color: const Color(0xFF1B92C7), width: 0.5),
  1167. color: const Color(0xFF04A4FE),
  1168. shape: BoxShape.circle),
  1169. child: Icon(
  1170. IconData(isPlaying ? 0xe652 : 0xe653,
  1171. fontFamily: Constants.IconFontFamily),
  1172. size: isPlaying ? 15 : 18,
  1173. color: Colors.white,
  1174. ),
  1175. ),
  1176. isPlaying
  1177. ? Stack(
  1178. children: <Widget>[
  1179. Container(
  1180. height: 18,
  1181. width: 19,
  1182. ),
  1183. Positioned(
  1184. bottom: 0,
  1185. child: VideoAnim(
  1186. begin: 18,
  1187. start: 0.444,
  1188. end: 4.5,
  1189. )),
  1190. Positioned(
  1191. left: 7,
  1192. bottom: 0,
  1193. child: VideoAnim(
  1194. begin: 4.5,
  1195. end: 18,
  1196. )),
  1197. Positioned(
  1198. left: 14,
  1199. bottom: 0,
  1200. child: VideoAnim(
  1201. begin: 18,
  1202. end: 4.5,
  1203. ))
  1204. ],
  1205. )
  1206. : Stack(
  1207. children: <Widget>[
  1208. Container(
  1209. height: 18,
  1210. width: 19,
  1211. ),
  1212. Positioned(
  1213. bottom: 0, child: CustomUI.buildAudioContaniner(12)),
  1214. Positioned(
  1215. left: 7,
  1216. bottom: 0,
  1217. child: CustomUI.buildAudioContaniner(4.5)),
  1218. Positioned(
  1219. left: 14,
  1220. bottom: 0,
  1221. child: CustomUI.buildAudioContaniner(18))
  1222. ],
  1223. ),
  1224. Expanded(child: SizedBox()),
  1225. fixedText(time.toStringAsFixed(0),
  1226. color: Constants.BlackTextColor, fontSize: 16)
  1227. ])),
  1228. );
  1229. List<Widget> showMsg = [];
  1230. showMsg.add(DownloadItem(
  1231. msg: widget.msg,
  1232. child: soundWidget,
  1233. isShowProgress: false,
  1234. ));
  1235. double width = 130;
  1236. double minWidth = 0;
  1237. if (textList.length > 0 && textList[curTextType].length > 0) {
  1238. width = _getTextWidth(textList[curTextType]) + 20;
  1239. width = min(width, Screen.width - 120);
  1240. minWidth = max(width, 150);
  1241. if (width < 130) {
  1242. width = 130;
  1243. }
  1244. showMsg.add(Padding(
  1245. padding: EdgeInsets.symmetric(vertical: 5),
  1246. child: Divider(
  1247. height: 1,
  1248. )));
  1249. showMsg.add(Container(
  1250. child: extendedText(
  1251. textList[curTextType],
  1252. color: Constants.BlackTextColor,
  1253. hideKeyboard: widget.hideKeyboard,
  1254. fontSize: FontSize,
  1255. ),
  1256. alignment: Alignment.centerLeft,
  1257. constraints:
  1258. BoxConstraints(maxWidth: Screen.width - 120, minHeight: 22),
  1259. ));
  1260. }
  1261. if (msg.transTag != 0) {
  1262. minWidth = 200;
  1263. showMsg.add(Divider(color: Color(0xFFECECEC), height: 3));
  1264. Widget tranWidget = _transProcessWidget(msg.transTag);
  1265. showMsg.add(tranWidget);
  1266. }
  1267. return Container(
  1268. width: width + 20,
  1269. constraints:
  1270. msg.transTag != 0 ? BoxConstraints(minWidth: minWidth) : null,
  1271. child: Column(
  1272. crossAxisAlignment: CrossAxisAlignment.start, children: showMsg),
  1273. padding: EdgeInsets.symmetric(horizontal: 9, vertical: 10.5),
  1274. decoration: BoxDecoration(
  1275. color: Colors.white,
  1276. border: Border.all(color: ReciveBorderColor, width: 0.5),
  1277. borderRadius: BorderRadius.all(Radius.circular(ChatRadius))),
  1278. );
  1279. }
  1280. void showFullImg(BuildContext context, MsgModel msg) {
  1281. print('显示图片');
  1282. Navigator.push(context,
  1283. MaterialPageRoute<void>(builder: (BuildContext context) {
  1284. return PhotoPage(msg: msg);
  1285. }));
  1286. }
  1287. _reveiveMsg(BuildContext context) {
  1288. Widget item;
  1289. switch (ChatType.valueOf(widget.msg.msgType)) {
  1290. case ChatType.TextChatType:
  1291. item = _receiveText(widget.msg);
  1292. break;
  1293. case ChatType.EmoticonType:
  1294. item = _receiveJIF(widget.msg);
  1295. break;
  1296. case ChatType.ImageChatType:
  1297. if (widget.msg.extraFile != null) {
  1298. item = _receiveImg(context, widget.msg.msgContent,
  1299. downloadData: widget.msg.extraFile);
  1300. } else {
  1301. item = _receiveImg(context, widget.msg.msgContent);
  1302. }
  1303. break;
  1304. case ChatType.ShortVideoChatType:
  1305. item = _receiveVideo(context, widget.msg.msgContent,
  1306. downloadData: widget.msg.extraFile);
  1307. break;
  1308. case ChatType.ShortVoiceChatType:
  1309. item = _receiveSound(context, widget.msg.msgContent);
  1310. break;
  1311. case ChatType.PlaceChatType:
  1312. item = PlaceItem(isMe: false, placeContent: widget.msg.msgContent);
  1313. break;
  1314. case ChatType.FileChatType:
  1315. item = _receiveFileMsgItem();
  1316. break;
  1317. default:
  1318. }
  1319. return wrapItemWithMenu(item);
  1320. }
  1321. Widget _receiveFileMsgItem() {
  1322. return DownloadItem(
  1323. isAutoDown: false,
  1324. msg: widget.msg,
  1325. onComplete: () {
  1326. if (mounted) {
  1327. setState(() {});
  1328. }
  1329. },
  1330. child: Container(
  1331. height: 100,
  1332. constraints: BoxConstraints(maxWidth: Screen.width - 120),
  1333. padding: EdgeInsets.symmetric(horizontal: 9, vertical: 10.5),
  1334. decoration: BoxDecoration(
  1335. color: Colors.white,
  1336. border: Border.all(color: ReciveBorderColor, width: 0.5),
  1337. borderRadius: BorderRadius.all(Radius.circular(ChatRadius))),
  1338. child: FileMsgItem(widget.msg)));
  1339. }
  1340. Widget _getReceivedMessageLayout(BuildContext context) {
  1341. bool hasHeadImg = true;
  1342. var memberModel = widget.memberModel;
  1343. if (memberModel == null) {
  1344. return Container();
  1345. }
  1346. if (memberModel.avtar == null || memberModel.avtar.length == 0) {
  1347. hasHeadImg = false;
  1348. }
  1349. GroupInfoModel infoModel = Provider.of<GroupInfoModel>(context);
  1350. var refName = Provider.of<RefNameProvider>(context)
  1351. .getGroupRefName(infoModel.sessionId, memberModel.memberId);
  1352. bool isShowSoundSate =
  1353. widget.msg.msgType == ChatType.ShortVoiceChatType.value &&
  1354. widget.msg.soundListened == 0;
  1355. return Row(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
  1356. Container(
  1357. margin: const EdgeInsets.only(right: 8.0),
  1358. child: GestureDetector(
  1359. child: ClipRRect(
  1360. borderRadius: BorderRadius.circular(8),
  1361. child: hasHeadImg
  1362. ? CachedNetworkImage(
  1363. imageUrl: memberModel.avtar,
  1364. placeholder: (context, url) => Image.asset(
  1365. Constants.DefaultHeadImgUrl,
  1366. width: 40,
  1367. height: 40,
  1368. ),
  1369. width: 40,
  1370. height: 40,
  1371. )
  1372. : SizedBox(
  1373. width: 40,
  1374. height: 40,
  1375. child: Image.asset(R.assetsImagesDefaultNorAvatar))),
  1376. onTap: () {
  1377. AppNavigator.pushProfileInfoPage(context, memberModel.memberId,
  1378. fromWhere: 2,
  1379. addMode: !FriendListMgr().isMyFriend(memberModel.memberId)
  1380. ? 1
  1381. : 0);
  1382. },
  1383. onLongPress: () {
  1384. print('long press user');
  1385. MessageMgr().emit('Alter User Message', memberModel);
  1386. },
  1387. )),
  1388. infoModel.isShowName > 0
  1389. ? Column(
  1390. crossAxisAlignment: CrossAxisAlignment.start,
  1391. children: <Widget>[
  1392. Container(
  1393. padding: EdgeInsets.only(left: 9),
  1394. child: fixedText(refName, fontSize: 12, color: Colors.grey),
  1395. ),
  1396. SizedBox(height: 2),
  1397. _reveiveMsg(context),
  1398. ],
  1399. )
  1400. : _reveiveMsg(context),
  1401. isShowSoundSate
  1402. ? Container(
  1403. margin: EdgeInsets.only(
  1404. left: 8, top: infoModel.isShowName > 0 ? 38 : 20),
  1405. child: CircleAvatar(
  1406. radius: 3.5,
  1407. backgroundColor: Colors.red,
  1408. ))
  1409. : Container()
  1410. ]);
  1411. }
  1412. }