Hibok
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

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