SystemContactView.swift 83 lignes · 3123 octets
import Contacts
import ContactsUI
import SwiftUI

// Port of contact/ContactInsertIntent.kt — maps a ContactCard onto the system
// "new contact" UI (CNContactViewController(forNewContact:)).

enum ContactInsertMapper {
    static func makeContact(_ card: ContactCard) -> CNMutableContact {
        let contact = CNMutableContact()
        if let first = card.firstName?.nilIfBlank {
            contact.givenName = first
            if let last = card.lastName?.nilIfBlank {
                contact.familyName = last
            }
        } else if let last = card.lastName?.nilIfBlank {
            contact.familyName = last
        } else if let full = card.fullName?.nilIfBlank {
            // Android passed the display NAME as a single extra.
            contact.givenName = full
        }
        if let company = card.company?.nilIfBlank {
            contact.organizationName = company
        }
        if let job = card.jobTitle?.nilIfBlank {
            contact.jobTitle = job
        }
        if let phone = card.phones.first?.nilIfBlank {
            contact.phoneNumbers = [
                CNLabeledValue(label: CNLabelPhoneNumberMobile, value: CNPhoneNumber(stringValue: phone))
            ]
        }
        if let email = card.emails.first?.nilIfBlank {
            contact.emailAddresses = [
                CNLabeledValue(label: CNLabelWork, value: email as NSString)
            ]
        }
        if let site = card.website?.nilIfBlank {
            contact.urlAddresses = [
                CNLabeledValue(label: CNLabelWork, value: site as NSString)
            ]
        }
        if let address = card.address?.nilIfBlank {
            let postal = CNMutablePostalAddress()
            postal.street = address
            contact.postalAddresses = [CNLabeledValue(label: CNLabelWork, value: postal)]
        }
        // Android also passed NOTES; `CNContact.note` requires the restricted
        // com.apple.developer.contacts.notes entitlement, so it is skipped here.
        return contact
    }
}

/// `CNContactViewController(forNewContact:)` wrapped for SwiftUI presentation.
struct SystemContactView: UIViewControllerRepresentable {
    let card: ContactCard
    let onDismiss: () -> Void

    func makeUIViewController(context: Context) -> UINavigationController {
        let controller = CNContactViewController(forNewContact: ContactInsertMapper.makeContact(card))
        controller.delegate = context.coordinator
        return UINavigationController(rootViewController: controller)
    }

    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}

    func makeCoordinator() -> Coordinator { Coordinator(onDismiss: onDismiss) }

    final class Coordinator: NSObject, CNContactViewControllerDelegate {
        private let onDismiss: () -> Void

        init(onDismiss: @escaping () -> Void) {
            self.onDismiss = onDismiss
        }

        func contactViewController(
            _ viewController: CNContactViewController,
            didCompleteWith contact: CNContact?
        ) {
            onDismiss()
        }
    }
}