@capgo/capacitor-contacts 7.1.1 → 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.
- package/CapgoCapacitorContacts.podspec +1 -1
- package/LICENSE +373 -21
- package/Package.swift +2 -2
- package/README.md +2 -4
- package/android/build.gradle +9 -9
- package/android/src/main/java/app/capgo/contacts/CapacitorContactsPlugin.java +797 -26
- package/ios/Sources/CapacitorContactsPlugin/CapacitorContactsPlugin.swift +509 -16
- package/package.json +15 -15
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import Capacitor
|
|
2
2
|
import Contacts
|
|
3
|
+
import ContactsUI
|
|
3
4
|
import UIKit
|
|
4
5
|
|
|
5
6
|
@objc(CapacitorContactsPlugin)
|
|
6
7
|
public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
8
|
+
private let pluginVersion: String = "8.0.1"
|
|
7
9
|
public let identifier = "CapacitorContactsPlugin"
|
|
8
10
|
public let jsName = "CapacitorContacts"
|
|
9
11
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -27,7 +29,8 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
27
29
|
CAPPluginMethod(name: "pickContacts", returnType: CAPPluginReturnPromise),
|
|
28
30
|
CAPPluginMethod(name: "updateContactById", returnType: CAPPluginReturnPromise),
|
|
29
31
|
CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
|
|
30
|
-
CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise)
|
|
32
|
+
CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
|
|
33
|
+
CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
|
|
31
34
|
]
|
|
32
35
|
|
|
33
36
|
private let contactStore = CNContactStore()
|
|
@@ -151,6 +154,10 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
156
|
|
|
157
|
+
@objc func getPluginVersion(_ call: CAPPluginCall) {
|
|
158
|
+
call.resolve(["version": self.pluginVersion])
|
|
159
|
+
}
|
|
160
|
+
|
|
154
161
|
@objc override public func checkPermissions(_ call: CAPPluginCall) {
|
|
155
162
|
let status = authorizationStatus()
|
|
156
163
|
call.resolve(status)
|
|
@@ -177,24 +184,284 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
177
184
|
})
|
|
178
185
|
}
|
|
179
186
|
|
|
180
|
-
// MARK: -
|
|
187
|
+
// MARK: - Write operations
|
|
188
|
+
|
|
189
|
+
@objc func createContact(_ call: CAPPluginCall) {
|
|
190
|
+
guard let options = call.options["options"] as? JSObject,
|
|
191
|
+
let contactData = options["contact"] as? JSObject else {
|
|
192
|
+
call.reject("Missing contact data.")
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
ensureAuthorized(call) {
|
|
197
|
+
let newContact = CNMutableContact()
|
|
198
|
+
self.populateContact(newContact, from: contactData)
|
|
199
|
+
|
|
200
|
+
let saveRequest = CNSaveRequest()
|
|
201
|
+
saveRequest.add(newContact, toContainerWithIdentifier: nil)
|
|
181
202
|
|
|
182
|
-
|
|
183
|
-
|
|
203
|
+
do {
|
|
204
|
+
try self.contactStore.execute(saveRequest)
|
|
205
|
+
call.resolve(["id": newContact.identifier])
|
|
206
|
+
} catch {
|
|
207
|
+
call.reject("Failed to create contact.", nil, error)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
184
210
|
}
|
|
185
211
|
|
|
186
|
-
@objc func
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
212
|
+
@objc func updateContactById(_ call: CAPPluginCall) {
|
|
213
|
+
guard let options = call.options["options"] as? JSObject,
|
|
214
|
+
let identifier = options["id"] as? String,
|
|
215
|
+
let contactData = options["contact"] as? JSObject else {
|
|
216
|
+
call.reject("Missing contact identifier or data.")
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
ensureAuthorized(call) {
|
|
221
|
+
do {
|
|
222
|
+
let keysToFetch: [CNKeyDescriptor] = [
|
|
223
|
+
CNContactIdentifierKey as CNKeyDescriptor,
|
|
224
|
+
CNContactGivenNameKey as CNKeyDescriptor,
|
|
225
|
+
CNContactFamilyNameKey as CNKeyDescriptor,
|
|
226
|
+
CNContactMiddleNameKey as CNKeyDescriptor,
|
|
227
|
+
CNContactNamePrefixKey as CNKeyDescriptor,
|
|
228
|
+
CNContactNameSuffixKey as CNKeyDescriptor,
|
|
229
|
+
CNContactOrganizationNameKey as CNKeyDescriptor,
|
|
230
|
+
CNContactJobTitleKey as CNKeyDescriptor,
|
|
231
|
+
CNContactEmailAddressesKey as CNKeyDescriptor,
|
|
232
|
+
CNContactPhoneNumbersKey as CNKeyDescriptor,
|
|
233
|
+
CNContactPostalAddressesKey as CNKeyDescriptor,
|
|
234
|
+
CNContactUrlAddressesKey as CNKeyDescriptor,
|
|
235
|
+
CNContactBirthdayKey as CNKeyDescriptor,
|
|
236
|
+
CNContactNoteKey as CNKeyDescriptor,
|
|
237
|
+
CNContactImageDataKey as CNKeyDescriptor
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
|
|
241
|
+
let mutableContact = contact.mutableCopy() as! CNMutableContact
|
|
242
|
+
|
|
243
|
+
self.populateContact(mutableContact, from: contactData)
|
|
244
|
+
|
|
245
|
+
let saveRequest = CNSaveRequest()
|
|
246
|
+
saveRequest.update(mutableContact)
|
|
247
|
+
|
|
248
|
+
try self.contactStore.execute(saveRequest)
|
|
249
|
+
call.resolve()
|
|
250
|
+
} catch {
|
|
251
|
+
call.reject("Failed to update contact.", nil, error)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@objc func deleteContactById(_ call: CAPPluginCall) {
|
|
257
|
+
guard let options = call.options["options"] as? JSObject,
|
|
258
|
+
let identifier = options["id"] as? String else {
|
|
259
|
+
call.reject("Missing contact identifier.")
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
ensureAuthorized(call) {
|
|
264
|
+
do {
|
|
265
|
+
let keysToFetch: [CNKeyDescriptor] = [CNContactIdentifierKey as CNKeyDescriptor]
|
|
266
|
+
let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
|
|
267
|
+
let mutableContact = contact.mutableCopy() as! CNMutableContact
|
|
268
|
+
|
|
269
|
+
let saveRequest = CNSaveRequest()
|
|
270
|
+
saveRequest.delete(mutableContact)
|
|
271
|
+
|
|
272
|
+
try self.contactStore.execute(saveRequest)
|
|
273
|
+
call.resolve()
|
|
274
|
+
} catch {
|
|
275
|
+
call.reject("Failed to delete contact.", nil, error)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// MARK: - Group operations
|
|
281
|
+
|
|
282
|
+
@objc func getGroups(_ call: CAPPluginCall) {
|
|
283
|
+
ensureAuthorized(call) {
|
|
284
|
+
do {
|
|
285
|
+
let groups = try self.contactStore.groups(matching: nil)
|
|
286
|
+
let serialized: [JSObject] = groups.map { group in
|
|
287
|
+
var result: JSObject = [:]
|
|
288
|
+
result["id"] = group.identifier
|
|
289
|
+
result["name"] = group.name
|
|
290
|
+
return result
|
|
291
|
+
}
|
|
292
|
+
call.resolve(["groups": serialized])
|
|
293
|
+
} catch {
|
|
294
|
+
call.reject("Failed to fetch groups.", nil, error)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
@objc func getGroupById(_ call: CAPPluginCall) {
|
|
300
|
+
guard let options = call.options["options"] as? JSObject,
|
|
301
|
+
let identifier = options["id"] as? String else {
|
|
302
|
+
call.reject("Missing group identifier.")
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
ensureAuthorized(call) {
|
|
307
|
+
do {
|
|
308
|
+
let groups = try self.contactStore.groups(matching: nil)
|
|
309
|
+
if let group = groups.first(where: { $0.identifier == identifier }) {
|
|
310
|
+
var result: JSObject = [:]
|
|
311
|
+
result["id"] = group.identifier
|
|
312
|
+
result["name"] = group.name
|
|
313
|
+
call.resolve(["group": result])
|
|
314
|
+
} else {
|
|
315
|
+
call.resolve(["group": nil])
|
|
316
|
+
}
|
|
317
|
+
} catch {
|
|
318
|
+
call.reject("Failed to fetch group.", nil, error)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
@objc func createGroup(_ call: CAPPluginCall) {
|
|
324
|
+
guard let options = call.options["options"] as? JSObject,
|
|
325
|
+
let groupData = options["group"] as? JSObject,
|
|
326
|
+
let name = groupData["name"] as? String else {
|
|
327
|
+
call.reject("Missing group name.")
|
|
328
|
+
return
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
ensureAuthorized(call) {
|
|
332
|
+
let newGroup = CNMutableGroup()
|
|
333
|
+
newGroup.name = name
|
|
334
|
+
|
|
335
|
+
let saveRequest = CNSaveRequest()
|
|
336
|
+
saveRequest.add(newGroup, toContainerWithIdentifier: nil)
|
|
337
|
+
|
|
338
|
+
do {
|
|
339
|
+
try self.contactStore.execute(saveRequest)
|
|
340
|
+
call.resolve(["id": newGroup.identifier])
|
|
341
|
+
} catch {
|
|
342
|
+
call.reject("Failed to create group.", nil, error)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
@objc func deleteGroupById(_ call: CAPPluginCall) {
|
|
348
|
+
guard let options = call.options["options"] as? JSObject,
|
|
349
|
+
let identifier = options["id"] as? String else {
|
|
350
|
+
call.reject("Missing group identifier.")
|
|
351
|
+
return
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
ensureAuthorized(call) {
|
|
355
|
+
do {
|
|
356
|
+
let groups = try self.contactStore.groups(matching: nil)
|
|
357
|
+
if let group = groups.first(where: { $0.identifier == identifier }) {
|
|
358
|
+
let mutableGroup = group.mutableCopy() as! CNMutableGroup
|
|
359
|
+
let saveRequest = CNSaveRequest()
|
|
360
|
+
saveRequest.delete(mutableGroup)
|
|
361
|
+
try self.contactStore.execute(saveRequest)
|
|
362
|
+
call.resolve()
|
|
363
|
+
} else {
|
|
364
|
+
call.reject("Group not found.")
|
|
365
|
+
}
|
|
366
|
+
} catch {
|
|
367
|
+
call.reject("Failed to delete group.", nil, error)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// MARK: - UI picker and display operations
|
|
373
|
+
|
|
374
|
+
private var currentPickerCall: CAPPluginCall?
|
|
375
|
+
|
|
376
|
+
@objc func pickContact(_ call: CAPPluginCall) {
|
|
377
|
+
DispatchQueue.main.async {
|
|
378
|
+
self.currentPickerCall = call
|
|
379
|
+
let picker = CNContactPickerViewController()
|
|
380
|
+
picker.delegate = self
|
|
381
|
+
self.bridge?.viewController?.present(picker, animated: true)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
@objc func pickContacts(_ call: CAPPluginCall) {
|
|
386
|
+
DispatchQueue.main.async {
|
|
387
|
+
self.currentPickerCall = call
|
|
388
|
+
let picker = CNContactPickerViewController()
|
|
389
|
+
picker.delegate = self
|
|
390
|
+
self.bridge?.viewController?.present(picker, animated: true)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
@objc func displayContactById(_ call: CAPPluginCall) {
|
|
395
|
+
guard let options = call.options["options"] as? JSObject,
|
|
396
|
+
let identifier = options["id"] as? String else {
|
|
397
|
+
call.reject("Missing contact identifier.")
|
|
398
|
+
return
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
ensureAuthorized(call) {
|
|
402
|
+
do {
|
|
403
|
+
let keysToFetch = self.keysToFetch(for: nil)
|
|
404
|
+
let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
|
|
405
|
+
|
|
406
|
+
DispatchQueue.main.async {
|
|
407
|
+
let viewController = CNContactViewController(for: contact)
|
|
408
|
+
viewController.allowsEditing = false
|
|
409
|
+
let navController = UINavigationController(rootViewController: viewController)
|
|
410
|
+
self.bridge?.viewController?.present(navController, animated: true)
|
|
411
|
+
call.resolve()
|
|
412
|
+
}
|
|
413
|
+
} catch {
|
|
414
|
+
call.reject("Failed to display contact.", nil, error)
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
@objc func displayCreateContact(_ call: CAPPluginCall) {
|
|
420
|
+
DispatchQueue.main.async {
|
|
421
|
+
let newContact = CNMutableContact()
|
|
422
|
+
|
|
423
|
+
if let options = call.options["options"] as? JSObject,
|
|
424
|
+
let contactData = options["contact"] as? JSObject {
|
|
425
|
+
self.populateContact(newContact, from: contactData)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
let viewController = CNContactViewController(forNewContact: newContact)
|
|
429
|
+
viewController.delegate = self
|
|
430
|
+
viewController.contactStore = self.contactStore
|
|
431
|
+
|
|
432
|
+
let navController = UINavigationController(rootViewController: viewController)
|
|
433
|
+
self.currentPickerCall = call
|
|
434
|
+
self.bridge?.viewController?.present(navController, animated: true)
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
@objc func displayUpdateContactById(_ call: CAPPluginCall) {
|
|
439
|
+
guard let options = call.options["options"] as? JSObject,
|
|
440
|
+
let identifier = options["id"] as? String else {
|
|
441
|
+
call.reject("Missing contact identifier.")
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
ensureAuthorized(call) {
|
|
446
|
+
do {
|
|
447
|
+
let keysToFetch = self.keysToFetch(for: nil)
|
|
448
|
+
let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
|
|
449
|
+
|
|
450
|
+
DispatchQueue.main.async {
|
|
451
|
+
let mutableContact = contact.mutableCopy() as! CNMutableContact
|
|
452
|
+
let viewController = CNContactViewController(for: mutableContact)
|
|
453
|
+
viewController.allowsEditing = true
|
|
454
|
+
viewController.contactStore = self.contactStore
|
|
455
|
+
|
|
456
|
+
let navController = UINavigationController(rootViewController: viewController)
|
|
457
|
+
self.bridge?.viewController?.present(navController, animated: true)
|
|
458
|
+
call.resolve()
|
|
459
|
+
}
|
|
460
|
+
} catch {
|
|
461
|
+
call.reject("Failed to display contact for editing.", nil, error)
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
198
465
|
|
|
199
466
|
// MARK: - Helpers
|
|
200
467
|
|
|
@@ -512,4 +779,230 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
512
779
|
return "unknown"
|
|
513
780
|
}
|
|
514
781
|
}
|
|
782
|
+
|
|
783
|
+
private func populateContact(_ contact: CNMutableContact, from data: JSObject) {
|
|
784
|
+
if let givenName = data["givenName"] as? String {
|
|
785
|
+
contact.givenName = givenName
|
|
786
|
+
}
|
|
787
|
+
if let familyName = data["familyName"] as? String {
|
|
788
|
+
contact.familyName = familyName
|
|
789
|
+
}
|
|
790
|
+
if let middleName = data["middleName"] as? String {
|
|
791
|
+
contact.middleName = middleName
|
|
792
|
+
}
|
|
793
|
+
if let namePrefix = data["namePrefix"] as? String {
|
|
794
|
+
contact.namePrefix = namePrefix
|
|
795
|
+
}
|
|
796
|
+
if let nameSuffix = data["nameSuffix"] as? String {
|
|
797
|
+
contact.nameSuffix = nameSuffix
|
|
798
|
+
}
|
|
799
|
+
if let organizationName = data["organizationName"] as? String {
|
|
800
|
+
contact.organizationName = organizationName
|
|
801
|
+
}
|
|
802
|
+
if let jobTitle = data["jobTitle"] as? String {
|
|
803
|
+
contact.jobTitle = jobTitle
|
|
804
|
+
}
|
|
805
|
+
if let note = data["note"] as? String {
|
|
806
|
+
contact.note = note
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if let emailAddresses = data["emailAddresses"] as? [[String: Any]] {
|
|
810
|
+
contact.emailAddresses = emailAddresses.compactMap { emailData in
|
|
811
|
+
guard let value = emailData["value"] as? String else { return nil }
|
|
812
|
+
let label = emailData["type"] as? String ?? "OTHER"
|
|
813
|
+
let cnLabel = reverseMapEmailLabel(label, customLabel: emailData["label"] as? String)
|
|
814
|
+
return CNLabeledValue(label: cnLabel, value: value as NSString)
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if let phoneNumbers = data["phoneNumbers"] as? [[String: Any]] {
|
|
819
|
+
contact.phoneNumbers = phoneNumbers.compactMap { phoneData in
|
|
820
|
+
guard let value = phoneData["value"] as? String else { return nil }
|
|
821
|
+
let label = phoneData["type"] as? String ?? "OTHER"
|
|
822
|
+
let cnLabel = reverseMapPhoneLabel(label, customLabel: phoneData["label"] as? String)
|
|
823
|
+
return CNLabeledValue(label: cnLabel, value: CNPhoneNumber(stringValue: value))
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if let postalAddresses = data["postalAddresses"] as? [[String: Any]] {
|
|
828
|
+
contact.postalAddresses = postalAddresses.compactMap { addressData in
|
|
829
|
+
let postalAddress = CNMutablePostalAddress()
|
|
830
|
+
if let street = addressData["street"] as? String {
|
|
831
|
+
postalAddress.street = street
|
|
832
|
+
}
|
|
833
|
+
if let city = addressData["city"] as? String {
|
|
834
|
+
postalAddress.city = city
|
|
835
|
+
}
|
|
836
|
+
if let state = addressData["state"] as? String {
|
|
837
|
+
postalAddress.state = state
|
|
838
|
+
}
|
|
839
|
+
if let postalCode = addressData["postalCode"] as? String {
|
|
840
|
+
postalAddress.postalCode = postalCode
|
|
841
|
+
}
|
|
842
|
+
if let country = addressData["country"] as? String {
|
|
843
|
+
postalAddress.country = country
|
|
844
|
+
}
|
|
845
|
+
if let isoCountryCode = addressData["isoCountryCode"] as? String {
|
|
846
|
+
postalAddress.isoCountryCode = isoCountryCode
|
|
847
|
+
}
|
|
848
|
+
let label = addressData["type"] as? String ?? "OTHER"
|
|
849
|
+
let cnLabel = reverseMapPostalLabel(label, customLabel: addressData["label"] as? String)
|
|
850
|
+
return CNLabeledValue(label: cnLabel, value: postalAddress)
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
if let urlAddresses = data["urlAddresses"] as? [[String: Any]] {
|
|
855
|
+
contact.urlAddresses = urlAddresses.compactMap { urlData in
|
|
856
|
+
guard let value = urlData["value"] as? String else { return nil }
|
|
857
|
+
let label = urlData["type"] as? String ?? "OTHER"
|
|
858
|
+
let cnLabel = reverseMapURLLabel(label, customLabel: urlData["label"] as? String)
|
|
859
|
+
return CNLabeledValue(label: cnLabel, value: value as NSString)
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if let birthdayData = data["birthday"] as? [String: Any] {
|
|
864
|
+
var dateComponents = DateComponents()
|
|
865
|
+
if let day = birthdayData["day"] as? Int {
|
|
866
|
+
dateComponents.day = day
|
|
867
|
+
}
|
|
868
|
+
if let month = birthdayData["month"] as? Int {
|
|
869
|
+
dateComponents.month = month
|
|
870
|
+
}
|
|
871
|
+
if let year = birthdayData["year"] as? Int {
|
|
872
|
+
dateComponents.year = year
|
|
873
|
+
}
|
|
874
|
+
contact.birthday = dateComponents
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if let photoBase64 = data["photo"] as? String,
|
|
878
|
+
let photoData = Data(base64Encoded: photoBase64) {
|
|
879
|
+
contact.imageData = photoData
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
private func reverseMapEmailLabel(_ type: String, customLabel: String?) -> String {
|
|
884
|
+
switch type {
|
|
885
|
+
case "HOME":
|
|
886
|
+
return CNLabelHome
|
|
887
|
+
case "WORK":
|
|
888
|
+
return CNLabelWork
|
|
889
|
+
case "ICLOUD":
|
|
890
|
+
return CNLabelEmailiCloud
|
|
891
|
+
case "OTHER":
|
|
892
|
+
return CNLabelOther
|
|
893
|
+
case "CUSTOM":
|
|
894
|
+
return customLabel ?? CNLabelOther
|
|
895
|
+
default:
|
|
896
|
+
return CNLabelOther
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
private func reverseMapPhoneLabel(_ type: String, customLabel: String?) -> String {
|
|
901
|
+
switch type {
|
|
902
|
+
case "MOBILE":
|
|
903
|
+
return CNLabelPhoneNumberMobile
|
|
904
|
+
case "IPHONE":
|
|
905
|
+
return CNLabelPhoneNumberiPhone
|
|
906
|
+
case "MAIN":
|
|
907
|
+
return CNLabelPhoneNumberMain
|
|
908
|
+
case "HOME_FAX":
|
|
909
|
+
return CNLabelPhoneNumberHomeFax
|
|
910
|
+
case "WORK_FAX":
|
|
911
|
+
return CNLabelPhoneNumberWorkFax
|
|
912
|
+
case "OTHER_FAX":
|
|
913
|
+
return CNLabelPhoneNumberOtherFax
|
|
914
|
+
case "PAGER":
|
|
915
|
+
return CNLabelPhoneNumberPager
|
|
916
|
+
case "HOME":
|
|
917
|
+
return CNLabelHome
|
|
918
|
+
case "WORK":
|
|
919
|
+
return CNLabelWork
|
|
920
|
+
case "OTHER":
|
|
921
|
+
return CNLabelOther
|
|
922
|
+
case "CUSTOM":
|
|
923
|
+
return customLabel ?? CNLabelOther
|
|
924
|
+
default:
|
|
925
|
+
return CNLabelOther
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
private func reverseMapPostalLabel(_ type: String, customLabel: String?) -> String {
|
|
930
|
+
switch type {
|
|
931
|
+
case "HOME":
|
|
932
|
+
return CNLabelHome
|
|
933
|
+
case "WORK":
|
|
934
|
+
return CNLabelWork
|
|
935
|
+
case "OTHER":
|
|
936
|
+
return CNLabelOther
|
|
937
|
+
case "CUSTOM":
|
|
938
|
+
return customLabel ?? CNLabelOther
|
|
939
|
+
default:
|
|
940
|
+
return CNLabelOther
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
private func reverseMapURLLabel(_ type: String, customLabel: String?) -> String {
|
|
945
|
+
switch type {
|
|
946
|
+
case "HOMEPAGE":
|
|
947
|
+
return CNLabelURLAddressHomePage
|
|
948
|
+
case "HOME":
|
|
949
|
+
return CNLabelHome
|
|
950
|
+
case "WORK":
|
|
951
|
+
return CNLabelWork
|
|
952
|
+
case "OTHER":
|
|
953
|
+
return CNLabelOther
|
|
954
|
+
case "CUSTOM":
|
|
955
|
+
return customLabel ?? CNLabelOther
|
|
956
|
+
default:
|
|
957
|
+
return CNLabelOther
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// MARK: - CNContactPickerDelegate
|
|
963
|
+
|
|
964
|
+
extension CapacitorContactsPlugin: CNContactPickerDelegate {
|
|
965
|
+
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
|
|
966
|
+
guard let call = currentPickerCall else { return }
|
|
967
|
+
currentPickerCall = nil
|
|
968
|
+
|
|
969
|
+
let includeGroupIds = true
|
|
970
|
+
var membership: [String: [String]] = [:]
|
|
971
|
+
let contactIds = contacts.map(\.identifier)
|
|
972
|
+
membership = groupMembershipMap(for: contactIds)
|
|
973
|
+
|
|
974
|
+
let serialized = contacts.map { serialize(contact: $0, fields: nil, membership: membership) }
|
|
975
|
+
call.resolve(["contacts": serialized])
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
|
|
979
|
+
guard let call = currentPickerCall else { return }
|
|
980
|
+
currentPickerCall = nil
|
|
981
|
+
|
|
982
|
+
let membership = groupMembershipMap(for: [contact.identifier])
|
|
983
|
+
let serialized = serialize(contact: contact, fields: nil, membership: membership)
|
|
984
|
+
call.resolve(["contacts": [serialized]])
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
public func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
|
|
988
|
+
guard let call = currentPickerCall else { return }
|
|
989
|
+
currentPickerCall = nil
|
|
990
|
+
call.resolve(["contacts": []])
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// MARK: - CNContactViewControllerDelegate
|
|
995
|
+
|
|
996
|
+
extension CapacitorContactsPlugin: CNContactViewControllerDelegate {
|
|
997
|
+
public func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
|
|
998
|
+
viewController.dismiss(animated: true)
|
|
999
|
+
guard let call = currentPickerCall else { return }
|
|
1000
|
+
currentPickerCall = nil
|
|
1001
|
+
|
|
1002
|
+
if let contact = contact {
|
|
1003
|
+
call.resolve(["id": contact.identifier])
|
|
1004
|
+
} else {
|
|
1005
|
+
call.resolve([:])
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
515
1008
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-contacts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"description": "Work with device contacts using Capacitor APIs",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"CapgoCapacitorContacts.podspec"
|
|
17
17
|
],
|
|
18
18
|
"author": "Cap-go <contact@capgo.app>",
|
|
19
|
-
"license": "
|
|
19
|
+
"license": "MPL-2.0",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
22
|
"url": "git+https://github.com/Cap-go/capacitor-contacts.git"
|
|
@@ -51,27 +51,27 @@
|
|
|
51
51
|
"prepublishOnly": "npm run build"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@capacitor/android": "^
|
|
55
|
-
"@capacitor/cli": "^
|
|
56
|
-
"@capacitor/core": "^
|
|
57
|
-
"@capacitor/docgen": "^0.3.
|
|
58
|
-
"@capacitor/ios": "^
|
|
54
|
+
"@capacitor/android": "^8.0.0",
|
|
55
|
+
"@capacitor/cli": "^8.0.0",
|
|
56
|
+
"@capacitor/core": "^8.0.0",
|
|
57
|
+
"@capacitor/docgen": "^0.3.1",
|
|
58
|
+
"@capacitor/ios": "^8.0.0",
|
|
59
59
|
"@ionic/eslint-config": "^0.4.0",
|
|
60
60
|
"@ionic/prettier-config": "^4.0.0",
|
|
61
61
|
"@ionic/swiftlint-config": "^2.0.0",
|
|
62
|
-
"@types/node": "^
|
|
63
|
-
"eslint": "^8.57.
|
|
62
|
+
"@types/node": "^24.10.1",
|
|
63
|
+
"eslint": "^8.57.1",
|
|
64
64
|
"eslint-plugin-import": "^2.31.0",
|
|
65
65
|
"husky": "^9.1.7",
|
|
66
|
-
"prettier": "^3.
|
|
67
|
-
"prettier-plugin-java": "^2.
|
|
68
|
-
"rimraf": "^6.0
|
|
69
|
-
"rollup": "^4.
|
|
66
|
+
"prettier": "^3.6.2",
|
|
67
|
+
"prettier-plugin-java": "^2.7.7",
|
|
68
|
+
"rimraf": "^6.1.0",
|
|
69
|
+
"rollup": "^4.53.2",
|
|
70
70
|
"swiftlint": "^2.0.0",
|
|
71
|
-
"typescript": "^5.
|
|
71
|
+
"typescript": "^5.9.3"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@capacitor/core": ">=
|
|
74
|
+
"@capacitor/core": ">=8.0.0"
|
|
75
75
|
},
|
|
76
76
|
"eslintConfig": {
|
|
77
77
|
"extends": "@ionic/eslint-config/recommended"
|