image_picker_util.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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. // 3. 根据photosType来处理不同的控制器和photoGroups
  63. switch (photosType) {
  64. case PhotosType.screenshots:
  65. ScreenShotsController screenshotController = Get.find<ScreenShotsController>();
  66. screenshotController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id)));
  67. screenshotController.photoGroups.removeWhere((element) => element.images.isEmpty);
  68. selectedScreenshotPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element));
  69. screenshotController.restoreSelections();
  70. break;
  71. case PhotosType.similarPhotos:
  72. SimilarPhotoController similarController = Get.find<SimilarPhotoController>();
  73. similarController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id)));
  74. similarController.photoGroups.removeWhere((element) => element.images.isEmpty);
  75. selectedSimilarPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element));
  76. similarController.restoreSelections();
  77. break;
  78. case PhotosType.locationPhotos:
  79. LocationsSinglePhotoController locationsSingleController = Get.find<LocationsSinglePhotoController>();
  80. locationsSingleController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id)));
  81. locationsSingleController.photoGroups.removeWhere((element) => element.images.isEmpty);
  82. LocationsPhotoController locationsPhotoController = Get.find<LocationsPhotoController>();
  83. locationsPhotoController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id)));
  84. locationsPhotoController.photoGroups.removeWhere((element) => element.images.isEmpty);
  85. selectedLocationPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element));
  86. locationsSingleController.restoreSelections();
  87. locationsPhotoController.restoreSelections();
  88. break;
  89. case PhotosType.peoplePhotos:
  90. PeoplePhotoController peoplePhotoController = Get.find<PeoplePhotoController>();
  91. peoplePhotoController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id)));
  92. peoplePhotoController.photoGroups.removeWhere((element) => element.images.isEmpty);
  93. selectedPeoplePhotosIds.removeWhere((element) => selectedPhotosIds.contains(element));
  94. peoplePhotoController.restoreSelections();
  95. break;
  96. case PhotosType.blurryPhotos:
  97. ScreenShotsController blurryController = Get.find<ScreenShotsController>();
  98. blurryController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id)));
  99. blurryController.photoGroups.removeWhere((element) => element.images.isEmpty);
  100. selectedBlurryPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element));
  101. blurryController.restoreSelections();
  102. break;
  103. }
  104. // 4. 清空已选择的照片ID集合
  105. selectedPhotosIds.clear();
  106. }
  107. // 更新照片数据
  108. static Future<void> updatePhotos(
  109. List<Map<String, dynamic>> photoGroups) async {
  110. clearAllPhotos();
  111. for (var group in photoGroups) {
  112. String type = group['type'] as String;
  113. Map<dynamic, dynamic> groupData = group['group'] as Map<dynamic, dynamic>;
  114. List<dynamic> photos = groupData['photos'] as List<dynamic>;
  115. int totalSize = groupData['totalSize'] as int;
  116. int count = groupData['count'] as int;
  117. switch (type) {
  118. case 'screenshots':
  119. screenshotPhotos.value = await _convertToAssetEntities(photos);
  120. screenshotsSize.value = totalSize;
  121. break;
  122. case 'similar':
  123. similarPhotos.add(await _convertToAssetEntities(photos));
  124. similarPhotosSize.value = totalSize;
  125. similarPhotoCount.value = count;
  126. break;
  127. case 'location':
  128. String location = group['name'] as String;
  129. locationPhotos[location] = await _convertToAssetEntities(photos);
  130. locationsSize.value = totalSize;
  131. break;
  132. case 'people':
  133. peoplePhotos.value = await _convertToAssetEntities(photos);
  134. peopleSize.value = totalSize;
  135. break;
  136. case 'blurry':
  137. blurryPhotos.value = await _convertToAssetEntities(photos);
  138. blurrySize.value = totalSize;
  139. break;
  140. }
  141. }
  142. }
  143. // 将原始照片数据转换为 AssetEntity 列表
  144. static Future<List<AssetEntity>> _convertToAssetEntities(
  145. List<dynamic> photos) async {
  146. List<AssetEntity> entities = [];
  147. for (var photo in photos) {
  148. final entity = await AssetEntity.fromId(photo['id'] as String);
  149. if (entity != null) {
  150. entities.add(entity);
  151. }
  152. }
  153. return entities;
  154. }
  155. //申请权限
  156. static Future<bool> requestPermissionExtend() async {
  157. final PermissionState ps = await PhotoManager.requestPermissionExtend(
  158. requestOption: const PermissionRequestOption(
  159. androidPermission: AndroidPermission(
  160. type: permissionType,
  161. mediaLocation: false,
  162. )));
  163. return ps.hasAccess;
  164. }
  165. //判断是否有权限
  166. static Future<bool> hasPermission() async {
  167. final PermissionState ps = await PhotoManager.getPermissionState(
  168. requestOption: const PermissionRequestOption(
  169. androidPermission: AndroidPermission(
  170. type: permissionType,
  171. mediaLocation: false,
  172. )));
  173. return ps.hasAccess;
  174. }
  175. static String formatFileSize(int bytes, {int decimals = 2}) {
  176. if (bytes <= 0) return '0 B';
  177. const suffixes = ['B', 'KB', 'MB', 'GB', 'TB'];
  178. var i = (log(bytes) / log(1024)).floor();
  179. // 确保不超过数组范围
  180. i = i < suffixes.length ? i : suffixes.length - 1;
  181. // 计算实际大小
  182. final size = bytes / pow(1024, i);
  183. // 格式化数字,处理小数点位数
  184. String sizeStr;
  185. if (size >= 100) {
  186. // 大于100的只保留整数
  187. sizeStr = size.round().toString();
  188. } else {
  189. // 小于100的保留指定小数位
  190. sizeStr = size.toStringAsFixed(decimals);
  191. }
  192. // 移除末尾的0和不必要的小数点
  193. sizeStr = sizeStr.replaceAll(RegExp(r'\.?0+$'), '');
  194. return '$sizeStr ${suffixes[i]}';
  195. }
  196. /// 直接转换为 GB 单位
  197. static String formatToGB(int bytes, {int decimals = 2}) {
  198. if (bytes <= 0) return '0 GB';
  199. final gb = bytes / pow(1024, 3); // 直接转换为 GB
  200. // 格式化数字,处理小数点位数
  201. String sizeStr;
  202. if (gb >= 100) {
  203. // 大于100的只保留整数
  204. sizeStr = gb.round().toString();
  205. } else {
  206. // 小于100的保留指定小数位
  207. sizeStr = gb.toStringAsFixed(decimals);
  208. }
  209. // 移除末尾的0和不必要的小数点
  210. sizeStr = sizeStr.replaceAll(RegExp(r'\.?0+$'), '');
  211. return '$sizeStr GB';
  212. }
  213. /// 格式化存储大小
  214. static String formatSize(double sizeInGB) {
  215. if (sizeInGB < 0.001) {
  216. // 小于 1MB
  217. return '${(sizeInGB * 1024 * 1024).toStringAsFixed(1)} ';
  218. } else if (sizeInGB < 1) {
  219. // 小于 1GB
  220. return '${(sizeInGB * 1024).toStringAsFixed(1)} ';
  221. } else if (sizeInGB < 1024) {
  222. // 小于 1TB
  223. return '${sizeInGB.toStringAsFixed(1)} ';
  224. } else {
  225. // 大于等于 1TB
  226. return '${(sizeInGB / 1024).toStringAsFixed(1)} ';
  227. }
  228. }
  229. }