Hibok
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

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