Przeglądaj źródła

[feat]新增日历tab页,修改部分文本错误

云天逵 11 miesięcy temu
rodzic
commit
ce96b30fe7

BIN
assets/images/icon_calendar_sort.webp


BIN
assets/images/icon_tab_calendar_selected.webp


BIN
assets/images/icon_tab_calendar_unselect.webp


+ 68 - 0
lib/module/calendar/calendar_controller.dart

@@ -0,0 +1,68 @@
+import 'package:clean/module/people_photo/photo_group.dart';
+import 'package:intl/intl.dart';
+import 'package:wechat_assets_picker/wechat_assets_picker.dart';
+
+import '../../base/base_controller.dart';
+import 'package:get/get.dart';
+
+import '../../utils/file_utils.dart';
+import '../../utils/image_util.dart';
+import '../image_picker/image_picker_util.dart';
+import 'calendar_month_view.dart';
+
+class CalendarController extends BaseController {
+  RxList<PhotoGroup> monthlyAlbums = <PhotoGroup>[].obs;
+  RxList<AssetEntity> imageList = <AssetEntity>[].obs;
+
+  @override
+  void onInit() {
+    super.onInit();
+    loadAssets();
+  }
+
+  // 加载并分组图片
+  Future<void> loadAssets() async {
+    final List<AssetEntity> result = await ImagePickerUtil.loadAssetsAndroid();
+    result.sort((a, b) => b.createDateTime.compareTo(a.createDateTime));
+
+    imageList.value = result;
+    updateMonthlyAssets();
+  }
+
+  // 更新按月份分组的照片
+  void updateMonthlyAssets() {
+    Map<String, List<AssetEntity>> groupedAssets = {};
+
+    for (var asset in imageList) {
+      final monthKey = DateFormat('yyyy-MM').format(asset.createDateTime);
+      groupedAssets.putIfAbsent(monthKey, () => []).add(asset);
+    }
+
+
+    monthlyAlbums.clear();
+    groupedAssets.forEach((month, assets) {
+      assets
+          .sort((a, b) => b.createDateTime.compareTo(a.createDateTime)); // 时间排序
+      monthlyAlbums.add(PhotoGroup(month: month, images: assets, isSelected: false));
+    });
+
+    // 打印结果
+    for (var album in monthlyAlbums) {
+      print('${album.month}: ${album.images.length} 张照片');
+    }
+  }
+
+  void clickMonthCard(PhotoGroup photoGroup) {
+    print("clickMonthCard");
+    CalendarMonthPage.start(photoGroup: photoGroup);
+  }
+
+  void clickImage(){
+    print("clickImage");
+  }
+
+
+
+}
+
+

+ 139 - 0
lib/module/calendar/calendar_month_controller.dart

@@ -0,0 +1,139 @@
+import 'package:clean/base/base_controller.dart';
+import 'package:get/get.dart';
+import 'package:wechat_assets_picker/wechat_assets_picker.dart';
+
+import '../image_picker/image_picker_util.dart';
+import '../people_photo/photo_group.dart';
+
+class CalendarMonthController extends BaseController {
+  late final Rx<PhotoGroup> photoGroup =
+      PhotoGroup(isSelected: false, images: []).obs;
+  final RxDouble selectedFilesSize = 0.0.obs;
+  RxInt selectedFileCount = 0.obs;
+  final RxSet<String> selectedPhotosIds = <String>{}.obs;
+
+  // 是否是选择模式
+  RxBool isSelectMode = false.obs;
+
+  @override
+  void onInit() {
+    _getArgs();
+    super.onInit();
+  }
+
+  void _getArgs() {
+    final parameters = Get.arguments;
+    photoGroup.value = parameters?['PhotoGroup'] as PhotoGroup;
+  }
+
+  clickBack() {
+    print('CalendarMonthController clickBack');
+    Get.back();
+  }
+
+  // 切换图片组选中状态
+  void toggleGroupSelection(List<AssetEntity> imagesList) {
+    final newValue = !photoGroup.value.isSelected.value;
+    photoGroup.value.toggleSelectAll(newValue);
+
+    for (var image in photoGroup.value.images) {
+      updateSelectedPhotosIds(image.id, newValue);
+    }
+    selectedFileCount.value = selectedPhotosIds.length;
+    updateSelectedFilesSize();
+  }
+
+  Future<void> updateSelectedFilesSize() async {
+    // 如果没有选中的文件,直接返回
+    if (selectedFileCount.value == 0) {
+      selectedFilesSize.value = 0;
+      return;
+    }
+    double totalSize = 0;
+
+    for (int i = 0; i < photoGroup.value.images.length; i++) {
+      if (photoGroup.value.selectedImages[i]) {
+        // 检查缓存
+        final assetId = photoGroup.value.images[i].id;
+        if (ImagePickerUtil.fileSizeCache.containsKey(assetId)) {
+          totalSize += ImagePickerUtil.fileSizeCache[assetId]!;
+        } else {
+          final file = await photoGroup.value.images[i].file;
+          if (file != null) {
+            final size = (await file.length()) / 1024; // 转换为KB
+            totalSize += size;
+            ImagePickerUtil.fileSizeCache[assetId] = size;
+          }
+        }
+      }
+    }
+
+    selectedFilesSize.value = totalSize;
+    print("selectedFilesSize: $selectedFilesSize");
+    PhotoManager.clearFileCache();
+  }
+
+  void updateSelectedPhotosIds(String photoId, bool isSelected) {
+    if (isSelected) {
+      selectedPhotosIds.add(photoId);
+    } else {
+      selectedPhotosIds.remove(photoId);
+    }
+  }
+
+  clickImage(List<AssetEntity> images, int imageIndex) {
+    print("CalendarMonthController clickImage");
+  }
+
+  Future<void> toggleImageSelection(
+      List<AssetEntity> groupTitle, int imageIndex) async {
+    print("BasePhotoController toggleImageSelection");
+
+    final image = photoGroup.value.images[imageIndex];
+    final selected = !photoGroup.value.selectedImages[imageIndex];
+
+    photoGroup.value.selectedImages[imageIndex] = selected;
+    updateSelectedPhotosIds(image.id, selected);
+
+    photoGroup.value.isSelected.value =
+        photoGroup.value.selectedImages.every((selected) => selected);
+
+    selectedFileCount.value = selectedPhotosIds.length;
+
+    // 更新文件大小
+    if (selected) {
+      // 如果选中,增加文件大小
+      if (ImagePickerUtil.fileSizeCache.containsKey(image.id)) {
+        selectedFilesSize.value += ImagePickerUtil.fileSizeCache[image.id]!;
+      } else {
+        final file = await image.file;
+        if (file != null) {
+          selectedFilesSize.value += (await file.length()) / 1024; // 转换为KB
+        }
+      }
+    } else {
+      // 如果取消选中,减少文件大小
+      if (ImagePickerUtil.fileSizeCache.containsKey(image.id)) {
+        selectedFilesSize.value -= ImagePickerUtil.fileSizeCache[image.id]!;
+      } else {
+        final file = await image.file;
+        if (file != null) {
+          selectedFilesSize.value -= (await file.length()) / 1024; // 转换为KB
+        }
+      }
+    }
+
+    PhotoManager.clearFileCache();
+  }
+
+  // 将selectedFilesSize转成String类型,然后单位转换,如果超过1MB,则转成MB,超过1GB,则转成GB,否则KB
+  String get selectedFilesSizeString {
+    if (selectedFilesSize.value > 1024) {
+      return "${(selectedFilesSize.value / 1024).toStringAsFixed(2)}MB";
+    } else if (selectedFilesSize.value > 1024 * 1024) {
+      return "${(selectedFilesSize.value / 1024 / 1024).toStringAsFixed(2)}GB";
+    } else {
+      return "${(selectedFilesSize.value).toStringAsFixed(2)}KB";
+    }
+  }
+}

+ 344 - 0
lib/module/calendar/calendar_month_view.dart

@@ -0,0 +1,344 @@
+import 'package:clean/base/base_page.dart';
+import 'package:clean/module/calendar/calendar_month_controller.dart';
+import 'package:flutter/Material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+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 '../people_photo/photo_group.dart';
+import 'calendar_state.dart';
+
+class CalendarMonthPage extends BasePage<CalendarMonthController> {
+  const CalendarMonthPage({Key? key}) : super(key: key);
+
+  static void start({required PhotoGroup photoGroup}) {
+    Get.toNamed(RoutePath.calendarMonth, arguments: {
+      "PhotoGroup": photoGroup,
+    });
+  }
+
+  @override
+  bool statusBarDarkFont() {
+    return false;
+  }
+
+  @override
+  bool immersive() {
+    return true;
+  }
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Stack(children: [
+      PopScope(
+          canPop: false,
+          onPopInvokedWithResult: (didPop, result) {
+            if (didPop) {
+              return;
+            }
+            controller.isSelectMode.value
+                ? controller.isSelectMode.value = false
+                : controller.clickBack();
+          },
+          child: SafeArea(
+            child: Obx(() {
+              if (controller.photoGroup.value.images.isEmpty) {
+                return _noNoPicturesCard();
+              }
+              return Column(
+                children: [
+                  _titleCard(),
+                  Obx(() {
+                    return Expanded(
+                      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.photoGroup.value.images.length,
+                          itemBuilder: _buildPhotoItem(
+                              controller.photoGroup.value.images)),
+                    );
+                  }),
+                  Obx(() {
+                    return controller.isSelectMode.value
+                        ? controller.selectedPhotosIds.isNotEmpty
+                            ? _bottomBarCard()
+                            : Container()
+                        : Container();
+                  }),
+                  SizedBox(height: 8.h),
+                ],
+              );
+            }),
+          )),
+      IgnorePointer(
+        child: Assets.images.bgHome.image(
+          width: 360.w,
+        ),
+      ),
+    ]);
+  }
+
+  Widget _titleCard() {
+    return Container(
+      alignment: Alignment.centerLeft,
+      padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          Obx(() {
+            return Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: [
+                controller.isSelectMode.value
+                    ? GestureDetector(
+                        onTap: () {
+                          controller.isSelectMode.value = false;
+                        },
+                        child: Container(
+                          width: 71.w,
+                          height: 30.h,
+                          decoration: ShapeDecoration(
+                            color: Color(0xFF2A3E55),
+                            shape: RoundedRectangleBorder(
+                              borderRadius: BorderRadius.circular(83.r),
+                            ),
+                          ),
+                          child: Center(
+                            child: Text(
+                              'Cancel',
+                              style: TextStyle(
+                                color: Colors.white,
+                                fontSize: 14.sp,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                          ),
+                        ))
+                    : GestureDetector(
+                        onTap: controller.clickBack,
+                        child: Assets.images.iconBackArrow.image(
+                          width: 28.w,
+                          height: 28.h,
+                        ),
+                      ),
+                controller.photoGroup.value.images.isEmpty
+                    ? Container()
+                    : GestureDetector(
+                        onTap: () => controller.isSelectMode.value
+                            ? controller.toggleGroupSelection(
+                                controller.photoGroup.value.images)
+                            : null,
+                        child: Obx(() => controller.isSelectMode.value
+                            ? Text(
+                                controller.photoGroup.value.isSelected.value
+                                    ? 'Deselect All'
+                                    : 'Select All',
+                                style: TextStyle(
+                                  color: Colors.white.withValues(alpha: 0.7),
+                                  fontSize: 14.sp,
+                                  fontWeight: FontWeight.w400,
+                                ),
+                              )
+                            : GestureDetector(
+                                onTap: () {
+                                  controller.isSelectMode.value = true;
+                                },
+                                child: Container(
+                                  width: 71.w,
+                                  height: 30.h,
+                                  alignment: Alignment.center,
+                                  decoration: ShapeDecoration(
+                                    color: Color(0xFF1F2D3F),
+                                    shape: RoundedRectangleBorder(
+                                      borderRadius: BorderRadius.circular(83.r),
+                                    ),
+                                  ),
+                                  child: Text(
+                                    'Select',
+                                    style: TextStyle(
+                                      color: Colors.white,
+                                      fontSize: 14.sp,
+                                      fontWeight: FontWeight.w400,
+                                    ),
+                                  ),
+                                ),
+                              )),
+                      ),
+              ],
+            );
+          }),
+          controller.photoGroup.value.images.isEmpty
+              ? Container()
+              : Column(
+                  children: [
+                    SizedBox(height: 12.h),
+                    Text(
+                      CalendarState.formatMonth(
+                          controller.photoGroup.value.month ?? ""),
+                      style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 24.sp,
+                        fontWeight: FontWeight.w700,
+                      ),
+                    ),
+                    SizedBox(height: 20.h),
+                  ],
+                ),
+        ],
+      ),
+    );
+  }
+
+  Widget Function(BuildContext, int) _buildPhotoItem(
+          List<AssetEntity> images) =>
+      (context, index) {
+        final group = controller.photoGroup.value;
+
+        return GestureDetector(
+          onTap: () => controller.clickImage(images, index),
+          child: Obx(() {
+            final isSelected = group.selectedImages[index];
+            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),
+                    ),
+                    image: DecorationImage(
+                      image: AssetEntityImageProvider(
+                        group.images[index],
+                        thumbnailSize: const ThumbnailSize.square(300),
+                        isOriginal: false,
+                      ),
+                      fit: BoxFit.cover,
+                    ),
+                  ),
+                ),
+                Positioned(
+                  right: 8.w,
+                  bottom: 8.h,
+                  child: Visibility(
+                      visible: controller.isSelectMode.value,
+                      child: GestureDetector(
+                          onTap: () =>
+                              controller.toggleImageSelection(images, index),
+                          child: Container(
+                            child: isSelected
+                                ? Center(
+                                    child: Assets.images.iconSelected.image(
+                                      width: 20.w,
+                                      height: 20.h,
+                                    ),
+                                  )
+                                : Center(
+                                    child: Assets.images.iconUnselected.image(
+                                    width: 20.w,
+                                    height: 20.h,
+                                  )),
+                          ))),
+                ),
+              ],
+            );
+          }),
+        );
+      };
+
+  Widget _bottomBarCard() {
+    return GestureDetector(
+        onTap: () {
+          // controller.clickDelete();
+        },
+        child: Container(
+          width: 328.w,
+          height: 48.h,
+          decoration: ShapeDecoration(
+            color: Color(0xFF0279FB),
+            shape: RoundedRectangleBorder(
+              borderRadius: BorderRadius.circular(10.r),
+            ),
+          ),
+          padding: EdgeInsets.symmetric(horizontal: 16.w),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              Assets.images.iconDelete.image(
+                width: 18.w,
+                height: 18.h,
+              ),
+              SizedBox(width: 5.w),
+              Obx(() {
+                return Text(
+                  'delete ${controller.selectedFilesSizeString}',
+                  textAlign: TextAlign.center,
+                  style: TextStyle(
+                    color: Colors.white,
+                    fontSize: 16.sp,
+                    fontWeight: FontWeight.w500,
+                  ),
+                );
+              }),
+            ],
+          ),
+        ));
+  }
+
+  Widget _noNoPicturesCard() {
+    return Column(
+      children: [
+        _titleCard(),
+        SizedBox(
+          height: 170.h,
+        ),
+        Container(
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              Container(
+                width: 70.w,
+                height: 70.h,
+                clipBehavior: Clip.antiAlias,
+                decoration: BoxDecoration(),
+                child: Assets.images.iconNoPictures.image(),
+              ),
+              SizedBox(height: 22.h),
+              Text(
+                'No pictures found',
+                textAlign: TextAlign.center,
+                style: TextStyle(
+                  color: Colors.white,
+                  fontSize: 20.sp,
+                  fontWeight: FontWeight.w700,
+                ),
+              ),
+              SizedBox(height: 12.h),
+              Text(
+                'No pictures available at the moment',
+                textAlign: TextAlign.center,
+                style: TextStyle(
+                  color: Colors.white.withValues(alpha: 0.6),
+                  fontSize: 14.sp,
+                  fontWeight: FontWeight.w400,
+                ),
+              ),
+            ],
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 15 - 0
lib/module/calendar/calendar_state.dart

@@ -0,0 +1,15 @@
+import 'package:intl/intl.dart';
+
+class CalendarState {
+
+ static String formatMonth(String month) {
+    try {
+      DateTime date = DateFormat('yyyy-MM').parse(month);
+      return DateFormat('MMM , yyyy').format(date); // 转换为 "Nov, 2024" 格式
+    } catch (e) {
+      return month; // 如果解析失败,返回原始字符串
+    }
+  }
+
+
+}

+ 155 - 0
lib/module/calendar/calendar_view.dart

@@ -0,0 +1,155 @@
+import 'dart:ui';
+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:wechat_assets_picker/wechat_assets_picker.dart';
+
+import '../../base/base_view.dart';
+import '../../resource/assets.gen.dart';
+import '../people_photo/photo_group.dart';
+import 'calendar_state.dart';
+
+class CalendarPage extends BaseView<CalendarController> {
+  const CalendarPage({super.key});
+
+  @override
+  Color backgroundColor() => const Color(0xFF05050D); // 修正返回类型
+
+  @override
+  double viewHeight() => double.infinity; // 统一返回类型
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Stack(
+      children: [
+        SafeArea(
+          child: CustomScrollView(
+            slivers: [
+              SliverToBoxAdapter(child: titleCard()),
+              Obx(() {
+                return SliverList(
+                  delegate: SliverChildBuilderDelegate(
+                        (context, index) {
+                      return monthCard(controller.monthlyAlbums[index]);
+                    },
+                    childCount: controller.monthlyAlbums.length, // 添加 itemCount
+                  ),
+                );
+              }),
+              SliverToBoxAdapter(child: SizedBox(height: 40.h)),
+            ],
+          ),
+        ),
+        IgnorePointer(
+          child: Assets.images.bgHome.image(
+            width: 360.w,
+          ),
+        ),
+      ],
+    );
+  }
+
+  Widget titleCard() {
+    return Padding(
+      padding: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.h),
+      child: Row(
+        children: [
+          Text(
+            'Memory Lane',
+            textAlign: TextAlign.center,
+            style: TextStyle(
+              color: Colors.white,
+              fontSize: 24.sp,
+              fontWeight: FontWeight.w900,
+            ),
+          ),
+          Spacer(),
+          Assets.images.iconCalendarSort.image(width: 28.w, height: 28.w),
+        ],
+      ),
+    );
+  }
+
+  Widget monthCard(PhotoGroup photoGroup) {
+    return GestureDetector(
+        onTap: () => controller.clickMonthCard(photoGroup),
+        child: Container(
+          margin: EdgeInsets.only(left: 16.w, right: 16.w, top: 12.h),
+          width: 328.w,
+          height: 209.h,
+          decoration: ShapeDecoration(
+            color: Colors.white.withValues(alpha: 0.12),
+            shape: RoundedRectangleBorder(
+              borderRadius: BorderRadius.circular(14.sp),
+            ),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Spacer(),
+              Padding(
+                padding: EdgeInsets.only(left: 12.0.w, right: 12.0.w),
+                child: Row(
+                  children: [
+                    Text(
+                      CalendarState.formatMonth(photoGroup.month ?? ""),
+                      style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 16.sp,
+                        fontWeight: FontWeight.w700,
+                      ),
+                    ),
+                    Spacer(),
+                    Obx(() {
+                      return Text(
+                        '${photoGroup.selectedCount}/${photoGroup.images
+                            .length}',
+                        textAlign: TextAlign.center,
+                        style: TextStyle(
+                          color: Colors.white.withValues(alpha: 0.8),
+                          fontSize: 12.sp,
+                          fontWeight: FontWeight.w500,
+                        ),
+                      );
+                    }),
+                  ],
+                ),
+              ),
+              Spacer(),
+              Row(
+                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                children: List.generate(2, (index) {
+                  if (index < photoGroup.images.length) {
+                    return GestureDetector(
+                        onTap: controller.clickImage,
+                        child: Container(
+                          width: 146.w,
+                          height: 146.w,
+                          decoration: BoxDecoration(
+                            borderRadius: BorderRadius.circular(12.r),
+                            image: DecorationImage(
+                              image: AssetEntityImageProvider(
+                                  photoGroup.images[index],
+                                  isOriginal: false),
+                              fit: BoxFit.cover,
+                            ),
+                          ),
+                        ));
+                  } else {
+                    return Container(
+                      width: 146.w,
+                      height: 146.w,
+                      decoration: BoxDecoration(
+                        borderRadius: BorderRadius.circular(12.r),
+                      ),
+                    );
+                  }
+                }),
+              ),
+              Spacer(),
+            ],
+          ),
+        ));
+  }
+}

+ 1 - 1
lib/module/locations_photo/locations_single_photo_view.dart

@@ -168,7 +168,7 @@ class LocationsSinglePhotoPage
             SizedBox(width: 5.w),
             Obx(() {
               return Text(
-                '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString})',
+                'Delete ${controller.selectedFileCount.value} Photos (${controller.selectedFilesSizeString})',
                 textAlign: TextAlign.center,
                 style: TextStyle(
                   color: Colors.white,

+ 1 - 1
lib/module/main/main_controller.dart

@@ -14,7 +14,7 @@ import '../../utils/file_utils.dart';
 
 class MainController extends BaseController {
 
-  final _currentIndex = 0.obs;
+  final _currentIndex = 1.obs;
   int get currentIndex => _currentIndex.value;
 
   @override

+ 7 - 0
lib/module/main/main_view.dart

@@ -1,3 +1,4 @@
+import 'package:clean/module/calendar/calendar_view.dart';
 import 'package:clean/module/more/more_view.dart';
 import 'package:clean/utils/expand.dart';
 import 'package:convex_bottom_bar/convex_bottom_bar.dart';
@@ -15,6 +16,7 @@ class MainTabPage extends BasePage<MainController> {
   MainTabPage({super.key});
 
   final pages = [
+    const CalendarPage(),
     const HomePage(),
     const MorePage(),
   ];
@@ -27,6 +29,7 @@ class MainTabPage extends BasePage<MainController> {
   bool immersive() {
     return true;
   }
+
   @override
   bool statusBarDarkFont() {
     // TODO: implement statusBarDarkFont
@@ -56,12 +59,16 @@ class MainTabPage extends BasePage<MainController> {
         activeColor: Colors.transparent,
         items: [
           TabItem(
+              icon: Assets.images.iconTabCalendarUnselect.image(),
+              activeIcon: Assets.images.iconTabCalendarSelected.image()),
+          TabItem(
               icon: Assets.images.iconTabHomeUnselect.image(),
               activeIcon: Assets.images.iconTabHomeSelected.image()),
           TabItem(
               icon: Assets.images.iconTabMoreUnselect.image(),
               activeIcon: Assets.images.iconTabMoreSelected.image()),
         ],
+        initialActiveIndex: controller.currentIndex,
         onTap: (int i) {
           if (controller.currentIndex != i) {
             controller.changeIndex(i);

+ 4 - 0
lib/module/people_photo/photo_group.dart

@@ -20,6 +20,9 @@ class PhotoGroup {
   // 照片组的位置
   final String? location;
 
+  // 照片组的月份
+  final String? month;
+
   // 获取已选中的图片数量
   int get selectedCount => selectedImages.where((selected) => selected).length;
 
@@ -30,6 +33,7 @@ class PhotoGroup {
     required bool isSelected,
     required this.images,
     this.location,
+    this.month,
   })  : isSelected = isSelected.obs,
         selectedImages = RxList<bool>.filled(images.length, isSelected);
 

+ 8 - 8
lib/module/photo_preview/photo_preview_view.dart

@@ -81,8 +81,8 @@ class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
                             index,
                             horizontalOffsetPercentage,
                             verticalOffsetPercentage) {
-                          print(
-                              'index: $index, horizontalOffsetPercentage: $horizontalOffsetPercentage, verticalOffsetPercentage: $verticalOffsetPercentage');
+                          // print(
+                          //     'index: $index, horizontalOffsetPercentage: $horizontalOffsetPercentage, verticalOffsetPercentage: $verticalOffsetPercentage');
                           final assetEntity = controller.listAssetEntity[index];
                           return Stack(
                             children: [
@@ -98,22 +98,22 @@ class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
                               if (horizontalOffsetPercentage != 0)
                                 Positioned(
                                   top: 0,
-                                  right: horizontalOffsetPercentage < -10
+                                  right: horizontalOffsetPercentage < -10.w
                                       ? 0
                                       : null,
-                                  left: horizontalOffsetPercentage > 10
+                                  left: horizontalOffsetPercentage > 10.w
                                       ? 0
                                       : null,
                                   child: Container(
                                       child: Column(
                                     children: [
-                                      (horizontalOffsetPercentage < -10)
+                                      (horizontalOffsetPercentage < -10.w)
                                           ? Assets.images.iconPhotoPreviewDelete
                                               .image(
                                               width: 60.w,
                                               height: 60.w,
                                             )
-                                          : (horizontalOffsetPercentage > 10)
+                                          : (horizontalOffsetPercentage > 10.w)
                                               ? Assets
                                                   .images.iconPhotoPreviewKeep
                                                   .image(
@@ -121,7 +121,7 @@ class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
                                                   height: 60.w,
                                                 )
                                               : SizedBox(),
-                                      (horizontalOffsetPercentage < -10)
+                                      (horizontalOffsetPercentage < -10.w)
                                           ? Text(
                                               'Delete ',
                                               style: TextStyle(
@@ -130,7 +130,7 @@ class PhotoPreviewPage extends BasePage<PhotoPreviewController> {
                                                 fontWeight: FontWeight.w500,
                                               ),
                                             )
-                                          : (horizontalOffsetPercentage > 10)
+                                          : (horizontalOffsetPercentage > 10.w)
                                               ? Text(
                                                   'Keep',
                                                   style: TextStyle(

+ 1 - 1
lib/module/screenshots_blurry/screenshots_view.dart

@@ -179,7 +179,7 @@ class ScreenshotsPage extends BasePage<ScreenShotsController> {
               SizedBox(width: 5.w),
               Obx(() {
                 return Text(
-                  '${controller.selectedFileCount.value} files selected (${controller.selectedFilesSizeString})',
+                  'Delete ${controller.selectedFileCount.value} Photos (${controller.selectedFilesSizeString})',
                   textAlign: TextAlign.center,
                   style: TextStyle(
                     color: Colors.white,

+ 7 - 0
lib/router/app_pages.dart

@@ -1,5 +1,7 @@
 import 'package:clean/module/analysis/analysis_controller.dart';
 import 'package:clean/module/analysis/analysis_view.dart';
+import 'package:clean/module/calendar/calendar_controller.dart';
+import 'package:clean/module/calendar/calendar_month_controller.dart';
 import 'package:clean/module/home/home_controller.dart';
 import 'package:clean/module/locations_photo/locations_photo_controller.dart';
 import 'package:clean/module/locations_photo/locations_photo_view.dart';
@@ -35,6 +37,7 @@ import 'package:get/get.dart';
 
 import '../module/browser/browser_controller.dart';
 import '../module/browser/browser_view.dart';
+import '../module/calendar/calendar_month_view.dart';
 import '../module/main/main_controller.dart';
 import '../module/photo_info/photo_info_view.dart';
 import '../module/privacy/privacy_controller.dart';
@@ -64,6 +67,7 @@ abstract class RoutePath {
   static const splash = '/splash';
   static const wallpaper = '/wallpaper';
   static const intro = '/intro';
+  static const calendarMonth = '/calendarMonth';
 }
 
 class AppBinding extends Bindings {
@@ -89,6 +93,8 @@ class AppBinding extends Bindings {
     lazyPut(() => SplashController());
     lazyPut(() => WallPaperController());
     lazyPut(() => IntroController());
+    lazyPut(() => CalendarController());
+    lazyPut(() => CalendarMonthController());
   }
 
   void lazyPut<S>(InstanceBuilderCallback<S> builder) {
@@ -119,4 +125,5 @@ final generalPages = [
   GetPage(name: RoutePath.splash, page: () => SplashPage()),
   GetPage(name: RoutePath.wallpaper, page: () => WallPaperPage()),
   GetPage(name: RoutePath.intro, page: () => IntroPage()),
+  GetPage(name: RoutePath.calendarMonth, page: () => CalendarMonthPage()),
 ];