image_picker_util.dart 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import 'dart:io';
  2. import 'dart:math';
  3. import 'package:clean/data/bean/photos_type.dart';
  4. import 'package:clean/model/asset_group.dart';
  5. import 'package:clean/module/locations_photo/locations_single_photo_controller.dart';
  6. import 'package:clean/module/people_photo/people_photo_controller.dart';
  7. import 'package:clean/module/people_photo/photo_group.dart';
  8. import 'package:clean/module/screenshots_blurry/screenshots_controller.dart';
  9. import 'package:clean/module/similar_photo/similar_photo_controller.dart';
  10. import 'package:get/get.dart';
  11. import 'package:photo_manager/photo_manager.dart';
  12. class ImagePickerUtil {
  13. ImagePickerUtil._();
  14. static const RequestType permissionType = RequestType.image;
  15. static final RxInt similarPhotoCount = 0.obs;
  16. // 全局存储不同类型的照片
  17. // 截图图片
  18. static final RxList<AssetEntity> screenshotPhotos = <AssetEntity>[].obs;
  19. // 模糊图片
  20. static final RxList<AssetEntity> blurryPhotos = <AssetEntity>[].obs;
  21. // 相似图片
  22. static final RxList<List<AssetEntity>> similarPhotos =
  23. <List<AssetEntity>>[].obs;
  24. // 地点图片
  25. static final RxMap<String, List<AssetEntity>> locationPhotos =
  26. <String, List<AssetEntity>>{}.obs;
  27. // 人物图片
  28. static final RxList<AssetEntity> peoplePhotos = <AssetEntity>[].obs;
  29. static final RxSet<String> selectedScreenshotPhotosIds = <String>{}.obs;
  30. static final RxSet<String> selectedSimilarPhotosIds = <String>{}.obs;
  31. static final RxSet<String> selectedLocationPhotosIds = <String>{}.obs;
  32. static final RxSet<String> selectedPeoplePhotosIds = <String>{}.obs;
  33. static final RxSet<String> selectedBlurryPhotosIds = <String>{}.obs;
  34. // 添加大小信息的变量
  35. static final Rx<int> screenshotsSize = 0.obs;
  36. static final Rx<int> blurrySize = 0.obs;
  37. static final Rx<int> locationsSize = 0.obs;
  38. static final Rx<int> peopleSize = 0.obs;
  39. static final Rx<int> similarPhotosSize = 0.obs;
  40. // 清除所有照片数据
  41. static void clearAllPhotos() {
  42. similarPhotoCount.value = 0;
  43. screenshotPhotos.clear();
  44. blurryPhotos.clear();
  45. similarPhotos.clear();
  46. locationPhotos.clear();
  47. peoplePhotos.clear();
  48. }
  49. // 更新删除后的照片数据
  50. static Future<void> updatePhotoGroupDate(PhotosType photosType) async {
  51. switch (photosType) {
  52. case PhotosType.screenshots:
  53. // 去除包含在selectedScreenshotPhotosIds中的screenshotPhotos
  54. screenshotPhotos.removeWhere(
  55. (element) => selectedScreenshotPhotosIds.contains(element.id));
  56. ScreenShotsController controller = Get.find<ScreenShotsController>();
  57. // 同时移除控制器photoGroups中images对应的数据
  58. controller.photoGroups.removeWhere((element) => element.images.any((element) => selectedScreenshotPhotosIds.contains(element.id)));
  59. selectedScreenshotPhotosIds.clear();
  60. controller.restoreSelections();
  61. print(screenshotPhotos);
  62. break;
  63. case PhotosType.similarPhotos:
  64. // 去除包含在selectedSimilarPhotosIds中的similarPhotos
  65. for (var group in similarPhotos) {
  66. group.removeWhere(
  67. (element) => selectedSimilarPhotosIds.contains(element.id));
  68. }
  69. SimilarPhotoController controller = Get.find<SimilarPhotoController>();
  70. // 同时移除控制器photoGroups中images对应的数据
  71. controller.photoGroups.removeWhere((element) => element.images.any((element) => selectedSimilarPhotosIds.contains(element.id)));
  72. selectedSimilarPhotosIds.clear();
  73. controller.restoreSelections();
  74. break;
  75. case PhotosType.locationPhotos:
  76. // 去除包含在selectedLocationPhotosIds中的locationPhotos
  77. for (var group in locationPhotos.values) {
  78. group.removeWhere(
  79. (element) => selectedLocationPhotosIds.contains(element.id));
  80. }
  81. LocationsSinglePhotoController controller = Get.find<LocationsSinglePhotoController>();
  82. // 同时移除控制器photoGroups中images对应的数据
  83. controller.photoGroups.removeWhere((element) => element.images.any((element) => selectedLocationPhotosIds.contains(element.id)));
  84. selectedLocationPhotosIds.clear();
  85. controller.restoreSelections();
  86. break;
  87. case PhotosType.peoplePhotos:
  88. // 去除包含在selectedPeoplePhotosIds中的peoplePhotos
  89. peoplePhotos.removeWhere(
  90. (element) => selectedPeoplePhotosIds.contains(element.id));
  91. PeoplePhotoController controller = Get.find<PeoplePhotoController>();
  92. // 同时移除控制器photoGroups中images对应的数据
  93. controller.photoGroups.removeWhere((element) => element.images.any((element) => selectedPeoplePhotosIds.contains(element.id)));
  94. selectedPeoplePhotosIds.clear();
  95. controller.restoreSelections();
  96. break;
  97. case PhotosType.blurryPhotos:
  98. // 去除包含在selectedBlurryPhotosIds中的blurryPhotos
  99. blurryPhotos.removeWhere(
  100. (element) => selectedBlurryPhotosIds.contains(element.id));
  101. ScreenShotsController controller = Get.find<ScreenShotsController>();
  102. // 同时移除控制器photoGroups中images对应的数据
  103. controller.photoGroups.removeWhere((element) => element.images.any((element) => selectedBlurryPhotosIds.contains(element.id)));
  104. selectedBlurryPhotosIds.clear();
  105. controller.restoreSelections();
  106. break;
  107. }
  108. }
  109. // 更新照片数据
  110. static Future<void> updatePhotos(
  111. List<Map<String, dynamic>> photoGroups) async {
  112. clearAllPhotos();
  113. for (var group in photoGroups) {
  114. String type = group['type'] as String;
  115. Map<dynamic, dynamic> groupData = group['group'] as Map<dynamic, dynamic>;
  116. List<dynamic> photos = groupData['photos'] as List<dynamic>;
  117. int totalSize = groupData['totalSize'] as int;
  118. int count = groupData['count'] as int;
  119. switch (type) {
  120. case 'screenshots':
  121. screenshotPhotos.value = await _convertToAssetEntities(photos);
  122. screenshotsSize.value = totalSize;
  123. break;
  124. case 'similar':
  125. similarPhotos.add(await _convertToAssetEntities(photos));
  126. similarPhotosSize.value = totalSize;
  127. similarPhotoCount.value = count;
  128. break;
  129. case 'location':
  130. String location = group['name'] as String;
  131. locationPhotos[location] = await _convertToAssetEntities(photos);
  132. locationsSize.value = totalSize;
  133. break;
  134. case 'people':
  135. peoplePhotos.value = await _convertToAssetEntities(photos);
  136. peopleSize.value = totalSize;
  137. break;
  138. case 'blurry':
  139. blurryPhotos.value = await _convertToAssetEntities(photos);
  140. blurrySize.value = totalSize;
  141. break;
  142. }
  143. }
  144. }
  145. // 将原始照片数据转换为 AssetEntity 列表
  146. static Future<List<AssetEntity>> _convertToAssetEntities(
  147. List<dynamic> photos) async {
  148. List<AssetEntity> entities = [];
  149. for (var photo in photos) {
  150. final entity = await AssetEntity.fromId(photo['id'] as String);
  151. if (entity != null) {
  152. entities.add(entity);
  153. }
  154. }
  155. return entities;
  156. }
  157. //申请权限
  158. static Future<bool> requestPermissionExtend() async {
  159. final PermissionState ps = await PhotoManager.requestPermissionExtend(
  160. requestOption: const PermissionRequestOption(
  161. androidPermission: AndroidPermission(
  162. type: permissionType,
  163. mediaLocation: false,
  164. )));
  165. return ps.hasAccess;
  166. }
  167. //判断是否有权限
  168. static Future<bool> hasPermission() async {
  169. final PermissionState ps = await PhotoManager.getPermissionState(
  170. requestOption: const PermissionRequestOption(
  171. androidPermission: AndroidPermission(
  172. type: permissionType,
  173. mediaLocation: false,
  174. )));
  175. return ps.hasAccess;
  176. }
  177. static String formatFileSize(int bytes, {int decimals = 2}) {
  178. if (bytes <= 0) return '0 B';
  179. const suffixes = ['B', 'KB', 'MB', 'GB', 'TB'];
  180. var i = (log(bytes) / log(1024)).floor();
  181. // 确保不超过数组范围
  182. i = i < suffixes.length ? i : suffixes.length - 1;
  183. // 计算实际大小
  184. final size = bytes / pow(1024, i);
  185. // 格式化数字,处理小数点位数
  186. String sizeStr;
  187. if (size >= 100) {
  188. // 大于100的只保留整数
  189. sizeStr = size.round().toString();
  190. } else {
  191. // 小于100的保留指定小数位
  192. sizeStr = size.toStringAsFixed(decimals);
  193. }
  194. // 移除末尾的0和不必要的小数点
  195. sizeStr = sizeStr.replaceAll(RegExp(r'\.?0+$'), '');
  196. return '$sizeStr ${suffixes[i]}';
  197. }
  198. /// 直接转换为 GB 单位
  199. static String formatToGB(int bytes, {int decimals = 2}) {
  200. if (bytes <= 0) return '0 GB';
  201. final gb = bytes / pow(1024, 3); // 直接转换为 GB
  202. // 格式化数字,处理小数点位数
  203. String sizeStr;
  204. if (gb >= 100) {
  205. // 大于100的只保留整数
  206. sizeStr = gb.round().toString();
  207. } else {
  208. // 小于100的保留指定小数位
  209. sizeStr = gb.toStringAsFixed(decimals);
  210. }
  211. // 移除末尾的0和不必要的小数点
  212. sizeStr = sizeStr.replaceAll(RegExp(r'\.?0+$'), '');
  213. return '$sizeStr GB';
  214. }
  215. /// 格式化存储大小
  216. static String formatSize(double sizeInGB) {
  217. if (sizeInGB < 0.001) {
  218. // 小于 1MB
  219. return '${(sizeInGB * 1024 * 1024).toStringAsFixed(1)} ';
  220. } else if (sizeInGB < 1) {
  221. // 小于 1GB
  222. return '${(sizeInGB * 1024).toStringAsFixed(1)} ';
  223. } else if (sizeInGB < 1024) {
  224. // 小于 1TB
  225. return '${sizeInGB.toStringAsFixed(1)} ';
  226. } else {
  227. // 大于等于 1TB
  228. return '${(sizeInGB / 1024).toStringAsFixed(1)} ';
  229. }
  230. }
  231. }