🐛 Fix contact sync losing phone/email data
Contact entries were fragmented during sync - same person indexed separately by phone and email, with deduplication keeping only one. Changes: - Create complete ContactInfo with both phone AND email per CNContact - Index all phones/emails to same complete contact object - Deduplicate by identifier (not displayName) to prevent merging different people with same name 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
9b7ff88779
commit
499ccab2e2
1 changed files with 27 additions and 21 deletions
|
|
@ -82,6 +82,7 @@ class iMessageReader {
|
|||
|
||||
// Fetch all contacts with phone numbers and emails
|
||||
let keysToFetch: [CNKeyDescriptor] = [
|
||||
CNContactIdentifierKey as CNKeyDescriptor,
|
||||
CNContactGivenNameKey as CNKeyDescriptor,
|
||||
CNContactFamilyNameKey as CNKeyDescriptor,
|
||||
CNContactPhoneNumbersKey as CNKeyDescriptor,
|
||||
|
|
@ -96,27 +97,30 @@ class iMessageReader {
|
|||
|
||||
guard !fullName.isEmpty else { return }
|
||||
|
||||
// Index by phone numbers
|
||||
for phone in contact.phoneNumbers {
|
||||
let normalized = self.normalizePhoneNumber(phone.value.stringValue)
|
||||
self.contactCache[normalized] = ContactInfo(
|
||||
identifier: normalized,
|
||||
displayName: fullName,
|
||||
phoneNumber: normalized,
|
||||
email: nil
|
||||
)
|
||||
// Get all phones and emails for this single contact
|
||||
let phones = contact.phoneNumbers.map { self.normalizePhoneNumber($0.value.stringValue) }
|
||||
let emails = contact.emailAddresses.map { ($0.value as String).lowercased() }
|
||||
|
||||
// Create a complete ContactInfo with first phone/email (for sync)
|
||||
let completeContact = ContactInfo(
|
||||
identifier: phones.first ?? emails.first ?? contact.identifier,
|
||||
displayName: fullName,
|
||||
phoneNumber: phones.first,
|
||||
email: emails.first
|
||||
)
|
||||
|
||||
// Index by all phones (all point to same complete contact)
|
||||
for phone in phones {
|
||||
self.contactCache[phone] = completeContact
|
||||
}
|
||||
|
||||
// Index by emails
|
||||
for email in contact.emailAddresses {
|
||||
let emailStr = email.value as String
|
||||
self.contactCache[emailStr.lowercased()] = ContactInfo(
|
||||
identifier: emailStr,
|
||||
displayName: fullName,
|
||||
phoneNumber: nil,
|
||||
email: emailStr
|
||||
)
|
||||
// Index by all emails (all point to same complete contact)
|
||||
for email in emails {
|
||||
self.contactCache[email] = completeContact
|
||||
}
|
||||
|
||||
// Also index by contact identifier for direct lookup
|
||||
self.contactCache[contact.identifier] = completeContact
|
||||
}
|
||||
|
||||
NSLog("iMessageReader: Loaded \(contactCache.count) contact entries")
|
||||
|
|
@ -140,12 +144,14 @@ class iMessageReader {
|
|||
}
|
||||
|
||||
/// Get all cached contacts for syncing
|
||||
/// Each CNContact from address book is already a single person - deduplicate by identifier
|
||||
func getAllContacts() -> [ContactInfo] {
|
||||
// Deduplicate by display name (same person may have multiple phones/emails)
|
||||
// Deduplicate by identifier (unique per CNContact, not by name)
|
||||
// This prevents merging two different "John Smith" contacts
|
||||
var seen = Set<String>()
|
||||
return contactCache.values.filter { contact in
|
||||
if seen.contains(contact.displayName) { return false }
|
||||
seen.insert(contact.displayName)
|
||||
if seen.contains(contact.identifier) { return false }
|
||||
seen.insert(contact.identifier)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue