Hibok
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

939 rindas
33 KiB

  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'dart:typed_data';
  4. import 'package:chat/chat/keyboard_icon.dart';
  5. import 'package:chat/chat/record_view.dart';
  6. import 'package:chat/chat/util_keyboard.dart';
  7. import 'package:chat/data/UserData.dart';
  8. import 'package:chat/data/constants.dart';
  9. import 'package:chat/generated/i18n.dart';
  10. import 'package:chat/home/alter_select_view.dart';
  11. import 'package:chat/models/ChatMsg.dart';
  12. import 'package:chat/models/group_info_model.dart';
  13. import 'package:chat/models/keyboard_provider.dart';
  14. import 'package:chat/proto/all.pbserver.dart';
  15. import 'package:chat/utils/CustomUI.dart';
  16. import 'package:chat/utils/MessageMgr.dart';
  17. import 'package:chat/utils/file_cache_mgr.dart';
  18. import 'package:chat/utils/group_member_model.dart';
  19. import 'package:chat/utils/image_util.dart';
  20. import 'package:chat/utils/keyboard_utils.dart';
  21. import 'package:chat/utils/msgHandler.dart';
  22. import 'package:chat/utils/screen.dart';
  23. import 'package:chat/utils/sound_util.dart';
  24. import 'package:flutter/material.dart';
  25. import 'package:flutter/services.dart';
  26. import 'package:flutter_screenutil/flutter_screenutil.dart';
  27. import 'package:multi_image_picker/multi_image_picker.dart';
  28. import 'package:oktoast/oktoast.dart';
  29. import 'package:provider/provider.dart';
  30. import 'package:shared_preferences/shared_preferences.dart';
  31. import 'emoji_gif_text.dart';
  32. import 'emoji_text.dart';
  33. class InputBar extends StatefulWidget {
  34. final Function sendMsg;
  35. final bool isTranslateHK;
  36. InputBar({this.sendMsg,this.isTranslateHK=false});
  37. @override
  38. InputBarState createState() => InputBarState();
  39. }
  40. class InputBarState extends State<InputBar>
  41. with SingleTickerProviderStateMixin {
  42. final TextEditingController _textCtrl = TextEditingController();
  43. FocusNode editFocus = NoKeyboardEditableTextFocusNode();
  44. bool _isComposingMessage = false;
  45. PageController pageController;
  46. double keyboardHeight;
  47. KeyboardBloc _bloc = KeyboardBloc();
  48. GlobalKey _key = GlobalKey();
  49. int currentStickersPage = 0;
  50. //回复相关
  51. MsgModel refMsg;
  52. //@成员数组
  53. List<GroupMemberModel> alterMemberList = [];
  54. int lastTxtLen = 0;
  55. @override
  56. void initState() {
  57. super.initState();
  58. print('~~~~~~~~~~inputbar initState~~~~~~~~~~~');
  59. pageController = new PageController();
  60. getKeyboardHeight();
  61. _bloc.start();
  62. //处理引用事件
  63. MessageMgr().on('Reply Select Message', replySelectMsg);
  64. //处理@事件
  65. MessageMgr().on('Alter User Message', alterOtherMember);
  66. }
  67. @override
  68. void didChangeDependencies() {
  69. super.didChangeDependencies();
  70. editFocus?.requestFocus();
  71. }
  72. //获取键盘高度,之前保存的
  73. getKeyboardHeight() async {
  74. var sp = await SharedPreferences.getInstance();
  75. keyboardHeight = sp.getDouble(Constants.KeyboardHeight);
  76. if (keyboardHeight == null || keyboardHeight < 100) {
  77. keyboardHeight = 280;
  78. }
  79. }
  80. @override
  81. void dispose() {
  82. _key = null;
  83. _textCtrl.dispose();
  84. _bloc.dispose();
  85. editFocus.dispose();
  86. editFocus = null;
  87. MessageMgr().off('Reply Select Message', replySelectMsg);
  88. MessageMgr().off('Alter User Message', alterOtherMember);
  89. super.dispose();
  90. }
  91. //引用某句话
  92. replySelectMsg(args) async {
  93. refMsg = args;
  94. print('处理引用消息');
  95. setState(() {
  96. showKeyBoard();
  97. });
  98. }
  99. //快捷@某成员
  100. alterOtherMember(memberInfo) {
  101. if (!alterMemberList.contains(memberInfo)) {
  102. alterMemberList.add(memberInfo);
  103. }
  104. print('选中的成员~~~~~~~~~~~~ ${memberInfo.refName}');
  105. String textStr;
  106. if (_textCtrl.text.length > 0) {
  107. textStr = '${_textCtrl.text} @${memberInfo.refName} ';
  108. } else {
  109. textStr = '@${memberInfo.refName} ';
  110. }
  111. _textCtrl.value = TextEditingValue(
  112. text: textStr,
  113. selection:
  114. TextSelection.fromPosition(TextPosition(offset: textStr.length)));
  115. setState(() {
  116. showKeyBoard();
  117. _isComposingMessage = _textCtrl.text.length > 0;
  118. });
  119. }
  120. //显示键盘
  121. showKeyBoard() {
  122. Provider.of<KeyboardIndexProvider>(context, listen: false)
  123. .changeSelectIndex(0);
  124. editFocus.requestFocus();
  125. Provider.of<KeyboardIndexProvider>(context, listen: false)
  126. .changeReadOnlyKey(false);
  127. // SystemChannels.textInput.invokeMethod('TextInput.show');
  128. }
  129. _getRefShortText() {
  130. if (refMsg == null) {
  131. return null;
  132. }
  133. String desc = '';
  134. if (refMsg == null || refMsg.msgType == null) {
  135. return '';
  136. }
  137. switch (ChatType.valueOf(refMsg.msgType)) {
  138. case ChatType.TextChatType:
  139. desc = utf8.decode(refMsg.msgContent);
  140. break;
  141. case ChatType.EmoticonType:
  142. desc = '[${I18n.of(context).emoji}]';
  143. break;
  144. case ChatType.ImageChatType:
  145. desc = '[${I18n.of(context).picture}]';
  146. break;
  147. case ChatType.ShortVideoChatType:
  148. desc = '[${I18n.of(context).video}]';
  149. break;
  150. case ChatType.PlaceChatType:
  151. desc = '[${I18n.of(context).locate}]';
  152. break;
  153. case ChatType.ShortVoiceChatType:
  154. desc = '[${I18n.of(context).voice}]';
  155. break;
  156. case ChatType.GiftChatType:
  157. GiftChat giftChat = GiftChat.fromBuffer(refMsg.msgContent);
  158. if (giftChat.tuId == UserData().basicInfo.userId) {
  159. desc = I18n.of(context).you_get;
  160. } else {
  161. desc = I18n.of(context).you_give;
  162. }
  163. break;
  164. case ChatType.RedWalletChatType:
  165. desc = '[${I18n.of(context).red_money}]';
  166. break;
  167. case ChatType.GroupChatNoticeType:
  168. desc = '[${I18n.of(context).msg_notice}]';
  169. break;
  170. case ChatType.FileChatType:
  171. desc = '[${I18n.of(context).file}]';
  172. break;
  173. default:
  174. }
  175. GroupInfoModel groupInfoModel = Provider.of<GroupInfoModel>(context);
  176. var member = groupInfoModel.getMember(refMsg.from);
  177. return '${member.refName}: $desc';
  178. }
  179. bool isReceiver = false;
  180. @override
  181. Widget build(BuildContext context) {
  182. int curKeyboardIndex =
  183. Provider.of<KeyboardIndexProvider>(context).curKeyboardIndex;
  184. bool readOnly =
  185. Provider.of<KeyboardIndexProvider>(context, listen: false).readOnly;
  186. bool isGroup = Provider.of<bool>(context);
  187. Widget centerWidget;
  188. Widget input = Container(
  189. child:
  190. TextField(
  191. // textSelectionControls: ExtendedMaterialTextSelectionControls(),
  192. keyboardAppearance: Brightness.light,
  193. onChanged: (String messageText) {
  194. if (_textCtrl.text.length > 0) {
  195. var last = messageText.substring(_textCtrl.text.length - 1);
  196. if (last == '@' && _textCtrl.text.length > lastTxtLen) {
  197. editFocus.unfocus();
  198. _openAlterSelectPage();
  199. }
  200. }
  201. lastTxtLen = _textCtrl.text.length;
  202. setState(() {
  203. _isComposingMessage = _textCtrl.text.length > 0;
  204. });
  205. },
  206. key: _key,
  207. readOnly: readOnly,
  208. autofocus: true,
  209. cursorColor: Constants.BlueTextColor,
  210. style: TextStyle(
  211. fontSize: ScreenUtil().setSp(16),
  212. textBaseline: TextBaseline.alphabetic),
  213. maxLines: 3,
  214. minLines: 1,
  215. // specialTextSpanBuilder: MySpecialTextSpanBuilder(
  216. // showAtBackground: true,
  217. // ),
  218. controller: _textCtrl,
  219. textInputAction: TextInputAction.newline,
  220. inputFormatters: <TextInputFormatter>[
  221. LengthLimitingTextInputFormatter(600) //限制长度
  222. ],
  223. onSubmitted: _textMessageSubmitted,
  224. focusNode: editFocus,
  225. onTap: () {
  226. showKeyBoard();
  227. Provider.of<KeyboardIndexProvider>(context, listen: false)
  228. .changeReadOnlyKey(false);
  229. },
  230. decoration: InputDecoration(
  231. hintText: I18n.of(context).input_content,
  232. hintStyle: TextStyle(color: const Color(0xffBDBDBD), fontSize: 16),
  233. border: null,
  234. hintMaxLines: 1,
  235. contentPadding: EdgeInsets.only(left: 5, right: 5, top: 8, bottom: 8),
  236. ),
  237. ),
  238. );
  239. if (refMsg == null) {
  240. centerWidget = input;
  241. } else {
  242. var desc = _getRefShortText();
  243. centerWidget = Column(
  244. crossAxisAlignment: CrossAxisAlignment.start,
  245. children: <Widget>[
  246. Container(
  247. child: Row(mainAxisSize: MainAxisSize.min, children: [
  248. Container(
  249. child: Text(
  250. desc,
  251. maxLines: 1,
  252. overflow: TextOverflow.ellipsis,
  253. textScaleFactor: 1.0,
  254. ),
  255. constraints: BoxConstraints(maxWidth: Screen.width - 220),
  256. ),
  257. InkWell(
  258. child: Container(
  259. child: Icon(Icons.close, size: 10),
  260. padding: EdgeInsets.fromLTRB(10, 5, 5, 5),
  261. ),
  262. onTap: () {
  263. refMsg = null;
  264. setState(() {});
  265. },
  266. )
  267. ]),
  268. padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
  269. decoration: BoxDecoration(
  270. color: Colors.grey[200],
  271. border: Border.all(color: Colors.grey),
  272. borderRadius: BorderRadius.circular(10))),
  273. input
  274. ],
  275. );
  276. }
  277. return GestureDetector(
  278. onTap: () {
  279. print('放置触控隐藏键盘');
  280. },
  281. child: Container(
  282. width: Screen.width,
  283. color: Colors.white,
  284. child: Column(
  285. children: <Widget>[
  286. Container(
  287. padding: EdgeInsets.symmetric(horizontal: 7, vertical: 7),
  288. alignment: Alignment.topCenter,
  289. decoration: BoxDecoration(
  290. color: Colors.white,
  291. border: Border(top: BorderSide(color: Color(0xFFDFDFDF)))),
  292. child: Row(
  293. children: <Widget>[
  294. //emoji图标
  295. KeyboardIcon(
  296. iconCode: 0xe64d,
  297. selectIconCode: 0xe651,
  298. isSelect: curKeyboardIndex == 1,
  299. size: 27,
  300. onTap: () {
  301. isReceiver = !isReceiver;
  302. SoundUtils.instance.setReceiver(isReceiver);
  303. //
  304. if (curKeyboardIndex == 1) {
  305. Provider.of<KeyboardIndexProvider>(context,
  306. listen: false)
  307. .changeReadOnlyKey(false);
  308. showKeyBoard();
  309. } else {
  310. Provider.of<KeyboardIndexProvider>(context,
  311. listen: false)
  312. .changeSelectIndex(1);
  313. currentStickersPage = 0;
  314. }
  315. }),
  316. SizedBox(width: 10),
  317. //输入框
  318. Expanded(child: centerWidget), SizedBox(width: 10),
  319. _isComposingMessage
  320. ? InkWell(
  321. child: Padding(
  322. padding: EdgeInsets.fromLTRB(50, 2, 10, 2),
  323. child: Icon(
  324. Icons.send,
  325. color: Color(0xFF087FF3),
  326. size: 28,
  327. )),
  328. onTap: _sendTextMessage)
  329. : Container(
  330. child: Row(
  331. children: <Widget>[
  332. KeyboardIcon(
  333. iconCode: 0xe64b,
  334. isSelect: curKeyboardIndex == 2,
  335. size: 28,
  336. onTap: () {
  337. if (curKeyboardIndex == 2) {
  338. showKeyBoard();
  339. } else {
  340. Provider.of<KeyboardIndexProvider>(
  341. context,
  342. listen: false)
  343. .changeSelectIndex(2);
  344. }
  345. }),
  346. SizedBox(width: 10),
  347. KeyboardIcon(
  348. iconCode: 0xe64f,
  349. isSelect: curKeyboardIndex == 3,
  350. size: 28,
  351. onTap: () {
  352. if (curKeyboardIndex == 3) {
  353. showKeyBoard();
  354. } else {
  355. Provider.of<KeyboardIndexProvider>(
  356. context,
  357. listen: false)
  358. .changeSelectIndex(3);
  359. }
  360. }),
  361. SizedBox(width: 10),
  362. KeyboardIcon(
  363. iconCode: 0xe60c,
  364. isSelect: curKeyboardIndex == 4,
  365. size: 26,
  366. onTap: () {
  367. _openPhotoView();
  368. }),
  369. ],
  370. ),
  371. )
  372. ],
  373. ),
  374. ),
  375. Divider(height: 1, color: const Color(0xffE0E0E0)),
  376. StreamBuilder(
  377. stream: _bloc.stream,
  378. builder: (BuildContext context, AsyncSnapshot snapshot) {
  379. double keyHeight = MediaQuery.of(context).viewInsets.bottom;
  380. if (keyHeight > 10) {
  381. keyboardHeight = keyHeight;
  382. UserData().setKeyboardHeight(keyHeight);
  383. }
  384. return Container(
  385. width: double.infinity,
  386. color: Colors.white,
  387. height: curKeyboardIndex == -1 || curKeyboardIndex == 4
  388. ? 0
  389. : keyboardHeight,
  390. child: curKeyboardIndex >= 1 && curKeyboardIndex < 4
  391. ? IndexedStack(
  392. children: <Widget>[
  393. Container(
  394. color: Colors.white,
  395. width: double.infinity,
  396. height: double.infinity,
  397. child: InkWell(
  398. onTap: () {},
  399. child: Container(
  400. height: keyboardHeight,
  401. child: Column(
  402. children: <Widget>[
  403. Container(
  404. height: keyboardHeight - 50,
  405. child: PageView.custom(
  406. controller: pageController,
  407. onPageChanged: (page) {
  408. setState(() {
  409. currentStickersPage =
  410. page;
  411. });
  412. },
  413. childrenDelegate:
  414. new SliverChildBuilderDelegate(
  415. (context, index) {
  416. return index == 0
  417. ? buildEmojiGird()
  418. : buildGifGird();
  419. },
  420. childCount: 2,
  421. )),
  422. ),
  423. Divider(
  424. height: 1,
  425. color: Color(0xffE0E0E0),
  426. ),
  427. Container(
  428. height: 49,
  429. child: Row(
  430. children: <Widget>[
  431. InkWell(
  432. child: Container(
  433. width: 59,
  434. padding:
  435. EdgeInsets.all(10),
  436. color:
  437. currentStickersPage ==
  438. 0
  439. ? const Color(
  440. 0xFFEDEDED)
  441. : Colors.white,
  442. child: Image.asset(
  443. 'assets/images/chat/emoji.png'),
  444. ),
  445. onTap: () {
  446. pageController
  447. .jumpToPage(0);
  448. },
  449. ),
  450. InkWell(
  451. child: Container(
  452. padding:
  453. EdgeInsets.all(8),
  454. width: 59,
  455. color:
  456. currentStickersPage ==
  457. 1
  458. ? const Color(
  459. 0xFFEDEDED)
  460. : Colors.white,
  461. child: Image.asset(
  462. 'assets/images/chat/onion.png'),
  463. ),
  464. onTap: () {
  465. pageController
  466. .jumpToPage(1);
  467. },
  468. )
  469. ],
  470. ),
  471. ),
  472. ],
  473. ),
  474. ),
  475. )),
  476. UtilKeyboard(
  477. keyboardHeight: keyboardHeight,
  478. isGroup: isGroup,
  479. sendMsg: widget.sendMsg),
  480. RecordView(
  481. keyboardHeight: keyboardHeight,
  482. sendMsg: _sendSoundMsg),
  483. ],
  484. index: curKeyboardIndex - 1,
  485. )
  486. : Container());
  487. },
  488. )
  489. ],
  490. )),
  491. );
  492. }
  493. Widget buildEmojiGird() {
  494. return Container(
  495. height: keyboardHeight,
  496. child: Stack(
  497. children: <Widget>[
  498. Padding(
  499. padding: EdgeInsets.fromLTRB(5, 8, 50, 0),
  500. child: GridView.builder(
  501. controller: new ScrollController(keepScrollOffset: false),
  502. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  503. crossAxisCount: 7, crossAxisSpacing: 0, mainAxisSpacing: 0),
  504. itemBuilder: (context, index) {
  505. return GestureDetector(
  506. child: Container(
  507. padding: EdgeInsets.all(7),
  508. child: Image.asset(EmojiUitl
  509. .instance.emojiMap[EmojiText.flag + "${index + 1}]"]),
  510. ),
  511. behavior: HitTestBehavior.translucent,
  512. onTap: () {
  513. insertText(EmojiText.flag + "${index + 1}]", _textCtrl);
  514. setState(() {
  515. _isComposingMessage = _textCtrl.text.length > 0;
  516. });
  517. },
  518. );
  519. },
  520. itemCount: EmojiUitl.instance.emojiMap.length,
  521. padding: EdgeInsets.all(5.0),
  522. ),
  523. ),
  524. Positioned.fill(
  525. child: Container(
  526. padding: EdgeInsets.fromLTRB(0, 0, 0, 14),
  527. alignment: Alignment(1, 1),
  528. child: InkWell(
  529. onTap: () {
  530. deleteText(_textCtrl);
  531. setState(() {
  532. _isComposingMessage = _textCtrl.text.length > 0;
  533. });
  534. },
  535. child: Container(
  536. decoration: BoxDecoration(
  537. color: Color(0x4d0E0E10),
  538. borderRadius: BorderRadius.only(
  539. topLeft: Radius.circular(4.0),
  540. bottomLeft: Radius.circular(4))),
  541. width: 37,
  542. height: 28,
  543. child: Icon(
  544. IconData(
  545. 0xe679,
  546. fontFamily: 'iconfont',
  547. ),
  548. size: 16,
  549. color: Colors.white,
  550. ),
  551. ),
  552. ),
  553. )),
  554. ],
  555. ),
  556. );
  557. }
  558. Widget buildGifGird() {
  559. return Container(
  560. padding: EdgeInsets.fromLTRB(8, 6, 8, 0),
  561. height: keyboardHeight,
  562. child: GridView.builder(
  563. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  564. crossAxisCount: 5, crossAxisSpacing: 12.0, mainAxisSpacing: 12.0),
  565. itemBuilder: (context, index) {
  566. return GestureDetector(
  567. child: Image.asset(EmojiGifUitl
  568. .instance.emojiMap[EmojiGifText.flag + "_${index + 1}>"]),
  569. behavior: HitTestBehavior.translucent,
  570. onTap: () {
  571. _sendMessage(EmojiGifText.flag + "_${index + 1}>", true);
  572. },
  573. );
  574. },
  575. itemCount: EmojiGifUitl.instance.emojiMap.length,
  576. padding: EdgeInsets.all(5.0),
  577. ),
  578. );
  579. }
  580. void _openAlterSelectPage() async {
  581. bool isGroup = Provider.of<bool>(context);
  582. if (isGroup) {
  583. GroupInfoModel groupInfoModel = Provider.of<GroupInfoModel>(context);
  584. editFocus.unfocus();
  585. Provider.of<KeyboardIndexProvider>(context, listen: false)
  586. .changeReadOnlyKey(true);
  587. GroupMemberModel member =
  588. await AlterSelectPage.pickAlterUser(context, groupInfoModel);
  589. if (member != null) {
  590. print('选中的成员~~~~~~~~~~~~ ${member.refName}');
  591. _textCtrl.text = '${_textCtrl.text}${member.refName} ';
  592. alterMemberList.add(member);
  593. }
  594. editFocus.requestFocus();
  595. Provider.of<KeyboardIndexProvider>(context, listen: false)
  596. .changeReadOnlyKey(false);
  597. }
  598. }
  599. List<int> getAlterUsers(String messageText) {
  600. List<String> alterUserList = [];
  601. RegExp alterStr = RegExp(r'@+(\S+)');
  602. Iterable<Match> matches = alterStr.allMatches(messageText);
  603. print('~~~~~~~~~~~~~~${matches.length}~~~~~~~~~~~~~~~');
  604. for (Match m in matches) {
  605. print('~~~~~~~~~~~~~~${m.group(1)}~~~~~~~~~~~~~~~');
  606. alterUserList.add(m.group(1));
  607. }
  608. List<int> finalAlterList = [];
  609. for (var member in alterMemberList) {
  610. if (alterUserList.contains(member.refName)) {
  611. finalAlterList.add(member.memberId);
  612. print('有效成员 ${member.refName}');
  613. }
  614. }
  615. return finalAlterList;
  616. }
  617. void _openPhotoView() async {
  618. // Provider.of<KeyboardIndexProvider>(context, listen: false)
  619. // .changeSelectIndex(4);
  620. List<Asset> resultList = List<Asset>();
  621. try {
  622. resultList = await MultiImagePicker.pickImages(
  623. maxImages: 9,
  624. enableCamera: false,
  625. selectedAssets: [],
  626. cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
  627. materialOptions: MaterialOptions(
  628. actionBarColor: "#50A7F9",
  629. actionBarTitle: "Hibok",
  630. allViewTitle: "",
  631. useDetailsView: false,
  632. selectCircleStrokeColor: "#000000",
  633. ),
  634. );
  635. if (resultList != null && resultList.length > 0) {
  636. for (var i = 0; i < resultList.length; i++) {
  637. Asset photoEntity = resultList[i];
  638. ByteData byteData = await photoEntity.getByteData();
  639. File file = await FileCacheMgr().writeFile('temp-photo-${DateTime.now().millisecondsSinceEpoch}-${photoEntity.name}', byteData.buffer.asInt8List(0));
  640. _sendPhotoFile(file);
  641. }
  642. }
  643. } on Exception catch (e) {
  644. print(e.toString());
  645. }
  646. // var photos = await PhotoPicker.pickAsset(
  647. // context: context,
  648. // themeColor: Color(0xFFF0F0F0),
  649. // textColor: Color(0xFF3F3F3F),
  650. // pickType: PickType.onlyImage);
  651. //
  652. // if (photos != null && photos.length > 0) {
  653. // for (var i = 0; i < photos.length; i++) {
  654. // AssetEntity photoEntity = photos[i];
  655. // var file = await photoEntity.file;
  656. // _sendPhotoFile(file);
  657. // }
  658. // }
  659. ///防止再点键盘不谈
  660. }
  661. void _sendSoundMsg(String soundPath, int duration) {
  662. bool isGroup = Provider.of<bool>(context);
  663. int friendId = 0;
  664. if (!isGroup) {
  665. friendId = Provider.of<int>(context);
  666. }
  667. ChatChannelType channelType =isGroup ? ChatChannelType.Group : ChatChannelType.Session;
  668. if(widget.isTranslateHK){
  669. channelType = ChatChannelType.TransHK;
  670. print('聊天是 TransHK');
  671. }
  672. print('群聊模式 $isGroup');
  673. var msg = MsgHandler.createSendMsg(
  674. ChatType.ShortVoiceChatType, Uint8List(0),
  675. localFile: soundPath,
  676. friendId: friendId,
  677. extra: duration,
  678. channelType: channelType);
  679. widget.sendMsg(msg);
  680. }
  681. void _sendPhotoFile(File imgFile) async {
  682. var imgSize = await imgFile.length();
  683. print('图片大小:${imgSize / 1024}KB');
  684. var sendImg;
  685. if (imgSize > 33 * 1024 * 1024) {
  686. showToast(I18n.of(context).video_more_big);
  687. return;
  688. }
  689. bool isNeedUpload = false;
  690. if (imgSize > ImgSizeLimit) {
  691. print('图片大于 $ImgSizeLimit,压缩');
  692. //发送压缩图 WidgetUtil.getCompressImg(path,quality: 80,percentage: 80);
  693. sendImg = await WidgetUtil.getCompressImg(imgFile.absolute.path );
  694. isNeedUpload = true;
  695. } else {
  696. sendImg = imgFile.readAsBytesSync();
  697. }
  698. var rect = await WidgetUtil.getImageWH(
  699. image: Image.memory(Uint8List.fromList(sendImg)));
  700. print('图片大小 Rect : $rect');
  701. int aspectRatio = rect.width * 100 ~/ rect.height;
  702. bool isGroup = Provider.of<bool>(context);
  703. print('群聊输入模式 $isGroup');
  704. int friendId = 0;
  705. if (!isGroup) {
  706. friendId = Provider.of<int>(context);
  707. }
  708. ChatChannelType channelType =isGroup ? ChatChannelType.Group : ChatChannelType.Session;
  709. if(widget.isTranslateHK){
  710. channelType = ChatChannelType.TransHK;
  711. print('聊天是 TransHK');
  712. }
  713. var msg = MsgHandler.createSendMsg(ChatType.ImageChatType, sendImg,
  714. localFile: isNeedUpload ? imgFile.absolute.path : null,
  715. extra: aspectRatio,
  716. friendId: friendId,
  717. channelType: channelType);
  718. widget.sendMsg(msg);
  719. }
  720. Future<Null> _textMessageSubmitted(String text) async {
  721. if (!checkMessage()) {
  722. _textCtrl.clear();
  723. alterMemberList.clear();
  724. lastTxtLen = 0;
  725. return;
  726. }
  727. _textCtrl.clear();
  728. _sendMessage(text);
  729. }
  730. _sendTextMessage() {
  731. if (!checkMessage()) {
  732. return;
  733. }
  734. var sendStr = _textCtrl.text;
  735. _textCtrl.clear();
  736. _sendMessage(sendStr);
  737. }
  738. bool checkMessage() {
  739. if (_textCtrl.text.length == 0) {
  740. showToast(I18n.of(context).msg_not);
  741. return false;
  742. }
  743. return true;
  744. }
  745. _sendMessage(String messageText, [bool isGift = false]) {
  746. bool isGroup = Provider.of<bool>(context);
  747. int friendId = 0;
  748. List<int> alterUsers;
  749. if (!isGroup) {
  750. friendId = Provider.of<int>(context);
  751. } else {
  752. if (!isGift) {
  753. //检查@的人员
  754. alterUsers = getAlterUsers(messageText);
  755. }
  756. }
  757. ChatChannelType channelType =isGroup ? ChatChannelType.Group : ChatChannelType.Session;
  758. if(widget.isTranslateHK){
  759. channelType = ChatChannelType.TransHK;
  760. print('聊天是 TransHK');
  761. }
  762. MsgModel msg = MsgHandler.createSendMsg(
  763. isGift ? ChatType.EmoticonType : ChatType.TextChatType, messageText,
  764. friendId: friendId,
  765. refMsg: refMsg,
  766. refShortTxt: _getRefShortText(),
  767. altUsers: alterUsers,
  768. channelType: channelType);
  769. widget.sendMsg(msg);
  770. if (!isGift) {
  771. if (refMsg != null) {
  772. refMsg = null;
  773. }
  774. alterMemberList.clear();
  775. lastTxtLen = 0;
  776. }
  777. setState(() {
  778. _isComposingMessage = _textCtrl.text.length > 0;
  779. });
  780. }
  781. ///emoji插入表情-处理换行
  782. static void insertText(String text, TextEditingController _textCtrl) {
  783. var value = _textCtrl.value;
  784. var start = value.selection.baseOffset;
  785. var end = value.selection.extentOffset;
  786. if (value.selection.isValid) {
  787. String newText = "";
  788. if (value.selection.isCollapsed) {
  789. if (end > 0) {
  790. newText += value.text.substring(0, end);
  791. }
  792. newText += text;
  793. if (value.text.length > end) {
  794. newText += value.text.substring(end, value.text.length);
  795. }
  796. } else {
  797. newText = value.text.replaceRange(start, end, text);
  798. end = start;
  799. }
  800. _textCtrl.value = value.copyWith(
  801. text: newText,
  802. selection: value.selection.copyWith(
  803. baseOffset: end + text.length, extentOffset: end + text.length));
  804. } else {
  805. _textCtrl.value = TextEditingValue(
  806. text: text,
  807. selection:
  808. TextSelection.fromPosition(TextPosition(offset: text.length)));
  809. }
  810. }
  811. static void deleteText(TextEditingController _textController) {
  812. var value = _textController.value;
  813. var selection = value.selection;
  814. var text = value.text;
  815. String newText = '';
  816. if (selection.baseOffset != selection.extentOffset) {
  817. newText = selection.textBefore(text) + selection.textAfter(text);
  818. _textController.value = TextEditingValue(
  819. text: newText,
  820. selection: selection.copyWith(
  821. baseOffset: selection.baseOffset,
  822. extentOffset: selection.baseOffset));
  823. } else {
  824. int offsetLength = 1;
  825. String text = _textController.text;
  826. if (text.substring(text.length - 1, text.length) == ']') {
  827. ///删除表情
  828. int end = _textController.text.lastIndexOf('[');
  829. offsetLength = text.length - end;
  830. }
  831. newText = text.substring(0, selection.baseOffset - offsetLength) +
  832. selection.textAfter(text);
  833. _textController.value = TextEditingValue(
  834. text: newText,
  835. selection: selection.copyWith(
  836. baseOffset: selection.baseOffset - offsetLength,
  837. extentOffset: selection.baseOffset - offsetLength));
  838. }
  839. }
  840. }