Hibok
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

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