Hibok
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

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