Hibok
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

417 Zeilen
13 KiB

  1. import 'dart:io';
  2. import 'dart:typed_data';
  3. import 'package:chat/chat/ChatPageItem.dart';
  4. import 'package:chat/data/UserData.dart';
  5. import 'package:chat/data/chat_data_mgr.dart';
  6. import 'package:chat/data/constants.dart';
  7. import 'package:chat/generated/i18n.dart';
  8. import 'package:chat/models/ChatMsg.dart';
  9. import 'package:chat/models/UserInfo.dart';
  10. import 'package:chat/proto/chat.pb.dart';
  11. import 'package:chat/r.dart';
  12. import 'package:chat/utils/CustomUI.dart';
  13. import 'package:chat/utils/HttpUtil.dart';
  14. import 'package:chat/utils/TokenMgr.dart';
  15. import 'package:chat/utils/file_cache_mgr.dart';
  16. import 'package:chat/utils/image_util.dart';
  17. import 'package:chat/utils/keyboard_utils.dart';
  18. import 'package:chat/utils/msgHandler.dart';
  19. import 'package:chat/utils/screen.dart';
  20. import 'package:dio/dio.dart';
  21. import 'package:flutter/material.dart';
  22. import 'package:flutter/services.dart';
  23. import 'package:flutter_screenutil/flutter_screenutil.dart';
  24. import 'package:multi_image_picker/multi_image_picker.dart';
  25. import 'package:oktoast/oktoast.dart';
  26. import 'package:chat/utils/MessageMgr.dart';
  27. class CompanyServerPage extends StatefulWidget {
  28. @override
  29. _CompanyServerPageState createState() => _CompanyServerPageState();
  30. }
  31. class _CompanyServerPageState extends State<CompanyServerPage> {
  32. final TextEditingController _textCtrl = TextEditingController();
  33. FocusNode editFocus = NoKeyboardEditableTextFocusNode();
  34. // bool _isComposingMessage = false;
  35. double keyboardHeight;
  36. KeyboardBloc _bloc = KeyboardBloc();
  37. ScrollController _scrollCtrl = ScrollController();
  38. List<MsgModel> msgList = [];
  39. static int companyId = 10000;
  40. final ValueNotifier<bool> updateProgress = ValueNotifier<bool>(false);
  41. UserInfo companyInfo = UserInfo(
  42. userId: companyId,
  43. headimgurl: R.assetsImagesServerIcon,
  44. nickName: I18n.of(Constants.getCurrentContext()).feedback_assistant);
  45. @override
  46. void initState() {
  47. super.initState();
  48. _bloc.start();
  49. //10000号为服务小助手
  50. MsgHandler.updateActiveSesstion(companyId);
  51. msgList = ChatDataMgr().getRecord();
  52. MessageMgr().on('New Chat Message', receiveMsg);
  53. }
  54. @override
  55. void dispose() {
  56. MsgHandler.curActiveSession = 0;
  57. _textCtrl.dispose();
  58. _bloc.dispose();
  59. editFocus.dispose();
  60. _scrollCtrl.dispose();
  61. MessageMgr().off('New Chat Message', receiveMsg);
  62. super.dispose();
  63. }
  64. receiveMsg(sessionId) {
  65. print('收到反馈助手消息');
  66. if (mounted) {
  67. setState(() {});
  68. if (_scrollCtrl.hasClients) {
  69. _scrollCtrl.animateTo(0,
  70. duration: new Duration(milliseconds: 500), curve: Curves.ease);
  71. }
  72. }
  73. }
  74. hideKeyBoard() {
  75. editFocus.unfocus();
  76. }
  77. bool checkMessage() {
  78. if (_textCtrl.text.length == 0) {
  79. showToast(I18n.of(context).msg_not);
  80. return false;
  81. }
  82. return true;
  83. }
  84. Future<Null> _textMessageSubmitted(String text) async {
  85. if (!checkMessage()) {
  86. _textCtrl.clear();
  87. return;
  88. }
  89. _textCtrl.clear();
  90. _sendMessage(text);
  91. }
  92. _sendTextMessage() {
  93. if (!checkMessage()) {
  94. return;
  95. }
  96. var sendStr = _textCtrl.text;
  97. _textCtrl.clear();
  98. _sendMessage(sendStr);
  99. }
  100. _sendMessage(String messageText) {
  101. MsgModel msg = MsgHandler.createSendMsg(ChatType.TextChatType, messageText,
  102. friendId: companyId, channelType: ChatChannelType.CSD);
  103. setState(() {
  104. updateProgress.value = _textCtrl.text.length > 0;
  105. });
  106. sendMsg(msg);
  107. }
  108. sendMsg(MsgModel msg) async {
  109. ChatDataMgr().saveCompanyMsg(msg);
  110. if (mounted) {
  111. setState(() {});
  112. if (_scrollCtrl.hasClients) {
  113. _scrollCtrl.animateTo(0,
  114. duration: new Duration(milliseconds: 500), curve: Curves.ease);
  115. }
  116. }
  117. await HttpUtil().commitInfoToCompany(msg);
  118. if (mounted) {
  119. setState(() {});
  120. }
  121. }
  122. void _openPhotoView() async {
  123. List<Asset> resultList = List<Asset>();
  124. try {
  125. resultList = await MultiImagePicker.pickImages(
  126. maxImages: 9,
  127. enableCamera: false,
  128. selectedAssets: [],
  129. cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
  130. materialOptions: MaterialOptions(
  131. actionBarColor: "#50A7F9",
  132. actionBarTitle: "Hibok",
  133. allViewTitle: "",
  134. useDetailsView: true,
  135. selectCircleStrokeColor: "#000000",
  136. ),
  137. );
  138. // if (resultList != null && resultList.length > 0) {
  139. // for (var i = 0; i < resultList.length; i++) {
  140. // Asset photoEntity = resultList[i];
  141. // ByteData byteData = await photoEntity.getByteData();
  142. // File file = await FileCacheMgr().writeFile('temp-photo-${DateTime.now().millisecondsSinceEpoch}.png', byteData.buffer.asInt8List(0));
  143. // _sendPhotoFile(file);
  144. // }
  145. // }
  146. if (resultList != null && resultList.length > 0) {
  147. List<File> fileList = [];
  148. for (var i = 0; i < resultList.length; i++) {
  149. Asset photoEntity = resultList[i];
  150. print('名字:${photoEntity.name}');
  151. ByteData byteData = await photoEntity.getByteData();
  152. File file = await FileCacheMgr().writeFile('temp-photo-${DateTime.now().millisecondsSinceEpoch}.png', byteData.buffer.asInt8List(0));
  153. fileList.add(file);
  154. }
  155. print('文件列表${fileList.length}');
  156. Map data = {"type": 3, "userId": UserData().basicInfo.userId};
  157. data['sign'] = TokenMgr().getSign(data);
  158. Response res = await HttpUtil().uploadFiles(
  159. fileList, data, 'upload/post/postfiles', 'image',
  160. isShowLoading: true);
  161. var resData = res.data;
  162. if (resData['code'] == 0 && resData['msg'] != null) {
  163. List<String> imgUrlList = [];
  164. imgUrlList.addAll(resData['msg'].split("|"));
  165. for(int k=0;k<imgUrlList.length;k++){
  166. _sendPhotoFile(fileList[k],imgUrlList[k]);
  167. }
  168. setState(() {});
  169. }
  170. }
  171. } on Exception catch (e) {
  172. print(e.toString());
  173. }
  174. // var photos = await PhotoPicker.pickAsset(
  175. // context: context,
  176. // themeColor: Color(0xFFF0F0F0),
  177. // textColor: Color(0xFF3F3F3F),
  178. // pickType: PickType.onlyImage);
  179. //
  180. // if (photos != null && photos.length > 0) {
  181. // for (var i = 0; i < photos.length; i++) {
  182. // AssetEntity photoEntity = photos[i];
  183. // var file = await photoEntity.file;
  184. // _sendPhotoFile(file);
  185. // }
  186. // }
  187. }
  188. void _sendPhotoFile(File imgFile,String imageUrl) async {
  189. // var imgSize = await imgFile.length();
  190. //
  191. // print('图片大小:${imgSize / 1024}KB');
  192. // var sendImg;
  193. //
  194. // if (imgSize > 33 * 1024 * 1024) {
  195. // showToast(I18n.of(context).video_more_big);
  196. // return;
  197. // }
  198. // bool isNeedUpload = false;
  199. // if (imgSize > ImgSizeLimit) {
  200. // print('图片大于 $ImgSizeLimit,压缩');
  201. // //发送压缩图
  202. // sendImg = await WidgetUtil.getCompressImg(imgFile.absolute.path );
  203. // isNeedUpload = true;
  204. // } else {
  205. // sendImg = imgFile.readAsBytesSync();
  206. // }
  207. var sendImg = imgFile.readAsBytesSync();
  208. var rect = await WidgetUtil.getImageWH(
  209. image: Image.memory(Uint8List.fromList(sendImg)));
  210. print('图片大小 Rect : $rect');
  211. int aspectRatio = rect.width * 100 ~/ rect.height;
  212. var msg = MsgHandler.createSendMsg(ChatType.ImageChatType, imageUrl,
  213. localFile: imgFile.absolute.path,
  214. extra: aspectRatio,
  215. friendId: companyId,
  216. channelType: ChatChannelType.CSD);
  217. sendMsg(msg);
  218. }
  219. _inputBar() {
  220. Widget input = Container(
  221. child: TextField(
  222. keyboardAppearance: Brightness.light,
  223. onChanged: (String messageText) {
  224. updateProgress.value = _textCtrl.text.length > 0;
  225. },
  226. cursorColor: Constants.BlueTextColor,
  227. style: TextStyle(
  228. fontSize: ScreenUtil().setSp(16),
  229. textBaseline: TextBaseline.alphabetic),
  230. maxLines: 3,
  231. minLines: 1,
  232. controller: _textCtrl,
  233. textInputAction: TextInputAction.newline,
  234. inputFormatters: <TextInputFormatter>[
  235. LengthLimitingTextInputFormatter(600) //限制长度
  236. ],
  237. onSubmitted: _textMessageSubmitted,
  238. focusNode: editFocus,
  239. decoration: InputDecoration(
  240. hintText: I18n.of(context).input_content,
  241. hintStyle: TextStyle(color: const Color(0xffBDBDBD), fontSize: 16),
  242. border: null,
  243. hintMaxLines: 1,
  244. contentPadding: EdgeInsets.only(left: 5, right: 5, top: 8, bottom: 8),
  245. ),
  246. ),
  247. );
  248. return ValueListenableBuilder(
  249. builder: (BuildContext context, bool isComp,
  250. Widget child) {
  251. return GestureDetector(
  252. onTap: () {
  253. print('放置触控隐藏键盘');
  254. },
  255. child: Container(
  256. width: Screen.width,
  257. color: Colors.white,
  258. child: Container(
  259. padding: EdgeInsets.symmetric(horizontal: 7, vertical: 7),
  260. alignment: Alignment.topCenter,
  261. decoration: BoxDecoration(
  262. color: Colors.white,
  263. border: Border(top: BorderSide(color: Color(0xFFDFDFDF)))),
  264. child: Row(
  265. children: <Widget>[
  266. //输入框
  267. Expanded(child: input), SizedBox(width: 10),
  268. isComp
  269. ? InkWell(
  270. child: Padding(
  271. padding: EdgeInsets.fromLTRB(50, 2, 10, 2),
  272. child: Icon(
  273. Icons.send,
  274. color: Color(0xFF087FF3),
  275. size: 28,
  276. )),
  277. onTap: _sendTextMessage)
  278. : InkWell(
  279. child: Icon(
  280. IconData(0xe60c,
  281. fontFamily: Constants.IconFontFamily),
  282. color: Color(0xFF797A7C),
  283. size: 26,
  284. ),
  285. onTap: () {
  286. _openPhotoView();
  287. }),
  288. ],
  289. ))))
  290. ;
  291. },
  292. valueListenable: updateProgress,
  293. );
  294. }
  295. Widget _buildMessageList() {
  296. return Container(
  297. alignment: Alignment.topCenter,
  298. child: msgList.length == 0
  299. ? Padding(
  300. padding: EdgeInsets.all(8),
  301. child: Text(
  302. I18n.of(context).feedback_tips,
  303. textAlign: TextAlign.center,
  304. textScaleFactor: 1.0,
  305. style: TextStyle(color: Colors.grey, fontSize: 12),
  306. ))
  307. : Scrollbar(
  308. child: ListView.builder(
  309. reverse: true,
  310. shrinkWrap: true,
  311. itemCount: msgList.length,
  312. controller: _scrollCtrl,
  313. padding: EdgeInsets.all(8.0),
  314. itemBuilder: _buildItem,
  315. )),
  316. );
  317. }
  318. Widget _buildItem(BuildContext context, int index) {
  319. var lastMsgTime;
  320. if (index < msgList.length - 1) {
  321. lastMsgTime = msgList[index + 1].time;
  322. }
  323. MsgModel msg = msgList[index];
  324. return ChatPageItem(
  325. key: Key(msg.time.toString()),
  326. msg: msg,
  327. lastMsgTime: lastMsgTime,
  328. friendInfo: companyInfo);
  329. }
  330. @override
  331. Widget build(BuildContext context) {
  332. return GestureDetector(
  333. onTap: hideKeyBoard,
  334. child: Scaffold(
  335. backgroundColor: const Color(0xFFE2E9F1),
  336. appBar: AppBar(
  337. title: Text(
  338. I18n.of(context).feedback_assistant,
  339. textScaleFactor: 1.0,
  340. style:
  341. TextStyle(color: Constants.BlackTextColor, fontSize: 16.47),
  342. ),
  343. leading: CustomUI.buildCustomLeading(context),
  344. titleSpacing: -10,
  345. centerTitle: false,
  346. elevation: 1,
  347. ),
  348. body: SafeArea(
  349. child: Column(
  350. children: <Widget>[
  351. Expanded(child: _buildMessageList()),
  352. _inputBar(),
  353. ],
  354. ))),
  355. );
  356. }
  357. }