import 'dart:io'; import 'dart:math'; import 'package:clean/data/bean/photos_type.dart'; import 'package:clean/model/asset_group.dart'; import 'package:clean/module/locations_photo/locations_photo_controller.dart'; import 'package:clean/module/locations_photo/locations_single_photo_controller.dart'; import 'package:clean/module/people_photo/people_photo_controller.dart'; import 'package:clean/module/people_photo/photo_group.dart'; import 'package:clean/module/photo_preview/photo_preview_controller.dart'; import 'package:clean/module/screenshots_blurry/screenshots_controller.dart'; import 'package:clean/module/similar_photo/similar_photo_controller.dart'; import 'package:get/get.dart'; import 'package:photo_manager/photo_manager.dart'; class ImagePickerUtil { ImagePickerUtil._(); static const RequestType permissionType = RequestType.image; static final RxInt similarPhotoCount = 0.obs; // 全局存储不同类型的照片 // 截图图片 static final RxList screenshotPhotos = [].obs; // 模糊图片 static final RxList blurryPhotos = [].obs; // 相似图片 static final RxList> similarPhotos = >[].obs; // 地点图片 static final RxMap> locationPhotos = >{}.obs; // 人物图片 static final RxList peoplePhotos = [].obs; static final RxSet selectedScreenshotPhotosIds = {}.obs; static final RxSet selectedSimilarPhotosIds = {}.obs; static final RxSet selectedLocationPhotosIds = {}.obs; static final RxSet selectedPeoplePhotosIds = {}.obs; static final RxSet selectedBlurryPhotosIds = {}.obs; // 添加大小信息的变量 static final Rx screenshotsSize = 0.obs; static final Rx blurrySize = 0.obs; static final Rx locationsSize = 0.obs; static final Rx peopleSize = 0.obs; static final Rx similarPhotosSize = 0.obs; // 用来缓存文件大小 static final Map fileSizeCache = {}; // 清除所有照片数据 static void clearAllPhotos() { screenshotPhotos.clear(); blurryPhotos.clear(); similarPhotos.clear(); locationPhotos.clear(); peoplePhotos.clear(); } static Future updatePhotoGroupDate(PhotosType photosType,Set selectedPhotosIds) async { // 1. 统一移除相关的照片列表 screenshotPhotos.removeWhere((element) => selectedPhotosIds.contains(element.id)); for (var group in similarPhotos) { group.removeWhere((element) => selectedPhotosIds.contains(element.id)); } locationPhotos.forEach((key, group) => group.removeWhere((element) => selectedPhotosIds.contains(element.id))); peoplePhotos.removeWhere((element) => selectedPhotosIds.contains(element.id)); blurryPhotos.removeWhere((element) => selectedPhotosIds.contains(element.id)); // 2. 移除空的集合 similarPhotos.removeWhere((element) => element.isEmpty); locationPhotos.removeWhere((key, value) => value.isEmpty); selectedScreenshotPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); selectedSimilarPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); selectedLocationPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); selectedPeoplePhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); selectedBlurryPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); // 3. 根据photosType来处理不同的控制器和photoGroups switch (photosType) { case PhotosType.screenshots: ScreenShotsController screenshotController = Get.find(); screenshotController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id))); screenshotController.photoGroups.removeWhere((element) => element.images.isEmpty); selectedScreenshotPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); screenshotController.restoreSelections(); break; case PhotosType.similarPhotos: SimilarPhotoController similarController = Get.find(); similarController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id))); similarController.photoGroups.removeWhere((element) => element.images.isEmpty); selectedSimilarPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); similarController.restoreSelections(); break; case PhotosType.locationPhotos: LocationsSinglePhotoController locationsSingleController = Get.find(); locationsSingleController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id))); locationsSingleController.photoGroups.removeWhere((element) => element.images.isEmpty); LocationsPhotoController locationsPhotoController = Get.find(); locationsPhotoController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id))); locationsPhotoController.photoGroups.removeWhere((element) => element.images.isEmpty); selectedLocationPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); locationsSingleController.restoreSelections(); locationsPhotoController.restoreSelections(); break; case PhotosType.peoplePhotos: PeoplePhotoController peoplePhotoController = Get.find(); peoplePhotoController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id))); peoplePhotoController.photoGroups.removeWhere((element) => element.images.isEmpty); selectedPeoplePhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); peoplePhotoController.restoreSelections(); break; case PhotosType.blurryPhotos: ScreenShotsController blurryController = Get.find(); blurryController.photoGroups.removeWhere((element) => element.images.any((image) => selectedPhotosIds.contains(image.id))); blurryController.photoGroups.removeWhere((element) => element.images.isEmpty); selectedBlurryPhotosIds.removeWhere((element) => selectedPhotosIds.contains(element)); blurryController.restoreSelections(); break; } } // 更新照片数据 static Future updatePhotos( List> photoGroups) async { clearAllPhotos(); for (var group in photoGroups) { String type = group['type'] as String; Map groupData = group['group'] as Map; List photos = groupData['photos'] as List; int totalSize = groupData['totalSize'] as int; int count = groupData['count'] as int; switch (type) { case 'screenshots': screenshotPhotos.value = await _convertToAssetEntities(photos); screenshotsSize.value = totalSize; break; case 'similar': similarPhotos.add(await _convertToAssetEntities(photos)); similarPhotosSize.value = totalSize; similarPhotoCount.value = count; break; case 'location': String location = group['name'] as String; locationPhotos[location] = await _convertToAssetEntities(photos); locationsSize.value = totalSize; break; case 'people': peoplePhotos.value = await _convertToAssetEntities(photos); peopleSize.value = totalSize; break; case 'blurry': blurryPhotos.value = await _convertToAssetEntities(photos); blurrySize.value = totalSize; break; } } } // 将原始照片数据转换为 AssetEntity 列表 static Future> _convertToAssetEntities( List photos) async { List entities = []; for (var photo in photos) { final entity = await AssetEntity.fromId(photo['id'] as String); if (entity != null) { entities.add(entity); } } return entities; } //申请权限 static Future requestPermissionExtend() async { final PermissionState ps = await PhotoManager.requestPermissionExtend( requestOption: const PermissionRequestOption( androidPermission: AndroidPermission( type: permissionType, mediaLocation: false, ))); return ps.hasAccess; } //判断是否有权限 static Future hasPermission() async { final PermissionState ps = await PhotoManager.getPermissionState( requestOption: const PermissionRequestOption( androidPermission: AndroidPermission( type: permissionType, mediaLocation: false, ))); return ps.hasAccess; } static String formatFileSize(int bytes, {int decimals = 2}) { if (bytes <= 0) return '0 B'; const suffixes = ['B', 'KB', 'MB', 'GB', 'TB']; var i = (log(bytes) / log(1024)).floor(); // 确保不超过数组范围 i = i < suffixes.length ? i : suffixes.length - 1; // 计算实际大小 final size = bytes / pow(1024, i); // 格式化数字,处理小数点位数 String sizeStr; if (size >= 100) { // 大于100的只保留整数 sizeStr = size.round().toString(); } else { // 小于100的保留指定小数位 sizeStr = size.toStringAsFixed(decimals); } // 移除末尾的0和不必要的小数点 sizeStr = sizeStr.replaceAll(RegExp(r'\.?0+$'), ''); return '$sizeStr ${suffixes[i]}'; } /// 直接转换为 GB 单位 static String formatToGB(int bytes, {int decimals = 2}) { if (bytes <= 0) return '0 GB'; final gb = bytes / pow(1024, 3); // 直接转换为 GB // 格式化数字,处理小数点位数 String sizeStr; if (gb >= 100) { // 大于100的只保留整数 sizeStr = gb.round().toString(); } else { // 小于100的保留指定小数位 sizeStr = gb.toStringAsFixed(decimals); } // 移除末尾的0和不必要的小数点 sizeStr = sizeStr.replaceAll(RegExp(r'\.?0+$'), ''); return '$sizeStr GB'; } /// 格式化存储大小 static String formatSize(double sizeInGB) { if (sizeInGB < 0.001) { // 小于 1MB return '${(sizeInGB * 1024 * 1024).toStringAsFixed(1)} '; } else if (sizeInGB < 1) { // 小于 1GB return '${(sizeInGB * 1024).toStringAsFixed(1)} '; } else if (sizeInGB < 1024) { // 小于 1TB return '${sizeInGB.toStringAsFixed(1)} '; } else { // 大于等于 1TB return '${(sizeInGB / 1024).toStringAsFixed(1)} '; } } static Future> loadAssetsAndroid({bool sortByDate = true}) async { final PermissionState result = await PhotoManager.requestPermissionExtend(); if (!result.isAuth) return []; // 选择相册 final List albums = await PhotoManager.getAssetPathList( type: RequestType.image, filterOption: FilterOptionGroup( orders: [ // 根据创建日期排序,降序(最新的在前) OrderOption( type: OrderOptionType.createDate, asc: !sortByDate, // 是否升序排列 ), ], ), ); if (albums.isEmpty) return []; // 获取图片资源 final List assets = await albums.first.getAssetListPaged( page: 0, size: 10000, // 获取 10000 张图片 ); return assets; } }