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.
 
 
 
 
 
 

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