Hibok
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

433 lines
15 KiB

  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'dart:typed_data';
  4. import 'dart:ui';
  5. import 'package:cached_network_image/cached_network_image.dart';
  6. import 'package:chat/data/group_data_mgr.dart';
  7. import 'package:chat/models/group_info_model.dart';
  8. import 'package:chat/utils/screen.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:flutter/rendering.dart';
  11. import 'package:flutter/widgets.dart';
  12. //import 'package:flutter_image_compress/flutter_image_compress.dart';
  13. import 'package:flutter_native_image/flutter_native_image.dart';
  14. import '../r.dart';
  15. import 'file_cache_mgr.dart';
  16. import 'group_member_model.dart';
  17. const ImgSizeLimit = 60 * 1024;
  18. /// Widget Util.
  19. class WidgetUtil {
  20. bool _hasMeasured = false;
  21. double _width;
  22. double _height;
  23. /// Widget rendering listener.
  24. /// Widget渲染监听.
  25. /// context: Widget context.
  26. /// isOnce: true,Continuous monitoring false,Listen only once.
  27. /// onCallBack: Widget Rect CallBack.
  28. void asyncPrepare(
  29. BuildContext context, bool isOnce, ValueChanged<Rect> onCallBack) {
  30. if (_hasMeasured) return;
  31. WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) {
  32. RenderBox box = context.findRenderObject();
  33. if (box != null && box.semanticBounds != null) {
  34. if (isOnce) _hasMeasured = true;
  35. double width = box.semanticBounds.width;
  36. double height = box.semanticBounds.height;
  37. if (_width != width || _height != height) {
  38. _width = width;
  39. _height = height;
  40. if (onCallBack != null) onCallBack(box.semanticBounds);
  41. }
  42. }
  43. });
  44. }
  45. /// Widget渲染监听.
  46. void asyncPrepares(bool isOnce, ValueChanged<Rect> onCallBack) {
  47. if (_hasMeasured) return;
  48. WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) {
  49. if (isOnce) _hasMeasured = true;
  50. if (onCallBack != null) onCallBack(null);
  51. });
  52. }
  53. ///get Widget Bounds (width, height, left, top, right, bottom and so on).Widgets must be rendered completely.
  54. ///获取widget Rect
  55. static Rect getWidgetBounds(BuildContext context) {
  56. RenderBox box = context.findRenderObject();
  57. return (box != null && box.semanticBounds != null)
  58. ? box.semanticBounds
  59. : Rect.zero;
  60. }
  61. static getCompressImg(String imgPath,
  62. {int quality = 20, int percentage = 20}) async {
  63. File compressedFile = await FlutterNativeImage.compressImage(imgPath,
  64. quality: quality, percentage: percentage);
  65. var k = compressedFile.readAsBytesSync().toList();
  66. print('A图片压缩完毕 : ${k.length}');
  67. // compressedFile.
  68. // var compressImg = await FlutterImageCompress.compressWithFile(imgPath,
  69. // quality: 20, minWidth: Screen.width.toInt());
  70. // print('B图片压缩完毕 : ${compressImg.length}');
  71. // if (compressImg.length > ImgSizeLimit) {
  72. // //仍大于,再压缩一次
  73. // compressImg = await FlutterImageCompress.compressWithFile(imgPath,
  74. // quality: 20, minWidth: (Screen.width * 0.5).toInt());
  75. // }
  76. return k;
  77. }
  78. ///Get the coordinates of the widget on the screen.Widgets must be rendered completely.
  79. ///获取widget在屏幕上的坐标,widget必须渲染完成
  80. static Offset getWidgetLocalToGlobal(BuildContext context) {
  81. RenderBox box = context.findRenderObject();
  82. return box == null ? Offset.zero : box.localToGlobal(Offset.zero);
  83. }
  84. /// get image width height,load error return Rect.zero.(unit px)
  85. /// 获取图片宽高,加载错误情况返回 Rect.zero.(单位 px)
  86. /// image
  87. /// url network
  88. /// local url , package
  89. static Future<Rect> getImageWH(
  90. {Image image, String url, String localUrl, String package}) {
  91. if (image == null && url == null && localUrl == null) {
  92. return Future.value(Rect.zero);
  93. }
  94. Completer<Rect> completer = Completer<Rect>();
  95. Image img = image != null
  96. ? image
  97. : ((url != null && url.isNotEmpty)
  98. ? Image.network(url)
  99. : Image.asset(localUrl, package: package));
  100. img.image
  101. .resolve(new ImageConfiguration())
  102. .addListener(new ImageStreamListener(
  103. (ImageInfo info, bool _) {
  104. completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(),
  105. info.image.height.toDouble()));
  106. },
  107. onError: (dynamic exception, StackTrace stackTrace) {
  108. completer.completeError(exception, stackTrace);
  109. },
  110. ));
  111. return completer.future;
  112. }
  113. /// get image width height, load error throw exception.(unit px)
  114. /// 获取图片宽高,加载错误会抛出异常.(单位 px)
  115. /// image
  116. /// url network
  117. /// local url (full path/全路径,example:"assets/images/ali_connors.png",""assets/images/3.0x/ali_connors.png"" );
  118. /// package
  119. static Future<Rect> getImageWHE(
  120. {Image image, String url, String localUrl, String package}) {
  121. if (image == null && url == null && localUrl == null) {
  122. return Future.value(Rect.zero);
  123. }
  124. Completer<Rect> completer = Completer<Rect>();
  125. Image img = image != null
  126. ? image
  127. : ((url != null && url.isNotEmpty)
  128. ? Image.network(url)
  129. : Image.asset(localUrl, package: package));
  130. img.image
  131. .resolve(new ImageConfiguration())
  132. .addListener(new ImageStreamListener(
  133. (ImageInfo info, bool _) {
  134. completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(),
  135. info.image.height.toDouble()));
  136. },
  137. onError: (dynamic exception, StackTrace stackTrace) {
  138. completer.completeError(exception, stackTrace);
  139. },
  140. ));
  141. return completer.future;
  142. }
  143. static ImageProvider groupAvatar(String path) {
  144. path = FileCacheMgr.replacePath(path);
  145. Uint8List fileData = File(path).readAsBytesSync();
  146. // print('fileData ${fileData.length}');
  147. return MemoryImage(fileData);
  148. }
  149. static Widget getAvatarNew(
  150. GroupInfoModel model, GlobalKey key, Function backPath) {
  151. List<GroupMemberModel> members = [];
  152. for (int k = 0; k < model.members.length; k++) {
  153. //只加入存在群的
  154. GroupMemberModel mo = model.members[k];
  155. if (mo.inGroup == 1) {
  156. members.add(mo);
  157. }
  158. }
  159. if (model.image != null && model.image.length > 2) {
  160. print('${model.name} 群头像地址:${model.image}');
  161. File file = new File(model.image);
  162. // int filelength = file.readAsBytesSync().length;
  163. // print('群头像地址file size : $filelength');
  164. if (file.existsSync()) {
  165. //防止头像文件被清除后
  166. Uint8List pngBytes = file.readAsBytesSync();
  167. print('pngBytes.lengthInBytes length;${pngBytes.lengthInBytes}');
  168. if (pngBytes.lengthInBytes > 8000) {
  169. return ClipRRect(
  170. borderRadius: BorderRadius.circular(5),
  171. child: Container(
  172. color: Color(0xffE9E9E9),
  173. width: 52,
  174. height: 52,
  175. child: Image.file(
  176. File(FileCacheMgr.replacePath(model.image)),
  177. fit: BoxFit.contain,
  178. width: 50,
  179. height: 50,
  180. ),
  181. ),
  182. );
  183. }
  184. } else {
  185. backPath('');
  186. }
  187. }
  188. ///先让下面的图片显示,5秒后截图保存图片
  189. Future.delayed(Duration(seconds: 3), () async {
  190. // print('没有群图片-开始生成保存到本地:${model.members.length}');
  191. try {
  192. RenderRepaintBoundary boundary = key.currentContext.findRenderObject();
  193. var image = await boundary.toImage(pixelRatio: 2);
  194. ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
  195. Uint8List pngBytes = byteData.buffer.asUint8List();
  196. File file = await FileCacheMgr()
  197. .writeFile(model.sessionId.toString(), pngBytes);
  198. print('图片地址byteData${byteData.lengthInBytes}');
  199. if (byteData.lengthInBytes > 8000 && members.length > 1) {
  200. //图片保存成功
  201. GroupInfoMgr().updateAvatar(model.sessionId, file.path);
  202. backPath(file.path);
  203. }
  204. // ImageGallerySaver.saveImage(pngBytes);
  205. // return pngBytes;//这个对象就是图片数据
  206. } catch (e) {
  207. print(e);
  208. }
  209. });
  210. if (members.length > 9) {
  211. members = members.sublist(0, 9);
  212. }
  213. if (members.length > 0) {
  214. double itemSize = 10;
  215. switch (members.length) {
  216. case 1:
  217. return RepaintBoundary(
  218. key: key,
  219. child: ClipRRect(
  220. borderRadius: BorderRadius.circular(3),
  221. child: Container(
  222. color: Color(0xffE9E9E9),
  223. width: 52,
  224. height: 52,
  225. child: Padding(
  226. padding: EdgeInsets.all(1),
  227. child: CachedNetworkImage(
  228. imageUrl: members[0].avtar,
  229. width: 45,
  230. height: 45,
  231. placeholder: (context, url) => Image.asset(
  232. R.assetsImagesDefaultNorAvatar,
  233. width: 45,
  234. height: 45,
  235. )),
  236. ),
  237. ),
  238. ),
  239. );
  240. break;
  241. case 2:
  242. return RepaintBoundary(
  243. key: key,
  244. child: ClipRRect(
  245. borderRadius: BorderRadius.circular(3),
  246. child: Container(
  247. color: Color(0xffE9E9E9),
  248. width: 52,
  249. height: 52,
  250. child: Row(
  251. children: <Widget>[
  252. Padding(
  253. padding: EdgeInsets.all(1),
  254. child: ClipRRect(
  255. borderRadius: BorderRadius.circular(3),
  256. child: CachedNetworkImage(
  257. imageUrl: members[0].avtar,
  258. width: 23,
  259. height: 23,
  260. placeholder: (context, url) => Image.asset(
  261. R.assetsImagesDefaultNorAvatar,
  262. width: 23,
  263. height: 23,
  264. )),
  265. ),
  266. ),
  267. Padding(
  268. padding: EdgeInsets.all(1),
  269. child: ClipRRect(
  270. borderRadius: BorderRadius.circular(3),
  271. child: CachedNetworkImage(
  272. imageUrl: members[1].avtar,
  273. width: 23,
  274. height: 23,
  275. placeholder: (context, url) => Image.asset(
  276. R.assetsImagesDefaultNorAvatar,
  277. width: 23,
  278. height: 23,
  279. )),
  280. ),
  281. )
  282. ],
  283. ),
  284. ),
  285. ),
  286. );
  287. case 3:
  288. return RepaintBoundary(
  289. key: key,
  290. child: ClipRRect(
  291. borderRadius: BorderRadius.circular(3),
  292. child: Container(
  293. color: Color(0xffE9E9E9),
  294. width: 52,
  295. height: 52,
  296. child: Column(
  297. children: <Widget>[
  298. Padding(
  299. padding: EdgeInsets.all(1),
  300. child: ClipRRect(
  301. borderRadius: BorderRadius.circular(3),
  302. child: CachedNetworkImage(
  303. imageUrl: members[0].avtar,
  304. width: 23,
  305. height: 23,
  306. placeholder: (context, url) => Image.asset(
  307. R.assetsImagesDefaultNorAvatar,
  308. width: 23,
  309. height: 23,
  310. )),
  311. ),
  312. ),
  313. Row(
  314. children: <Widget>[
  315. Padding(
  316. padding: EdgeInsets.all(1),
  317. child: ClipRRect(
  318. borderRadius: BorderRadius.circular(3),
  319. child: CachedNetworkImage(
  320. imageUrl: members[1].avtar,
  321. width: 23,
  322. height: 23,
  323. placeholder: (context, url) => Image.asset(
  324. R.assetsImagesDefaultNorAvatar,
  325. width: 23,
  326. height: 23,
  327. )),
  328. ),
  329. ),
  330. Padding(
  331. padding: EdgeInsets.all(1),
  332. child: ClipRRect(
  333. borderRadius: BorderRadius.circular(3),
  334. child: CachedNetworkImage(
  335. imageUrl: members[2].avtar,
  336. width: 23,
  337. height: 23,
  338. placeholder: (context, url) => Image.asset(
  339. R.assetsImagesDefaultNorAvatar,
  340. width: 23,
  341. height: 23,
  342. )),
  343. ),
  344. )
  345. ],
  346. )
  347. ],
  348. ),
  349. ),
  350. ),
  351. );
  352. }
  353. if (members.length == 4) {
  354. itemSize = 23;
  355. } else {
  356. itemSize = 15;
  357. }
  358. List<Widget> widgetList = [];
  359. for (int k = 0; k < members.length; k++) {
  360. widgetList.add(Padding(
  361. padding: EdgeInsets.all(1),
  362. child: ClipRRect(
  363. borderRadius: BorderRadius.circular(3),
  364. child: CachedNetworkImage(
  365. imageUrl: members[k].avtar,
  366. width: itemSize,
  367. height: itemSize,
  368. placeholder: (context, url) => Image.asset(
  369. R.assetsImagesDefaultNorAvatar,
  370. width: itemSize,
  371. height: itemSize,
  372. )),
  373. ),
  374. ));
  375. }
  376. return RepaintBoundary(
  377. key: key,
  378. child: ClipRRect(
  379. borderRadius: BorderRadius.circular(3),
  380. child: Container(
  381. color: Color(0xffE9E9E9),
  382. width: 52,
  383. height: 52,
  384. alignment: Alignment.center,
  385. child: Wrap(
  386. crossAxisAlignment: WrapCrossAlignment.start,
  387. children: widgetList),
  388. ),
  389. ),
  390. );
  391. } else {
  392. return ClipRRect(
  393. borderRadius: BorderRadius.circular(3),
  394. child: Container(
  395. color: Color(0xffE9E9E9),
  396. ),
  397. );
  398. }
  399. }
  400. }