Hibok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

936 lines
33 KiB

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