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.
 
 
 
 
 
 

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