Hibok
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

896 行
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 = '[${I18n.of(context).file}]';
  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:
  193. TextField(
  194. // textSelectionControls: ExtendedMaterialTextSelectionControls(),
  195. keyboardAppearance: Brightness.light,
  196. onChanged: (String messageText) {
  197. if (_textCtrl.text.length > 0) {
  198. var last = messageText.substring(_textCtrl.text.length - 1);
  199. if (last == '@' && _textCtrl.text.length > lastTxtLen) {
  200. editFocus.unfocus();
  201. _openAlterSelectPage();
  202. }
  203. }
  204. lastTxtLen = _textCtrl.text.length;
  205. setState(() {
  206. _isComposingMessage = _textCtrl.text.length > 0;
  207. });
  208. },
  209. key: _key,
  210. readOnly: readOnly,
  211. autofocus: true,
  212. cursorColor: Constants.BlueTextColor,
  213. style: TextStyle(
  214. fontSize: ScreenUtil().setSp(16),
  215. textBaseline: TextBaseline.alphabetic),
  216. maxLines: 3,
  217. minLines: 1,
  218. // specialTextSpanBuilder: MySpecialTextSpanBuilder(
  219. // showAtBackground: true,
  220. // ),
  221. controller: _textCtrl,
  222. textInputAction: TextInputAction.newline,
  223. inputFormatters: <TextInputFormatter>[
  224. LengthLimitingTextInputFormatter(600) //限制长度
  225. ],
  226. onSubmitted: _textMessageSubmitted,
  227. focusNode: editFocus,
  228. onTap: () {
  229. showKeyBoard();
  230. Provider.of<KeyboardIndexProvider>(context, listen: false)
  231. .changeReadOnlyKey(false);
  232. },
  233. decoration: InputDecoration(
  234. hintText: I18n.of(context).input_content,
  235. hintStyle: TextStyle(color: const Color(0xffBDBDBD), fontSize: 16),
  236. border: null,
  237. hintMaxLines: 1,
  238. contentPadding: EdgeInsets.only(left: 5, right: 5, top: 8, bottom: 8),
  239. ),
  240. ),
  241. );
  242. if (refMsg == null) {
  243. centerWidget = input;
  244. } else {
  245. var desc = _getRefShortText();
  246. centerWidget = Column(
  247. crossAxisAlignment: CrossAxisAlignment.start,
  248. children: <Widget>[
  249. Container(
  250. child: Row(mainAxisSize: MainAxisSize.min, children: [
  251. Container(
  252. child: Text(
  253. desc,
  254. maxLines: 1,
  255. overflow: TextOverflow.ellipsis,
  256. textScaleFactor: 1.0,
  257. ),
  258. constraints: BoxConstraints(maxWidth: Screen.width - 220),
  259. ),
  260. InkWell(
  261. child: Container(
  262. child: Icon(Icons.close, size: 10),
  263. padding: EdgeInsets.fromLTRB(10, 5, 5, 5),
  264. ),
  265. onTap: () {
  266. refMsg = null;
  267. setState(() {});
  268. },
  269. )
  270. ]),
  271. padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
  272. decoration: BoxDecoration(
  273. color: Colors.grey[200],
  274. border: Border.all(color: Colors.grey),
  275. borderRadius: BorderRadius.circular(10))),
  276. input
  277. ],
  278. );
  279. }
  280. return GestureDetector(
  281. onTap: () {
  282. print('放置触控隐藏键盘');
  283. },
  284. child: Container(
  285. width: Screen.width,
  286. color: Colors.white,
  287. child: Column(
  288. children: <Widget>[
  289. Container(
  290. padding: EdgeInsets.symmetric(horizontal: 7, vertical: 7),
  291. alignment: Alignment.topCenter,
  292. decoration: BoxDecoration(
  293. color: Colors.white,
  294. border: Border(top: BorderSide(color: Color(0xFFDFDFDF)))),
  295. child: Row(
  296. children: <Widget>[
  297. //emoji图标
  298. KeyboardIcon(
  299. iconCode: 0xe64d,
  300. selectIconCode: 0xe651,
  301. isSelect: curKeyboardIndex == 1,
  302. size: 27,
  303. onTap: () {
  304. isReceiver = !isReceiver;
  305. SoundUtils.instance.setReceiver(isReceiver);
  306. //
  307. if (curKeyboardIndex == 1) {
  308. Provider.of<KeyboardIndexProvider>(context,
  309. listen: false)
  310. .changeReadOnlyKey(false);
  311. showKeyBoard();
  312. } else {
  313. Provider.of<KeyboardIndexProvider>(context,
  314. listen: false)
  315. .changeSelectIndex(1);
  316. currentStickersPage = 0;
  317. }
  318. }),
  319. SizedBox(width: 10),
  320. //输入框
  321. Expanded(child: centerWidget), SizedBox(width: 10),
  322. _isComposingMessage
  323. ? InkWell(
  324. child: Padding(
  325. padding: EdgeInsets.fromLTRB(50, 2, 10, 2),
  326. child: Icon(
  327. Icons.send,
  328. color: Color(0xFF087FF3),
  329. size: 28,
  330. )),
  331. onTap: _sendTextMessage)
  332. : Container(
  333. child: Row(
  334. children: <Widget>[
  335. KeyboardIcon(
  336. iconCode: 0xe64b,
  337. isSelect: curKeyboardIndex == 2,
  338. size: 28,
  339. onTap: () {
  340. if (curKeyboardIndex == 2) {
  341. showKeyBoard();
  342. } else {
  343. Provider.of<KeyboardIndexProvider>(
  344. context,
  345. listen: false)
  346. .changeSelectIndex(2);
  347. }
  348. }),
  349. SizedBox(width: 10),
  350. KeyboardIcon(
  351. iconCode: 0xe64f,
  352. isSelect: curKeyboardIndex == 3,
  353. size: 28,
  354. onTap: () {
  355. if (curKeyboardIndex == 3) {
  356. showKeyBoard();
  357. } else {
  358. Provider.of<KeyboardIndexProvider>(
  359. context,
  360. listen: false)
  361. .changeSelectIndex(3);
  362. }
  363. }),
  364. SizedBox(width: 10),
  365. KeyboardIcon(
  366. iconCode: 0xe60c,
  367. isSelect: curKeyboardIndex == 4,
  368. size: 26,
  369. onTap: () {
  370. _openPhotoView();
  371. }),
  372. ],
  373. ),
  374. )
  375. ],
  376. ),
  377. ),
  378. Divider(height: 1, color: const Color(0xffE0E0E0)),
  379. StreamBuilder(
  380. stream: _bloc.stream,
  381. builder: (BuildContext context, AsyncSnapshot snapshot) {
  382. double keyHeight = MediaQuery.of(context).viewInsets.bottom;
  383. if (keyHeight > 10) {
  384. keyboardHeight = keyHeight;
  385. UserData().setKeyboardHeight(keyHeight);
  386. }
  387. return Container(
  388. width: double.infinity,
  389. color: Colors.white,
  390. height: curKeyboardIndex == -1 || curKeyboardIndex == 4
  391. ? 0
  392. : keyboardHeight,
  393. child: curKeyboardIndex >= 1 && curKeyboardIndex < 4
  394. ? IndexedStack(
  395. children: <Widget>[
  396. Container(
  397. color: Colors.white,
  398. width: double.infinity,
  399. height: double.infinity,
  400. child: InkWell(
  401. onTap: () {},
  402. child: Container(
  403. height: keyboardHeight,
  404. child: Column(
  405. children: <Widget>[
  406. Container(
  407. height: keyboardHeight - 50,
  408. child: PageView.custom(
  409. controller: pageController,
  410. onPageChanged: (page) {
  411. setState(() {
  412. currentStickersPage =
  413. page;
  414. });
  415. },
  416. childrenDelegate:
  417. new SliverChildBuilderDelegate(
  418. (context, index) {
  419. return index == 0
  420. ? buildEmojiGird()
  421. : buildGifGird();
  422. },
  423. childCount: 2,
  424. )),
  425. ),
  426. Divider(
  427. height: 1,
  428. color: Color(0xffE0E0E0),
  429. ),
  430. Container(
  431. height: 49,
  432. child: Row(
  433. children: <Widget>[
  434. InkWell(
  435. child: Container(
  436. width: 59,
  437. padding:
  438. EdgeInsets.all(10),
  439. color:
  440. currentStickersPage ==
  441. 0
  442. ? const Color(
  443. 0xFFEDEDED)
  444. : Colors.white,
  445. child: Image.asset(
  446. 'assets/images/chat/emoji.png'),
  447. ),
  448. onTap: () {
  449. pageController
  450. .jumpToPage(0);
  451. },
  452. ),
  453. InkWell(
  454. child: Container(
  455. padding:
  456. EdgeInsets.all(8),
  457. width: 59,
  458. color:
  459. currentStickersPage ==
  460. 1
  461. ? const Color(
  462. 0xFFEDEDED)
  463. : Colors.white,
  464. child: Image.asset(
  465. 'assets/images/chat/onion.png'),
  466. ),
  467. onTap: () {
  468. pageController
  469. .jumpToPage(1);
  470. },
  471. )
  472. ],
  473. ),
  474. ),
  475. ],
  476. ),
  477. ),
  478. )),
  479. UtilKeyboard(
  480. keyboardHeight: keyboardHeight,
  481. isGroup: isGroup,
  482. sendMsg: widget.sendMsg),
  483. RecordView(
  484. keyboardHeight: keyboardHeight,
  485. sendMsg: _sendSoundMsg),
  486. ],
  487. index: curKeyboardIndex - 1,
  488. )
  489. : Container());
  490. },
  491. )
  492. ],
  493. )),
  494. );
  495. }
  496. Widget buildEmojiGird() {
  497. return Container(
  498. height: keyboardHeight,
  499. child: Stack(
  500. children: <Widget>[
  501. Padding(
  502. padding: EdgeInsets.fromLTRB(5, 8, 50, 0),
  503. child: GridView.builder(
  504. controller: new ScrollController(keepScrollOffset: false),
  505. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  506. crossAxisCount: 7, crossAxisSpacing: 0, mainAxisSpacing: 0),
  507. itemBuilder: (context, index) {
  508. return GestureDetector(
  509. child: Container(
  510. padding: EdgeInsets.all(7),
  511. child: Image.asset(EmojiUitl
  512. .instance.emojiMap[EmojiText.flag + "${index + 1}]"]),
  513. ),
  514. behavior: HitTestBehavior.translucent,
  515. onTap: () {
  516. insertText(EmojiText.flag + "${index + 1}]", _textCtrl);
  517. setState(() {
  518. _isComposingMessage = _textCtrl.text.length > 0;
  519. });
  520. },
  521. );
  522. },
  523. itemCount: EmojiUitl.instance.emojiMap.length,
  524. padding: EdgeInsets.all(5.0),
  525. ),
  526. ),
  527. Positioned.fill(
  528. child: Container(
  529. padding: EdgeInsets.fromLTRB(0, 0, 0, 14),
  530. alignment: Alignment(1, 1),
  531. child: InkWell(
  532. onTap: () {
  533. deleteText(_textCtrl);
  534. setState(() {
  535. _isComposingMessage = _textCtrl.text.length > 0;
  536. });
  537. },
  538. child: Container(
  539. decoration: BoxDecoration(
  540. color: Color(0x4d0E0E10),
  541. borderRadius: BorderRadius.only(
  542. topLeft: Radius.circular(4.0),
  543. bottomLeft: Radius.circular(4))),
  544. width: 37,
  545. height: 28,
  546. child: Icon(
  547. IconData(
  548. 0xe679,
  549. fontFamily: 'iconfont',
  550. ),
  551. size: 16,
  552. color: Colors.white,
  553. ),
  554. ),
  555. ),
  556. )),
  557. ],
  558. ),
  559. );
  560. }
  561. Widget buildGifGird() {
  562. return Container(
  563. padding: EdgeInsets.fromLTRB(8, 6, 8, 0),
  564. height: keyboardHeight,
  565. child: GridView.builder(
  566. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  567. crossAxisCount: 5, crossAxisSpacing: 12.0, mainAxisSpacing: 12.0),
  568. itemBuilder: (context, index) {
  569. return GestureDetector(
  570. child: Image.asset(EmojiGifUitl
  571. .instance.emojiMap[EmojiGifText.flag + "_${index + 1}>"]),
  572. behavior: HitTestBehavior.translucent,
  573. onTap: () {
  574. _sendMessage(EmojiGifText.flag + "_${index + 1}>", true);
  575. },
  576. );
  577. },
  578. itemCount: EmojiGifUitl.instance.emojiMap.length,
  579. padding: EdgeInsets.all(5.0),
  580. ),
  581. );
  582. }
  583. void _openAlterSelectPage() async {
  584. bool isGroup = Provider.of<bool>(context);
  585. if (isGroup) {
  586. GroupInfoModel groupInfoModel = Provider.of<GroupInfoModel>(context);
  587. editFocus.unfocus();
  588. Provider.of<KeyboardIndexProvider>(context, listen: false)
  589. .changeReadOnlyKey(true);
  590. GroupMemberModel member =
  591. await AlterSelectPage.pickAlterUser(context, groupInfoModel);
  592. if (member != null) {
  593. print('选中的成员~~~~~~~~~~~~ ${member.refName}');
  594. _textCtrl.text = '${_textCtrl.text}${member.refName} ';
  595. alterMemberList.add(member);
  596. }
  597. editFocus.requestFocus();
  598. Provider.of<KeyboardIndexProvider>(context, listen: false)
  599. .changeReadOnlyKey(false);
  600. }
  601. }
  602. List<int> getAlterUsers(String messageText) {
  603. List<String> alterUserList = [];
  604. RegExp alterStr = RegExp(r'@+(\S+)');
  605. Iterable<Match> matches = alterStr.allMatches(messageText);
  606. print('~~~~~~~~~~~~~~${matches.length}~~~~~~~~~~~~~~~');
  607. for (Match m in matches) {
  608. print('~~~~~~~~~~~~~~${m.group(1)}~~~~~~~~~~~~~~~');
  609. alterUserList.add(m.group(1));
  610. }
  611. List<int> finalAlterList = [];
  612. for (var member in alterMemberList) {
  613. if (alterUserList.contains(member.refName)) {
  614. finalAlterList.add(member.memberId);
  615. print('有效成员 ${member.refName}');
  616. }
  617. }
  618. return finalAlterList;
  619. }
  620. void _openPhotoView() async {
  621. // Provider.of<KeyboardIndexProvider>(context, listen: false)
  622. // .changeSelectIndex(4);
  623. var photos = await PhotoPicker.pickAsset(
  624. context: context,
  625. themeColor: Color(0xFFF0F0F0),
  626. textColor: Color(0xFF3F3F3F),
  627. pickType: PickType.onlyImage);
  628. if (photos != null && photos.length > 0) {
  629. for (var i = 0; i < photos.length; i++) {
  630. AssetEntity photoEntity = photos[i];
  631. var file = await photoEntity.file;
  632. _sendPhotoFile(file);
  633. }
  634. }
  635. ///防止再点键盘不谈
  636. }
  637. void _sendSoundMsg(String soundPath, int duration) {
  638. bool isGroup = Provider.of<bool>(context);
  639. int friendId = 0;
  640. if (!isGroup) {
  641. friendId = Provider.of<int>(context);
  642. }
  643. print('群聊模式 $isGroup');
  644. var msg = MsgHandler.createSendMsg(
  645. ChatType.ShortVoiceChatType, Uint8List(0),
  646. localFile: soundPath,
  647. friendId: friendId,
  648. extra: duration,
  649. channelType: isGroup ? ChatChannelType.Group : ChatChannelType.Session);
  650. widget.sendMsg(msg);
  651. }
  652. void _sendPhotoFile(File imgFile) async {
  653. var imgSize = await imgFile.length();
  654. print('图片大小:${imgSize / 1024}KB');
  655. var sendImg;
  656. if (imgSize > 33 * 1024 * 1024) {
  657. showToast(I18n.of(context).video_more_big);
  658. return;
  659. }
  660. bool isNeedUpload = false;
  661. if (imgSize > ImgSizeLimit) {
  662. print('图片大于 $ImgSizeLimit,压缩');
  663. //发送压缩图 WidgetUtil.getCompressImg(path,quality: 80,percentage: 80);
  664. sendImg = await WidgetUtil.getCompressImg(imgFile.absolute.path );
  665. isNeedUpload = true;
  666. } else {
  667. sendImg = imgFile.readAsBytesSync();
  668. }
  669. var rect = await WidgetUtil.getImageWH(
  670. image: Image.memory(Uint8List.fromList(sendImg)));
  671. print('图片大小 Rect : $rect');
  672. int aspectRatio = rect.width * 100 ~/ rect.height;
  673. bool isGroup = Provider.of<bool>(context);
  674. print('群聊输入模式 $isGroup');
  675. int friendId = 0;
  676. if (!isGroup) {
  677. friendId = Provider.of<int>(context);
  678. }
  679. var msg = MsgHandler.createSendMsg(ChatType.ImageChatType, sendImg,
  680. localFile: isNeedUpload ? imgFile.absolute.path : null,
  681. extra: aspectRatio,
  682. friendId: friendId,
  683. channelType: isGroup ? ChatChannelType.Group : ChatChannelType.Session);
  684. widget.sendMsg(msg);
  685. }
  686. Future<Null> _textMessageSubmitted(String text) async {
  687. if (!checkMessage()) {
  688. _textCtrl.clear();
  689. alterMemberList.clear();
  690. lastTxtLen = 0;
  691. return;
  692. }
  693. _textCtrl.clear();
  694. _sendMessage(text);
  695. }
  696. _sendTextMessage() {
  697. if (!checkMessage()) {
  698. return;
  699. }
  700. var sendStr = _textCtrl.text;
  701. _textCtrl.clear();
  702. _sendMessage(sendStr);
  703. }
  704. bool checkMessage() {
  705. if (_textCtrl.text.length == 0) {
  706. showToast(I18n.of(context).msg_not);
  707. return false;
  708. }
  709. return true;
  710. }
  711. _sendMessage(String messageText, [bool isGift = false]) {
  712. bool isGroup = Provider.of<bool>(context);
  713. int friendId = 0;
  714. List<int> alterUsers;
  715. if (!isGroup) {
  716. friendId = Provider.of<int>(context);
  717. } else {
  718. if (!isGift) {
  719. //检查@的人员
  720. alterUsers = getAlterUsers(messageText);
  721. }
  722. }
  723. MsgModel msg = MsgHandler.createSendMsg(
  724. isGift ? ChatType.EmoticonType : ChatType.TextChatType, messageText,
  725. friendId: friendId,
  726. refMsg: refMsg,
  727. refShortTxt: _getRefShortText(),
  728. altUsers: alterUsers,
  729. channelType: isGroup ? ChatChannelType.Group : ChatChannelType.Session);
  730. widget.sendMsg(msg);
  731. if (!isGift) {
  732. if (refMsg != null) {
  733. refMsg = null;
  734. }
  735. alterMemberList.clear();
  736. lastTxtLen = 0;
  737. }
  738. setState(() {
  739. _isComposingMessage = _textCtrl.text.length > 0;
  740. });
  741. }
  742. ///emoji插入表情-处理换行
  743. static void insertText(String text, TextEditingController _textCtrl) {
  744. var value = _textCtrl.value;
  745. var start = value.selection.baseOffset;
  746. var end = value.selection.extentOffset;
  747. if (value.selection.isValid) {
  748. String newText = "";
  749. if (value.selection.isCollapsed) {
  750. if (end > 0) {
  751. newText += value.text.substring(0, end);
  752. }
  753. newText += text;
  754. if (value.text.length > end) {
  755. newText += value.text.substring(end, value.text.length);
  756. }
  757. } else {
  758. newText = value.text.replaceRange(start, end, text);
  759. end = start;
  760. }
  761. _textCtrl.value = value.copyWith(
  762. text: newText,
  763. selection: value.selection.copyWith(
  764. baseOffset: end + text.length, extentOffset: end + text.length));
  765. } else {
  766. _textCtrl.value = TextEditingValue(
  767. text: text,
  768. selection:
  769. TextSelection.fromPosition(TextPosition(offset: text.length)));
  770. }
  771. }
  772. static void deleteText(TextEditingController _textController) {
  773. var value = _textController.value;
  774. var selection = value.selection;
  775. var text = value.text;
  776. String newText = '';
  777. if (selection.baseOffset != selection.extentOffset) {
  778. newText = selection.textBefore(text) + selection.textAfter(text);
  779. _textController.value = TextEditingValue(
  780. text: newText,
  781. selection: selection.copyWith(
  782. baseOffset: selection.baseOffset,
  783. extentOffset: selection.baseOffset));
  784. } else {
  785. int offsetLength = 1;
  786. String text = _textController.text;
  787. if (text.substring(text.length - 1, text.length) == ']') {
  788. ///删除表情
  789. int end = _textController.text.lastIndexOf('[');
  790. offsetLength = text.length - end;
  791. }
  792. newText = text.substring(0, selection.baseOffset - offsetLength) +
  793. selection.textAfter(text);
  794. _textController.value = TextEditingValue(
  795. text: newText,
  796. selection: selection.copyWith(
  797. baseOffset: selection.baseOffset - offsetLength,
  798. extentOffset: selection.baseOffset - offsetLength));
  799. }
  800. }
  801. }