Hibok
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

426 satır
13 KiB

  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'dart:typed_data';
  4. import 'package:chat/chat/gift_select_widget.dart';
  5. import 'package:chat/data/UserData.dart';
  6. import 'package:chat/generated/i18n.dart';
  7. import 'package:chat/home/VipPage.dart';
  8. import 'package:chat/map/google_map_location_picker.dart';
  9. import 'package:chat/models/UserInfo.dart';
  10. import 'package:chat/models/money_change.dart';
  11. import 'package:chat/proto/all.pbserver.dart';
  12. import 'package:chat/utils/ChargeMoney.dart';
  13. import 'package:chat/utils/CustomUI.dart';
  14. import 'package:chat/utils/HttpUtil.dart';
  15. import 'package:chat/data/constants.dart';
  16. import 'package:chat/utils/app_navigator.dart';
  17. import 'package:chat/utils/blacklist_mgr.dart';
  18. import 'package:chat/utils/image_util.dart';
  19. import 'package:chat/utils/msgHandler.dart';
  20. import 'package:chat/utils/screen.dart';
  21. import 'package:dio/dio.dart';
  22. import 'package:flutter/material.dart';
  23. import 'package:flutter_image_compress/flutter_image_compress.dart';
  24. import 'package:google_maps_flutter/google_maps_flutter.dart';
  25. import 'package:image_picker/image_picker.dart';
  26. import 'package:oktoast/oktoast.dart';
  27. import 'package:permission_handler/permission_handler.dart';
  28. import 'package:provider/provider.dart';
  29. import 'package:video_thumbnail/video_thumbnail.dart';
  30. import 'package:file_picker/file_picker.dart';
  31. import '../r.dart';
  32. class UtilKeyboard extends StatefulWidget {
  33. final double keyboardHeight;
  34. final Function sendMsg;
  35. final bool isGroup;
  36. UtilKeyboard({this.keyboardHeight, this.sendMsg, this.isGroup});
  37. @override
  38. _UtilKeyboardState createState() => _UtilKeyboardState();
  39. }
  40. class _UtilKeyboardState extends State<UtilKeyboard> {
  41. bool isAuthority = false;
  42. @override
  43. Widget build(BuildContext context) {
  44. bool isShowRedPacket = UserData().redPacketSW > 0;
  45. List<Widget> iconList = [];
  46. iconList.add(
  47. _buildOtherSelect(R.assetsImagesChatItem1, I18n.of(context).camera, () {
  48. print('开始选择拍照');
  49. _sendPicture(context);
  50. }));
  51. iconList.add(
  52. _buildOtherSelect(R.assetsImagesChatItem2, I18n.of(context).video, () {
  53. print('开始选择视频');
  54. _sendVideo(context);
  55. }));
  56. if (!widget.isGroup) {
  57. iconList.add(
  58. _buildOtherSelect(R.assetsImagesChatItem3, I18n.of(context).chat, () {
  59. _audioChat(context);
  60. }));
  61. }
  62. iconList.add(
  63. _buildOtherSelect(R.assetsImagesChatItem4, I18n.of(context).locate, () {
  64. _openMap(context);
  65. }));
  66. if (!widget.isGroup) {
  67. iconList.add(Offstage(
  68. offstage: !isShowRedPacket,
  69. child: _buildOtherSelect(
  70. R.assetsImagesChatItem5, I18n.of(context).red_money, () {
  71. AppNavigator.pushCoinBagPage(context);
  72. })));
  73. iconList.add(_buildOtherSelect(
  74. R.assetsImagesChatItem6, I18n.of(context).giving_gift, () {
  75. _showGiftSheet(context);
  76. }));
  77. }
  78. iconList.add(_buildOtherSelect(R.assetsImagesChatItem7, '文件', () async {
  79. _sendFile(context);
  80. }));
  81. return Container(
  82. width: Screen.width,
  83. color: Colors.white,
  84. height: widget.keyboardHeight,
  85. padding: EdgeInsets.only(top: 20, bottom: 10, left: 20),
  86. alignment: Alignment.topLeft,
  87. child: Wrap(spacing: 10.0, runSpacing: 20.0, children: iconList));
  88. }
  89. _showGiftSheet(BuildContext context) {
  90. int friendId = 0;
  91. if (!widget.isGroup) {
  92. friendId = Provider.of<int>(context);
  93. }
  94. showModalBottomSheet(
  95. context: context,
  96. elevation: 2.0,
  97. shape: RoundedRectangleBorder(
  98. borderRadius: BorderRadius.only(
  99. topLeft: Radius.circular(20), topRight: Radius.circular(20))),
  100. backgroundColor: Colors.transparent,
  101. builder: (BuildContext context) {
  102. return StatefulBuilder(
  103. builder: (BuildContext context, setBottomSheetState) {
  104. return GiftSelectWidget(friendId, widget.sendMsg);
  105. },
  106. );
  107. });
  108. }
  109. _openMap(BuildContext context) async {
  110. if (await CustomUI.showPermissionSetting(
  111. context, PermissionGroup.location, I18n.of(context).open_location)) {
  112. var result = await LocationPicker.pickLocation(
  113. context, 'AIzaSyAb9JNtW0BEZ_qLeDg87ZhvxSmZply-7hU',
  114. initialCenter: LatLng(UserData().latitude, UserData().longitude));
  115. if (result == null ||
  116. result.address == null ||
  117. result.address.length == 0) {
  118. return;
  119. }
  120. var reslutStr = jsonEncode(result);
  121. int friendId = 0;
  122. if (!widget.isGroup) {
  123. friendId = Provider.of<int>(context);
  124. }
  125. var msg = MsgHandler.createSendMsg(
  126. ChatType.PlaceChatType, utf8.encode(reslutStr),
  127. friendId: friendId,
  128. channelType:
  129. widget.isGroup ? ChatChannelType.Group : ChatChannelType.Session);
  130. widget.sendMsg(msg);
  131. }
  132. }
  133. _audioChat(BuildContext context) async {
  134. if (await CustomUI.showPermissionSetting(context,
  135. PermissionGroup.microphone, I18n.of(context).video_permission)) {
  136. int friendId = Provider.of<int>(context);
  137. UserInfo info = await HttpUtil().getFriendInfo(friendId, true);
  138. if (info == null) {
  139. print('获取用户信息失败');
  140. return;
  141. }
  142. if (info.chatStatus == 0) {
  143. showToast(I18n.of(context).cantt_voice);
  144. return;
  145. }
  146. if (BlacklistMgr.isBlaklistMe(info.userId)) {
  147. showToast(I18n.of(context).you_are_blaklisted);
  148. return;
  149. }
  150. if (BlacklistMgr.isInMyblaklist(info.userId)) {
  151. showToast(I18n.of(context).reject_message);
  152. return;
  153. }
  154. //对方关闭陌生人消息,则提示
  155. if (!info.isCanStrangerNews) {
  156. showToast(I18n.of(context).stranger_close_tips);
  157. return;
  158. }
  159. if (info.isAuthority ||
  160. (!UserData().isMan() && UserData().basicInfo.isAttestation) ||
  161. info.distince < 200) {
  162. isAuthority = true;
  163. }
  164. becomeVip() {
  165. Navigator.of(context).push(
  166. new MaterialPageRoute(
  167. builder: (context) {
  168. return VipPage();
  169. },
  170. ),
  171. );
  172. }
  173. payCallback() {
  174. if (Provider.of<MoneyChangeProvider>(context).money <
  175. UserData().accountPrice) {
  176. Navigator.of(context).pop();
  177. CustomUI.buildOneConfirm(
  178. context,
  179. I18n.of(context).balance_insufficien,
  180. I18n.of(context).recharge, () {
  181. Navigator.of(context).pop();
  182. ChargeMoney.showChargeSheet(context, () {});
  183. });
  184. return;
  185. }
  186. Navigator.of(context).pop();
  187. HttpUtil().buyChatAccount(UserData().accountPrice, info.userId, context,
  188. () {
  189. isAuthority = true;
  190. });
  191. }
  192. freeTime() {
  193. HttpUtil().userFreeTime(context, info.userId, 2, () {
  194. UserData().basicInfo.usedNum++;
  195. Navigator.of(context).pop();
  196. isAuthority = true;
  197. });
  198. }
  199. if (!isAuthority) {
  200. if (UserData().isVip) {
  201. UserData().basicInfo.freeNum < UserData().basicInfo.usedNum
  202. ? CustomUI.buildOneConfirm(
  203. context,
  204. I18n.of(context).unlock_information,
  205. I18n.of(context)
  206. .pay_unlock
  207. .replaceFirst('/s1', UserData().accountPrice.toString()),
  208. payCallback)
  209. : CustomUI.buildOneConfirm(
  210. context,
  211. I18n.of(context).unlock_information,
  212. I18n.of(context).unlock_choose,
  213. freeTime,
  214. );
  215. } else {
  216. CustomUI.buildTowConfirm(
  217. context,
  218. I18n.of(context).unlock_information,
  219. I18n.of(context).become_member,
  220. becomeVip,
  221. I18n.of(context)
  222. .pay_unlock
  223. .replaceFirst('/s1', UserData().accountPrice.toString()),
  224. payCallback);
  225. }
  226. return;
  227. }
  228. AppNavigator.pushAudioChatPage(context, info);
  229. }
  230. }
  231. void _sendPicture(BuildContext context) async {
  232. if (await CustomUI.showPermissionSetting(
  233. context, PermissionGroup.camera, I18n.of(context).camera_permission)) {
  234. File imgFile = await ImagePicker.pickImage(source: ImageSource.camera);
  235. if (imgFile == null) {
  236. return;
  237. }
  238. var imgSize = await imgFile.length();
  239. print('图片大小:${imgSize / 1024}KB');
  240. var sendImg;
  241. bool isNeedUpload = false;
  242. if (imgSize > ImgSizeLimit) {
  243. print('图片大于 $ImgSizeLimit,压缩');
  244. //发送压缩图
  245. sendImg = await WidgetUtil.getCompressImg(imgFile.absolute.path);
  246. isNeedUpload = true;
  247. } else {
  248. sendImg = imgFile.readAsBytesSync().toList();
  249. }
  250. var rect = await WidgetUtil.getImageWH(
  251. image: Image.memory(Uint8List.fromList(sendImg)));
  252. int aspectRatio = rect.width * 100 ~/ rect.height;
  253. int friendId = 0;
  254. if (!widget.isGroup) {
  255. friendId = Provider.of<int>(context);
  256. }
  257. var msg = MsgHandler.createSendMsg(ChatType.ImageChatType, sendImg,
  258. extra: aspectRatio,
  259. friendId: friendId,
  260. localFile: isNeedUpload ? imgFile.absolute.path : null,
  261. channelType:
  262. widget.isGroup ? ChatChannelType.Group : ChatChannelType.Session);
  263. widget.sendMsg(msg);
  264. }
  265. }
  266. void _sendFile(BuildContext context) async {
  267. File file = await FilePicker.getFile();
  268. int fileSize = file.lengthSync();
  269. print('选择的文件 ${file.path} 大小 $fileSize');
  270. if (fileSize > 33 * 1024 * 1024) {
  271. showToast('文件大于33M');
  272. return;
  273. }
  274. int friendId = 0;
  275. if (!widget.isGroup) {
  276. friendId = Provider.of<int>(context);
  277. }
  278. var fileName = file.path.split('/').last;
  279. print('fileName $fileName');
  280. var ext = '';
  281. var extList = fileName.split('.');
  282. if (extList.length > 1) {
  283. ext = extList.last;
  284. }
  285. print('ext $ext');
  286. var fileMsg = FileChat.create();
  287. fileMsg.type = ext;
  288. fileMsg.size = fileSize;
  289. fileMsg.name = fileName;
  290. var msg = MsgHandler.createSendMsg(ChatType.FileChatType, fileMsg.writeToBuffer(),
  291. friendId: friendId,
  292. localFile: file.path,
  293. channelType:
  294. widget.isGroup ? ChatChannelType.Group : ChatChannelType.Session);
  295. widget.sendMsg(msg);
  296. }
  297. void _sendVideo(BuildContext context) async {
  298. if (await CustomUI.showPhotoPermissionSetting(context)) {
  299. File video = await ImagePicker.pickVideo(source: ImageSource.gallery);
  300. if (video == null) {
  301. return;
  302. }
  303. var videoSize = await video.length();
  304. print('视频大小:$videoSize');
  305. if (videoSize > 33 * 1024 * 1024) {
  306. showToast(I18n.of(Constants.getCurrentContext()).video_more_big);
  307. return;
  308. }
  309. final thumbnail = await getVideoThumbnail(video);
  310. var rect = await WidgetUtil.getImageWH(
  311. image: Image.memory(Uint8List.fromList(thumbnail)));
  312. int aspectRatio = rect.width * 100 ~/ rect.height;
  313. int friendId = 0;
  314. if (!widget.isGroup) {
  315. friendId = Provider.of<int>(context);
  316. }
  317. var msg = MsgHandler.createSendMsg(ChatType.ShortVideoChatType, thumbnail,
  318. extra: aspectRatio,
  319. friendId: friendId,
  320. localFile: video.path,
  321. channelType:
  322. widget.isGroup ? ChatChannelType.Group : ChatChannelType.Session);
  323. widget.sendMsg(msg);
  324. }
  325. }
  326. getVideoThumbnail(File video) async {
  327. List<int> thumbnail = await VideoThumbnail.thumbnailData(
  328. imageFormat: ImageFormat.JPEG,
  329. video: video.path,
  330. quality: 20,
  331. );
  332. if (thumbnail.length > ImgSizeLimit) {
  333. print('图片较大 ${thumbnail.length}');
  334. thumbnail =
  335. await FlutterImageCompress.compressWithList(thumbnail, quality: 10);
  336. print('压缩后 ${thumbnail.length}');
  337. }
  338. return thumbnail;
  339. }
  340. }
  341. Widget _buildOtherSelect(String imgPath, String title, VoidCallback onTap) {
  342. var imgWidth = Screen.width / 4 - 20;
  343. return InkWell(
  344. child: Container(
  345. width: imgWidth,
  346. child: Column(
  347. children: <Widget>[
  348. SizedBox(
  349. child: Image.asset(imgPath, fit: BoxFit.contain),
  350. width: 40,
  351. height: 40,
  352. ),
  353. SizedBox(height: 5),
  354. Text(title,
  355. maxLines: 1,
  356. overflow: TextOverflow.ellipsis,
  357. textScaleFactor: 1.0,
  358. style: TextStyle(color: Color(0xFF090909), fontSize: 12))
  359. ],
  360. ),
  361. ),
  362. onTap: onTap,
  363. );
  364. }