Hibok
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

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