import 'dart:convert'; import 'dart:io'; import 'package:clean/base/base_controller.dart'; import 'package:clean/dialog/loading_dialog.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 backupFiles = [].obs; // 存储选中的 final RxSet selectedFiles = {}.obs; RxMap> backupFilesMap = >{}.obs; @override void onInit() { // TODO: implement onInit super.onInit(); loadBackupFiles(); } void init() { } // 获取备份文件列表 Future loadBackupFiles() async { final directory = await getApplicationDocumentsDirectory(); final files = Directory('${directory.path}/contacts').listSync(); final List 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> 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 backupContacts() async { LoadingDialog.show(displayTime: 100); try { if (!await FlutterContacts.requestPermission()) { throw Exception('通讯录权限被拒绝'); } List 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(); // LoadingDialog.hide(); ToastUtil.show("Successful"); print('备份成功: ${file.path}'); } catch (e) { LoadingDialog.hide(); ToastUtil.show("Failed"); print('备份失败: $e'); } } // 恢复通讯录 Future 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: [ //操作按钮集合 CupertinoActionSheetAction( onPressed: () async { Navigator.pop(context); try { // 获取所有联系人 List contacts = await FlutterContacts.getContacts( withProperties: true, withPhoto: true, ); for (var contact in contacts) { await contact.delete(); } // 读取文件内容 String contactsJsonString = await file.readAsString(); List 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 deleteBtnClick() async { showCupertinoModalPopup( context: Get.context!, builder: (context) { return CupertinoActionSheet( actions: [ //操作按钮集合 CupertinoActionSheetAction( onPressed: () async { Navigator.pop(context); // 获取要删除的资产 final fileToDelete = backupFiles.where((file) => selectedFiles.contains(file.path)).toList(); // for (var file in fileToDelete) { await file.delete(); } ToastUtil.show("Successful"); exitEditMode(); loadBackupFiles(); }, child: Text( 'Delete', style: TextStyle( color: "#FC4C4F".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, ), ), ), ); }, ); } }