|
|
@@ -33,17 +33,12 @@ class ContactDuplicateController extends BaseController {
|
|
|
loadDuplicateContacts();
|
|
|
}
|
|
|
|
|
|
-// 按共享电话号码分组联系人
|
|
|
+ // 按共享电话号码分组联系人
|
|
|
Map<Contact, List<Contact>> groupContactsBySharedPhones(
|
|
|
List<Contact> contacts) {
|
|
|
final UnionFind uf = UnionFind();
|
|
|
final Map<String, List<Contact>> phoneToContactsMap = {};
|
|
|
|
|
|
- // 获取所有联系人
|
|
|
- List<Contact> contacts = await FlutterContacts.getContacts(
|
|
|
- withProperties: true,
|
|
|
- withPhoto: true,
|
|
|
- );
|
|
|
// 遍历所有联系人,建立电话号码与联系人的映射
|
|
|
for (var contact in contacts) {
|
|
|
for (var phone in contact.phones) {
|
|
|
@@ -54,9 +49,6 @@ class ContactDuplicateController extends BaseController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 按名字的首字母排序
|
|
|
- contacts
|
|
|
- .sort((a, b) => (a.displayName ?? '').compareTo(b.displayName ?? ''));
|
|
|
// 合并拥有相同电话号码的联系人
|
|
|
for (var phone in phoneToContactsMap.keys) {
|
|
|
final contactList = phoneToContactsMap[phone]!;
|
|
|
@@ -68,17 +60,6 @@ class ContactDuplicateController extends BaseController {
|
|
|
// 整理分组结果
|
|
|
final Map<Contact, List<Contact>> groupedContacts = {};
|
|
|
for (var contact in contacts) {
|
|
|
- if (contact.phones.isNotEmpty) {
|
|
|
- for (var phone in contact.phones) {
|
|
|
- final phoneNumber = phone.number;
|
|
|
-
|
|
|
- if (phoneNumber.isNotEmpty) {
|
|
|
- if (!groupedContacts.containsKey(phoneNumber)) {
|
|
|
- groupedContacts[phoneNumber] = [];
|
|
|
- }
|
|
|
- groupedContacts[phoneNumber]!.add(contact);
|
|
|
- }
|
|
|
- }
|
|
|
final root = uf.find(contact);
|
|
|
if (!groupedContacts.containsKey(root)) {
|
|
|
groupedContacts[root] = [];
|
|
|
@@ -86,7 +67,6 @@ class ContactDuplicateController extends BaseController {
|
|
|
groupedContacts[root]!.add(contact);
|
|
|
}
|
|
|
|
|
|
- Map<String, List<Contact>> tempContacts = {};
|
|
|
Map<Contact, List<Contact>> tempContacts = {};
|
|
|
tempContacts.addAll(groupedContacts);
|
|
|
for (var key in groupedContacts.keys) {
|
|
|
@@ -95,296 +75,295 @@ class ContactDuplicateController extends BaseController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- contactsByPhoneNumber.value = tempContacts;
|
|
|
return tempContacts;
|
|
|
}
|
|
|
|
|
|
Future<void> loadDuplicateContacts() async {
|
|
|
- Map<String, List<Contact>> groupedContacts = {};
|
|
|
-
|
|
|
- // 获取所有联系人
|
|
|
- List<Contact> contacts = await FlutterContacts.getContacts(
|
|
|
- withProperties: true,
|
|
|
- withPhoto: true,
|
|
|
- );
|
|
|
-
|
|
|
- // 按名字的首字母排序
|
|
|
- contacts
|
|
|
- .sort((a, b) => (a.displayName ?? '').compareTo(b.displayName ?? ''));
|
|
|
-
|
|
|
- final duplicateContact = groupContactsBySharedPhones(contacts);
|
|
|
-
|
|
|
- // for (var contact in contacts) {
|
|
|
- // if (contact.phones.isNotEmpty) {
|
|
|
- // for (var phone in contact.phones) {
|
|
|
- // final phoneNumber = phone.number;
|
|
|
- //
|
|
|
- // if (phoneNumber.isNotEmpty) {
|
|
|
- // if (!groupedContacts.containsKey(phoneNumber)) {
|
|
|
- // groupedContacts[phoneNumber] = [];
|
|
|
- // }
|
|
|
- // groupedContacts[phoneNumber]!.add(contact);
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
- //
|
|
|
- // Map<String, List<Contact>> tempContacts = {};
|
|
|
- // tempContacts.addAll(groupedContacts);
|
|
|
- // for (var key in groupedContacts.keys) {
|
|
|
- // if (groupedContacts[key]?.length == 1) {
|
|
|
- // tempContacts.remove(key);
|
|
|
- // }
|
|
|
- // }
|
|
|
-
|
|
|
- contactsByPhoneNumber.value = duplicateContact;
|
|
|
-
|
|
|
- contactCount = 0;
|
|
|
- for (var key in contactsByPhoneNumber.keys) {
|
|
|
- if (contactsByPhoneNumber[key] != null) {
|
|
|
- contactCount += contactsByPhoneNumber[key]!.length;
|
|
|
+ Map<String, List<Contact>> groupedContacts = {};
|
|
|
+
|
|
|
+ // 获取所有联系人
|
|
|
+ List<Contact> contacts = await FlutterContacts.getContacts(
|
|
|
+ withProperties: true,
|
|
|
+ withPhoto: true,
|
|
|
+ );
|
|
|
+
|
|
|
+ // 按名字的首字母排序
|
|
|
+ contacts
|
|
|
+ .sort((a, b) => (a.displayName ?? '').compareTo(b.displayName ?? ''));
|
|
|
+
|
|
|
+ final duplicateContact = groupContactsBySharedPhones(contacts);
|
|
|
+
|
|
|
+ // for (var contact in contacts) {
|
|
|
+ // if (contact.phones.isNotEmpty) {
|
|
|
+ // for (var phone in contact.phones) {
|
|
|
+ // final phoneNumber = phone.number;
|
|
|
+ //
|
|
|
+ // if (phoneNumber.isNotEmpty) {
|
|
|
+ // if (!groupedContacts.containsKey(phoneNumber)) {
|
|
|
+ // groupedContacts[phoneNumber] = [];
|
|
|
+ // }
|
|
|
+ // groupedContacts[phoneNumber]!.add(contact);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // Map<String, List<Contact>> tempContacts = {};
|
|
|
+ // tempContacts.addAll(groupedContacts);
|
|
|
+ // for (var key in groupedContacts.keys) {
|
|
|
+ // if (groupedContacts[key]?.length == 1) {
|
|
|
+ // tempContacts.remove(key);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ contactsByPhoneNumber.value = duplicateContact;
|
|
|
+
|
|
|
+ contactCount = 0;
|
|
|
+ for (var key in contactsByPhoneNumber.keys) {
|
|
|
+ if (contactsByPhoneNumber[key] != null) {
|
|
|
+ contactCount += contactsByPhoneNumber[key]!.length;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // 选择/取消选择联系人
|
|
|
- void toggleSelectContact(Contact contact) {
|
|
|
- // final asset = ContactState.contactList.firstWhere((contact) => contact.id == selectContact.id);
|
|
|
+ // 选择/取消选择联系人
|
|
|
+ void toggleSelectContact(Contact contact) {
|
|
|
+ // final asset = ContactState.contactList.firstWhere((contact) => contact.id == selectContact.id);
|
|
|
|
|
|
- final contacts = contactsByPhoneNumber[contact];
|
|
|
- if (contacts != null) {
|
|
|
- for (var contact in contacts) {
|
|
|
- if (selectedContacts.contains(contact.id)) {
|
|
|
- selectedContacts.remove(contact.id);
|
|
|
- } else {
|
|
|
- selectedContacts.add(contact.id);
|
|
|
+ final contacts = contactsByPhoneNumber[contact];
|
|
|
+ if (contacts != null) {
|
|
|
+ for (var contact in contacts) {
|
|
|
+ if (selectedContacts.contains(contact.id)) {
|
|
|
+ selectedContacts.remove(contact.id);
|
|
|
+ } else {
|
|
|
+ selectedContacts.add(contact.id);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // 更新全选状态
|
|
|
- isAllSelected.value = selectedContacts.length == contactCount;
|
|
|
- }
|
|
|
+ // 更新全选状态
|
|
|
+ isAllSelected.value = selectedContacts.length == contactCount;
|
|
|
+ }
|
|
|
|
|
|
- // 全选/取消全选
|
|
|
- void toggleSelectAll() {
|
|
|
- if (isAllSelected.value) {
|
|
|
- selectedContacts.clear();
|
|
|
- } else {
|
|
|
- for (var key in contactsByPhoneNumber.keys) {
|
|
|
- if (contactsByPhoneNumber[key] != null) {
|
|
|
- for (var contact in contactsByPhoneNumber[key]!) {
|
|
|
- selectedContacts.add(contact.id);
|
|
|
+ // 全选/取消全选
|
|
|
+ void toggleSelectAll() {
|
|
|
+ if (isAllSelected.value) {
|
|
|
+ selectedContacts.clear();
|
|
|
+ } else {
|
|
|
+ for (var key in contactsByPhoneNumber.keys) {
|
|
|
+ if (contactsByPhoneNumber[key] != null) {
|
|
|
+ for (var contact in contactsByPhoneNumber[key]!) {
|
|
|
+ selectedContacts.add(contact.id);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ isAllSelected.value = !isAllSelected.value;
|
|
|
}
|
|
|
- isAllSelected.value = !isAllSelected.value;
|
|
|
- }
|
|
|
|
|
|
- // 退出编辑模式时清空选择
|
|
|
- void exitEditMode() {
|
|
|
- isEdit.value = false;
|
|
|
- selectedContacts.clear();
|
|
|
- isAllSelected.value = false;
|
|
|
- }
|
|
|
-
|
|
|
- // 合并联系人
|
|
|
- Future<void> mergeBtnClick(List<Contact> contacts) async {
|
|
|
- if (!userRepository.isVip()) {
|
|
|
- StorePage.start();
|
|
|
- return;
|
|
|
+ // 退出编辑模式时清空选择
|
|
|
+ void exitEditMode() {
|
|
|
+ isEdit.value = false;
|
|
|
+ selectedContacts.clear();
|
|
|
+ isAllSelected.value = false;
|
|
|
}
|
|
|
|
|
|
- LoadingDialog.show(displayTime: 100);
|
|
|
+ // 合并联系人
|
|
|
+ Future<void> mergeBtnClick(List<Contact> contacts) async {
|
|
|
+ if (!userRepository.isVip()) {
|
|
|
+ StorePage.start();
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- Contact newContact = contacts.first;
|
|
|
+ LoadingDialog.show(displayTime: 100);
|
|
|
|
|
|
- for (var contact in contacts) {
|
|
|
- if (contact != newContact) {
|
|
|
- for (var phone in contact.phones) {
|
|
|
- var canAdd = true;
|
|
|
- for (var newPhone in newContact.phones) {
|
|
|
- if (phone.number == newPhone.number) {
|
|
|
- canAdd = false;
|
|
|
+ Contact newContact = contacts.first;
|
|
|
+
|
|
|
+ for (var contact in contacts) {
|
|
|
+ if (contact != newContact) {
|
|
|
+ for (var phone in contact.phones) {
|
|
|
+ var canAdd = true;
|
|
|
+ for (var newPhone in newContact.phones) {
|
|
|
+ if (phone.number == newPhone.number) {
|
|
|
+ canAdd = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (canAdd) {
|
|
|
+ newContact.phones.add(phone);
|
|
|
}
|
|
|
}
|
|
|
- if (canAdd) {
|
|
|
- newContact.phones.add(phone);
|
|
|
- }
|
|
|
- }
|
|
|
- if (newContact.thumbnail == null) {
|
|
|
- if (contact.thumbnail != null) {
|
|
|
- newContact.thumbnail = contact.thumbnail;
|
|
|
+ if (newContact.thumbnail == null) {
|
|
|
+ if (contact.thumbnail != null) {
|
|
|
+ newContact.thumbnail = contact.thumbnail;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (newContact.photo == null) {
|
|
|
- if (contact.photo != null) {
|
|
|
- newContact.photo = contact.photo;
|
|
|
+ if (newContact.photo == null) {
|
|
|
+ if (contact.photo != null) {
|
|
|
+ newContact.photo = contact.photo;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (newContact.name.first.isEmpty) {
|
|
|
- if (contact.name.first.isNotEmpty) {
|
|
|
- newContact.name.first = contact.name.first;
|
|
|
+ if (newContact.name.first.isEmpty) {
|
|
|
+ if (contact.name.first.isNotEmpty) {
|
|
|
+ newContact.name.first = contact.name.first;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (newContact.name.last.isEmpty) {
|
|
|
- if (contact.name.last.isNotEmpty) {
|
|
|
- newContact.name.last = contact.name.last;
|
|
|
+ if (newContact.name.last.isEmpty) {
|
|
|
+ if (contact.name.last.isNotEmpty) {
|
|
|
+ newContact.name.last = contact.name.last;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (newContact.name.last.isEmpty) {
|
|
|
- if (contact.name.last.isNotEmpty) {
|
|
|
- newContact.name.last = contact.name.last;
|
|
|
+ if (newContact.name.last.isEmpty) {
|
|
|
+ if (contact.name.last.isNotEmpty) {
|
|
|
+ newContact.name.last = contact.name.last;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.emails.isNotEmpty) {
|
|
|
- for (var email in contact.emails) {
|
|
|
- newContact.emails.add(email);
|
|
|
+ if (contact.emails.isNotEmpty) {
|
|
|
+ for (var email in contact.emails) {
|
|
|
+ newContact.emails.add(email);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.addresses.isNotEmpty) {
|
|
|
- for (var address in contact.addresses) {
|
|
|
- newContact.addresses.add(address);
|
|
|
+ if (contact.addresses.isNotEmpty) {
|
|
|
+ for (var address in contact.addresses) {
|
|
|
+ newContact.addresses.add(address);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.organizations.isNotEmpty) {
|
|
|
- for (var organization in contact.organizations) {
|
|
|
- newContact.organizations.add(organization);
|
|
|
+ if (contact.organizations.isNotEmpty) {
|
|
|
+ for (var organization in contact.organizations) {
|
|
|
+ newContact.organizations.add(organization);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.websites.isNotEmpty) {
|
|
|
- for (var website in contact.websites) {
|
|
|
- newContact.websites.add(website);
|
|
|
+ if (contact.websites.isNotEmpty) {
|
|
|
+ for (var website in contact.websites) {
|
|
|
+ newContact.websites.add(website);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.socialMedias.isNotEmpty) {
|
|
|
- for (var socialMedia in contact.socialMedias) {
|
|
|
- newContact.socialMedias.add(socialMedia);
|
|
|
+ if (contact.socialMedias.isNotEmpty) {
|
|
|
+ for (var socialMedia in contact.socialMedias) {
|
|
|
+ newContact.socialMedias.add(socialMedia);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.events.isNotEmpty) {
|
|
|
- for (var event in contact.events) {
|
|
|
- newContact.events.add(event);
|
|
|
+ if (contact.events.isNotEmpty) {
|
|
|
+ for (var event in contact.events) {
|
|
|
+ newContact.events.add(event);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.notes.isNotEmpty) {
|
|
|
- for (var note in contact.notes) {
|
|
|
- newContact.notes.add(note);
|
|
|
+ if (contact.notes.isNotEmpty) {
|
|
|
+ for (var note in contact.notes) {
|
|
|
+ newContact.notes.add(note);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- if (contact.groups.isNotEmpty) {
|
|
|
- for (var group in contact.groups) {
|
|
|
- newContact.groups.add(group);
|
|
|
+ if (contact.groups.isNotEmpty) {
|
|
|
+ for (var group in contact.groups) {
|
|
|
+ newContact.groups.add(group);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- for (var contact in contacts) {
|
|
|
- await contact.delete();
|
|
|
- }
|
|
|
|
|
|
- newContact.id = "";
|
|
|
- await FlutterContacts.insertContact(newContact);
|
|
|
-
|
|
|
- exitEditMode();
|
|
|
- await loadDuplicateContacts();
|
|
|
+ for (var contact in contacts) {
|
|
|
+ await contact.delete();
|
|
|
+ }
|
|
|
|
|
|
- ToastUtil.show("Merge Successful");
|
|
|
- }
|
|
|
+ newContact.id = "";
|
|
|
+ await FlutterContacts.insertContact(newContact);
|
|
|
|
|
|
- void deleteBtnClick() {
|
|
|
- // 获取要删除的资产
|
|
|
- final contactToDelete = ContactState.contactList
|
|
|
- .where((contact) => selectedContacts.contains(contact.id))
|
|
|
- .toList();
|
|
|
+ exitEditMode();
|
|
|
+ await loadDuplicateContacts();
|
|
|
|
|
|
- LoadingDialog.show(displayTime: 100);
|
|
|
- for (var contact in contactToDelete) {
|
|
|
- contact.delete();
|
|
|
+ ToastUtil.show("Merge Successful");
|
|
|
}
|
|
|
|
|
|
- ToastUtil.show("Successful");
|
|
|
- exitEditMode();
|
|
|
- ContactState.loadContacts();
|
|
|
- }
|
|
|
+ void deleteBtnClick() {
|
|
|
+ // 获取要删除的资产
|
|
|
+ final contactToDelete = ContactState.contactList
|
|
|
+ .where((contact) => selectedContacts.contains(contact.id))
|
|
|
+ .toList();
|
|
|
|
|
|
- // 统计联系人的信息数量
|
|
|
- int _countContactInfo(Contact contact) {
|
|
|
- int count = 0;
|
|
|
+ LoadingDialog.show(displayTime: 100);
|
|
|
+ for (var contact in contactToDelete) {
|
|
|
+ contact.delete();
|
|
|
+ }
|
|
|
|
|
|
- // 统计姓名
|
|
|
- if (contact.name.first.isNotEmpty || contact.name.last.isNotEmpty) {
|
|
|
- count++;
|
|
|
+ ToastUtil.show("Successful");
|
|
|
+ exitEditMode();
|
|
|
+ ContactState.loadContacts();
|
|
|
}
|
|
|
|
|
|
- // 统计电话号码
|
|
|
- if (contact.phones.isNotEmpty) {
|
|
|
- count += contact.phones.length;
|
|
|
- }
|
|
|
+ // 统计联系人的信息数量
|
|
|
+ int _countContactInfo(Contact contact) {
|
|
|
+ int count = 0;
|
|
|
|
|
|
- // 统计电子邮件
|
|
|
- if (contact.emails.isNotEmpty) {
|
|
|
- count += contact.emails.length;
|
|
|
- }
|
|
|
+ // 统计姓名
|
|
|
+ if (contact.name.first.isNotEmpty || contact.name.last.isNotEmpty) {
|
|
|
+ count++;
|
|
|
+ }
|
|
|
|
|
|
- // 统计地址
|
|
|
- if (contact.addresses.isNotEmpty) {
|
|
|
- count += contact.addresses.length;
|
|
|
- }
|
|
|
+ // 统计电话号码
|
|
|
+ if (contact.phones.isNotEmpty) {
|
|
|
+ count += contact.phones.length;
|
|
|
+ }
|
|
|
|
|
|
- if (contact.events.isNotEmpty) {
|
|
|
- count += contact.events.length;
|
|
|
- }
|
|
|
+ // 统计电子邮件
|
|
|
+ if (contact.emails.isNotEmpty) {
|
|
|
+ count += contact.emails.length;
|
|
|
+ }
|
|
|
|
|
|
- if (contact.notes.isNotEmpty) {
|
|
|
- count += contact.notes.length;
|
|
|
- }
|
|
|
+ // 统计地址
|
|
|
+ if (contact.addresses.isNotEmpty) {
|
|
|
+ count += contact.addresses.length;
|
|
|
+ }
|
|
|
|
|
|
- if (contact.socialMedias.isNotEmpty) {
|
|
|
- count += contact.socialMedias.length;
|
|
|
- }
|
|
|
+ if (contact.events.isNotEmpty) {
|
|
|
+ count += contact.events.length;
|
|
|
+ }
|
|
|
|
|
|
- if (contact.websites.isNotEmpty) {
|
|
|
- count += contact.websites.length;
|
|
|
- }
|
|
|
+ if (contact.notes.isNotEmpty) {
|
|
|
+ count += contact.notes.length;
|
|
|
+ }
|
|
|
|
|
|
- if (contact.organizations.isNotEmpty) {
|
|
|
- count += contact.organizations.length;
|
|
|
- }
|
|
|
+ if (contact.socialMedias.isNotEmpty) {
|
|
|
+ count += contact.socialMedias.length;
|
|
|
+ }
|
|
|
|
|
|
- // 统计图片
|
|
|
- if (contact.photo != null) {
|
|
|
- if (contact.photo!.isNotEmpty) {
|
|
|
- count++;
|
|
|
+ if (contact.websites.isNotEmpty) {
|
|
|
+ count += contact.websites.length;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (contact.organizations.isNotEmpty) {
|
|
|
+ count += contact.organizations.length;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统计图片
|
|
|
+ if (contact.photo != null) {
|
|
|
+ if (contact.photo!.isNotEmpty) {
|
|
|
+ count++;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- return count;
|
|
|
+ return count;
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
// 并查集类
|
|
|
-class UnionFind {
|
|
|
+ class UnionFind {
|
|
|
final Map<Contact, Contact> _parent = {};
|
|
|
|
|
|
// 查找根节点
|
|
|
Contact find(Contact contact) {
|
|
|
- if (!_parent.containsKey(contact)) {
|
|
|
- _parent[contact] = contact;
|
|
|
- } else if (_parent[contact] != contact) {
|
|
|
- _parent[contact] = find(_parent[contact]!); // 路径压缩
|
|
|
- }
|
|
|
- return _parent[contact]!;
|
|
|
+ if (!_parent.containsKey(contact)) {
|
|
|
+ _parent[contact] = contact;
|
|
|
+ } else if (_parent[contact] != contact) {
|
|
|
+ _parent[contact] = find(_parent[contact]!); // 路径压缩
|
|
|
+ }
|
|
|
+ return _parent[contact]!;
|
|
|
}
|
|
|
|
|
|
// 合并两个集合
|
|
|
void union(Contact a, Contact b) {
|
|
|
- final rootA = find(a);
|
|
|
- final rootB = find(b);
|
|
|
- if (rootA != rootB) {
|
|
|
- _parent[rootB] = rootA;
|
|
|
- }
|
|
|
+ final rootA = find(a);
|
|
|
+ final rootB = find(b);
|
|
|
+ if (rootA != rootB) {
|
|
|
+ _parent[rootB] = rootA;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
-}
|