Bladeren bron

[feat]添加计算分类照片容量的功能

Destiny 1 jaar geleden
bovenliggende
commit
15d2968147
23 gewijzigde bestanden met toevoegingen van 361 en 272 verwijderingen
  1. 3 0
      ios/Runner.xcodeproj/project.pbxproj
  2. 6 114
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
  3. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
  4. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
  5. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
  6. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
  7. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
  8. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
  9. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
  10. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
  11. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
  12. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
  13. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
  14. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
  15. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
  16. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
  17. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
  18. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo.png
  19. 13 0
      lib/model/asset_group.dart
  20. 124 112
      lib/module/home/home_view.dart
  21. 84 12
      lib/module/image_picker/image_picker_util.dart
  22. 92 4
      plugins/classify_photo/ios/Classes/ClassifyPhoto.swift
  23. 39 30
      plugins/classify_photo/ios/Classes/ClassifyPhotoPlugin.swift

+ 3 - 0
ios/Runner.xcodeproj/project.pbxproj

@@ -491,6 +491,7 @@
 				DEVELOPMENT_TEAM = WU64MT4KXD;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = Clean;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -674,6 +675,7 @@
 				DEVELOPMENT_TEAM = WU64MT4KXD;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = Clean;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -697,6 +699,7 @@
 				DEVELOPMENT_TEAM = WU64MT4KXD;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = Clean;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",

+ 6 - 114
ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -1,122 +1,14 @@
 {
   "images" : [
     {
-      "size" : "20x20",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-20x20@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "20x20",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-20x20@3x.png",
-      "scale" : "3x"
-    },
-    {
-      "size" : "29x29",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-29x29@1x.png",
-      "scale" : "1x"
-    },
-    {
-      "size" : "29x29",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-29x29@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "29x29",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-29x29@3x.png",
-      "scale" : "3x"
-    },
-    {
-      "size" : "40x40",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-40x40@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "40x40",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-40x40@3x.png",
-      "scale" : "3x"
-    },
-    {
-      "size" : "60x60",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-60x60@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "60x60",
-      "idiom" : "iphone",
-      "filename" : "Icon-App-60x60@3x.png",
-      "scale" : "3x"
-    },
-    {
-      "size" : "20x20",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-20x20@1x.png",
-      "scale" : "1x"
-    },
-    {
-      "size" : "20x20",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-20x20@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "29x29",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-29x29@1x.png",
-      "scale" : "1x"
-    },
-    {
-      "size" : "29x29",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-29x29@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "40x40",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-40x40@1x.png",
-      "scale" : "1x"
-    },
-    {
-      "size" : "40x40",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-40x40@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "76x76",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-76x76@1x.png",
-      "scale" : "1x"
-    },
-    {
-      "size" : "76x76",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-76x76@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "83.5x83.5",
-      "idiom" : "ipad",
-      "filename" : "Icon-App-83.5x83.5@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "size" : "1024x1024",
-      "idiom" : "ios-marketing",
-      "filename" : "Icon-App-1024x1024@1x.png",
-      "scale" : "1x"
+      "filename" : "app_logo.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
     }
   ],
   "info" : {
-    "version" : 1,
-    "author" : "xcode"
+    "author" : "xcode",
+    "version" : 1
   }
 }

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png


BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_logo.png


+ 13 - 0
lib/model/asset_group.dart

@@ -0,0 +1,13 @@
+import 'package:wechat_assets_picker/wechat_assets_picker.dart';
+
+class AssetGroup {
+  final List<AssetEntity> assets;
+  final int totalSize;
+  final int count;
+
+  AssetGroup({
+    required this.assets,
+    required this.totalSize,
+    required this.count,
+  });
+}

+ 124 - 112
lib/module/home/home_view.dart

@@ -33,17 +33,17 @@ class HomePage extends BaseView<HomeController> {
         SafeArea(
           child: SingleChildScrollView(
               child: Column(
-            children: [
-              titleCard(),
-              storageCard(),
-              similarCard(),
-              quickPhotoCard(),
-              peopleCard(),
-              locationsCard(),
-              screenshotsAndBlurryCard(),
-              SizedBox(height: 40.h),
-            ],
-          )),
+                children: [
+                  titleCard(),
+                  storageCard(),
+                  similarCard(),
+                  quickPhotoCard(),
+                  peopleCard(),
+                  locationsCard(),
+                  screenshotsAndBlurryCard(),
+                  SizedBox(height: 40.h),
+                ],
+              )),
         ),
         IgnorePointer(
           child: Assets.images.bgHome.image(
@@ -144,50 +144,51 @@ class HomePage extends BaseView<HomeController> {
             CircularChartAnnotation(
               widget: Container(
                   child: Column(
-                mainAxisSize: MainAxisSize.min,
-                crossAxisAlignment: CrossAxisAlignment.center,
-                children: [
-                  Row(
-                    mainAxisAlignment: MainAxisAlignment.center,
-                    crossAxisAlignment: CrossAxisAlignment.end,
+                    mainAxisSize: MainAxisSize.min,
+                    crossAxisAlignment: CrossAxisAlignment.center,
                     children: [
-                      Obx(() {
-                        return Text(
-                          controller.usedSpacePercentage.toStringAsFixed(0),
-                          textAlign: TextAlign.end,
-                          style: TextStyle(
-                            color: Colors.white
-                                .withValues(alpha: 0.8999999761581421),
-                            fontSize: 30.sp,
-                            height: 1,
-                            fontWeight: FontWeight.w400,
+                      Row(
+                        mainAxisAlignment: MainAxisAlignment.center,
+                        crossAxisAlignment: CrossAxisAlignment.end,
+                        children: [
+                          Obx(() {
+                            return Text(
+                              controller.usedSpacePercentage.toStringAsFixed(0),
+                              textAlign: TextAlign.end,
+                              style: TextStyle(
+                                color: Colors.white
+                                    .withValues(alpha: 0.8999999761581421),
+                                fontSize: 30.sp,
+                                height: 1,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            );
+                          }),
+                          Text(
+                            '%',
+                            textAlign: TextAlign.end,
+                            style: TextStyle(
+                              color: Colors.white
+                                  .withValues(alpha: 0.8999999761581421),
+                              fontSize: 14.87.r,
+                              fontWeight: FontWeight.w500,
+                            ),
                           ),
-                        );
-                      }),
+                        ],
+                      ),
                       Text(
-                        '%',
-                        textAlign: TextAlign.end,
+                        'used',
+                        textAlign: TextAlign.center,
                         style: TextStyle(
-                          color: Colors.white
-                              .withValues(alpha: 0.8999999761581421),
+                          color: Colors.white.withValues(
+                              alpha: 0.6000000238418579),
                           fontSize: 14.87.r,
+                          height: 1,
                           fontWeight: FontWeight.w500,
                         ),
-                      ),
+                      )
                     ],
-                  ),
-                  Text(
-                    'used',
-                    textAlign: TextAlign.center,
-                    style: TextStyle(
-                      color: Colors.white.withValues(alpha: 0.6000000238418579),
-                      fontSize: 14.87.r,
-                      height: 1,
-                      fontWeight: FontWeight.w500,
-                    ),
-                  )
-                ],
-              )),
+                  )),
               horizontalAlignment: ChartAlignment.center,
               verticalAlignment: ChartAlignment.center,
               radius: '0%',
@@ -256,7 +257,7 @@ class HomePage extends BaseView<HomeController> {
                       text: controller.totalSpace.toStringAsFixed(1),
                       style: TextStyle(
                         color:
-                            Colors.white.withValues(alpha: 0.6000000238418579),
+                        Colors.white.withValues(alpha: 0.6000000238418579),
                         fontSize: 13.sp,
                         fontWeight: FontWeight.w400,
                       ),
@@ -265,7 +266,7 @@ class HomePage extends BaseView<HomeController> {
                       text: 'GB',
                       style: TextStyle(
                         color:
-                            Colors.white.withValues(alpha: 0.6000000238418579),
+                        Colors.white.withValues(alpha: 0.6000000238418579),
                         fontSize: 13.sp,
                         fontWeight: FontWeight.w500,
                       ),
@@ -421,13 +422,16 @@ class HomePage extends BaseView<HomeController> {
                   ),
                 ],
               ),
-              CleanUpButton(
-                label: 'Clean up',
-                size: '0 GB',
-                onTap: () {
-                  controller.similarCleanClick();
-                },
-              ),
+              Obx(() {
+                return CleanUpButton(
+                  label: 'Clean up',
+                  size: ImagePickerUtil.formatFileSize(
+                      ImagePickerUtil.similarPhotosSize.value),
+                  onTap: () {
+                    controller.similarCleanClick();
+                  },
+                );
+              }),
             ],
           ),
           // SizedBox(height: 19.h),
@@ -440,23 +444,23 @@ class HomePage extends BaseView<HomeController> {
                     size: 70.w,
                     image: controller.similarPhotos.length < 4
                         ? Assets.images.iconHomeNoPhoto.image(
-                            width: 70.w * 0.45,
-                            height: 70.w * 0.45,
-                          )
+                      width: 70.w * 0.45,
+                      height: 70.w * 0.45,
+                    )
                         : AssetEntityImage(
-                            width: 70.w,
-                            height: 70.w,
-                            controller.similarPhotos[index],
-                            isOriginal: false,
-                            thumbnailSize: const ThumbnailSize.square(300),
-                            fit: BoxFit.cover,
-                            errorBuilder: (context, error, stackTrace) {
-                              return Assets.images.iconHomeNoPhoto.image(
-                                width: 70.w * 0.45,
-                                height: 70.w * 0.45,
-                              );
-                            },
-                          ));
+                      width: 70.w,
+                      height: 70.w,
+                      controller.similarPhotos[index],
+                      isOriginal: false,
+                      thumbnailSize: const ThumbnailSize.square(300),
+                      fit: BoxFit.cover,
+                      errorBuilder: (context, error, stackTrace) {
+                        return Assets.images.iconHomeNoPhoto.image(
+                          width: 70.w * 0.45,
+                          height: 70.w * 0.45,
+                        );
+                      },
+                    ));
               }),
             );
           }),
@@ -518,15 +522,15 @@ class HomePage extends BaseView<HomeController> {
                     return ImageContainer(
                       image: controller.peoplePhotos.length < 2
                           ? Assets.images.iconHomeNoPhoto.image(
-                              width: 146.w * 0.45,
-                              height: 146.w * 0.45,
-                            )
+                        width: 146.w * 0.45,
+                        height: 146.w * 0.45,
+                      )
                           : Image.file(
-                              width: 146.w,
-                              height: 146.w,
-                              controller.peoplePhotos[index],
-                              fit: BoxFit.cover,
-                            ),
+                        width: 146.w,
+                        height: 146.w,
+                        controller.peoplePhotos[index],
+                        fit: BoxFit.cover,
+                      ),
                       // 可以传入不同的路径
                       size: 146.w,
                     );
@@ -539,13 +543,16 @@ class HomePage extends BaseView<HomeController> {
           Positioned(
             bottom: 20.h,
             right: 20.w,
-            child: CleanUpButton(
-              label: 'Clean up',
-              size: '0 GB',
-              onTap: () {
-                controller.peopleCleanClick();
-              },
-            ),
+            child: Obx(() {
+              return CleanUpButton(
+                label: 'Clean up',
+                size: ImagePickerUtil.formatFileSize(
+                    ImagePickerUtil.peopleSize.value),
+                onTap: () {
+                  controller.peopleCleanClick();
+                },
+              );
+            }),
           ),
         ],
       ),
@@ -593,15 +600,15 @@ class HomePage extends BaseView<HomeController> {
                   return Center(
                     child: controller.locationPhoto.value == null
                         ? Assets.images.iconHomeNoPhoto.image(
-                            width: 60.w,
-                            height: 60.h,
-                          )
+                      width: 60.w,
+                      height: 60.h,
+                    )
                         : Image.file(
-                            width: 304.w,
-                            height: 171.h,
-                            controller.locationPhoto.value!,
-                            fit: BoxFit.cover,
-                          ),
+                      width: 304.w,
+                      height: 171.h,
+                      controller.locationPhoto.value!,
+                      fit: BoxFit.cover,
+                    ),
                   );
                 }),
               ),
@@ -611,13 +618,16 @@ class HomePage extends BaseView<HomeController> {
           Positioned(
             bottom: 20.h,
             right: 8.w,
-            child: CleanUpButton(
-              label: 'Clean up',
-              size: '0 GB',
-              onTap: () {
-                controller.locationCleanClick();
-              },
-            ),
+            child: Obx(() {
+              return CleanUpButton(
+                label: 'Clean up',
+                size: ImagePickerUtil.formatFileSize(
+                    ImagePickerUtil.locationsSize.value),
+                onTap: () {
+                  controller.locationCleanClick();
+                },
+              );
+            }),
           ),
         ],
       ),
@@ -635,24 +645,26 @@ class HomePage extends BaseView<HomeController> {
             _buildCard(
                 'Screenshots',
                 'Clean up',
-                '0 GB',
+                ImagePickerUtil.formatFileSize(
+                    ImagePickerUtil.screenshotsSize.value),
                 controller.screenshotPhoto.value == null
                     ? Assets.images.iconHomeNoPhoto.image(
-                        width: 60.w,
-                        height: 60.h,
-                      )
+                  width: 60.w,
+                  height: 60.h,
+                )
                     : Image.file(
-                        width: 144.w,
-                        height: 142.h,
-                        controller.screenshotPhoto.value!,
-                        fit: BoxFit.cover,
-                      ), onTap: () {
+                  width: 144.w,
+                  height: 142.h,
+                  controller.screenshotPhoto.value!,
+                  fit: BoxFit.cover,
+                ), onTap: () {
               controller.screenshotCleanClick();
             }),
             _buildCard(
                 'Blurry',
                 'Clean up',
-                '0 GB',
+                ImagePickerUtil.formatFileSize(
+                    ImagePickerUtil.screenshotsSize.value),
                 Assets.images.iconHomeNoPhoto.image(
                   width: 60.w,
                   height: 60.h,

+ 84 - 12
lib/module/image_picker/image_picker_util.dart

@@ -1,5 +1,7 @@
 import 'dart:io';
+import 'dart:math';
 
+import 'package:clean/model/asset_group.dart';
 import 'package:get/get.dart';
 import 'package:photo_manager/photo_manager.dart';
 
@@ -11,13 +13,24 @@ class ImagePickerUtil {
   // 全局存储不同类型的照片
   // 截图图片
   static final RxList<AssetEntity> screenshotPhotos = <AssetEntity>[].obs;
+
   // 相似图片
-  static final RxList<List<AssetEntity>> similarPhotos = <List<AssetEntity>>[].obs;
+  static final RxList<List<AssetEntity>> similarPhotos =
+      <List<AssetEntity>>[].obs;
+
   // 地点图片
-  static final RxMap<String, List<AssetEntity>> locationPhotos = <String, List<AssetEntity>>{}.obs;
+  static final RxMap<String, List<AssetEntity>> locationPhotos =
+      <String, List<AssetEntity>>{}.obs;
+
   // 人物图片
   static final RxList<AssetEntity> peoplePhotos = <AssetEntity>[].obs;
 
+  // 添加大小信息的变量
+  static final Rx<int> screenshotsSize = 0.obs;
+  static final Rx<int> locationsSize = 0.obs;
+  static final Rx<int> peopleSize = 0.obs;
+  static final Rx<int> similarPhotosSize = 0.obs;
+
   // 清除所有照片数据
   static void clearAllPhotos() {
     screenshotPhotos.clear();
@@ -27,32 +40,42 @@ class ImagePickerUtil {
   }
 
   // 更新照片数据
-  static Future<void> updatePhotos(List<Map<String, dynamic>> photoGroups) async {
+  static Future<void> updatePhotos(
+      List<Map<String, dynamic>> photoGroups) async {
     clearAllPhotos();
 
     for (var group in photoGroups) {
       String type = group['type'] as String;
-      List<dynamic> photos = group['group'] as List<dynamic>;
+      Map<dynamic, dynamic> groupData = group['group'] as Map<dynamic, dynamic>;
+      List<dynamic> photos = groupData['photos'] as List<dynamic>;
+      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;
           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;
       }
     }
   }
+
   // 将原始照片数据转换为 AssetEntity 列表
-  static Future<List<AssetEntity>> _convertToAssetEntities(List<dynamic> photos) async {
+  static Future<List<AssetEntity>> _convertToAssetEntities(
+      List<dynamic> photos) async {
     List<AssetEntity> entities = [];
     for (var photo in photos) {
       final entity = await AssetEntity.fromId(photo['id'] as String);
@@ -68,9 +91,9 @@ class ImagePickerUtil {
     final PermissionState ps = await PhotoManager.requestPermissionExtend(
         requestOption: const PermissionRequestOption(
             androidPermission: AndroidPermission(
-              type: permissionType,
-              mediaLocation: false,
-            )));
+      type: permissionType,
+      mediaLocation: false,
+    )));
     return ps.hasAccess;
   }
 
@@ -79,10 +102,59 @@ class ImagePickerUtil {
     final PermissionState ps = await PhotoManager.getPermissionState(
         requestOption: const PermissionRequestOption(
             androidPermission: AndroidPermission(
-              type: permissionType,
-              mediaLocation: false,
-            )));
+      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';
+  }
+}

+ 92 - 4
plugins/classify_photo/ios/Classes/ClassifyPhoto.swift

@@ -2,12 +2,23 @@ import Photos
 import Vision
 
 class ClassifyPhoto {
+    
+    struct PhotoSizeInfo {
+        var totalSize: Int64 = 0
+        var count: Int = 0
+    }
 
     struct ClassifiedPhotos {
         var screenshots: [PHAsset] = []
         var locations: [String: [PHAsset]] = [:] // 按地点分组
         var people: [String: [PHAsset]] = [:]     // 按人物分组
         var similarPhotos: [[PHAsset]] = [] // 存储相似照片组
+        
+        // 添加容量信息
+        var screenshotsSize: PhotoSizeInfo = PhotoSizeInfo()
+        var locationsSize: PhotoSizeInfo = PhotoSizeInfo()
+        var peopleSize: PhotoSizeInfo = PhotoSizeInfo()
+        var similarPhotosSize: PhotoSizeInfo = PhotoSizeInfo()
     }
 
     func classifyPhotos(
@@ -70,12 +81,54 @@ class ClassifyPhoto {
                     }
                     group.leave()
                 }
-
-                // 等待所有处理完成
+                
+                // 在所有分类完成后计算大小
                 group.notify(queue: .main) {
-                    progressHandler("分类完成", 1.0)
-                    completion(result)
+                    let sizeGroup = DispatchGroup()
+                    
+                    // 计算截图大小
+                    sizeGroup.enter()
+                    self.calculateAssetsSize(result.screenshots) { sizeInfo in
+                        result.screenshotsSize = sizeInfo
+                        sizeGroup.leave()
+                    }
+                    
+                    // 计算地点照片大小
+                    sizeGroup.enter()
+                    let locationAssets = Array(result.locations.values.flatMap { $0 })
+                    self.calculateAssetsSize(locationAssets) { sizeInfo in
+                        result.locationsSize = sizeInfo
+                        sizeGroup.leave()
+                    }
+                    
+                    // 计算人物照片大小
+                    sizeGroup.enter()
+                    let peopleAssets = Array(result.people.values.flatMap { $0 })
+                    self.calculateAssetsSize(peopleAssets) { sizeInfo in
+                        result.peopleSize = sizeInfo
+                        sizeGroup.leave()
+                    }
+                    
+                    // 计算相似照片大小
+                    sizeGroup.enter()
+                    let similarAssets = Array(result.similarPhotos.flatMap { $0 })
+                    self.calculateAssetsSize(similarAssets) { sizeInfo in
+                        result.similarPhotosSize = sizeInfo
+                        sizeGroup.leave()
+                    }
+                    
+                    // 所有大小计算完成后回调
+                    sizeGroup.notify(queue: .main) {
+                        progressHandler("分类完成", 1.0)
+                        completion(result)
+                    }
                 }
+
+//                // 等待所有处理完成
+//                group.notify(queue: .main) {
+//                    progressHandler("分类完成", 1.0)
+//                    completion(result)
+//                }
             }
         }
 
@@ -338,3 +391,38 @@ class ClassifyPhoto {
         completion(screenshots)
     }
 }
+
+extension ClassifyPhoto {
+    
+    // 获取资源大小的辅助方法
+    private func getAssetSize(_ asset: PHAsset, completion: @escaping (Int64) -> Void) {
+        let resources = PHAssetResource.assetResources(for: asset)
+        if let resource = resources.first {
+            var size: Int64 = 0
+            if let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong {
+                size = Int64(unsignedInt64)
+            }
+            completion(size)
+        } else {
+            completion(0)
+        }
+    }
+
+    // 计算资产组的总大小
+    private func calculateAssetsSize(_ assets: [PHAsset], completion: @escaping (PhotoSizeInfo) -> Void) {
+        let group = DispatchGroup()
+        var totalSize: Int64 = 0
+        
+        for asset in assets {
+            group.enter()
+            getAssetSize(asset) { size in
+                totalSize += size
+                group.leave()
+            }
+        }
+        
+        group.notify(queue: .main) {
+            completion(PhotoSizeInfo(totalSize: totalSize, count: assets.count))
+        }
+    }
+}

+ 39 - 30
plugins/classify_photo/ios/Classes/ClassifyPhotoPlugin.swift

@@ -43,7 +43,7 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
                    
                    // 处理截图
                    mainGroup.enter()
-                   self.processPhotoGroup(assets: result.screenshots, groupName: "screenshots") { groupData in
+                   self.processPhotoGroup(assets: result.screenshots, groupName: "screenshots", sizeInfo: result.screenshotsSize) { groupData in
                        if !groupData.isEmpty {
                            resultData.append(["group": groupData, "type": "screenshots"])
                        }
@@ -53,7 +53,7 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
                    // 处理相似照片组
                    for photoGroup in result.similarPhotos {
                        mainGroup.enter()
-                       self.processPhotoGroup(assets: photoGroup, groupName: "similar") { groupData in
+                       self.processPhotoGroup(assets: photoGroup, groupName: "similar", sizeInfo: result.similarPhotosSize) { groupData in
                            if !groupData.isEmpty {
                                resultData.append(["group": groupData, "type": "similar"])
                            }
@@ -64,7 +64,7 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
                    // 处理地点分组
                    for (location, assets) in result.locations {
                        mainGroup.enter()
-                       self.processPhotoGroup(assets: assets, groupName: location) { groupData in
+                       self.processPhotoGroup(assets: assets, groupName: location, sizeInfo: result.locationsSize) { groupData in
                            if !groupData.isEmpty {
                                resultData.append(["group": groupData, "type": "location", "name": location])
                            }
@@ -75,7 +75,7 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
                    // 处理人物分组
                    for (person, assets) in result.people {
                        mainGroup.enter()
-                       self.processPhotoGroup(assets: assets, groupName: person) { groupData in
+                       self.processPhotoGroup(assets: assets, groupName: person, sizeInfo: result.peopleSize) { groupData in
                            if !groupData.isEmpty {
                                resultData.append(["group": groupData, "type": "people"])
                            }
@@ -192,35 +192,44 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
 //      }
   }
     
-    // 辅助方法:处理照片组
-      private func processPhotoGroup(assets: [PHAsset], groupName: String, completion: @escaping ([[String: Any]]) -> Void) {
-          let photoProcessGroup = DispatchGroup()
-          var groupData: [[String: Any]] = []
+    // 处理照片组的辅助方法
+  private func processPhotoGroup(
+    assets: [PHAsset],
+    groupName: String,
+    sizeInfo: ClassifyPhoto.PhotoSizeInfo,
+    completion: @escaping ([String: Any]) -> Void
+  ) {
+      let photoProcessGroup = DispatchGroup()
+      var photosData: [[String: Any]] = []
+      
+      for asset in assets {
+          photoProcessGroup.enter()
           
-          for asset in assets {
-              photoProcessGroup.enter()
-              
-              let options = PHContentEditingInputRequestOptions()
-              options.isNetworkAccessAllowed = true
+          let options = PHContentEditingInputRequestOptions()
+          options.isNetworkAccessAllowed = true
+          
+          asset.requestContentEditingInput(with: options) { (input, info) in
+              defer { photoProcessGroup.leave() }
               
-              asset.requestContentEditingInput(with: options) { (input, info) in
-                  defer { photoProcessGroup.leave() }
-                  
-                  if let input = input, let url = input.fullSizeImageURL {
-                      let photoInfo: [String: Any] = [
-                          "path": url.path,
-                          "id": asset.localIdentifier,
-                          "width": asset.pixelWidth,
-                          "height": asset.pixelHeight,
-                          "creationDate": asset.creationDate?.timeIntervalSince1970 ?? 0
-                      ]
-                      groupData.append(photoInfo)
-                  }
+              if let input = input, let url = input.fullSizeImageURL {
+                  let photoInfo: [String: Any] = [
+                      "path": url.path,
+                      "id": asset.localIdentifier,
+                      "width": asset.pixelWidth,
+                      "height": asset.pixelHeight,
+                      "creationDate": asset.creationDate?.timeIntervalSince1970 ?? 0
+                  ]
+                  photosData.append(photoInfo)
               }
           }
-          
-          photoProcessGroup.notify(queue: .main) {
-              completion(groupData)
-          }
       }
+      
+      photoProcessGroup.notify(queue: .main) {
+          completion([
+              "photos": photosData,
+              "totalSize": sizeInfo.totalSize,
+              "count": sizeInfo.count
+          ])
+      }
+  }
 }