Hibok
您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 
 
 
 

929 行
33 KiB

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