@aalzehla/capacitor-contacts 0.0.5 → 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/AalzehlaCapacitorContacts.podspec +2 -2
  2. package/README.md +69 -45
  3. package/android/build.gradle +15 -12
  4. package/android/src/main/java/getcapacitor/community/contacts/BiMap.java +45 -0
  5. package/android/src/main/java/getcapacitor/community/contacts/ContactPayload.java +286 -0
  6. package/android/src/main/java/getcapacitor/community/contacts/Contacts.java +384 -0
  7. package/android/src/main/java/getcapacitor/community/contacts/ContactsPlugin.java +255 -0
  8. package/android/src/main/java/getcapacitor/community/contacts/CreateContactInput.java +233 -0
  9. package/android/src/main/java/getcapacitor/community/contacts/GetContactsProjectionInput.java +214 -0
  10. package/dist/esm/definitions.d.ts +285 -19
  11. package/dist/esm/definitions.js +47 -1
  12. package/dist/esm/definitions.js.map +1 -1
  13. package/dist/esm/index.d.ts +3 -3
  14. package/dist/esm/index.js +3 -3
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/web.d.ts +9 -7
  17. package/dist/esm/web.js +21 -7
  18. package/dist/esm/web.js.map +1 -1
  19. package/dist/plugin.cjs.js +73 -14
  20. package/dist/plugin.cjs.js.map +1 -1
  21. package/dist/plugin.js +74 -15
  22. package/dist/plugin.js.map +1 -1
  23. package/ios/Plugin/BiMap.swift +42 -0
  24. package/ios/Plugin/ContactPayload.swift +227 -0
  25. package/ios/Plugin/Contacts.swift +227 -0
  26. package/ios/Plugin/ContactsPlugin.h +10 -0
  27. package/ios/Plugin/ContactsPlugin.m +14 -0
  28. package/ios/Plugin/ContactsPlugin.swift +221 -0
  29. package/ios/Plugin/CreateContactInput.swift +187 -0
  30. package/ios/Plugin/GetContactsProjectionInput.swift +119 -0
  31. package/ios/Plugin/Info.plist +24 -0
  32. package/package.json +32 -29
  33. package/Package.swift +0 -28
  34. package/android/src/main/java/com/aalzehla/capacitor/contacts/CapacitorContactsPlugin.java +0 -177
  35. package/android/src/main/java/com/aalzehla/capacitor/contacts/ContactDataExtractorVisitor.java +0 -122
  36. package/android/src/main/java/com/aalzehla/capacitor/contacts/ContactExtractorVisitor.java +0 -31
  37. package/android/src/main/java/com/aalzehla/capacitor/contacts/PluginContactFields.java +0 -17
  38. package/android/src/main/java/com/aalzehla/capacitor/contacts/contentQuery/ContentQuery.java +0 -83
  39. package/android/src/main/java/com/aalzehla/capacitor/contacts/contentQuery/ContentQueryService.java +0 -60
  40. package/android/src/main/java/com/aalzehla/capacitor/contacts/utils/Utils.java +0 -19
  41. package/android/src/main/java/com/aalzehla/capacitor/contacts/utils/Visitable.java +0 -5
  42. package/android/src/main/java/com/aalzehla/capacitor/contacts/utils/Visitor.java +0 -5
  43. package/dist/docs.json +0 -145
  44. package/ios/Sources/CapacitorContactsPlugin/CapacitorContactsPlugin.swift +0 -168
  45. package/ios/Tests/CapacitorContactsPluginTests/CapacitorContactsPluginTests.swift +0 -15
package/dist/plugin.js CHANGED
@@ -1,29 +1,88 @@
1
- var capacitorCapacitorContacts = (function (exports, core) {
1
+ var capacitorContacts = (function (exports, core) {
2
2
  'use strict';
3
3
 
4
- const CapacitorContacts$1 = core.registerPlugin('CapacitorContacts', {
5
- web: () => Promise.resolve().then(function () { return web; }).then(m => new m.CapacitorContactsWeb()),
4
+ exports.PhoneType = void 0;
5
+ (function (PhoneType) {
6
+ // Home / Work
7
+ PhoneType["Home"] = "home";
8
+ PhoneType["Work"] = "work";
9
+ // Other / Custom
10
+ PhoneType["Other"] = "other";
11
+ PhoneType["Custom"] = "custom";
12
+ // Phone specific
13
+ PhoneType["Mobile"] = "mobile";
14
+ PhoneType["FaxWork"] = "fax_work";
15
+ PhoneType["FaxHome"] = "fax_home";
16
+ PhoneType["Pager"] = "pager";
17
+ PhoneType["Callback"] = "callback";
18
+ PhoneType["Car"] = "car";
19
+ PhoneType["CompanyMain"] = "company_main";
20
+ PhoneType["Isdn"] = "isdn";
21
+ PhoneType["Main"] = "main";
22
+ PhoneType["OtherFax"] = "other_fax";
23
+ PhoneType["Radio"] = "radio";
24
+ PhoneType["Telex"] = "telex";
25
+ PhoneType["TtyTdd"] = "tty_tdd";
26
+ PhoneType["WorkMobile"] = "work_mobile";
27
+ PhoneType["WorkPager"] = "work_pager";
28
+ PhoneType["Assistant"] = "assistant";
29
+ PhoneType["Mms"] = "mms";
30
+ })(exports.PhoneType || (exports.PhoneType = {}));
31
+ exports.EmailType = void 0;
32
+ (function (EmailType) {
33
+ // Home / Work
34
+ EmailType["Home"] = "home";
35
+ EmailType["Work"] = "work";
36
+ // Other / Custom
37
+ EmailType["Other"] = "other";
38
+ EmailType["Custom"] = "custom";
39
+ // Email specific
40
+ EmailType["Mobile"] = "mobile";
41
+ })(exports.EmailType || (exports.EmailType = {}));
42
+ exports.PostalAddressType = void 0;
43
+ (function (PostalAddressType) {
44
+ // Home / Work
45
+ PostalAddressType["Home"] = "home";
46
+ PostalAddressType["Work"] = "work";
47
+ // Other / Custom
48
+ PostalAddressType["Other"] = "other";
49
+ PostalAddressType["Custom"] = "custom";
50
+ })(exports.PostalAddressType || (exports.PostalAddressType = {}));
51
+
52
+ const Contacts = core.registerPlugin('Contacts', {
53
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.ContactsWeb()),
6
54
  });
7
55
 
8
- class CapacitorContactsWeb extends core.WebPlugin {
9
- constructor() {
10
- super();
56
+ class ContactsWeb extends core.WebPlugin {
57
+ async checkPermissions() {
58
+ throw this.unimplemented('Not implemented on web.');
59
+ }
60
+ async requestPermissions() {
61
+ throw this.unimplemented('Not implemented on web.');
62
+ }
63
+ async getContact() {
64
+ throw this.unimplemented('Not implemented on web.');
65
+ }
66
+ async getContacts() {
67
+ throw this.unimplemented('Not implemented on web.');
68
+ }
69
+ async createContact() {
70
+ throw this.unimplemented('Not implemented on web.');
71
+ }
72
+ async deleteContact() {
73
+ throw this.unimplemented('Not implemented on web.');
74
+ }
75
+ async pickContact() {
76
+ throw this.unimplemented('Not implemented on web.');
11
77
  }
12
- async close() { }
13
78
  }
14
- const ContactPicker = new CapacitorContactsWeb();
15
- const CapacitorContacts = ContactPicker;
16
79
 
17
80
  var web = /*#__PURE__*/Object.freeze({
18
81
  __proto__: null,
19
- CapacitorContactsWeb: CapacitorContactsWeb,
20
- ContactPicker: ContactPicker,
21
- CapacitorContacts: CapacitorContacts
82
+ ContactsWeb: ContactsWeb
22
83
  });
23
84
 
24
- exports.CapacitorContacts = CapacitorContacts$1;
25
-
26
- Object.defineProperty(exports, '__esModule', { value: true });
85
+ exports.Contacts = Contacts;
27
86
 
28
87
  return exports;
29
88
 
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CapacitorContacts = registerPlugin('CapacitorContacts', {\n web: () => import('./web').then(m => new m.CapacitorContactsWeb()),\n});\nexport * from './definitions';\nexport { CapacitorContacts };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class CapacitorContactsWeb extends WebPlugin {\n constructor() {\n super();\n }\n async close() { }\n}\nconst ContactPicker = new CapacitorContactsWeb();\nconst CapacitorContacts = ContactPicker;\nexport { ContactPicker, CapacitorContacts };\n//# sourceMappingURL=web.js.map"],"names":["CapacitorContacts","registerPlugin","WebPlugin"],"mappings":";;;AACK,UAACA,mBAAiB,GAAGC,mBAAc,CAAC,mBAAmB,EAAE;IAC9D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,oBAAoB,EAAE,CAAC;IACtE,CAAC;;ICFM,MAAM,oBAAoB,SAASC,cAAS,CAAC;IACpD,IAAI,WAAW,GAAG;IAClB,QAAQ,KAAK,EAAE,CAAC;IAChB,KAAK;IACL,IAAI,MAAM,KAAK,GAAG,GAAG;IACrB,CAAC;IACD,MAAM,aAAa,GAAG,IAAI,oBAAoB,EAAE,CAAC;IACjD,MAAM,iBAAiB,GAAG,aAAa;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["export var PhoneType;\n(function (PhoneType) {\n // Home / Work\n PhoneType[\"Home\"] = \"home\";\n PhoneType[\"Work\"] = \"work\";\n // Other / Custom\n PhoneType[\"Other\"] = \"other\";\n PhoneType[\"Custom\"] = \"custom\";\n // Phone specific\n PhoneType[\"Mobile\"] = \"mobile\";\n PhoneType[\"FaxWork\"] = \"fax_work\";\n PhoneType[\"FaxHome\"] = \"fax_home\";\n PhoneType[\"Pager\"] = \"pager\";\n PhoneType[\"Callback\"] = \"callback\";\n PhoneType[\"Car\"] = \"car\";\n PhoneType[\"CompanyMain\"] = \"company_main\";\n PhoneType[\"Isdn\"] = \"isdn\";\n PhoneType[\"Main\"] = \"main\";\n PhoneType[\"OtherFax\"] = \"other_fax\";\n PhoneType[\"Radio\"] = \"radio\";\n PhoneType[\"Telex\"] = \"telex\";\n PhoneType[\"TtyTdd\"] = \"tty_tdd\";\n PhoneType[\"WorkMobile\"] = \"work_mobile\";\n PhoneType[\"WorkPager\"] = \"work_pager\";\n PhoneType[\"Assistant\"] = \"assistant\";\n PhoneType[\"Mms\"] = \"mms\";\n})(PhoneType || (PhoneType = {}));\nexport var EmailType;\n(function (EmailType) {\n // Home / Work\n EmailType[\"Home\"] = \"home\";\n EmailType[\"Work\"] = \"work\";\n // Other / Custom\n EmailType[\"Other\"] = \"other\";\n EmailType[\"Custom\"] = \"custom\";\n // Email specific\n EmailType[\"Mobile\"] = \"mobile\";\n})(EmailType || (EmailType = {}));\nexport var PostalAddressType;\n(function (PostalAddressType) {\n // Home / Work\n PostalAddressType[\"Home\"] = \"home\";\n PostalAddressType[\"Work\"] = \"work\";\n // Other / Custom\n PostalAddressType[\"Other\"] = \"other\";\n PostalAddressType[\"Custom\"] = \"custom\";\n})(PostalAddressType || (PostalAddressType = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst Contacts = registerPlugin('Contacts', {\n web: () => import('./web').then((m) => new m.ContactsWeb()),\n});\nexport * from './definitions';\nexport { Contacts };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class ContactsWeb extends WebPlugin {\n async checkPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n async requestPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n async getContact() {\n throw this.unimplemented('Not implemented on web.');\n }\n async getContacts() {\n throw this.unimplemented('Not implemented on web.');\n }\n async createContact() {\n throw this.unimplemented('Not implemented on web.');\n }\n async deleteContact() {\n throw this.unimplemented('Not implemented on web.');\n }\n async pickContact() {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["PhoneType","EmailType","PostalAddressType","registerPlugin","WebPlugin"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import Foundation
2
+
3
+ // Helper to enable bidirectional mapping.
4
+ public class BiMap<K: Hashable, V: Hashable> {
5
+ // The following map can be used for retrieving the key belonging to a certain value.
6
+ // This map is essentially the inverted version of `mapForValues`
7
+ private var mapForKeys: [V: K] = [:]
8
+ // The following map can be used for retrieving the value belonging to a certain key.
9
+ private var mapForValues: [K: V] = [:]
10
+
11
+ private var defaultKey: K
12
+ private var defaultValue: V
13
+
14
+ init(_ map: [K: V], _ defaultKey: K, _ defaultValue: V) {
15
+ self.mapForValues = map
16
+
17
+ for entry in map {
18
+ let key: K = entry.key
19
+ let value: V = entry.value
20
+ self.mapForKeys[value] = key
21
+ }
22
+
23
+ self.defaultKey = defaultKey
24
+ self.defaultValue = defaultValue
25
+ }
26
+
27
+ func getKey(_ v: V?) -> K {
28
+ let k: K? = self.mapForKeys[v ?? "" as! V]
29
+ guard let k = k else {
30
+ return self.defaultKey
31
+ }
32
+ return k
33
+ }
34
+
35
+ func getValue(_ k: K?) -> V {
36
+ let v: V? = self.mapForValues[k ?? "" as! K]
37
+ guard let v = v else {
38
+ return self.defaultValue
39
+ }
40
+ return v
41
+ }
42
+ }
@@ -0,0 +1,227 @@
1
+ import Foundation
2
+ import Contacts
3
+ import Capacitor
4
+
5
+ public class ContactPayload {
6
+
7
+ // Id
8
+ private var contactId: String
9
+
10
+ // Name
11
+ private var name: JSObject = JSObject()
12
+
13
+ // Organization
14
+ private var organization: JSObject = JSObject()
15
+
16
+ // Birthday
17
+ private var birthday: JSObject = JSObject()
18
+
19
+ // Note
20
+ private var note: String?
21
+
22
+ // Phones
23
+ private var phones: JSArray = JSArray()
24
+
25
+ // Emails
26
+ private var emails: JSArray = JSArray()
27
+
28
+ // URLs
29
+ private var urls: JSArray = JSArray()
30
+
31
+ // Postal Addresses
32
+ private var postalAddresses: JSArray = JSArray()
33
+
34
+ // Image
35
+ private var image: JSObject = JSObject()
36
+
37
+ init(_ contactId: String) {
38
+ self.contactId = contactId
39
+ }
40
+
41
+ static func getMimetype(_ data: Data) -> String {
42
+ var b: UInt8 = 0
43
+ data.copyBytes(to: &b, count: 1)
44
+ switch b {
45
+ case 0xFF:
46
+ return "image/jpeg"
47
+ default:
48
+ return "image/png"
49
+ }
50
+ }
51
+
52
+ static func getLabel(_ type: String?, _ rawType: String?) -> String? {
53
+ // On Android, a custom label is saved with `type` set to "custom" and a separate `label` attribute.
54
+ // On iOS, on the contrary, the custom value is just saved into the `type` attribute.
55
+
56
+ if type == "custom" {
57
+ return rawType
58
+ }
59
+
60
+ return nil
61
+ }
62
+
63
+ public func fillData(_ contact: CNContact) {
64
+ // Name
65
+ if contact.isKeyAvailable(CNContactGivenNameKey) {
66
+ let displayName = CNContactFormatter.string(from: contact, style: .fullName)
67
+ self.name["display"] = displayName
68
+ self.name["given"] = contact.givenName
69
+ self.name["middle"] = contact.middleName
70
+ self.name["family"] = contact.familyName
71
+ self.name["prefix"] = contact.namePrefix
72
+ self.name["suffix"] = contact.nameSuffix
73
+ }
74
+
75
+ // Organization
76
+ if contact.isKeyAvailable(CNContactJobTitleKey) {
77
+ self.organization["company"] = contact.organizationName
78
+ self.organization["jobTitle"] = contact.jobTitle
79
+ self.organization["department"] = contact.departmentName
80
+ }
81
+
82
+ // Birthday
83
+ if contact.isKeyAvailable(CNContactBirthdayKey) {
84
+ if let dateComponents = contact.birthday {
85
+ self.birthday["year"] = dateComponents.year
86
+ self.birthday["month"] = dateComponents.month
87
+ self.birthday["day"] = dateComponents.day
88
+ }
89
+ }
90
+
91
+ // Note
92
+ if contact.isKeyAvailable(CNContactNoteKey) {
93
+ self.note = contact.note
94
+ }
95
+
96
+ // Phones
97
+ if contact.isKeyAvailable(CNContactPhoneNumbersKey) {
98
+ self.phones = contact.phoneNumbers.map { phone in
99
+ let type = Contacts.phoneTypeMap.getKey(phone.label)
100
+
101
+ var phoneObject: JSObject = [
102
+ "type": type,
103
+ "number": phone.value.stringValue
104
+ ]
105
+
106
+ if let label = ContactPayload.getLabel(type, phone.label) {
107
+ phoneObject["label"] = label
108
+ }
109
+
110
+ return phoneObject
111
+ }
112
+ }
113
+
114
+ // Emails
115
+ if contact.isKeyAvailable(CNContactEmailAddressesKey) {
116
+ self.emails = contact.emailAddresses.map { email in
117
+ let type = Contacts.emailTypeMap.getKey(email.label)
118
+
119
+ var emailObject: JSObject = [
120
+ "type": type,
121
+ "address": email.value as String
122
+ ]
123
+
124
+ if let label = ContactPayload.getLabel(type, email.label) {
125
+ emailObject["label"] = label
126
+ }
127
+
128
+ return emailObject
129
+ }
130
+ }
131
+
132
+ // URLs
133
+ if contact.isKeyAvailable(CNContactUrlAddressesKey) {
134
+ self.urls = contact.urlAddresses.map { url in
135
+ return url.value as String
136
+ }
137
+ }
138
+
139
+ // Postal Addresses
140
+ if contact.isKeyAvailable(CNContactPostalAddressesKey) {
141
+ self.postalAddresses = contact.postalAddresses.map { postalAddress in
142
+ let type = Contacts.postalAddressTypeMap.getKey(postalAddress.label)
143
+ let formatted = CNPostalAddressFormatter.string(from: postalAddress.value, style: .mailingAddress)
144
+
145
+ var postalAddressObject: JSObject = [
146
+ "type": type,
147
+ "formatted": formatted,
148
+ "street": postalAddress.value.street,
149
+ "neighborhood": postalAddress.value.subAdministrativeArea,
150
+ "city": postalAddress.value.city,
151
+ "region": postalAddress.value.state,
152
+ "postcode": postalAddress.value.postalCode,
153
+ "country": postalAddress.value.country
154
+ ]
155
+
156
+ if let label = ContactPayload.getLabel(type, postalAddress.label) {
157
+ postalAddressObject["label"] = label
158
+ }
159
+
160
+ return postalAddressObject
161
+ }
162
+ }
163
+
164
+ // Image
165
+ if contact.isKeyAvailable(CNContactImageDataKey) {
166
+ if let image = contact.imageData {
167
+ let mimeType = ContactPayload.getMimetype(image)
168
+ let encodedImage = image.base64EncodedString()
169
+ self.image["base64String"] = "data:\(mimeType);base64,\(encodedImage)"
170
+ }
171
+ }
172
+ }
173
+
174
+ public func getJSObject() -> JSObject {
175
+ var contact = JSObject()
176
+
177
+ // Id
178
+ contact["contactId"] = self.contactId
179
+
180
+ // Name
181
+ if self.name.count > 0 {
182
+ contact["name"] = self.name
183
+ }
184
+
185
+ // Organization
186
+ if self.organization.count > 0 {
187
+ contact["organization"] = self.organization
188
+ }
189
+
190
+ // Birthday
191
+ if self.birthday.count > 0 {
192
+ contact["birthday"] = self.birthday
193
+ }
194
+
195
+ // Note
196
+ if self.note != nil {
197
+ contact["note"] = self.note
198
+ }
199
+
200
+ // Phones
201
+ if self.phones.count > 0 {
202
+ contact["phones"] = self.phones
203
+ }
204
+
205
+ // Emails
206
+ if self.emails.count > 0 {
207
+ contact["emails"] = self.emails
208
+ }
209
+
210
+ // URLs
211
+ if self.urls.count > 0 {
212
+ contact["urls"] = self.urls
213
+ }
214
+
215
+ // Postal Addresses
216
+ if self.postalAddresses.count > 0 {
217
+ contact["postalAddresses"] = self.postalAddresses
218
+ }
219
+
220
+ // Image
221
+ if self.image.count > 0 {
222
+ contact["image"] = self.image
223
+ }
224
+
225
+ return contact
226
+ }
227
+ }
@@ -0,0 +1,227 @@
1
+ import Foundation
2
+ import Contacts
3
+
4
+ public class Contacts: NSObject {
5
+ public static let phoneTypeMap = BiMap<String, String>([
6
+ // Home / Work
7
+ "home": CNLabelHome,
8
+ "work": CNLabelWork,
9
+ // Other
10
+ "other": CNLabelOther,
11
+ // Custom
12
+ "custom": "custom",
13
+ // Phone specific
14
+ "main": CNLabelPhoneNumberMain,
15
+ "mobile": CNLabelPhoneNumberMobile,
16
+ "pager": CNLabelPhoneNumberPager,
17
+ "fax_home": CNLabelPhoneNumberHomeFax,
18
+ "fax_work": CNLabelPhoneNumberWorkFax,
19
+ "fax_other": CNLabelPhoneNumberOtherFax,
20
+ //
21
+ //
22
+ // iOS only:
23
+ // School
24
+ // "school": CNLabelSchool, // (iOS ^13.x.x only)
25
+ // Phone specific
26
+ // "apple_watch": CNLabelPhoneNumberAppleWatch, // (iOS ^14.3.x only)
27
+ "iphone": CNLabelPhoneNumberiPhone
28
+ ], "custom", "custom")
29
+
30
+ public static let emailTypeMap = BiMap<String, String>([
31
+ // Home / Work
32
+ "home": CNLabelHome,
33
+ "work": CNLabelWork,
34
+ // Other
35
+ "other": CNLabelOther,
36
+ // Custom
37
+ "custom": "custom",
38
+ //
39
+ //
40
+ // iOS only:
41
+ // School
42
+ // "school": CNLabelSchool, // (iOS ^13.x.x only)
43
+ // Email specific
44
+ "icloud": CNLabelEmailiCloud
45
+ ], "custom", "custom")
46
+
47
+ public static let postalAddressTypeMap = BiMap<String, String>([
48
+ // Home / Work
49
+ "home": CNLabelHome,
50
+ "work": CNLabelWork,
51
+ // Other
52
+ "other": CNLabelOther,
53
+ // Custom
54
+ "custom": "custom"
55
+ //
56
+ //
57
+ // iOS only:
58
+ // School
59
+ // "school": CNLabelSchool, // (iOS ^13.x.x only)
60
+ ], "custom", "custom")
61
+
62
+ public func getContact(_ contactId: String, _ projection: GetContactsProjectionInput) -> ContactPayload? {
63
+ let projection = projection.getProjection()
64
+
65
+ let cs = CNContactStore()
66
+
67
+ do {
68
+ let contactResult = try cs.unifiedContact(withIdentifier: contactId, keysToFetch: projection)
69
+
70
+ let contact = ContactPayload(contactId)
71
+
72
+ contact.fillData(contactResult)
73
+
74
+ return contact
75
+ } catch {
76
+ return nil
77
+ }
78
+ }
79
+
80
+ public func getContacts(_ projection: GetContactsProjectionInput) -> [ContactPayload] {
81
+ let projection = projection.getProjection()
82
+
83
+ var contacts = [ContactPayload]()
84
+
85
+ let cs = CNContactStore()
86
+
87
+ do {
88
+ let request = CNContactFetchRequest(keysToFetch: projection)
89
+
90
+ try cs.enumerateContacts(with: request) { (contactData, _) in
91
+ let contact = ContactPayload(contactData.identifier)
92
+
93
+ contact.fillData(contactData)
94
+
95
+ contacts.append(contact)
96
+ }
97
+ } catch {
98
+ // oops
99
+ }
100
+
101
+ return contacts
102
+ }
103
+
104
+ public func createContact(_ contactInput: CreateContactInput) -> String? {
105
+ let newContact = CNMutableContact()
106
+
107
+ // Name
108
+ if let nameGiven = contactInput.nameGiven {
109
+ newContact.givenName = nameGiven
110
+ }
111
+ if let nameMiddle = contactInput.nameMiddle {
112
+ newContact.middleName = nameMiddle
113
+ }
114
+ if let nameFamily = contactInput.nameFamily {
115
+ newContact.familyName = nameFamily
116
+ }
117
+ if let namePrefix = contactInput.namePrefix {
118
+ newContact.namePrefix = namePrefix
119
+ }
120
+ if let nameSuffix = contactInput.nameSuffix {
121
+ newContact.nameSuffix = nameSuffix
122
+ }
123
+
124
+ // Organization
125
+ if let organizationName = contactInput.organizationName {
126
+ newContact.organizationName = organizationName
127
+ }
128
+ if let organizationJobTitle = contactInput.organizationJobTitle {
129
+ newContact.jobTitle = organizationJobTitle
130
+ }
131
+ if let organizationDepartment = contactInput.organizationDepartment {
132
+ newContact.departmentName = organizationDepartment
133
+ }
134
+
135
+ // Birthday
136
+ if let birthday = contactInput.birthday {
137
+ newContact.birthday = birthday
138
+ }
139
+
140
+ // Note
141
+ if let note = contactInput.note {
142
+ newContact.note = note
143
+ }
144
+
145
+ // Phones
146
+ newContact.phoneNumbers = contactInput.phones.map { phone in
147
+ return CNLabeledValue(
148
+ label: phone.type,
149
+ value: CNPhoneNumber(stringValue: phone.number ?? "")
150
+ )
151
+ }
152
+
153
+ // Email
154
+ newContact.emailAddresses = contactInput.emails.map { email in
155
+ return CNLabeledValue(
156
+ label: email.type,
157
+ value: email.address as? NSString ?? ""
158
+ )
159
+ }
160
+
161
+ // URLs
162
+ newContact.urlAddresses = contactInput.urls.map { url in
163
+ return CNLabeledValue(
164
+ label: nil,
165
+ value: url as NSString
166
+ )
167
+ }
168
+
169
+ // Postal Addresses
170
+ newContact.postalAddresses = contactInput.postalAddresses.map({ postalAddress in
171
+ let address = CNMutablePostalAddress()
172
+ address.street = postalAddress.street ?? ""
173
+ address.subAdministrativeArea = postalAddress.neighborhood ?? ""
174
+ address.city = postalAddress.city ?? ""
175
+ address.state = postalAddress.region ?? ""
176
+ address.postalCode = postalAddress.postcode ?? ""
177
+ address.country = postalAddress.country ?? ""
178
+
179
+ return CNLabeledValue(
180
+ label: postalAddress.type,
181
+ value: address
182
+ )
183
+ })
184
+
185
+ // Image
186
+ if let image = contactInput.image {
187
+ if let base64String = image.base64String {
188
+ if let data = Data(base64Encoded: base64String, options: .ignoreUnknownCharacters) {
189
+ newContact.imageData = data
190
+ }
191
+ }
192
+ }
193
+
194
+ do {
195
+ let cs = CNContactStore()
196
+ let saveRequest = CNSaveRequest()
197
+ saveRequest.add(newContact, toContainerWithIdentifier: nil)
198
+
199
+ try cs.execute(saveRequest)
200
+
201
+ if newContact.isKeyAvailable(CNContactIdentifierKey) {
202
+ return newContact.identifier
203
+ }
204
+
205
+ return nil
206
+ } catch {
207
+ return nil
208
+ }
209
+ }
210
+
211
+ public func deleteContact(_ contactId: String) -> Bool {
212
+ let cs = CNContactStore()
213
+
214
+ do {
215
+ let contactResult = try cs.unifiedContact(withIdentifier: contactId, keysToFetch: [CNContactIdentifierKey] as [CNKeyDescriptor])
216
+
217
+ let saveRequest = CNSaveRequest()
218
+ saveRequest.delete(contactResult.mutableCopy() as! CNMutableContact)
219
+
220
+ try cs.execute(saveRequest)
221
+
222
+ return true
223
+ } catch {
224
+ return false
225
+ }
226
+ }
227
+ }
@@ -0,0 +1,10 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ //! Project version number for Plugin.
4
+ FOUNDATION_EXPORT double PluginVersionNumber;
5
+
6
+ //! Project version string for Plugin.
7
+ FOUNDATION_EXPORT const unsigned char PluginVersionString[];
8
+
9
+ // In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
10
+
@@ -0,0 +1,14 @@
1
+ #import <Foundation/Foundation.h>
2
+ #import <Capacitor/Capacitor.h>
3
+
4
+ // Define the plugin using the CAP_PLUGIN Macro, and
5
+ // each method the plugin supports using the CAP_PLUGIN_METHOD macro.
6
+ CAP_PLUGIN(ContactsPlugin, "Contacts",
7
+ CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise);
8
+ CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise);
9
+ CAP_PLUGIN_METHOD(getContact, CAPPluginReturnPromise);
10
+ CAP_PLUGIN_METHOD(getContacts, CAPPluginReturnPromise);
11
+ CAP_PLUGIN_METHOD(createContact, CAPPluginReturnPromise);
12
+ CAP_PLUGIN_METHOD(deleteContact, CAPPluginReturnPromise);
13
+ CAP_PLUGIN_METHOD(pickContact, CAPPluginReturnPromise);
14
+ )