Jelajahi Sumber

[feat]新增联系人备份页

Destiny 11 bulan lalu
induk
melakukan
2888042787

TEMPAT SAMPAH
assets/images/icon_contacts_file.webp


+ 19 - 6
lib/module/contact/all/all_controller.dart

@@ -1,5 +1,6 @@
 import 'package:clean/base/base_controller.dart';
 import 'package:clean/module/contact/contact_state.dart';
+import 'package:clean/utils/toast_util.dart';
 import 'package:flutter/Material.dart';
 import 'package:flutter_contacts/contact.dart';
 import 'package:get/get.dart';
@@ -27,12 +28,23 @@ class AllController extends BaseController {
 
   void scrollToInitial(String initial) {
     int index = ContactState.initials.indexOf(initial);
-    if (index != -1) {
-      itemScrollController.jumpTo(
-        index: index,
-        // curve: Curves,
-      );
-    }
+    var isScroll = true;
+    itemPositionsListener.itemPositions.addListener(() {
+      final positions = itemPositionsListener.itemPositions.value;
+      for (var position in positions) {
+        if (index == position.index) {
+          isScroll = false;
+        }
+        print('Item ${position.index} is visible at position ${position.itemLeadingEdge}');
+      }
+
+      if (index != -1 && isScroll) {
+        itemScrollController.scrollTo(
+          index: index, duration: Duration(milliseconds: 300),
+          // curve: Curves,
+        );
+      }
+    });
   }
 
   // 选择/取消选择联系人
@@ -74,6 +86,7 @@ class AllController extends BaseController {
       contact.delete();
     }
 
+    ToastUtil.show("Successful");
     exitEditMode();
     ContactState.loadContacts();
   }

+ 270 - 0
lib/module/contact/backup/controller.dart

@@ -1,5 +1,275 @@
+import 'dart:convert';
+import 'dart:io';
+
 import 'package:clean/base/base_controller.dart';
+import 'package:clean/utils/expand.dart';
+import 'package:clean/utils/toast_util.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_contacts/flutter_contacts.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:get/get_core/src/get_main.dart';
+import 'package:get/get_rx/src/rx_types/rx_types.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:wechat_camera_picker/wechat_camera_picker.dart';
 
 class ContactBackUpController extends BaseController {
 
+  // 是否为编辑状态
+  RxBool isEdit = false.obs;
+
+  // 是否全选
+  RxBool isAllSelected = false.obs;
+
+  RxList<FileSystemEntity> backupFiles = <FileSystemEntity>[].obs;
+
+  // 存储选中的
+  final RxSet<String> selectedFiles = <String>{}.obs;
+
+  RxMap<String, List<File>> backupFilesMap = <String, List<File>>{}.obs;
+
+  @override
+  void onInit() {
+    // TODO: implement onInit
+    super.onInit();
+    loadBackupFiles();
+  }
+
+  void init() {
+
+  }
+
+  // 获取备份文件列表
+  Future<void> loadBackupFiles() async {
+    final directory = await getApplicationDocumentsDirectory();
+    final files = Directory('${directory.path}/contacts').listSync();
+
+    final List<FileSystemEntity> entities = await Directory(
+        '${directory.path}/contacts').list().toList();
+
+    // 使用sort方法对文件列表进行排序
+    entities.sort((a, b) {
+      FileStat fileStatA = a.statSync();
+      FileStat fileStatB = b.statSync();
+      return fileStatB.changed.compareTo(fileStatA.changed);
+    });
+
+    backupFiles.clear();
+    Map<String, List<File>> filesMap = {};
+    for (var entity in entities) {
+      if (entity is File && entity.path.endsWith('.json')) {
+        backupFiles.add(entity);
+        final fileName = entity.path
+            .split('/')
+            .last;
+        final timestamp = fileName
+            .split('_')
+            .last
+            .split('.')
+            .first;
+        final dateTime = DateTime.fromMillisecondsSinceEpoch(
+            int.parse(timestamp));
+        final formattedDate = _formatDate(dateTime);
+
+        if (!filesMap.containsKey(formattedDate)) {
+          filesMap[formattedDate] = [];
+        }
+        filesMap[formattedDate]!.add(entity);
+      }
+    }
+
+    backupFilesMap.value = filesMap;
+  }
+
+  // 格式化日期为 "MMM dd, yyyy"
+  String _formatDate(DateTime dateTime) {
+    return '${_getMonthAbbreviation(dateTime.month)} ${dateTime.day}, ${dateTime
+        .year}';
+  }
+
+  // 获取月份的缩写(如 Jan, Feb)
+  String _getMonthAbbreviation(int month) {
+    switch (month) {
+      case 1:
+        return 'Jan';
+      case 2:
+        return 'Feb';
+      case 3:
+        return 'Mar';
+      case 4:
+        return 'Apr';
+      case 5:
+        return 'May';
+      case 6:
+        return 'Jun';
+      case 7:
+        return 'Jul';
+      case 8:
+        return 'Aug';
+      case 9:
+        return 'Sep';
+      case 10:
+        return 'Oct';
+      case 11:
+        return 'Nov';
+      case 12:
+        return 'Dec';
+      default:
+        return 'Unknown';
+    }
+  }
+
+
+  // 备份通讯录
+  Future<void> backupContacts() async {
+    try {
+      if (!await FlutterContacts.requestPermission()) {
+        throw Exception('通讯录权限被拒绝');
+      }
+
+      List<Contact> contacts = await FlutterContacts.getContacts(
+        withProperties: true,
+        withThumbnail: false,
+      );
+
+      // 生成文件名
+      final timestamp = DateTime
+          .now()
+          .millisecondsSinceEpoch;
+      final fileName = '${contacts.length} contacts_$timestamp.json';
+
+      // 保存到文件
+      final directory = await getApplicationDocumentsDirectory();
+      final dir = Directory('${directory.path}/contacts');
+      if (!dir.existsSync()) {
+        dir.createSync(recursive: true);
+      }
+
+      final file = File('${directory.path}/contacts/$fileName');
+      await file.writeAsString(jsonEncode(contacts));
+
+      // 刷新备份文件列表
+      loadBackupFiles();
+
+      print('备份成功: ${file.path}');
+    } catch (e) {
+      print('备份失败: $e');
+    }
+  }
+
+  // 恢复通讯录
+  Future<void> restoreContacts(File file) async {
+    if (!isEdit.value) {
+      showCupertinoModalPopup(
+        context: Get.context!,
+        builder: (context) {
+          return CupertinoActionSheet(
+            title: Text(
+              "Replace the current contacts in the phonebook with the selected backup file.",
+              style: TextStyle(color: "#6E6E6E".color, fontSize: 12.sp,),),
+            actions: <Widget>[
+              //操作按钮集合
+              CupertinoActionSheetAction(
+                onPressed: () async {
+                  Navigator.pop(context);
+                  try {
+                    // 获取所有联系人
+                    List<Contact> contacts = await FlutterContacts.getContacts(
+                      withProperties: true,
+                      withPhoto: true,
+                    );
+
+                    for (var contact in contacts) {
+                      await contact.delete();
+                    }
+
+                    // 读取文件内容
+                    String contactsJsonString = await file.readAsString();
+                    List<dynamic> contactsJson = jsonDecode(contactsJsonString);
+
+                    // 恢复联系人
+                    for (var contactJson in contactsJson) {
+                      Contact contact = Contact.fromJson(contactJson);
+                      contact.id = "";
+                      await FlutterContacts.insertContact(contact);
+                    }
+
+                    ToastUtil.show("Successful");
+                    print('恢复成功');
+                  } catch (e) {
+                    print('恢复失败: $e');
+                    ToastUtil.show("Failed");
+                  }
+                },
+                child: Text(
+                  'Restore now',
+                  style: TextStyle(
+                    color: "#007AFF".color,
+                    fontWeight: FontWeight.w500,
+                    fontSize: 16.sp,
+                  ),
+                ),
+              ),
+            ],
+            cancelButton: CupertinoActionSheetAction(
+              //取消按钮
+              onPressed: () {
+                Navigator.pop(context);
+              },
+              child: Text(
+                'Cancel',
+                style: TextStyle(
+                  color: "#007AFF".color,
+                  fontWeight: FontWeight.w500,
+                  fontSize: 16.sp,
+                ),
+              ),
+            ),
+          );
+        },
+      );
+    }
+  }
+
+  // 选择/取消选择联系人
+  void toggleSelectFile(File selectFile) {
+    final file = backupFiles.firstWhere((file) => file.path == selectFile.path);
+
+    if (selectedFiles.contains(selectFile.path)) {
+      selectedFiles.remove(selectFile.path);
+    } else {
+      selectedFiles.add(selectFile.path);
+    }
+    // 更新全选状态
+    isAllSelected.value = selectedFiles.length == backupFiles.length;
+  }
+
+  // 全选/取消全选
+  void toggleSelectAll() {
+    if (isAllSelected.value) {
+      selectedFiles.clear();
+    } else {
+      selectedFiles.addAll(backupFiles.map((file) => file.path));
+    }
+    isAllSelected.value = !isAllSelected.value;
+  }
+
+  // 退出编辑模式时清空选择
+  void exitEditMode() {
+    isEdit.value = false;
+    selectedFiles.clear();
+    isAllSelected.value = false;
+  }
+
+  Future<void> deleteBtnClick() async {
+    // 获取要删除的资产
+    final fileToDelete = backupFiles.where((file) => selectedFiles.contains(file.path)).toList();
+    //
+    for (var file in fileToDelete) {
+      await file.delete();
+    }
+    ToastUtil.show("Successful");
+    exitEditMode();
+    loadBackupFiles();
+  }
 }

+ 345 - 2
lib/module/contact/backup/view.dart

@@ -1,8 +1,14 @@
+import 'dart:io';
+
 import 'package:clean/base/base_page.dart';
 import 'package:clean/module/contact/backup/controller.dart';
 import 'package:clean/resource/assets.gen.dart';
+import 'package:clean/utils/expand.dart';
+import 'package:clean/utils/file_utils.dart';
 import 'package:flutter/Material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
 
 class ContactBackUpPage extends BasePage<ContactBackUpController> {
   const ContactBackUpPage({super.key});
@@ -17,9 +23,10 @@ class ContactBackUpPage extends BasePage<ContactBackUpController> {
 
   @override
   Widget buildBody(BuildContext context) {
+    controller.init();
     return Stack(
       children: [
-        // buildMain(context),
+        buildMain(context),
         IgnorePointer(
           child: Assets.images.bgHome.image(
             width: 360.w,
@@ -28,4 +35,340 @@ class ContactBackUpPage extends BasePage<ContactBackUpController> {
       ],
     );
   }
-}
+
+  Widget buildMain(BuildContext context) {
+    return SafeArea(
+      child: Container(
+        padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w),
+        child: Obx(() {
+          return Column(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              !controller.isEdit.value
+                  ? Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                      children: [
+                        GestureDetector(
+                          onTap: () {
+                            Get.back();
+                          },
+                          child: Assets.images.iconCommonBack
+                              .image(width: 28.w, height: 28.w),
+                        ),
+                        GestureDetector(
+                          onTap: () {
+                            controller.isEdit.value = true;
+                          },
+                          child: Container(
+                            width: 71.w,
+                            height: 30.h,
+                            decoration: BoxDecoration(
+                              color: "#1F2D3F".color,
+                              borderRadius: BorderRadius.all(
+                                Radius.circular(15.h),
+                              ),
+                            ),
+                            child: Center(
+                              child: Text(
+                                "Select",
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 14.sp,
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    )
+                  : Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                      children: [
+                        GestureDetector(
+                          onTap: () {
+                            controller.isEdit.value = false;
+                          },
+                          child: Container(
+                            width: 71.w,
+                            height: 30.h,
+                            decoration: BoxDecoration(
+                              color: "#1F2D3F".color,
+                              borderRadius: BorderRadius.all(
+                                Radius.circular(15.h),
+                              ),
+                            ),
+                            child: Center(
+                              child: Text(
+                                "Cancel",
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 14.sp,
+                                ),
+                              ),
+                            ),
+                          ),
+                        ),
+                        GestureDetector(
+                          onTap: () {
+                            // controller.toggleSelectAll();
+                          },
+                          child: Text(
+                            controller.isAllSelected.value
+                                ? "Deselect all"
+                                : "Select All",
+                            style: TextStyle(
+                              color: Colors.white.withOpacity(0.65),
+                              fontSize: 14.sp,
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
+              SizedBox(
+                height: 12.h,
+              ),
+              Row(
+                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                children: [
+                  Text(
+                    "Backup",
+                    style: TextStyle(
+                      color: Colors.white,
+                      fontWeight: FontWeight.w700,
+                      fontSize: 24.sp,
+                    ),
+                  ),
+                ],
+              ),
+              SizedBox(
+                height: 26.h,
+              ),
+              Expanded(
+                child: Obx(() {
+                  return ListView.builder(
+                    itemCount: controller.backupFilesMap.length,
+                    itemBuilder: (context, index) {
+                      final date =
+                          controller.backupFilesMap.keys.toList()[index];
+                      final files = controller.backupFilesMap[date]!;
+                      return Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          Text(
+                            date,
+                            style: TextStyle(
+                              color: Colors.white.withOpacity(0.7),
+                              fontSize: 14.sp,
+                              fontWeight: FontWeight.w500,
+                            ),
+                          ),
+                          SizedBox(
+                            height: 10.h,
+                          ),
+                          ...files.asMap().entries.map((entry) {
+                            final file = entry.value;
+                            final fileName = file.path
+                                .split('/')
+                                .last
+                                .split('_')
+                                .firstOrNull;
+                            final timestamp = file.path
+                                .split('/')
+                                .last
+                                .split('_')
+                                .last
+                                .split('.')
+                                .first;
+                            final dateTime =
+                                DateTime.fromMillisecondsSinceEpoch(
+                                    int.parse(timestamp));
+                            final time = _formatTime(dateTime);
+                            // final size = _fileSize(file);
+                            return FutureBuilder(
+                              future: _fileSize(file),
+                              builder: (context, snapshot) {
+                                final size = snapshot.data ?? 0;
+                                return GestureDetector(
+                                  onTap: () {
+                                    controller.restoreContacts(file);
+                                  },
+                                  child: Container(
+                                    margin: EdgeInsets.only(bottom: 10.h),
+                                    height: 60.h,
+                                    decoration: BoxDecoration(
+                                      color: Colors.white.withOpacity(0.12),
+                                      borderRadius: BorderRadius.all(
+                                          Radius.circular(10.r)),
+                                    ),
+                                    child: Row(
+                                      children: [
+                                        SizedBox(
+                                          width: 10.w,
+                                        ),
+                                        Assets.images.iconContactsFile
+                                            .image(width: 28.w, height: 28.w),
+                                        SizedBox(
+                                          width: 9.w,
+                                        ),
+                                        Column(
+                                          mainAxisAlignment:
+                                              MainAxisAlignment.center,
+                                          crossAxisAlignment:
+                                              CrossAxisAlignment.start,
+                                          children: [
+                                            Text(
+                                              fileName ?? "",
+                                              style: TextStyle(
+                                                color: Colors.white,
+                                                fontSize: 14.sp,
+                                                fontWeight: FontWeight.w500,
+                                              ),
+                                            ),
+                                            Text(
+                                              "$size | $time",
+                                              style: TextStyle(
+                                                color: Colors.white
+                                                    .withOpacity(0.8),
+                                                fontSize: 12.sp,
+                                              ),
+                                            ),
+                                          ],
+                                        ),
+                                        Spacer(),
+                                        // 删除按钮
+                                        Obx(() {
+                                          return Visibility(
+                                            visible: controller.isEdit.value,
+                                            child: GestureDetector(
+                                              onTap: () {
+                                                controller
+                                                    .toggleSelectFile(file);
+                                                // controller.toggleSelectContact(
+                                                //     contact);
+                                              },
+                                              child: Container(
+                                                child: controller.selectedFiles
+                                                        .contains(file.path)
+                                                    ? Center(
+                                                        child: Assets
+                                                            .images.iconSelected
+                                                            .image(
+                                                          width: 16.w,
+                                                          height: 16.h,
+                                                        ),
+                                                      )
+                                                    : Center(
+                                                        child: Assets.images
+                                                            .iconUnselected
+                                                            .image(
+                                                          width: 16.w,
+                                                          height: 16.h,
+                                                        ),
+                                                      ),
+                                              ),
+                                            ),
+                                          );
+                                        }),
+                                        SizedBox(width: 20.w,),
+                                      ],
+                                    ),
+                                  ),
+                                );
+                              },
+                            );
+                          }),
+                        ],
+                      );
+                    },
+                  );
+                }),
+              ),
+              controller.isEdit.value
+                  ? GestureDetector(
+                      onTap: () {
+                        controller.deleteBtnClick();
+                      },
+                      child: Container(
+                        width: 328.w,
+                        height: 48.h,
+                        decoration: BoxDecoration(
+                          color: "#0279FB".color,
+                          borderRadius: BorderRadius.all(
+                            Radius.circular(10.r),
+                          ),
+                        ),
+                        child: Center(
+                          child: Row(
+                            mainAxisAlignment: MainAxisAlignment.center,
+                            children: [
+                              Text(
+                                "Delete",
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 16.sp,
+                                  fontWeight: FontWeight.w500,
+                                ),
+                              ),
+                            ],
+                          ),
+                        ),
+                      ),
+                    )
+                  : GestureDetector(
+                      onTap: () {
+                        controller.backupContacts();
+                      },
+                      child: Container(
+                        width: 328.w,
+                        height: 48.h,
+                        decoration: BoxDecoration(
+                          color: "#0279FB".color,
+                          borderRadius: BorderRadius.all(
+                            Radius.circular(10.r),
+                          ),
+                        ),
+                        child: Center(
+                          child: Row(
+                            mainAxisAlignment: MainAxisAlignment.center,
+                            children: [
+                              Text(
+                                "Backup Now",
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 16.sp,
+                                  fontWeight: FontWeight.w500,
+                                ),
+                              ),
+                            ],
+                          ),
+                        ),
+                      ),
+                    ),
+            ],
+          );
+        }),
+      ),
+    );
+  }
+
+  Future<String> _fileSize(File file) async {
+    return _formatFileSize(await file.length());
+  }
+
+  // 格式化文件大小
+  String _formatFileSize(int bytes) {
+    if (bytes < 1024) {
+      return '$bytes B';
+    } else if (bytes < 1024 * 1024) {
+      return '${(bytes / 1024).toStringAsFixed(1)} KB';
+    } else {
+      return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
+    }
+  }
+
+  // 格式化时间为 "HH:mm"
+  String _formatTime(DateTime dateTime) {
+    return '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
+  }
+}

+ 3 - 3
lib/module/contact/contact_view.dart

@@ -99,7 +99,7 @@ class ContactPage extends BasePage<ContactController> {
                     height: 40.w,
                   ),
                   onTap: () {
-
+                    Get.toNamed(RoutePath.contactDuplicate);
                   },
                 ),
               ],
@@ -117,7 +117,7 @@ class ContactPage extends BasePage<ContactController> {
                     height: 40.w,
                   ),
                   onTap: () {
-
+                    Get.toNamed(RoutePath.contactIncomplete);
                   },
                 ),
                 _buildContactBtn(
@@ -127,7 +127,7 @@ class ContactPage extends BasePage<ContactController> {
                     height: 40.w,
                   ),
                   onTap: () {
-
+                    Get.toNamed(RoutePath.contactBackup);
                   },
                 ),
               ],

+ 31 - 0
lib/module/contact/duplicate/view.dart

@@ -0,0 +1,31 @@
+import 'package:clean/base/base_page.dart';
+import 'package:clean/module/contact/duplicate/controller.dart';
+import 'package:clean/resource/assets.gen.dart';
+import 'package:flutter/Material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+
+class ContactDuplicatePage extends BasePage<ContactDuplicateController> {
+  const ContactDuplicatePage({super.key});
+
+  @override
+  bool immersive() {
+    return true;
+  }
+
+  @override
+  bool statusBarDarkFont() => false;
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Stack(
+      children: [
+        // buildMain(context),
+        IgnorePointer(
+          child: Assets.images.bgHome.image(
+            width: 360.w,
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 5 - 0
lib/module/contact/incomplete/controller.dart

@@ -0,0 +1,5 @@
+import 'package:clean/base/base_controller.dart';
+
+class ContactInCompleteController extends BaseController {
+
+}

+ 31 - 0
lib/module/contact/incomplete/view.dart

@@ -0,0 +1,31 @@
+import 'package:clean/base/base_page.dart';
+import 'package:clean/module/contact/incomplete/controller.dart';
+import 'package:clean/resource/assets.gen.dart';
+import 'package:flutter/Material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+
+class ContactIncompletePage extends BasePage<ContactInCompleteController> {
+  const ContactIncompletePage({super.key});
+
+  @override
+  bool immersive() {
+    return true;
+  }
+
+  @override
+  bool statusBarDarkFont() => false;
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Stack(
+      children: [
+        // buildMain(context),
+        IgnorePointer(
+          child: Assets.images.bgHome.image(
+            width: 360.w,
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 16 - 0
lib/router/app_pages.dart

@@ -2,12 +2,18 @@ import 'package:clean/module/analysis/analysis_controller.dart';
 import 'package:clean/module/analysis/analysis_view.dart';
 import 'package:clean/module/contact/all/all_controller.dart';
 import 'package:clean/module/contact/all/all_view.dart';
+import 'package:clean/module/contact/backup/controller.dart';
+import 'package:clean/module/contact/backup/view.dart';
 import 'package:clean/module/contact/contact_controller.dart';
 import 'package:clean/module/contact/contact_view.dart';
 import 'package:clean/module/calendar/calendar_controller.dart';
 import 'package:clean/module/calendar/calendar_month_controller.dart';
 import 'package:clean/module/calendar/preview/calendar_preview_controller.dart';
 import 'package:clean/module/calendar/selected_preview/calendar_selected_preview_controller.dart';
+import 'package:clean/module/contact/duplicate/controller.dart';
+import 'package:clean/module/contact/duplicate/view.dart';
+import 'package:clean/module/contact/incomplete/controller.dart';
+import 'package:clean/module/contact/incomplete/view.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';
@@ -77,6 +83,9 @@ abstract class RoutePath {
   static const intro = '/intro';
   static const contact = '/contact';
   static const contactAll = '/contact/all';
+  static const contactBackup = '/contact/backup';
+  static const contactDuplicate = '/contact/duplicate';
+  static const contactIncomplete = '/contact/incomplete';
   static const calendarMonth = '/calendarMonth';
   static const calendarPreview =  '/calendarPreview';
   static const calendarSelectedPreview = '/calendarSelectedPreview';
@@ -107,6 +116,10 @@ class AppBinding extends Bindings {
     lazyPut(() => IntroController());
     lazyPut(() => ContactController());
     lazyPut(() => AllController());
+    lazyPut(() => ContactBackUpController());
+    lazyPut(() => ContactDuplicateController());
+    lazyPut(() => ContactInCompleteController());
+    lazyPut(() => AllController());
     lazyPut(() => CalendarController());
     lazyPut(() => CalendarMonthController());
     lazyPut(() => CalendarPreviewController());
@@ -143,6 +156,9 @@ final generalPages = [
   GetPage(name: RoutePath.intro, page: () => IntroPage()),
   GetPage(name: RoutePath.contact, page: () => ContactPage()),
   GetPage(name: RoutePath.contactAll, page: () => AllPage()),
+  GetPage(name: RoutePath.contactBackup, page: () => ContactBackUpPage()),
+  GetPage(name: RoutePath.contactDuplicate, page: () => ContactDuplicatePage()),
+  GetPage(name: RoutePath.contactIncomplete, page: () => ContactIncompletePage()),
   GetPage(name: RoutePath.calendarMonth, page: () => CalendarMonthPage()),
   GetPage(name: RoutePath.calendarPreview, page: () => CalendarPreviewPage()),
   GetPage(