Hibok
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

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