@capgo/capacitor-contacts 8.0.16 → 8.0.18
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.
|
@@ -40,7 +40,7 @@ import java.util.Set;
|
|
|
40
40
|
)
|
|
41
41
|
public class CapacitorContactsPlugin extends Plugin {
|
|
42
42
|
|
|
43
|
-
private final String pluginVersion = "8.0.
|
|
43
|
+
private final String pluginVersion = "8.0.18";
|
|
44
44
|
private static final int BATCH_SIZE = 50;
|
|
45
45
|
|
|
46
46
|
// MARK: - Implemented API surface
|
|
@@ -5,7 +5,7 @@ import UIKit
|
|
|
5
5
|
|
|
6
6
|
@objc(CapacitorContactsPlugin)
|
|
7
7
|
public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
8
|
-
private let pluginVersion: String = "8.0.
|
|
8
|
+
private let pluginVersion: String = "8.0.18"
|
|
9
9
|
public let identifier = "CapacitorContactsPlugin"
|
|
10
10
|
public let jsName = "CapacitorContacts"
|
|
11
11
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -368,22 +368,82 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
368
368
|
// MARK: - UI picker and display operations
|
|
369
369
|
|
|
370
370
|
private var currentPickerCall: CAPPluginCall?
|
|
371
|
+
// Holds a strong reference to the picker delegate so it isn't deallocated
|
|
372
|
+
// before the picker dismisses (CNContactPickerViewController delegates are weak).
|
|
373
|
+
private var currentPickerDelegate: NSObject?
|
|
371
374
|
|
|
372
375
|
@objc func pickContact(_ call: CAPPluginCall) {
|
|
373
376
|
DispatchQueue.main.async {
|
|
377
|
+
// Re-entrancy guard: only one picker can be active at a time.
|
|
378
|
+
if self.currentPickerCall != nil {
|
|
379
|
+
call.reject("A contact picker is already open.")
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
// Validate bridge and viewController are available before proceeding.
|
|
383
|
+
guard let viewController = self.bridge?.viewController else {
|
|
384
|
+
call.reject("Unable to present contact picker: no view controller available.")
|
|
385
|
+
return
|
|
386
|
+
}
|
|
374
387
|
self.currentPickerCall = call
|
|
388
|
+
// Use a single-selection delegate so iOS does NOT show checkboxes.
|
|
389
|
+
// CNContactPickerViewController enables multi-select UI only when the
|
|
390
|
+
// delegate implements the plural didSelect(contacts:) method.
|
|
391
|
+
let delegate = SingleContactPickerDelegate()
|
|
392
|
+
delegate.onSelect = { [weak self, call] contact in
|
|
393
|
+
guard let self else { return }
|
|
394
|
+
self.currentPickerCall = nil
|
|
395
|
+
self.currentPickerDelegate = nil
|
|
396
|
+
let membership = self.groupMembershipMap(for: [contact.identifier])
|
|
397
|
+
let serialized = self.serialize(contact: contact, fields: nil, membership: membership)
|
|
398
|
+
call.resolve(["contacts": [serialized]])
|
|
399
|
+
}
|
|
400
|
+
delegate.onCancel = { [weak self, call] in
|
|
401
|
+
guard let self else { return }
|
|
402
|
+
self.currentPickerCall = nil
|
|
403
|
+
self.currentPickerDelegate = nil
|
|
404
|
+
call.resolve(["contacts": []])
|
|
405
|
+
}
|
|
406
|
+
self.currentPickerDelegate = delegate
|
|
375
407
|
let picker = CNContactPickerViewController()
|
|
376
|
-
picker.delegate =
|
|
377
|
-
|
|
408
|
+
picker.delegate = delegate
|
|
409
|
+
viewController.present(picker, animated: true)
|
|
378
410
|
}
|
|
379
411
|
}
|
|
380
412
|
|
|
381
413
|
@objc func pickContacts(_ call: CAPPluginCall) {
|
|
382
414
|
DispatchQueue.main.async {
|
|
415
|
+
// Re-entrancy guard: only one picker can be active at a time.
|
|
416
|
+
if self.currentPickerCall != nil {
|
|
417
|
+
call.reject("A contact picker is already open.")
|
|
418
|
+
return
|
|
419
|
+
}
|
|
420
|
+
// Validate bridge and viewController are available before proceeding.
|
|
421
|
+
guard let viewController = self.bridge?.viewController else {
|
|
422
|
+
call.reject("Unable to present contact picker: no view controller available.")
|
|
423
|
+
return
|
|
424
|
+
}
|
|
383
425
|
self.currentPickerCall = call
|
|
426
|
+
// Use a multi-selection delegate so iOS shows checkboxes as expected.
|
|
427
|
+
let delegate = MultiContactPickerDelegate()
|
|
428
|
+
delegate.onSelect = { [weak self, call] contacts in
|
|
429
|
+
guard let self else { return }
|
|
430
|
+
self.currentPickerCall = nil
|
|
431
|
+
self.currentPickerDelegate = nil
|
|
432
|
+
let contactIds = contacts.map(\.identifier)
|
|
433
|
+
let membership = self.groupMembershipMap(for: contactIds)
|
|
434
|
+
let serialized = contacts.map { self.serialize(contact: $0, fields: nil, membership: membership) }
|
|
435
|
+
call.resolve(["contacts": serialized])
|
|
436
|
+
}
|
|
437
|
+
delegate.onCancel = { [weak self, call] in
|
|
438
|
+
guard let self else { return }
|
|
439
|
+
self.currentPickerCall = nil
|
|
440
|
+
self.currentPickerDelegate = nil
|
|
441
|
+
call.resolve(["contacts": []])
|
|
442
|
+
}
|
|
443
|
+
self.currentPickerDelegate = delegate
|
|
384
444
|
let picker = CNContactPickerViewController()
|
|
385
|
-
picker.delegate =
|
|
386
|
-
|
|
445
|
+
picker.delegate = delegate
|
|
446
|
+
viewController.present(picker, animated: true)
|
|
387
447
|
}
|
|
388
448
|
}
|
|
389
449
|
|
|
@@ -413,19 +473,29 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
413
473
|
|
|
414
474
|
@objc func displayCreateContact(_ call: CAPPluginCall) {
|
|
415
475
|
DispatchQueue.main.async {
|
|
476
|
+
// Re-entrancy guard: only one picker can be active at a time.
|
|
477
|
+
if self.currentPickerCall != nil {
|
|
478
|
+
call.reject("A contact picker is already open.")
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
// Validate bridge and viewController are available before proceeding.
|
|
482
|
+
guard let viewController = self.bridge?.viewController else {
|
|
483
|
+
call.reject("Unable to present contact editor: no view controller available.")
|
|
484
|
+
return
|
|
485
|
+
}
|
|
416
486
|
let newContact = CNMutableContact()
|
|
417
487
|
|
|
418
488
|
if let contactData = call.options["contact"] as? JSObject {
|
|
419
489
|
self.populateContact(newContact, from: contactData)
|
|
420
490
|
}
|
|
421
491
|
|
|
422
|
-
let
|
|
423
|
-
|
|
424
|
-
|
|
492
|
+
let contactViewController = CNContactViewController(forNewContact: newContact)
|
|
493
|
+
contactViewController.delegate = self
|
|
494
|
+
contactViewController.contactStore = self.contactStore
|
|
425
495
|
|
|
426
|
-
let navController = UINavigationController(rootViewController:
|
|
496
|
+
let navController = UINavigationController(rootViewController: contactViewController)
|
|
427
497
|
self.currentPickerCall = call
|
|
428
|
-
|
|
498
|
+
viewController.present(navController, animated: true)
|
|
429
499
|
}
|
|
430
500
|
}
|
|
431
501
|
|
|
@@ -960,35 +1030,47 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
960
1030
|
}
|
|
961
1031
|
}
|
|
962
1032
|
|
|
963
|
-
// MARK: -
|
|
1033
|
+
// MARK: - Single-selection picker delegate (no checkboxes in UI)
|
|
1034
|
+
// Only implementing the singular `didSelect contact:` tells iOS NOT to
|
|
1035
|
+
// enable multi-selection mode on CNContactPickerViewController.
|
|
964
1036
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
currentPickerCall = nil
|
|
1037
|
+
private class SingleContactPickerDelegate: NSObject, CNContactPickerDelegate {
|
|
1038
|
+
var onSelect: ((CNContact) -> Void)?
|
|
1039
|
+
var onCancel: (() -> Void)?
|
|
969
1040
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
membership = groupMembershipMap(for: contactIds)
|
|
1041
|
+
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
|
|
1042
|
+
onSelect?(contact)
|
|
1043
|
+
}
|
|
974
1044
|
|
|
975
|
-
|
|
976
|
-
|
|
1045
|
+
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
|
|
1046
|
+
onCancel?()
|
|
977
1047
|
}
|
|
978
1048
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1049
|
+
deinit {
|
|
1050
|
+
onSelect = nil
|
|
1051
|
+
onCancel = nil
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// MARK: - Multi-selection picker delegate (checkboxes enabled in UI)
|
|
1056
|
+
// Implementing the plural `didSelect contacts:` is what tells iOS to
|
|
1057
|
+
// enable multi-selection mode (checkboxes) on CNContactPickerViewController.
|
|
982
1058
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1059
|
+
private class MultiContactPickerDelegate: NSObject, CNContactPickerDelegate {
|
|
1060
|
+
var onSelect: (([CNContact]) -> Void)?
|
|
1061
|
+
var onCancel: (() -> Void)?
|
|
1062
|
+
|
|
1063
|
+
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
|
|
1064
|
+
onSelect?(contacts)
|
|
986
1065
|
}
|
|
987
1066
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1067
|
+
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
|
|
1068
|
+
onCancel?()
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
deinit {
|
|
1072
|
+
onSelect = nil
|
|
1073
|
+
onCancel = nil
|
|
992
1074
|
}
|
|
993
1075
|
}
|
|
994
1076
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-contacts",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.18",
|
|
4
4
|
"description": "Work with device contacts using Capacitor APIs",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -52,8 +52,7 @@
|
|
|
52
52
|
"prepublishOnly": "bun run build",
|
|
53
53
|
"check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs",
|
|
54
54
|
"example:install": "cd example-app && bun install --frozen-lockfile",
|
|
55
|
-
"example:build": "bun run build && cd example-app && bun install --frozen-lockfile && bun run build"
|
|
56
|
-
"example:capgo:deploy": "bun run example:build && bun scripts/deploy-example-capgo.mjs"
|
|
55
|
+
"example:build": "bun run build && cd example-app && bun install --frozen-lockfile && bun run build"
|
|
57
56
|
},
|
|
58
57
|
"devDependencies": {
|
|
59
58
|
"@capacitor/android": "^8.0.0",
|