image_picker_util.dart 11 KB

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