소스 검색

[feat]新增图片加载动画,修改ios应用名

云天逵 1 년 전
부모
커밋
52028e668d

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 0
assets/anim/anim_no_photo.json


+ 1 - 1
ios/Runner/Info.plist

@@ -17,7 +17,7 @@
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleName</key>
-	<string>clean</string>
+	<string>CleanPro</string>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>

+ 9 - 8
lib/module/calendar/calendar_month_view.dart

@@ -7,6 +7,7 @@ import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 import '../../data/bean/photos_type.dart';
 import '../../resource/assets.gen.dart';
 import '../../router/app_pages.dart';
+import '../../utils/styles.dart';
 import '../people_photo/photo_group.dart';
 import 'calendar_state.dart';
 
@@ -225,15 +226,15 @@ class CalendarMonthPage extends BasePage<CalendarMonthController> {
                       shape: RoundedRectangleBorder(
                         borderRadius: BorderRadius.circular(9.27.sp),
                       ),
-                      image: DecorationImage(
-                        image: AssetEntityImageProvider(
-                          controller.photoGroup.value.images[index],
-                          thumbnailSize: const ThumbnailSize.square(300),
-                          isOriginal: false,
-                        ),
-                        fit: BoxFit.cover,
-                      ),
+
                     ),
+                    child: ClipRRect(
+                      borderRadius: BorderRadius.circular(9.27.sp),
+                      child: AssetEntityImage( controller.photoGroup.value.images[index],
+                      thumbnailSize: const ThumbnailSize.square(300), width: 104.w,
+                      height: 104.w,fit: BoxFit.cover,
+                      isOriginal: false,frameBuilder: Styles.customFrameBuilder(),
+                      ),)
                   ),
                   if (controller.photoGroup.value.images[index].type == AssetType.video)
                     Positioned(

+ 23 - 15
lib/module/calendar/calendar_view.dart

@@ -3,10 +3,12 @@ import 'package:get/get.dart';
 import 'package:clean/module/calendar/calendar_controller.dart';
 import 'package:flutter/Material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:lottie/lottie.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
 import '../../base/base_view.dart';
 import '../../resource/assets.gen.dart';
+import '../../utils/styles.dart';
 import '../people_photo/photo_group.dart';
 import 'calendar_state.dart';
 
@@ -33,7 +35,7 @@ class CalendarPage extends BaseView<CalendarController> {
                 }
                 return SliverList(
                   delegate: SliverChildBuilderDelegate(
-                        (context, index) {
+                    (context, index) {
                       return monthCard(controller.monthlyAlbums[index]);
                     },
                     childCount: controller.monthlyAlbums.length, // 添加 itemCount
@@ -68,9 +70,10 @@ class CalendarPage extends BaseView<CalendarController> {
             ),
           ),
           Spacer(),
-         GestureDetector(
-            onTap: () => controller.clickSort(),
-            child: Assets.images.iconCalendarSort.image(width: 28.w, height: 28.w)),
+          GestureDetector(
+              onTap: () => controller.clickSort(),
+              child: Assets.images.iconCalendarSort
+                  .image(width: 28.w, height: 28.w)),
         ],
       ),
     );
@@ -108,8 +111,7 @@ class CalendarPage extends BaseView<CalendarController> {
                     Spacer(),
                     Obx(() {
                       return Text(
-                        '${photoGroup.selectedCount}/${photoGroup.images
-                            .length}',
+                        '${photoGroup.selectedCount}/${photoGroup.images.length}',
                         textAlign: TextAlign.center,
                         style: TextStyle(
                           color: Colors.white.withValues(alpha: 0.8),
@@ -135,12 +137,16 @@ class CalendarPage extends BaseView<CalendarController> {
                             height: 146.w,
                             decoration: BoxDecoration(
                               borderRadius: BorderRadius.circular(12.r),
-                              image: DecorationImage(
-                                image: AssetEntityImageProvider(
-                                  photoGroup.images[index],
-                                  isOriginal: false,
-                                ),
+
+                            ),
+                            child: ClipRRect(
+                              borderRadius: BorderRadius.circular(12.r),
+                              child: AssetEntityImage(
+                                width: 146.w,
+                                height: 146.w,
                                 fit: BoxFit.cover,
+                                photoGroup.images[index],
+                                frameBuilder: Styles.customFrameBuilder(),
                               ),
                             ),
                           ),
@@ -150,14 +156,17 @@ class CalendarPage extends BaseView<CalendarController> {
                               bottom: 8.w,
                               right: 8.w,
                               child: Container(
-                                padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
+                                padding: EdgeInsets.symmetric(
+                                    horizontal: 6.w, vertical: 2.h),
                                 decoration: BoxDecoration(
                                   color: Colors.black54,
                                   borderRadius: BorderRadius.circular(6.r),
                                 ),
                                 child: Text(
-                                  CalendarState.formatDuration(photoGroup.images[index].duration),
-                                  style: TextStyle(color: Colors.white, fontSize: 12.sp),
+                                  CalendarState.formatDuration(
+                                      photoGroup.images[index].duration),
+                                  style: TextStyle(
+                                      color: Colors.white, fontSize: 12.sp),
                                 ),
                               ),
                             ),
@@ -184,7 +193,6 @@ class CalendarPage extends BaseView<CalendarController> {
   Widget _noNoPicturesCard() {
     return Column(
       children: [
-
         SizedBox(
           height: 170.h,
         ),

+ 102 - 97
lib/module/calendar/preview/calendar_preview_view.dart

@@ -10,8 +10,10 @@ import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
 import '../../../resource/assets.gen.dart';
 import '../../../router/app_pages.dart';
+import '../../../utils/styles.dart';
 import '../../people_photo/photo_group.dart';
 import 'package:video_player/video_player.dart';
+
 class CalendarPreviewPage extends BasePage<CalendarPreviewController> {
   const CalendarPreviewPage({Key? key}) : super(key: key);
 
@@ -72,55 +74,59 @@ class CalendarPreviewPage extends BasePage<CalendarPreviewController> {
                       numberOfCardsDisplayed:
                           (controller.photoGroup.value.images.length == 1)
                               ? 1
-                              : 2,
+                              : 1,
                       onEnd: controller.onSwiperEnd,
                       cardBuilder: (context, index, horizontalOffsetPercentage,
                           verticalOffsetPercentage) {
-
                         final assetEntity =
                             controller.photoGroup.value.images[index];
                         return Stack(
                           children: [
-
                             ClipRRect(
                                 borderRadius: BorderRadius.circular(20.r),
                                 child:
-                              //   判断这个是不是视频
-                              assetEntity.type == AssetType.video
-                                  ? Stack(
-                                alignment: Alignment.center,
-                                children: [
-                                  AssetEntityImage(
-                                    assetEntity,
-                                    width: 314.w,
-                                    height: 392.h,
-                                    fit: BoxFit.cover,
+                                    //   判断这个是不是视频
+                                    assetEntity.type == AssetType.video
+                                        ? Stack(
+                                            alignment: Alignment.center,
+                                            children: [
+                                              AssetEntityImage(
+                                                assetEntity,
+                                                width: 314.w,
+                                                height: 392.h,
+                                                fit: BoxFit.cover,
+                                              ),
+                                              GestureDetector(
+                                                // 点击播放视频
+                                                onTap: () => controller
+                                                    .playVideo(assetEntity),
+                                                child: Icon(
+                                                  Icons.play_circle_filled,
+                                                  size: 50.w,
+                                                  color: Colors.white
+                                                      .withValues(alpha: 0.8),
+                                                ),
+                                              )
+                                            ],
+                                          )
+                                        : AssetEntityImage(
 
-                                  ),
-                                  GestureDetector(
-                                    // 点击播放视频
-                                    onTap: () => controller.playVideo(assetEntity),
-                                    child: Icon(
-                                      Icons.play_circle_filled,
-                                      size: 50.w,
-                                      color: Colors.white.withValues(alpha: 0.8),
-                                    ),
-                                  )
-                                ],
-                              )
-                                  :   AssetEntityImage(
-                                assetEntity,
-                                width: 314.w,
-                                height: 392.h,
-                                fit: BoxFit.cover,
-                                isOriginal: true,
-                                errorBuilder: (context, error, stackTrace) {
-                                  debugPrint('AssetEntityImage error $error');
-                                  return Container(
-                                  );
-                                },
-                              )
-                              ),
+                                            assetEntity,
+                                            width: 314.w,
+                                            height: 392.h,
+                                            fit: BoxFit.cover,
+                                            isOriginal: true,
+                                      loadingBuilder: (context,child,loadingProgress){
+
+                                      }
+                                            // errorBuilder:
+                                            //     (context, error, stackTrace) {
+                                            //   debugPrint(
+                                            //       'AssetEntityImage error $error');
+                                            //   return Container();
+                                            // },
+                                            // frameBuilder: Styles.animFrameBuilder(),
+                                          )),
                             if (horizontalOffsetPercentage != 0)
                               Positioned(
                                 top: 0,
@@ -258,70 +264,69 @@ class CalendarPreviewPage extends BasePage<CalendarPreviewController> {
 
   Widget _bottomBarCard() {
     return GestureDetector(
-        onTap:controller.clickJumpSelected,
-      child:
-      Container(
-      width: 360.w,
-      height: 81.h,
-      padding: EdgeInsets.symmetric(horizontal: 16.w),
-      decoration: ShapeDecoration(
-        color: Color(0xFF23232A),
-        shape: RoundedRectangleBorder(
-          side: BorderSide(
-              width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
-          borderRadius: BorderRadius.only(
-            topLeft: Radius.circular(14.r),
-            topRight: Radius.circular(14.r),
-          ),
-        ),
-      ),
-      child: Row(
-        mainAxisAlignment: MainAxisAlignment.spaceBetween,
-        children: [
-          Obx(() {
-            return Text(
-              '${controller.photoGroup.value.selectedPhotosIds.length} files selected (${controller.selectedFilesSizeString} )',
-              textAlign: TextAlign.center,
-              style: TextStyle(
-                color: Colors.white.withValues(alpha: 0.9),
-                fontSize: 13.sp,
-                fontWeight: FontWeight.w500,
+        onTap: controller.clickJumpSelected,
+        child: Container(
+          width: 360.w,
+          height: 81.h,
+          padding: EdgeInsets.symmetric(horizontal: 16.w),
+          decoration: ShapeDecoration(
+            color: Color(0xFF23232A),
+            shape: RoundedRectangleBorder(
+              side: BorderSide(
+                  width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
+              borderRadius: BorderRadius.only(
+                topLeft: Radius.circular(14.r),
+                topRight: Radius.circular(14.r),
               ),
-            );
-          }),
-          GestureDetector(
-              onTap: controller.clickDelete,
-              child: Container(
-                width: 108.w,
-                height: 38.h,
-                decoration: ShapeDecoration(
-                  color: Color(0xFF0279FB),
-                  shape: RoundedRectangleBorder(
-                    borderRadius: BorderRadius.circular(10.r),
+            ),
+          ),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              Obx(() {
+                return Text(
+                  '${controller.photoGroup.value.selectedPhotosIds.length} files selected (${controller.selectedFilesSizeString} )',
+                  textAlign: TextAlign.center,
+                  style: TextStyle(
+                    color: Colors.white.withValues(alpha: 0.9),
+                    fontSize: 13.sp,
+                    fontWeight: FontWeight.w500,
                   ),
-                ),
-                child: Row(
-                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                  children: [
-                    Text(
-                      'Delete',
-                      textAlign: TextAlign.center,
-                      style: TextStyle(
-                        color: Colors.white,
-                        fontSize: 16.sp,
-                        fontWeight: FontWeight.w500,
+                );
+              }),
+              GestureDetector(
+                  onTap: controller.clickDelete,
+                  child: Container(
+                    width: 108.w,
+                    height: 38.h,
+                    decoration: ShapeDecoration(
+                      color: Color(0xFF0279FB),
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(10.r),
                       ),
                     ),
-                    Assets.images.iconDelete.image(
-                      width: 18.w,
-                      height: 18.h,
+                    child: Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                      children: [
+                        Text(
+                          'Delete',
+                          textAlign: TextAlign.center,
+                          style: TextStyle(
+                            color: Colors.white,
+                            fontSize: 16.sp,
+                            fontWeight: FontWeight.w500,
+                          ),
+                        ),
+                        Assets.images.iconDelete.image(
+                          width: 18.w,
+                          height: 18.h,
+                        ),
+                      ],
                     ),
-                  ],
-                ),
-              )),
-        ],
-      ),
-    ));
+                  )),
+            ],
+          ),
+        ));
   }
 
   Widget bottomButtonCard() {

+ 11 - 12
lib/module/calendar/selected_preview/calendar_selected_preview_view.dart

@@ -213,23 +213,22 @@ class CalendarSelectedPreviewPage
             return Stack(
               children: [
                 Container(
-                  width: 104.w,
-                  height: 104.w,
-                  decoration: ShapeDecoration(
-                    color: Colors.white.withValues(alpha: 0.12),
-                    shape: RoundedRectangleBorder(
-                      borderRadius: BorderRadius.circular(9.27.sp),
+                    width: 104.w,
+                    height: 104.w,
+                    decoration: ShapeDecoration(
+                      color: Colors.white.withValues(alpha: 0.12),
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(9.27.sp),
+                      ),
                     ),
-                    image: DecorationImage(
-                      image: AssetEntityImageProvider(
+                    child: ClipRRect(
+                      borderRadius: BorderRadius.circular(9.27.sp),
+                      child: AssetEntityImage(
                         controller.photoGroup.value.images[index],
                         thumbnailSize: const ThumbnailSize.square(300),
                         isOriginal: false,
                       ),
-                      fit: BoxFit.cover,
-                    ),
-                  ),
-                ),
+                    )),
                 Positioned(
                   right: 8.w,
                   bottom: 8.h,

+ 5 - 2
lib/module/home/home_controller.dart

@@ -77,13 +77,14 @@ class HomeController extends BaseController {
     super.onInit();
 
     if (Platform.isAndroid) {
-      loadPhotosFromDirectory();
+      await loadPhotosFromDirectory();
+
     }
 
+
     if (await Permission.photos.request().isGranted) {
       PhotoManager.clearFileCache();
       getStorageInfo();
-
       handlePhotos();
     } else {
       ToastUtil.show("Please enable the album permission");
@@ -136,6 +137,8 @@ class HomeController extends BaseController {
         ImagePickerUtil.similarPhotos.add(result ?? []);
 
         ImagePickerUtil.blurryPhotos.value = result ?? [];
+
+
       } catch (e) {
         print('Error loading photos: $e');
       }

+ 243 - 210
lib/module/home/home_view.dart

@@ -10,6 +10,7 @@ import 'package:clean/utils/image_util.dart';
 import 'package:get/get.dart';
 import 'package:flutter/Material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:lottie/lottie.dart';
 import 'package:syncfusion_flutter_charts/charts.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
@@ -119,7 +120,9 @@ class HomePage extends BaseView<HomeController> {
                     Colors.red),
                 PieData(
                   'Unused Space',
-                 controller.isStorageScanned.value?  controller.freeSpacePercentage: 100,
+                  controller.isStorageScanned.value
+                      ? controller.freeSpacePercentage
+                      : 100,
                   Colors.white.withValues(alpha: 0.10000000149011612),
                 ),
               ],
@@ -180,7 +183,8 @@ class HomePage extends BaseView<HomeController> {
                     textAlign: TextAlign.center,
                     style: TextStyle(
                       color: Colors.white.withValues(alpha: 0.6000000238418579),
-                      fontSize:controller.isStorageScanned.value?  14.87.sp: 12.sp,
+                      fontSize:
+                          controller.isStorageScanned.value ? 14.87.sp : 12.sp,
                       height: 1,
                       fontWeight: FontWeight.w500,
                     ),
@@ -368,7 +372,10 @@ class HomePage extends BaseView<HomeController> {
   }
 
   Widget similarCard() {
-    return Container(
+    return GestureDetector(onTap: () {
+      controller.similarCleanClick();
+    },
+        child: Container(
       width: 328.w,
       height: 155.h,
       margin: EdgeInsets.only(top: 20.h),
@@ -427,7 +434,7 @@ class HomePage extends BaseView<HomeController> {
               Obx(() {
                 return CleanUpButton(
                   label:
-                      !controller.isScanned.value ? 'Scanning...' : 'Clean up',
+                  !controller.isScanned.value ? 'Scanning...' : 'Clean up',
                   size: ImagePickerUtil.formatFileSize(
                       ImagePickerUtil.similarPhotosSize.value),
                   onTap: () {
@@ -456,15 +463,19 @@ class HomePage extends BaseView<HomeController> {
                       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,
-                    );
-                  });
+                        return Assets.images.iconHomeNoPhoto.image(
+                          width: 70.w * 0.45,
+                          height: 70.w * 0.45,
+                        );
+                      });
                 }
                 return ImageContainer(
                   size: 70.w,
-                  image: image,
+                  image: Opacity(
+                    opacity: 0.22,
+                    child: Lottie.asset(Assets.anim.animNoPhoto,
+                        repeat: true, width: 100.w, height: 100.w),
+                  ),
                   // AssetEntityImage(
                   //         width: 70.w,
                   //         height: 70.w,
@@ -485,7 +496,7 @@ class HomePage extends BaseView<HomeController> {
           Spacer(),
         ],
       ),
-    );
+    ));
   }
 
   Widget quickPhotoCard() {
@@ -505,180 +516,197 @@ class HomePage extends BaseView<HomeController> {
   }
 
   Widget peopleCard() {
-    return Container(
-      margin: EdgeInsets.only(top: 12.h),
-      width: 328.w,
-      height: 205.h,
-      decoration: ShapeDecoration(
-        color: Colors.white.withValues(alpha: 0.12),
-        shape: RoundedRectangleBorder(
-          borderRadius: BorderRadius.circular(14.sp),
-        ),
-      ),
-      child: Stack(
-        children: [
-          Column(
-            crossAxisAlignment: CrossAxisAlignment.start,
+    return GestureDetector(
+        onTap: () {
+          controller.peopleCleanClick();
+        },
+        child: Container(
+          margin: EdgeInsets.only(top: 12.h),
+          width: 328.w,
+          height: 205.h,
+          decoration: ShapeDecoration(
+            color: Colors.white.withValues(alpha: 0.12),
+            shape: RoundedRectangleBorder(
+              borderRadius: BorderRadius.circular(14.sp),
+            ),
+          ),
+          child: Stack(
             children: [
-              Spacer(),
-              Padding(
-                padding: EdgeInsets.only(left: 14.0.w),
-                child: Text(
-                  'People',
-                  style: TextStyle(
-                    color: Colors.white,
-                    fontSize: 16.sp,
-                    fontWeight: FontWeight.w700,
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Spacer(),
+                  Padding(
+                    padding: EdgeInsets.only(left: 14.0.w),
+                    child: Text(
+                      'People',
+                      style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 16.sp,
+                        fontWeight: FontWeight.w700,
+                      ),
+                    ),
                   ),
-                ),
-              ),
-              Spacer(),
-              Obx(() {
-                return Row(
-                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                  children: List.generate(2, (index) {
-                    var image = Assets.images.iconHomeNoPhoto.image(
-                      width: 146.w * 0.45,
-                      height: 146.w * 0.45,
-                    );
-                    if (controller.peoplePhotos.length > index) {
-                      image = AssetEntityImage(
-                          width: 146.w,
-                          height: 146.w,
-                          controller.peoplePhotos[index],
-                          isOriginal: false,
-                          thumbnailSize: const ThumbnailSize.square(300),
-                          fit: BoxFit.cover,
-                          errorBuilder: (context, error, stackTrace) {
-                        return Assets.images.iconHomeNoPhoto.image(
+                  Spacer(),
+                  Obx(() {
+                    return Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                      children: List.generate(2, (index) {
+                        var image = Assets.images.iconHomeNoPhoto.image(
                           width: 146.w * 0.45,
                           height: 146.w * 0.45,
                         );
-                      });
-                    }
-                    return ImageContainer(
-                      image: image,
-                      size: 146.w,
-                      // Image.file(
-                      //   width: 146.w,
-                      //   height: 146.w,
-                      //   controller.peoplePhotos[index],
-                      //   fit: BoxFit.cover,
-                      // ),
-                      // 可以传入不同的路径
+                        if (controller.peoplePhotos.length > index) {
+                          image = AssetEntityImage(
+                              width: 146.w,
+                              height: 146.w,
+                              controller.peoplePhotos[index],
+                              isOriginal: false,
+                              thumbnailSize: const ThumbnailSize.square(300),
+                              fit: BoxFit.cover,
+                              errorBuilder: (context, error, stackTrace) {
+                            return Assets.images.iconHomeNoPhoto.image(
+                              width: 146.w * 0.45,
+                              height: 146.w * 0.45,
+                            );
+                          });
+                        }
+                        return ImageContainer(
+                          image: Opacity(
+                            opacity: 0.22,
+                            child: Lottie.asset(Assets.anim.animNoPhoto,
+                                repeat: true, width: 140.w, height: 140.w),
+                          ),
+                          size: 146.w,
+                          // Image.file(
+                          //   width: 146.w,
+                          //   height: 146.w,
+                          //   controller.peoplePhotos[index],
+                          //   fit: BoxFit.cover,
+                          // ),
+                          // 可以传入不同的路径
+                        );
+                      }),
                     );
                   }),
-                );
-              }),
-              Spacer(),
+                  Spacer(),
+                ],
+              ),
+              Positioned(
+                bottom: 20.h,
+                right: 20.w,
+                child: Obx(() {
+                  return CleanUpButton(
+                    label: !controller.isScanned.value
+                        ? 'Scanning...'
+                        : 'Clean up',
+                    size: ImagePickerUtil.formatFileSize(
+                        ImagePickerUtil.peopleSize.value),
+                    onTap: () {
+                      controller.peopleCleanClick();
+                    },
+                  );
+                }),
+              ),
             ],
           ),
-          Positioned(
-            bottom: 20.h,
-            right: 20.w,
-            child: Obx(() {
-              return CleanUpButton(
-                label: !controller.isScanned.value ? 'Scanning...' : 'Clean up',
-                size: ImagePickerUtil.formatFileSize(
-                    ImagePickerUtil.peopleSize.value),
-                onTap: () {
-                  controller.peopleCleanClick();
-                },
-              );
-            }),
-          ),
-        ],
-      ),
-    );
+        ));
   }
 
   Widget locationsCard() {
-    return Container(
-      padding: EdgeInsets.symmetric(horizontal: 12.w),
-      margin: EdgeInsets.only(top: 14.h),
-      width: 328.w,
-      height: 230.h,
-      decoration: ShapeDecoration(
-        color: Colors.white.withValues(alpha: 0.12),
-        shape: RoundedRectangleBorder(
-          borderRadius: BorderRadius.circular(14.sp),
-        ),
-      ),
-      child: Stack(
-        children: [
-          Column(
-            crossAxisAlignment: CrossAxisAlignment.start,
+    return GestureDetector(
+        onTap: () {
+          controller.locationCleanClick();
+        },
+        child: Container(
+          padding: EdgeInsets.symmetric(horizontal: 12.w),
+          margin: EdgeInsets.only(top: 14.h),
+          width: 328.w,
+          height: 230.h,
+          decoration: ShapeDecoration(
+            color: Colors.white.withValues(alpha: 0.12),
+            shape: RoundedRectangleBorder(
+              borderRadius: BorderRadius.circular(14.sp),
+            ),
+          ),
+          child: Stack(
             children: [
-              Spacer(),
-              Text(
-                'Locations',
-                style: TextStyle(
-                  color: Colors.white,
-                  fontSize: 16.sp,
-                  fontWeight: FontWeight.w700,
-                ),
-              ),
-              Spacer(),
-              Container(
-                width: 304.w,
-                height: 171.h,
-                clipBehavior: Clip.hardEdge,
-                decoration: ShapeDecoration(
-                  color: Color(0xFF272C33),
-                  shape: RoundedRectangleBorder(
-                    borderRadius: BorderRadius.circular(12.r),
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Spacer(),
+                  Text(
+                    'Locations',
+                    style: TextStyle(
+                      color: Colors.white,
+                      fontSize: 16.sp,
+                      fontWeight: FontWeight.w700,
+                    ),
                   ),
-                ),
+                  Spacer(),
+                  Container(
+                    width: 304.w,
+                    height: 171.h,
+                    clipBehavior: Clip.hardEdge,
+                    decoration: ShapeDecoration(
+                      color: Color(0xFF272C33),
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(12.r),
+                      ),
+                    ),
+                    child: Obx(() {
+                      return Center(
+                        child: controller.locationPhoto.value == null
+                            ? Opacity(
+                                opacity: 0.22,
+                                child: Lottie.asset(Assets.anim.animNoPhoto,
+                                    repeat: true, width: 160.w, height: 160.w),
+                              )
+                            : AssetEntityImage(
+                                width: 304.w,
+                                height: 171.h,
+                                controller.locationPhoto.value!,
+                                isOriginal: false,
+                                thumbnailSize: const ThumbnailSize.square(300),
+                                fit: BoxFit.cover,
+                                errorBuilder: (context, error, stackTrace) {
+                                  return Assets.images.iconHomeNoPhoto.image(
+                                    width: 60.w,
+                                    height: 60.h,
+                                  );
+                                },
+                              ),
+                        // Image.file(
+                        //         width: 304.w,
+                        //         height: 171.h,
+                        //         controller.locationPhoto.value!,
+                        //         fit: BoxFit.cover,
+                        //       ),
+                      );
+                    }),
+                  ),
+                  Spacer(),
+                ],
+              ),
+              Positioned(
+                bottom: 20.h,
+                right: 8.w,
                 child: Obx(() {
-                  return Center(
-                    child: controller.locationPhoto.value == null
-                        ? Assets.images.iconHomeNoPhoto.image(
-                            width: 60.w,
-                            height: 60.h,
-                          )
-                        : AssetEntityImage(
-                            width: 304.w,
-                            height: 171.h,
-                            controller.locationPhoto.value!,
-                            isOriginal: false,
-                            thumbnailSize: const ThumbnailSize.square(300),
-                            fit: BoxFit.cover,
-                            errorBuilder: (context, error, stackTrace) {
-                              return Assets.images.iconHomeNoPhoto.image(
-                                width: 60.w,
-                                height: 60.h,
-                              );
-                            },
-                          ),
-                    // Image.file(
-                    //         width: 304.w,
-                    //         height: 171.h,
-                    //         controller.locationPhoto.value!,
-                    //         fit: BoxFit.cover,
-                    //       ),
+                  return CleanUpButton(
+                    label: !controller.isScanned.value
+                        ? 'Scanning...'
+                        : 'Clean up',
+                    size: ImagePickerUtil.formatFileSize(
+                        ImagePickerUtil.locationsSize.value),
+                    onTap: () {
+                      controller.locationCleanClick();
+                    },
                   );
                 }),
               ),
-              Spacer(),
             ],
           ),
-          Positioned(
-            bottom: 20.h,
-            right: 8.w,
-            child: Obx(() {
-              return CleanUpButton(
-                label: !controller.isScanned.value ? 'Scanning...' : 'Clean up',
-                size: ImagePickerUtil.formatFileSize(
-                    ImagePickerUtil.locationsSize.value),
-                onTap: () {
-                  controller.locationCleanClick();
-                },
-              );
-            }),
-          ),
-        ],
-      ),
-    );
+        ));
   }
 
   Widget screenshotsAndBlurryCard() {
@@ -695,9 +723,10 @@ class HomePage extends BaseView<HomeController> {
               ImagePickerUtil.formatFileSize(
                   ImagePickerUtil.screenshotsSize.value),
               controller.screenshotPhoto.value == null
-                  ? Assets.images.iconHomeNoPhoto.image(
-                      width: 60.w,
-                      height: 60.h,
+                  ? Opacity(
+                      opacity: 0.22,
+                      child: Lottie.asset(Assets.anim.animNoPhoto,
+                          repeat: true, width: 100.w, height: 100.w),
                     )
                   : AssetEntityImage(
                       width: 144.w,
@@ -723,9 +752,10 @@ class HomePage extends BaseView<HomeController> {
                 ImagePickerUtil.formatFileSize(
                     ImagePickerUtil.blurrySize.value),
                 controller.blurryPhoto.value == null
-                    ? Assets.images.iconHomeNoPhoto.image(
-                        width: 60.w,
-                        height: 60.h,
+                    ? Opacity(
+                        opacity: 0.22,
+                        child: Lottie.asset(Assets.anim.animNoPhoto,
+                            repeat: true, width: 100.w, height: 100.w),
                       )
                     : AssetEntityImage(
                         width: 144.w,
@@ -749,52 +779,55 @@ class HomePage extends BaseView<HomeController> {
     );
   }
 
-  Widget _buildCard(String title, String buttonLabel, String size, Image image,
+  Widget _buildCard(String title, String buttonLabel, String size, Widget image,
       {required Function() onTap}) {
     return Stack(
       children: [
-        Container(
-          width: 160.w,
-          height: 189.h,
-          decoration: ShapeDecoration(
-            color: Colors.white.withValues(alpha: 0.12),
-            shape: RoundedRectangleBorder(
-              borderRadius: BorderRadius.circular(14.r),
+        GestureDetector(
+          onTap: onTap,
+          child: Container(
+            width: 160.w,
+            height: 189.h,
+            decoration: ShapeDecoration(
+              color: Colors.white.withValues(alpha: 0.12),
+              shape: RoundedRectangleBorder(
+                borderRadius: BorderRadius.circular(14.r),
+              ),
             ),
-          ),
-          child: Column(
-            crossAxisAlignment: CrossAxisAlignment.center,
-            children: [
-              Spacer(),
-              Container(
-                alignment: Alignment.centerLeft,
-                padding: EdgeInsets.only(left: 9.w),
-                child: Text(
-                  title,
-                  style: TextStyle(
-                    color: Colors.white,
-                    fontSize: 16.sp,
-                    fontWeight: FontWeight.w700,
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Spacer(),
+                Container(
+                  alignment: Alignment.centerLeft,
+                  padding: EdgeInsets.only(left: 9.w),
+                  child: Text(
+                    title,
+                    style: TextStyle(
+                      color: Colors.white,
+                      fontSize: 16.sp,
+                      fontWeight: FontWeight.w700,
+                    ),
                   ),
                 ),
-              ),
-              Spacer(),
-              Container(
-                width: 144.w,
-                height: 142.h,
-                clipBehavior: Clip.hardEdge,
-                decoration: ShapeDecoration(
-                  color: Color(0xFF272C33),
-                  shape: RoundedRectangleBorder(
-                    borderRadius: BorderRadius.circular(12.r),
+                Spacer(),
+                Container(
+                  width: 144.w,
+                  height: 142.h,
+                  clipBehavior: Clip.hardEdge,
+                  decoration: ShapeDecoration(
+                    color: Color(0xFF272C33),
+                    shape: RoundedRectangleBorder(
+                      borderRadius: BorderRadius.circular(12.r),
+                    ),
+                  ),
+                  child: Center(
+                    child: image,
                   ),
                 ),
-                child: Center(
-                  child: image,
-                ),
-              ),
-              Spacer(),
-            ],
+                Spacer(),
+              ],
+            ),
           ),
         ),
         Positioned(
@@ -874,7 +907,7 @@ class CleanUpButton extends StatelessWidget {
 }
 
 class ImageContainer extends StatelessWidget {
-  final Image image;
+  final Widget image;
   final double size;
 
   const ImageContainer({

+ 12 - 8
lib/module/locations_photo/locations_photo_view.dart

@@ -4,6 +4,7 @@ import 'package:clean/base/base_page.dart';
 import 'package:clean/module/locations_photo/locations_photo_controller.dart';
 import 'package:clean/resource/assets.gen.dart';
 import 'package:clean/router/app_pages.dart';
+import 'package:clean/utils/styles.dart';
 import 'package:flutter/Material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
@@ -37,7 +38,6 @@ class LocationsPhotoPage extends BasePage<LocationsPhotoController> {
       IgnorePointer(
         child: Assets.images.bgHome.image(
           width: 360.w,
-
         ),
       ),
     ]);
@@ -157,14 +157,18 @@ class LocationsPhotoPage extends BasePage<LocationsPhotoController> {
                               shape: RoundedRectangleBorder(
                                 borderRadius: BorderRadius.circular(8.r),
                               ),
-                              image: DecorationImage(
-                                image: AssetEntityImageProvider(
-                                  imagePath,
-                                  thumbnailSize:
-                                      const ThumbnailSize.square(300),
-                                  isOriginal: false,
-                                ),
+                            ),
+                            child: ClipRRect(
+                              borderRadius: BorderRadius.circular(8.r),
+                              child: AssetEntityImage(
+                                imagePath,
+                                width: 304.w,
+                                thumbnailSize: const ThumbnailSize.square(300),
+                                height: 171.h,
+                                frameBuilder: Styles.customFrameBuilder(width: 140.w,
+                                    height: 140.h),
                                 fit: BoxFit.cover,
+                                isOriginal: false,
                               ),
                             ),
                           ),

+ 57 - 49
lib/module/locations_photo/locations_single_photo_view.dart

@@ -9,6 +9,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
+import '../../utils/styles.dart';
+
 class LocationsSinglePhotoPage
     extends BasePage<LocationsSinglePhotoController> {
   const LocationsSinglePhotoPage({super.key});
@@ -33,7 +35,7 @@ class LocationsSinglePhotoPage
   Widget buildBody(BuildContext context) {
     return Stack(children: [
       PopScope(
-        canPop: false,
+          canPop: false,
           onPopInvokedWithResult: (didPop, result) {
             if (didPop) {
               return;
@@ -41,51 +43,51 @@ class LocationsSinglePhotoPage
             controller.clickBack();
           },
           child: Container(
-        child: SafeArea(
-          child: Obx(() {
-            if (controller.photoGroups.isEmpty) {
-              return _noNoPicturesCard();
-            }
-            return Column(
-              children: [
-                _titleCard(),
-                Expanded(
-                  child: Obx(() {
-                    return SizedBox(
-                      child: GridView.builder(
-                          padding: EdgeInsets.symmetric(horizontal: 16.w),
-                          scrollDirection: Axis.vertical,
-                          // 设置为垂直方向滚动
-                          physics: BouncingScrollPhysics(),
-                          gridDelegate:
-                              SliverGridDelegateWithFixedCrossAxisCount(
-                            crossAxisCount: 3, // 每行显示 3 个元素
-                            mainAxisSpacing: 8.w, // 垂直间距
-                            crossAxisSpacing: 8.h, // 水平间距
-                          ),
-                          itemCount: controller.photoGroups.first.images.length,
-                          itemBuilder: _buildPhotoItem(
-                              controller.photoGroups.first.images)),
-                    );
-                  }),
-                ),
-                Obx(() {
-                  if (controller.selectedFileCount.value == 0) {
-                    return SizedBox();
-                  } else {
-                    return _bottomBarCard();
-                  }
-                }),
-                SizedBox(height: 8.h),
-              ],
-            );
-          }),
-        ),
-      )),
+            child: SafeArea(
+              child: Obx(() {
+                if (controller.photoGroups.isEmpty) {
+                  return _noNoPicturesCard();
+                }
+                return Column(
+                  children: [
+                    _titleCard(),
+                    Expanded(
+                      child: Obx(() {
+                        return SizedBox(
+                          child: GridView.builder(
+                              padding: EdgeInsets.symmetric(horizontal: 16.w),
+                              scrollDirection: Axis.vertical,
+                              // 设置为垂直方向滚动
+                              physics: BouncingScrollPhysics(),
+                              gridDelegate:
+                                  SliverGridDelegateWithFixedCrossAxisCount(
+                                crossAxisCount: 3, // 每行显示 3 个元素
+                                mainAxisSpacing: 8.w, // 垂直间距
+                                crossAxisSpacing: 8.h, // 水平间距
+                              ),
+                              itemCount:
+                                  controller.photoGroups.first.images.length,
+                              itemBuilder: _buildPhotoItem(
+                                  controller.photoGroups.first.images)),
+                        );
+                      }),
+                    ),
+                    Obx(() {
+                      if (controller.selectedFileCount.value == 0) {
+                        return SizedBox();
+                      } else {
+                        return _bottomBarCard();
+                      }
+                    }),
+                    SizedBox(height: 8.h),
+                  ],
+                );
+              }),
+            ),
+          )),
       IgnorePointer(
         child: Assets.images.bgHome.image(
           width: 360.w,
-
         ),
       ),
     ]);
@@ -203,13 +205,19 @@ class LocationsSinglePhotoPage
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(9.27.sp),
                     ),
-                    image: DecorationImage(
-                      image: AssetEntityImageProvider(
-                        group.images[index],
-                        thumbnailSize: const ThumbnailSize.square(300),
-                        isOriginal: false,
-                      ),
+                  ),
+                  child: ClipRRect(
+                    borderRadius: BorderRadius.circular(9.27.sp),
+                    child: AssetEntityImage(
+                      group.images[index],
+                      width: 104.w,
+                      height: 104.w,
                       fit: BoxFit.cover,
+                      frameBuilder: Styles.customFrameBuilder(
+                        opacity: 0.22,
+                        width: 80.w,
+                        height: 80.w,
+                      ),
                     ),
                   ),
                 ),

+ 114 - 111
lib/module/people_photo/people_photo_view.dart

@@ -12,6 +12,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
+import '../../utils/styles.dart';
+
 class PeoplePhotoPage extends BasePage<PeoplePhotoController> {
   const PeoplePhotoPage({super.key});
 
@@ -34,54 +36,54 @@ class PeoplePhotoPage extends BasePage<PeoplePhotoController> {
   @override
   Widget buildBody(BuildContext context) {
     return Stack(children: [
-     PopScope(
-       canPop: false,
+      PopScope(
+        canPop: false,
         onPopInvokedWithResult: (didPop, result) {
           if (didPop) {
             return;
           }
           controller.clickBack();
         },
-       child:  Container(
-        child: SafeArea(
-          child: Obx(() {
-            if (controller.photoGroups.isEmpty ||
-                controller.photoGroups[0].images.isEmpty) {
-              return _noNoPicturesCard();
-            }
-            return Column(
-              children: [
-                _titleCard(),
-                // Photo groups
-                Flexible(
-                  child: Obx(() {
-                    return ListView(
-                      padding: EdgeInsets.symmetric(horizontal: 16.w),
-                      children: [
-                        ...controller.photoGroups.map((group) => Column(
-                              children: [
-                                _buildPhotoGroup(
-                                  images: group.images,
-                                  title: "photo: ${group.images.length}",
-                                  imageCount: group.images.length,
-                                ),
-                                SizedBox(height: 15.h),
-                              ],
-                            ))
-                      ],
-                    );
-                  }),
-                ),
-                _bottomBarCard(),
-              ],
-            );
-          }),
+        child: Container(
+          child: SafeArea(
+            child: Obx(() {
+              if (controller.photoGroups.isEmpty ||
+                  controller.photoGroups[0].images.isEmpty) {
+                return _noNoPicturesCard();
+              }
+              return Column(
+                children: [
+                  _titleCard(),
+                  // Photo groups
+                  Flexible(
+                    child: Obx(() {
+                      return ListView(
+                        padding: EdgeInsets.symmetric(horizontal: 16.w),
+                        children: [
+                          ...controller.photoGroups.map((group) => Column(
+                                children: [
+                                  _buildPhotoGroup(
+                                    images: group.images,
+                                    title: "photo: ${group.images.length}",
+                                    imageCount: group.images.length,
+                                  ),
+                                  SizedBox(height: 15.h),
+                                ],
+                              ))
+                        ],
+                      );
+                    }),
+                  ),
+                  _bottomBarCard(),
+                ],
+              );
+            }),
+          ),
         ),
-      ),),
+      ),
       IgnorePointer(
         child: Assets.images.bgHome.image(
           width: 360.w,
-
         ),
       ),
     ]);
@@ -95,7 +97,7 @@ class PeoplePhotoPage extends BasePage<PeoplePhotoController> {
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
           GestureDetector(
-            onTap:  controller.clickBack,
+            onTap: controller.clickBack,
             child: Assets.images.iconBackArrow.image(
               width: 28.w,
               height: 28.h,
@@ -125,76 +127,74 @@ class PeoplePhotoPage extends BasePage<PeoplePhotoController> {
 
   Widget _bottomBarCard() {
     return GestureDetector(
-      onTap: () {
-        controller.clickJumpSelect();
-      },
-      child: Container(
-        width: 360.w,
-        height: 81.h,
-        padding: EdgeInsets.symmetric(horizontal: 16.w),
-        decoration: ShapeDecoration(
-          color: Color(0xFF23232A),
-          shape: RoundedRectangleBorder(
-            side: BorderSide(
-                width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
-            borderRadius: BorderRadius.only(
-              topLeft: Radius.circular(14.r),
-              topRight: Radius.circular(14.r),
+        onTap: () {
+          controller.clickJumpSelect();
+        },
+        child: Container(
+          width: 360.w,
+          height: 81.h,
+          padding: EdgeInsets.symmetric(horizontal: 16.w),
+          decoration: ShapeDecoration(
+            color: Color(0xFF23232A),
+            shape: RoundedRectangleBorder(
+              side: BorderSide(
+                  width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
+              borderRadius: BorderRadius.only(
+                topLeft: Radius.circular(14.r),
+                topRight: Radius.circular(14.r),
+              ),
             ),
           ),
-        ),
-        child: Row(
-          mainAxisAlignment: MainAxisAlignment.spaceBetween,
-          children: [
-            Obx(() {
-              return Text(
-                '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString})',
-                textAlign: TextAlign.center,
-                style: TextStyle(
-                  color: Colors.white.withOpacity(0.9),
-                  fontSize: 13.sp,
-                  fontWeight: FontWeight.w500,
-                ),
-              );
-            }),
-            GestureDetector(
-              onTap: () {
-                controller.clickDelete();
-              },
-              child:
-              Container(
-                width: 108.w,
-                height: 38.h,
-                decoration: ShapeDecoration(
-                  color: Color(0xFF0279FB),
-                  shape: RoundedRectangleBorder(
-                    borderRadius: BorderRadius.circular(10.r),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              Obx(() {
+                return Text(
+                  '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString})',
+                  textAlign: TextAlign.center,
+                  style: TextStyle(
+                    color: Colors.white.withOpacity(0.9),
+                    fontSize: 13.sp,
+                    fontWeight: FontWeight.w500,
                   ),
-                ),
-                child: Row(
-                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                  children: [
-                    Text(
-                      'Delete',
-                      textAlign: TextAlign.center,
-                      style: TextStyle(
-                        color: Colors.white,
-                        fontSize: 16.sp,
-                        fontWeight: FontWeight.w500,
-                      ),
-                    ),
-                    Assets.images.iconDelete.image(
-                      width: 18.w,
-                      height: 18.h,
+                );
+              }),
+              GestureDetector(
+                onTap: () {
+                  controller.clickDelete();
+                },
+                child: Container(
+                  width: 108.w,
+                  height: 38.h,
+                  decoration: ShapeDecoration(
+                    color: Color(0xFF0279FB),
+                    shape: RoundedRectangleBorder(
+                      borderRadius: BorderRadius.circular(10.r),
                     ),
-                  ],
+                  ),
+                  child: Row(
+                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                    children: [
+                      Text(
+                        'Delete',
+                        textAlign: TextAlign.center,
+                        style: TextStyle(
+                          color: Colors.white,
+                          fontSize: 16.sp,
+                          fontWeight: FontWeight.w500,
+                        ),
+                      ),
+                      Assets.images.iconDelete.image(
+                        width: 18.w,
+                        height: 18.h,
+                      ),
+                    ],
+                  ),
                 ),
               ),
-            ),
-          ],
-        ),
-      )
-    );
+            ],
+          ),
+        ));
   }
 
   Widget _buildPhotoGroup({
@@ -303,15 +303,18 @@ class PeoplePhotoPage extends BasePage<PeoplePhotoController> {
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(9.27.sp),
                     ),
-                    image: DecorationImage(
-                      image: AssetEntityImageProvider(
-                        assetEntity,
-                        thumbnailSize: const ThumbnailSize.square(300),
-                        isOriginal: false,
-                      ),
-                      fit: BoxFit.cover,
-                    ),
                   ),
+                  child: ClipRRect(
+                      borderRadius: BorderRadius.circular(9.27.sp),
+                      child: AssetEntityImage(assetEntity,
+                          thumbnailSize: const ThumbnailSize.square(300),
+                          isOriginal: false,
+                          fit: BoxFit.cover,
+                          frameBuilder: Styles.customFrameBuilder(
+                            opacity: 0.22,
+                            width: 80.w,
+                            height: 80.w,
+                          ))),
                 ),
                 Positioned(
                     right: 6.w,

+ 15 - 11
lib/module/photo_info/photo_info_view.dart

@@ -51,7 +51,7 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
                       }
                       return Text(
                         controller.imageList[controller.currentImageIndex.value]
-                            .dateTitle ??
+                                .dateTitle ??
                             "",
                         style: TextStyle(
                           color: Colors.white,
@@ -79,7 +79,8 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
                       Container(
                         margin: EdgeInsets.only(left: 18.w),
                         child: Obx(() {
-                          return Column(
+                          return SingleChildScrollView(
+                              child: Column(
                             crossAxisAlignment: CrossAxisAlignment.start,
                             children: [
                               Text(
@@ -169,7 +170,8 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
                                 ),
                               ),
                               Visibility(
-                                visible: controller.focalLength.value.isNotEmpty,
+                                visible:
+                                    controller.focalLength.value.isNotEmpty,
                                 child: Column(
                                   children: [
                                     SizedBox(
@@ -264,9 +266,11 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
                                   ],
                                 ),
                               ),
-                              SizedBox(height: 32.h,),
+                              SizedBox(
+                                height: 32.h,
+                              ),
                             ],
-                          );
+                          ));
                         }),
                       ),
                       Center(
@@ -274,7 +278,7 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
                           onTap: () {
                             controller.deleteBtnClick(
                                 controller.imageList[
-                                controller.currentImageIndex.value],
+                                    controller.currentImageIndex.value],
                                 controller.currentImageIndex.value);
                           },
                           child: Container(
@@ -301,9 +305,9 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
                                     }
                                     return Text(
                                       controller.formatFileSize(controller
-                                          .imageList[controller
-                                          .currentImageIndex.value]
-                                          .size ??
+                                              .imageList[controller
+                                                  .currentImageIndex.value]
+                                              .size ??
                                           0),
                                       style: TextStyle(
                                         color: Colors.white,
@@ -362,7 +366,7 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
               padding: EdgeInsets.symmetric(
                 horizontal: 0.w,
                 vertical:
-                controller.currentImageIndex.value == index ? 0 : 20.h,
+                    controller.currentImageIndex.value == index ? 0 : 20.h,
               ),
               child: GestureDetector(
                 // onTap: () => _showImageDetail(asset),
@@ -381,7 +385,7 @@ class PhotoInfoPage extends BasePage<PhotoInfoController> {
                     child: FutureBuilder<File?>(
                       key: ValueKey(asset.id),
                       future:
-                      ImageUtil.getImageFile(controller.type.value, asset),
+                          ImageUtil.getImageFile(controller.type.value, asset),
                       builder: (context, snapshot) {
                         if (snapshot.hasData && snapshot.data != null) {
                           return InteractiveViewer(

+ 69 - 61
lib/module/photo_preview/photo_preview_view.dart

@@ -13,6 +13,8 @@ import 'package:get/get.dart';
 import 'package:lottie/lottie.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
+import '../../utils/styles.dart';
+
 class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
   PhotoPreviewPage({Key? key}) : super(key: key);
 
@@ -75,7 +77,7 @@ class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
                         onSwipe: controller.onSwipe,
                         onUndo: controller.onSwiperUndo,
                         numberOfCardsDisplayed:
-                            (controller.listAssetEntity.length == 1) ? 1 : 2,
+                            (controller.listAssetEntity.length == 1) ? 1 : 1,
                         onEnd: controller.onSwiperEnd,
                         cardBuilder: (context,
                             index,
@@ -118,6 +120,13 @@ class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
                                             width: 314.w,
                                             height: 392.h,
                                             fit: BoxFit.cover,
+                                            errorBuilder:
+                                                (context, error, stackTrace) {
+                                              debugPrint(
+                                                  'AssetEntityImage error $error');
+                                              return Container();
+                                            },
+                                            frameBuilder: Styles.animFrameBuilder(),
                                           ),
                               ),
                               if (horizontalOffsetPercentage != 0)
@@ -259,70 +268,69 @@ class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
 
   Widget _bottomBarCard() {
     return GestureDetector(
-      onTap: controller.clickJumpSelected,
-      child: Container(
-        width: 360.w,
-        height: 81.h,
-        padding: EdgeInsets.symmetric(horizontal: 16.w),
-        decoration: ShapeDecoration(
-          color: Color(0xFF23232A),
-          shape: RoundedRectangleBorder(
-            side: BorderSide(
-                width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
-            borderRadius: BorderRadius.only(
-              topLeft: Radius.circular(14.r),
-              topRight: Radius.circular(14.r),
+        onTap: controller.clickJumpSelected,
+        child: Container(
+          width: 360.w,
+          height: 81.h,
+          padding: EdgeInsets.symmetric(horizontal: 16.w),
+          decoration: ShapeDecoration(
+            color: Color(0xFF23232A),
+            shape: RoundedRectangleBorder(
+              side: BorderSide(
+                  width: 1.w, color: Colors.white.withValues(alpha: 0.1)),
+              borderRadius: BorderRadius.only(
+                topLeft: Radius.circular(14.r),
+                topRight: Radius.circular(14.r),
+              ),
             ),
           ),
-        ),
-        child: Row(
-          mainAxisAlignment: MainAxisAlignment.spaceBetween,
-          children: [
-            Obx(() {
-              return Text(
-                '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString} )',
-                textAlign: TextAlign.center,
-                style: TextStyle(
-                  color: Colors.white.withValues(alpha: 0.9),
-                  fontSize: 13.sp,
-                  fontWeight: FontWeight.w500,
-                ),
-              );
-            }),
-            GestureDetector(
-                onTap: controller.clickDelete,
-                child: Container(
-                  width: 108.w,
-                  height: 38.h,
-                  decoration: ShapeDecoration(
-                    color: Color(0xFF0279FB),
-                    shape: RoundedRectangleBorder(
-                      borderRadius: BorderRadius.circular(10.r),
-                    ),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              Obx(() {
+                return Text(
+                  '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString} )',
+                  textAlign: TextAlign.center,
+                  style: TextStyle(
+                    color: Colors.white.withValues(alpha: 0.9),
+                    fontSize: 13.sp,
+                    fontWeight: FontWeight.w500,
                   ),
-                  child: Row(
-                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                    children: [
-                      Text(
-                        'Delete',
-                        textAlign: TextAlign.center,
-                        style: TextStyle(
-                          color: Colors.white,
-                          fontSize: 16.sp,
-                          fontWeight: FontWeight.w500,
-                        ),
-                      ),
-                      Assets.images.iconDelete.image(
-                        width: 18.w,
-                        height: 18.h,
+                );
+              }),
+              GestureDetector(
+                  onTap: controller.clickDelete,
+                  child: Container(
+                    width: 108.w,
+                    height: 38.h,
+                    decoration: ShapeDecoration(
+                      color: Color(0xFF0279FB),
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(10.r),
                       ),
-                    ],
-                  ),
-                )),
-          ],
-        ),
-      )
-    );
+                    ),
+                    child: Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                      children: [
+                        Text(
+                          'Delete',
+                          textAlign: TextAlign.center,
+                          style: TextStyle(
+                            color: Colors.white,
+                            fontSize: 16.sp,
+                            fontWeight: FontWeight.w500,
+                          ),
+                        ),
+                        Assets.images.iconDelete.image(
+                          width: 18.w,
+                          height: 18.h,
+                        ),
+                      ],
+                    ),
+                  )),
+            ],
+          ),
+        ));
   }
 
   Widget bottomButtonCard() {

+ 14 - 6
lib/module/photo_preview/phtoto_selected_preview_view.dart

@@ -10,6 +10,8 @@ import 'package:lottie/lottie.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 import 'package:get/get.dart';
 
+import '../../utils/styles.dart';
+
 class PhotoSelectedPreviewPage
     extends BasePage<PhotoSelectedPreviewController> {
   const PhotoSelectedPreviewPage({super.key});
@@ -230,13 +232,19 @@ class PhotoSelectedPreviewPage
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(9.27.sp),
                     ),
-                    image: DecorationImage(
-                      image: AssetEntityImageProvider(
-                        group.images[index],
-                        thumbnailSize: const ThumbnailSize.square(300),
-                        isOriginal: false,
-                      ),
+                  ),
+                  child: ClipRRect(
+                    borderRadius: BorderRadius.circular(9.27.sp),
+                    child: AssetEntityImage(
+                      group.images[index],
+                      width: 104.w,
+                      thumbnailSize: const ThumbnailSize.square(300),
+                      height: 104.w,
                       fit: BoxFit.cover,
+                      frameBuilder: Styles.customFrameBuilder(
+                        width: 104.w,
+                        height: 104.w,
+                      ),
                     ),
                   ),
                 ),

+ 21 - 12
lib/module/screenshots_blurry/screenshots_view.dart

@@ -7,6 +7,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
+import '../../utils/styles.dart';
+
 class ScreenshotsPage extends BasePage<ScreenShotsController> {
   const ScreenshotsPage({super.key});
 
@@ -207,23 +209,30 @@ class ScreenshotsPage extends BasePage<ScreenShotsController> {
             return Stack(
               children: [
                 Container(
-                  width: 104.w,
-                  height: 104.w,
-                  decoration: ShapeDecoration(
-                    color: Colors.white.withValues(alpha: 0.12),
-                    shape: RoundedRectangleBorder(
-                      borderRadius: BorderRadius.circular(9.27.sp),
+                    width: 104.w,
+                    height: 104.w,
+                    decoration: ShapeDecoration(
+                      color: Colors.white.withValues(alpha: 0.12),
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(9.27.sp),
+                      ),
                     ),
-                    image: DecorationImage(
-                      image: AssetEntityImageProvider(
+                    child: ClipRRect(
+                      borderRadius: BorderRadius.circular(9.27.sp),
+                      child: AssetEntityImage(
                         group.images[index],
+                        width: 104.w,
+                        height: 104.w,
                         thumbnailSize: const ThumbnailSize.square(300),
+                        fit: BoxFit.cover,
+                        frameBuilder: Styles.customFrameBuilder(
+                          opacity: 0.22,
+                          width: 80.w,
+                          height: 80.w,
+                        ),
                         isOriginal: false,
                       ),
-                      fit: BoxFit.cover,
-                    ),
-                  ),
-                ),
+                    )),
                 Positioned(
                   right: 8.w,
                   bottom: 8.h,

+ 101 - 84
lib/module/similar_photo/similar_photo_view.dart

@@ -10,6 +10,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 import 'package:wechat_assets_picker/wechat_assets_picker.dart';
 
+import '../../utils/styles.dart';
+
 class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
   const SimilarPhotoPage({super.key});
 
@@ -60,7 +62,6 @@ class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
       IgnorePointer(
         child: Assets.images.bgHome.image(
           width: 360.w,
-
         ),
       ),
     ]);
@@ -105,69 +106,70 @@ class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
 
   Widget _bottomBarCard() {
     return GestureDetector(
-        onTap:controller.clickJumpSelect,
+        onTap: controller.clickJumpSelect,
         child: Container(
-      width: 360.w,
-      height: 81.h,
-      padding: EdgeInsets.symmetric(horizontal: 16.w),
-      decoration: ShapeDecoration(
-        color: Color(0xFF23232A),
-        shape: RoundedRectangleBorder(
-          side: BorderSide(width: 1.w, color: Colors.white.withOpacity(0.1)),
-          borderRadius: BorderRadius.only(
-            topLeft: Radius.circular(14.r),
-            topRight: Radius.circular(14.r),
-          ),
-        ),
-      ),
-      child: Row(
-        mainAxisAlignment: MainAxisAlignment.spaceBetween,
-        children: [
-          Obx(() {
-            return Text(
-              '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString})',
-              textAlign: TextAlign.center,
-              style: TextStyle(
-                color: Colors.white.withValues(alpha: 0.9),
-                fontSize: 13.sp,
-                fontWeight: FontWeight.w500,
-              ),
-            );
-          }),
-          GestureDetector(
-            onTap: () => controller.clickDelete(),
-            child: Container(
-              width: 108.w,
-              height: 38.h,
-              decoration: ShapeDecoration(
-                color: Color(0xFF0279FB),
-                shape: RoundedRectangleBorder(
-                  borderRadius: BorderRadius.circular(10.r),
-                ),
+          width: 360.w,
+          height: 81.h,
+          padding: EdgeInsets.symmetric(horizontal: 16.w),
+          decoration: ShapeDecoration(
+            color: Color(0xFF23232A),
+            shape: RoundedRectangleBorder(
+              side:
+                  BorderSide(width: 1.w, color: Colors.white.withOpacity(0.1)),
+              borderRadius: BorderRadius.only(
+                topLeft: Radius.circular(14.r),
+                topRight: Radius.circular(14.r),
               ),
-              child: Row(
-                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                children: [
-                  Text(
-                    'Delete',
-                    textAlign: TextAlign.center,
-                    style: TextStyle(
-                      color: Colors.white,
-                      fontSize: 16.sp,
-                      fontWeight: FontWeight.w500,
+            ),
+          ),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              Obx(() {
+                return Text(
+                  '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString})',
+                  textAlign: TextAlign.center,
+                  style: TextStyle(
+                    color: Colors.white.withValues(alpha: 0.9),
+                    fontSize: 13.sp,
+                    fontWeight: FontWeight.w500,
+                  ),
+                );
+              }),
+              GestureDetector(
+                onTap: () => controller.clickDelete(),
+                child: Container(
+                  width: 108.w,
+                  height: 38.h,
+                  decoration: ShapeDecoration(
+                    color: Color(0xFF0279FB),
+                    shape: RoundedRectangleBorder(
+                      borderRadius: BorderRadius.circular(10.r),
                     ),
                   ),
-                  Assets.images.iconDelete.image(
-                    width: 18.w,
-                    height: 18.h,
+                  child: Row(
+                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                    children: [
+                      Text(
+                        'Delete',
+                        textAlign: TextAlign.center,
+                        style: TextStyle(
+                          color: Colors.white,
+                          fontSize: 16.sp,
+                          fontWeight: FontWeight.w500,
+                        ),
+                      ),
+                      Assets.images.iconDelete.image(
+                        width: 18.w,
+                        height: 18.h,
+                      ),
+                    ],
                   ),
-                ],
-              ),
-            ),
-          )
-        ],
-      ),
-    ));
+                ),
+              )
+            ],
+          ),
+        ));
   }
 
   Widget _buildPhotoGroup({
@@ -208,7 +210,8 @@ class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
                 onTap: () => controller.toggleGroupSelection(imagesList),
                 child: Obx(() => Text(
                       controller.photoGroups
-                              .firstWhere((g) => g.images.toSet().containsAll(imagesList))
+                              .firstWhere((g) =>
+                                  g.images.toSet().containsAll(imagesList))
                               .isSelected
                               .value
                           ? 'Deselect All'
@@ -231,13 +234,14 @@ class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
                 // 第一张大图
                 if (imageCount > 0)
                   GestureDetector(
-                    onTap: () => controller.clickImage(imagesList, 0, PhotosType.similarPhotos),
+                    onTap: () => controller.clickImage(
+                        imagesList, 0, PhotosType.similarPhotos),
                     child: SizedBox(
                       width: 148.w,
                       height: 148.h,
                       child: Obx(() {
-                        final group = controller.photoGroups
-                            .firstWhere((g) => g.images.toSet().containsAll(imagesList));
+                        final group = controller.photoGroups.firstWhere(
+                            (g) => g.images.toSet().containsAll(imagesList));
                         return Stack(
                           children: [
                             Container(
@@ -246,16 +250,22 @@ class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
                                 shape: RoundedRectangleBorder(
                                   borderRadius: BorderRadius.circular(8.r),
                                 ),
-                                image: DecorationImage(
-                                  image: AssetEntityImageProvider(
+                              ),
+                              child: ClipRRect(
+                                  borderRadius: BorderRadius.circular(8.r),
+                                  child: AssetEntityImage(
+                                    width: 148.w,
+                                    height: 148.h,
                                     group.images[0],
+                                    fit: BoxFit.cover,
                                     thumbnailSize:
                                         const ThumbnailSize.square(300),
                                     isOriginal: false,
-                                  ),
-                                  fit: BoxFit.cover,
-                                ),
-                              ),
+                                    frameBuilder: Styles.customFrameBuilder(
+                                      width: 120.w,
+                                      height: 120.w,
+                                    ),
+                                  )),
                             ),
                             Positioned(
                               left: 8.w,
@@ -341,29 +351,38 @@ class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
                           (index) {
                             final realIndex = gridIndex * 4 + index + 1;
                             return GestureDetector(
-                              onTap: () =>
-                                  controller.clickImage(imagesList, realIndex, PhotosType.similarPhotos),
+                              onTap: () => controller.clickImage(imagesList,
+                                  realIndex, PhotosType.similarPhotos),
                               child: Obx(() {
-                                final group = controller.photoGroups
-                                    .firstWhere((g) => g.images.toSet().containsAll(imagesList));
+                                final group = controller.photoGroups.firstWhere(
+                                    (g) => g.images
+                                        .toSet()
+                                        .containsAll(imagesList));
                                 return Container(
                                   decoration: ShapeDecoration(
                                     color: Colors.white.withValues(alpha: 0.12),
                                     shape: RoundedRectangleBorder(
                                       borderRadius: BorderRadius.circular(8.r),
                                     ),
-                                    image: DecorationImage(
-                                      image: AssetEntityImageProvider(
-                                        group.images[realIndex],
-                                        thumbnailSize:
-                                            const ThumbnailSize.square(300),
-                                        isOriginal: false,
-                                      ),
-                                      fit: BoxFit.cover,
-                                    ),
                                   ),
                                   child: Stack(
                                     children: [
+                                      ClipRRect(
+                                        borderRadius:
+                                            BorderRadius.circular(8.r),
+                                        child: AssetEntityImage(
+                                          group.images[realIndex],
+                                          width: 142.w,
+                                          frameBuilder: Styles.customFrameBuilder(
+                                            width: 120.w,
+                                            height: 120.w,
+                                          ),
+                                          thumbnailSize:
+                                              const ThumbnailSize.square(300),
+                                          isOriginal: false,
+                                          fit: BoxFit.cover,
+                                        ),
+                                      ),
                                       Positioned(
                                         right: 4.w,
                                         bottom: 4.h,
@@ -422,8 +441,6 @@ class SimilarPhotoPage extends BasePage<SimilarPhotoController> {
               ),
               child: Center(
                 child: Obx(() => Text(
-
-
                       'Move ${controller.photoGroups.firstWhere((g) => g.images.toSet().containsAll(imagesList)).selectedImages.where((element) => element).length} to trash',
                       style: TextStyle(
                         color: Colors.white,

+ 55 - 0
lib/utils/styles.dart

@@ -0,0 +1,55 @@
+import 'package:flutter/Material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:lottie/lottie.dart';
+
+import '../resource/assets.gen.dart';
+
+class Styles {
+  Styles._();
+
+  static ImageFrameBuilder? animFrameBuilder({double? opacity, double? width,
+    double? height, bool? repeat,}) {
+    return (context, child,
+        frame, wasSynchronouslyLoaded) {
+      if (wasSynchronouslyLoaded) {
+        return child;
+      }
+      return AnimatedSwitcher(
+          duration: const Duration(
+              milliseconds: 0),
+          child: frame != null
+              ? child
+              : Center(
+              child: Opacity(
+                opacity: opacity ?? 0.22,
+                child: Lottie.asset(
+                    Assets
+                        .anim.animNoPhoto,
+                    width: width ?? 140.w,
+                    height: height ?? 140.w,
+                    repeat: repeat ?? true
+                ),
+              )));
+    };
+  }
+
+  static ImageFrameBuilder? customFrameBuilder({double? opacity, double? width,
+    double? height, bool? repeat,}) {
+    return (context, child,
+        frame, wasSynchronouslyLoaded) {
+      if (wasSynchronouslyLoaded) {
+        return child;
+      }
+      return AnimatedSwitcher(
+          duration: const Duration(
+              milliseconds: 0),
+          child: frame != null
+              ? child
+              : Center(
+              child: Opacity(
+                opacity: opacity ?? 0.22,
+                child:const CircularProgressIndicator(color: Colors.white38,),
+              )));
+    };
+  }
+}