Hibok
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

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