controller.dart 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import 'package:clean/base/base_controller.dart';
  2. import 'package:clean/data/repositories/user_repository.dart';
  3. import 'package:clean/handler/event_handler.dart';
  4. import 'package:clean/module/contact/contact_state.dart';
  5. import 'package:clean/module/store/store_view.dart';
  6. import 'package:flutter/Material.dart';
  7. import 'package:flutter/widgets.dart';
  8. import 'package:flutter_contacts/contact.dart';
  9. import 'package:get/get.dart';
  10. import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
  11. import '../../../data/consts/event_report_id.dart';
  12. import '../../../dialog/loading_dialog.dart';
  13. import '../../../utils/toast_util.dart';
  14. class ContactInCompleteController extends BaseController {
  15. // 存储不符合要求的联系人
  16. final RxList<Contact> filteredContacts = <Contact>[].obs;
  17. // 存储联系人按首字母分组
  18. final RxMap<String, List<Contact>> groupedContacts =
  19. <String, List<Contact>>{}.obs;
  20. // 存储联系人首字母
  21. final RxList<String> initials = <String>[].obs;
  22. // 是否全选
  23. final RxBool isAllSelected = false.obs;
  24. // 存储选中的联系人
  25. final RxSet<String> selectedContacts = <String>{}.obs;
  26. final ItemScrollController itemScrollController = ItemScrollController();
  27. final ItemPositionsListener itemPositionsListener =
  28. ItemPositionsListener.create();
  29. // isEdit
  30. final RxBool isEdit = false.obs;
  31. @override
  32. void onInit()async {
  33. super.onInit();
  34. }
  35. @override
  36. void onReady() {
  37. // TODO: implement onReady
  38. super.onReady();
  39. filterContacts();
  40. groupContacts();
  41. }
  42. // 过滤联系人
  43. void filterContacts() {
  44. filteredContacts.value = ContactState.contactList.where((contact) {
  45. final hasValidPhone =
  46. contact.phones.any((p) => isValidPhoneNumber(p.number ?? ''));
  47. return contact.phones.isEmpty || !hasValidPhone;
  48. }).toList();
  49. }
  50. bool isValidPhoneNumber(String phone) {
  51. // 如果电话号码为空,则返回false
  52. if (phone.isEmpty) return false;
  53. // 如果电话号码不是数字、空格、+号,则返回false
  54. return RegExp(r'^\+?[0-9 -]+$').hasMatch(phone);
  55. }
  56. Future<void> deleteBtnClick() async {
  57. EventHandler.report(EventId.event_08009);
  58. if (!userRepository.isVip()) {
  59. StorePage.start();
  60. return;
  61. }
  62. if (selectedContacts.isEmpty) {
  63. ToastUtil.show("Please select a contact");
  64. return;
  65. }
  66. print("deleteBtnClick selectedContacts: $selectedContacts");
  67. final contactToDelete = ContactState.contactList
  68. .where((contact) => selectedContacts.contains(contact.id))
  69. .toList();
  70. LoadingDialog.show(displayTime: 100);
  71. for (var contact in contactToDelete) {
  72. await contact.delete(); // 删除操作必须 `await`
  73. }
  74. LoadingDialog.hide();
  75. ToastUtil.show("Successful");
  76. exitEditMode();
  77. await ContactState.loadContacts(); // 确保联系人列表更新
  78. filterContacts(); // 重新筛选联系人
  79. groupContacts(); // 重新分组
  80. debugPrint("filteredContacts.length: ${filteredContacts.length}");
  81. }
  82. // 全选/取消全选
  83. void toggleSelectAll() {
  84. if (isAllSelected.value) {
  85. selectedContacts.clear();
  86. } else {
  87. selectedContacts
  88. .addAll(filteredContacts.map((contact) => contact.id));
  89. }
  90. isAllSelected.value = !isAllSelected.value;
  91. }
  92. // 退出编辑模式时清空选择
  93. void exitEditMode() {
  94. isEdit.value = false;
  95. selectedContacts.clear();
  96. isAllSelected.value = false;
  97. }
  98. // 滚动到指定首字母
  99. void groupContacts() {
  100. final Map<String, List<Contact>> map = {};
  101. for (var contact in filteredContacts) {
  102. final initial = contact.displayName.isNotEmpty == true
  103. ? contact.displayName[0].toUpperCase()
  104. : '#';
  105. map.putIfAbsent(initial, () => []).add(contact);
  106. }
  107. final sortedKeys = map.keys.toList()..sort();
  108. groupedContacts.value =
  109. Map.fromEntries(sortedKeys.map((key) => MapEntry(key, map[key]!)));
  110. initials.value = sortedKeys;
  111. }
  112. void scrollToInitial(String initial) {
  113. int index = ContactState.initials.indexOf(initial);
  114. if (index != -1) {
  115. final positions = itemPositionsListener.itemPositions.value;
  116. final isVisible = positions.any((position) => position.index == index);
  117. if (!isVisible) {
  118. itemScrollController.scrollTo(
  119. index: index,
  120. duration: Duration(milliseconds: 300),
  121. );
  122. }
  123. }
  124. }
  125. void toggleSelectContact(Contact selectContact) {
  126. print("selectContact: ${selectContact.displayName}");
  127. if (selectedContacts.contains(selectContact.id)) {
  128. selectedContacts.remove(selectContact.id);
  129. } else {
  130. selectedContacts.add(selectContact.id);
  131. }
  132. isAllSelected.value = selectedContacts.length == filteredContacts.length;
  133. }
  134. }