rust_macios/contacts/
cn_contact.rs

1use std::fmt::Debug;
2
3use crate::{
4    foundation::{NSArray, NSComparator, NSData, NSDateComponents, NSPredicate, NSString},
5    object,
6    objective_c_runtime::{
7        id,
8        macros::interface_impl,
9        nil,
10        traits::{FromId, PNSObject},
11    },
12    utils::to_bool,
13};
14use objc::{msg_send, sel, sel_impl};
15
16use super::{
17    CNContactRelation, CNInstantMessageAddress, CNLabeledValue, CNPhoneNumber, CNPostalAddress,
18    CNSocialProfile,
19};
20
21/// The types a contact can be.
22#[derive(Debug, Copy, Clone, PartialEq, Eq)]
23#[repr(i64)]
24pub enum CNContactType {
25    /// A person.
26    Person,
27    /// A organization.
28    Organization,
29}
30
31/// Indicates the sorting order for contacts.
32#[derive(Debug, Copy, Clone, PartialEq, Eq)]
33#[repr(i64)]
34pub enum CNContactSortOrder {
35    /// No sorting order.
36    None,
37    /// The user’s default sorting order.
38    UserDefault,
39    /// Sorting contacts by given name.
40    GivenName,
41    /// Sorting contacts by family name.
42    FamilyName,
43}
44
45object! {
46    /// An immutable object that stores information about a single contact, such as the contact's first name, phone numbers, and addresses.
47    unsafe pub struct CNContact;
48}
49
50#[interface_impl(NSObject)]
51impl CNContact {
52    /* Identifying the Contact
53     */
54
55    /// A value that uniquely identifies a contact on the device.
56    #[property]
57    pub fn identifier(&self) -> NSString {
58        unsafe { NSString::from_id(msg_send![self.m_self(), identifier]) }
59    }
60
61    /// An enum identifying the contact type.
62    #[property]
63    pub fn contact_type(&self) -> CNContactType {
64        unsafe { msg_send![self.m_self(), contactType] }
65    }
66
67    /// The name prefix of the contact.
68    #[property]
69    pub fn name_prefix(&self) -> NSString {
70        unsafe { NSString::from_id(msg_send![self.m_self(), namePrefix]) }
71    }
72
73    /// The given name of the contact.
74    #[property]
75    pub fn given_name(&self) -> NSString {
76        unsafe { NSString::from_id(msg_send![self.m_self(), givenName]) }
77    }
78
79    /// The middle name of the contact.
80    #[property]
81    pub fn middle_name(&self) -> NSString {
82        unsafe { NSString::from_id(msg_send![self.m_self(), middleName]) }
83    }
84
85    /// A string for the previous family name of the contact.
86    #[property]
87    pub fn family_name(&self) -> NSString {
88        unsafe { NSString::from_id(msg_send![self.m_self(), familyName]) }
89    }
90
91    /// A string for the previous family name of the contact.
92    #[property]
93    pub fn previous_family_name(&self) -> NSString {
94        unsafe { NSString::from_id(msg_send![self.m_self(), previousFamilyName]) }
95    }
96
97    /// The name suffix of the contact.
98    #[property]
99    pub fn name_suffix(&self) -> NSString {
100        unsafe { NSString::from_id(msg_send![self.m_self(), nameSuffix]) }
101    }
102
103    /// The nickname of the contact.
104    #[property]
105    pub fn nickname(&self) -> NSString {
106        unsafe { NSString::from_id(msg_send![self.m_self(), nickname]) }
107    }
108
109    /// The phonetic given name of the contact.
110    #[property]
111    pub fn phonetic_given_name(&self) -> NSString {
112        unsafe { NSString::from_id(msg_send![self.m_self(), phoneticGivenName]) }
113    }
114
115    /// The phonetic middle name of the contact.
116    #[property]
117    pub fn phonetic_middle_name(&self) -> NSString {
118        unsafe { NSString::from_id(msg_send![self.m_self(), phoneticMiddleName]) }
119    }
120
121    /// The phonetic family name of the contact.
122    #[property]
123    pub fn phonetic_family_name(&self) -> NSString {
124        unsafe { NSString::from_id(msg_send![self.m_self(), phoneticFamilyName]) }
125    }
126
127    /* Getting Work Information
128     */
129
130    /// The contact’s job title.
131    #[property]
132    pub fn job_title(&self) -> NSString {
133        unsafe { NSString::from_id(msg_send![self.m_self(), jobTitle]) }
134    }
135
136    /// The name of the department associated with the contact.
137    #[property]
138    pub fn department_name(&self) -> NSString {
139        unsafe { NSString::from_id(msg_send![self.m_self(), departmentName]) }
140    }
141
142    /// The name of the organization associated with the contact.
143    #[property]
144    pub fn organization_name(&self) -> NSString {
145        unsafe { NSString::from_id(msg_send![self.m_self(), organizationName]) }
146    }
147
148    /// The phonetic name of the organization associated with the contact.
149    #[property]
150    pub fn phonetic_organization_name(&self) -> NSString {
151        unsafe { NSString::from_id(msg_send![self.m_self(), phoneticOrganizationName]) }
152    }
153
154    /* Getting Addresses
155     */
156
157    /// An array of labeled postal addresses for a contact.
158    #[property]
159    pub fn postal_addresses(&self) -> NSArray<CNLabeledValue<CNPostalAddress>> {
160        unsafe { NSArray::from_id(msg_send![self.m_self(), postalAddresses]) }
161    }
162
163    /// An array of labeled email addresses for the contact.
164    #[property]
165    pub fn email_addresses(&self) -> NSArray<CNLabeledValue<NSString>> {
166        unsafe { NSArray::from_id(msg_send![self.m_self(), emailAddresses]) }
167    }
168
169    /// An array of labeled URL addresses for a contact.
170    #[property]
171    pub fn url_addresses(&self) -> NSArray<CNLabeledValue<NSString>> {
172        unsafe { NSArray::from_id(msg_send![self.m_self(), urlAddresses]) }
173    }
174
175    /* Getting Phone Information
176     */
177
178    /// An array of labeled phone numbers for a contact.
179    #[property]
180    pub fn phone_numbers(&self) -> NSArray<CNLabeledValue<CNPhoneNumber>> {
181        unsafe { NSArray::from_id(msg_send![self.m_self(), phoneNumbers]) }
182    }
183
184    /* Getting Social Profiles
185     */
186
187    /// An array of labeled social profiles for a contact.
188    #[property]
189    pub fn social_profiles(&self) -> NSArray<CNLabeledValue<CNSocialProfile>> {
190        unsafe { NSArray::from_id(msg_send![self.m_self(), socialProfiles]) }
191    }
192
193    /// A date component for the Gregorian birthday of the contact.
194    #[property]
195    pub fn birthday(&self) -> Option<NSDateComponents> {
196        unsafe {
197            let ptr = msg_send![self.m_self(), birthday];
198
199            if ptr != nil {
200                Some(NSDateComponents::from_id(ptr))
201            } else {
202                None
203            }
204        }
205    }
206
207    /* Getting Birthday Information
208     */
209
210    /// A date component for the non-Gregorian birthday of the contact.
211    #[property]
212    pub fn non_gregorian_birthday(&self) -> Option<NSDateComponents> {
213        unsafe {
214            let ptr = msg_send![self.m_self(), nonGregorianBirthday];
215
216            if ptr != nil {
217                Some(NSDateComponents::from_id(ptr))
218            } else {
219                None
220            }
221        }
222    }
223
224    /// An array containing labeled Gregorian dates.
225    #[property]
226    pub fn dates(&self) -> NSArray<CNLabeledValue<NSDateComponents>> {
227        unsafe { NSArray::from_id(msg_send![self.m_self(), dates]) }
228    }
229
230    /// A string containing notes for the contact.
231    #[property]
232    pub fn note(&self) -> NSString {
233        unsafe { NSString::from_id(msg_send![self.m_self(), note]) }
234    }
235
236    /* Getting Contact Images
237     */
238
239    /// The profile picture of a contact.
240    #[property]
241    pub fn image_data(&self) -> Option<NSData> {
242        unsafe {
243            let ptr = msg_send![self.m_self(), imageData];
244
245            if ptr != nil {
246                Some(NSData::from_id(ptr))
247            } else {
248                None
249            }
250        }
251    }
252
253    /// The thumbnail version of the contact’s profile picture.
254    #[property]
255    pub fn thumbnail_image_data(&self) -> Option<NSData> {
256        unsafe {
257            let ptr = msg_send![self.m_self(), thumbnailImageData];
258
259            if ptr != nil {
260                Some(NSData::from_id(ptr))
261            } else {
262                None
263            }
264        }
265    }
266
267    /// A Boolean indicating whether a contact has a profile picture.
268    #[property]
269    pub fn image_data_available(&self) -> bool {
270        unsafe { to_bool(msg_send![self.m_self(), imageDataAvailable]) }
271    }
272
273    /* Getting Related Information
274     */
275
276    /// An array of labeled relations for the contact.
277    #[property]
278    pub fn contact_relations(&self) -> NSArray<CNLabeledValue<CNContactRelation>> {
279        unsafe { NSArray::from_id(msg_send![self.m_self(), contactRelations]) }
280    }
281
282    /// An array of labeled IM addresses for the contact.
283    #[property]
284    pub fn instant_messaging_addresses(&self) -> NSArray<CNLabeledValue<CNInstantMessageAddress>> {
285        unsafe { NSArray::from_id(msg_send![self.m_self(), instantMessageAddresses]) }
286    }
287
288    /* Localizing Contact Data
289     */
290
291    /// Returns a string containing the localized contact property name.
292    #[method]
293    pub fn localized_string_for_key(property: NSString) -> NSString {
294        unsafe { NSString::from_id(msg_send![Self::m_class(), localizedStringForKey: property]) }
295    }
296
297    /* Comparing Contacts
298     */
299
300    /// Fetches all the keys required for the contact sort comparator.
301    #[method]
302    pub fn descriptor_for_all_comparator_keys() -> id {
303        unsafe { msg_send![Self::m_class(), descriptorForAllComparatorKeys] }
304    }
305
306    /// Returns a comparator to sort contacts with the specified order.
307    #[method]
308    pub fn comparator_for_name_sort_order(sort_order: CNContactSortOrder) -> NSComparator {
309        unsafe { msg_send![Self::m_class(), comparatorForNameSortOrder: sort_order] }
310    }
311
312    /// Returns a Boolean indicating whether the current contact is a unified contact and includes a contact with the specified identifier.
313    #[method]
314    pub fn is_unified_with_contact_with_identifier(&self, identifier: NSString) -> bool {
315        unsafe {
316            to_bool(msg_send![
317                self.m_self(),
318                isUnifiedWithContactWithIdentifier: identifier
319            ])
320        }
321    }
322
323    /// Determines whether the contact property value for the specified key is fetched.
324    #[method]
325    pub fn is_key_available(&self, key: NSString) -> bool {
326        unsafe { to_bool(msg_send![self.m_self(), isKeyAvailable: key]) }
327    }
328
329    /// Determines whether all contact property values for the specified keys are fetched.
330    #[method]
331    pub fn are_keys_available(&self, key_descriptors: NSArray<id>) -> bool {
332        unsafe { to_bool(msg_send![self.m_self(), areKeysAvailable: key_descriptors]) }
333    }
334
335    /* Getting Search Predicates
336     */
337
338    /// Returns a predicate to find the contacts matching the specified name.
339    #[method]
340    pub fn predicate_for_contacts_matching_name(name: NSString) -> NSPredicate {
341        unsafe {
342            NSPredicate::from_id(msg_send![
343                Self::m_class(),
344                predicateForContactsMatchingName: name
345            ])
346        }
347    }
348
349    /// Returns a predicate to find the contacts matching the specified identifiers.
350    #[method]
351    pub fn predicate_for_contacts_with_identifiers(identifiers: NSArray<String>) -> NSPredicate {
352        unsafe {
353            NSPredicate::from_id(msg_send![
354                Self::m_class(),
355                predicateForContactsWithIdentifiers: identifiers
356            ])
357        }
358    }
359
360    /// Returns a predicate to find the contacts that are members in the specified group.
361    #[method]
362    pub fn predicate_for_contacts_in_group_with_identifier(group: NSString) -> NSPredicate {
363        unsafe {
364            NSPredicate::from_id(msg_send![
365                Self::m_class(),
366                predicateForContactsInGroupWithIdentifier: group
367            ])
368        }
369    }
370
371    /// Returns a predicate to find the contacts in the specified container.
372    #[method]
373    pub fn predicate_for_contacts_in_container_with_identifier(container: NSString) -> NSPredicate {
374        unsafe {
375            NSPredicate::from_id(msg_send![
376                Self::m_class(),
377                predicateForContactsInContainerWithIdentifier: container
378            ])
379        }
380    }
381
382    /// Returns a predicate to find the contacts whose phone number matches the specified value.
383    #[method]
384    pub fn predicate_for_contacts_matching_phone_number(
385        phone_number: CNPhoneNumber,
386    ) -> NSPredicate {
387        unsafe {
388            NSPredicate::from_id(msg_send![
389                Self::m_class(),
390                predicateForContactsMatchingPhoneNumber: phone_number
391            ])
392        }
393    }
394
395    /// Returns a predicate to find the contacts whose email address matches the specified value.
396    #[method]
397    pub fn predicate_for_contacts_matching_email_address(email_address: NSString) -> NSPredicate {
398        unsafe {
399            NSPredicate::from_id(msg_send![
400                Self::m_class(),
401                predicateForContactsMatchingEmailAddress: email_address
402            ])
403        }
404    }
405}
406
407#[cfg(test)]
408mod tests {
409    use crate::{contacts::CNContactType, objective_c_runtime::traits::PNSObject};
410
411    use super::CNContact;
412
413    #[test]
414    fn test_contact() {
415        let contact = CNContact::m_new();
416
417        assert!(contact.birthday().is_none());
418        assert!(contact.contact_relations().count() == 0);
419        assert!(contact.contact_type() == CNContactType::Person);
420        assert!(contact.dates().count() == 0);
421        assert!(contact.department_name() == "");
422        assert!(contact.email_addresses().count() == 0);
423        assert!(contact.family_name() == "");
424        assert!(contact.given_name() == "");
425        assert!(contact.identifier() != "");
426        assert!(contact.image_data().is_none());
427        assert!(!contact.image_data_available());
428        assert!(contact.instant_messaging_addresses().count() == 0);
429        assert!(contact.job_title() == "");
430        assert!(contact.middle_name() == "");
431        assert!(contact.name_prefix() == "");
432        assert!(contact.name_suffix() == "");
433        assert!(contact.nickname() == "");
434        assert!(contact.non_gregorian_birthday().is_none());
435        assert!(contact.note() == "");
436        assert!(contact.organization_name() == "");
437        assert!(contact.phone_numbers().count() == 0);
438        assert!(contact.phonetic_given_name() == "");
439        assert!(contact.phonetic_middle_name() == "");
440        assert!(contact.phonetic_family_name() == "");
441        assert!(contact.postal_addresses().count() == 0);
442        assert!(contact.previous_family_name() == "");
443        assert!(contact.social_profiles().count() == 0);
444        assert!(contact.thumbnail_image_data().is_none());
445        assert!(contact.url_addresses().count() == 0);
446    }
447}