@capgo/capacitor-contacts 8.0.3 → 8.0.5
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.
|
@@ -39,7 +39,8 @@ import java.util.Set;
|
|
|
39
39
|
)
|
|
40
40
|
public class CapacitorContactsPlugin extends Plugin {
|
|
41
41
|
|
|
42
|
-
private final String pluginVersion = "8.0.
|
|
42
|
+
private final String pluginVersion = "8.0.5";
|
|
43
|
+
private static final int BATCH_SIZE = 50;
|
|
43
44
|
|
|
44
45
|
// MARK: - Implemented API surface
|
|
45
46
|
|
|
@@ -76,15 +77,15 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
Integer
|
|
81
|
-
|
|
80
|
+
Integer limit = call.getInt("limit", null);
|
|
81
|
+
Integer offset = call.getInt("offset", null);
|
|
82
|
+
Set<String> fields = parseFieldsArray(call);
|
|
82
83
|
|
|
83
84
|
try {
|
|
84
|
-
List<ContactBuilder> builders = fetchContacts(limit, offset);
|
|
85
|
+
List<ContactBuilder> builders = fetchContacts(limit, offset, fields);
|
|
85
86
|
JSArray contacts = new JSArray();
|
|
86
87
|
for (ContactBuilder builder : builders) {
|
|
87
|
-
contacts.put(builder.toJSObject());
|
|
88
|
+
contacts.put(builder.toJSObject(fields));
|
|
88
89
|
}
|
|
89
90
|
JSObject result = new JSObject();
|
|
90
91
|
result.put("contacts", contacts);
|
|
@@ -101,21 +102,22 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
101
102
|
return;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
String identifier = options.getString("id");
|
|
105
|
+
String identifier = call.getString("id");
|
|
106
106
|
if (identifier == null) {
|
|
107
107
|
call.reject("Missing contact identifier.");
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
try {
|
|
112
|
-
|
|
112
|
+
Set<String> fields = parseFieldsArray(call);
|
|
113
|
+
ContactBuilder builder = fetchContact(identifier, fields);
|
|
113
114
|
if (builder == null) {
|
|
114
115
|
call.resolve(new JSObject().put("contact", null));
|
|
115
116
|
return;
|
|
116
117
|
}
|
|
118
|
+
|
|
117
119
|
JSObject result = new JSObject();
|
|
118
|
-
result.put("contact", builder.toJSObject());
|
|
120
|
+
result.put("contact", builder.toJSObject(fields));
|
|
119
121
|
call.resolve(result);
|
|
120
122
|
} catch (Exception ex) {
|
|
121
123
|
call.reject("Failed to fetch contact.", null, ex);
|
|
@@ -215,8 +217,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
215
217
|
return;
|
|
216
218
|
}
|
|
217
219
|
|
|
218
|
-
JSObject
|
|
219
|
-
JSObject contactData = options.getJSObject("contact");
|
|
220
|
+
JSObject contactData = call.getObject("contact");
|
|
220
221
|
if (contactData == null) {
|
|
221
222
|
call.reject("Missing contact data.");
|
|
222
223
|
return;
|
|
@@ -237,9 +238,8 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
237
238
|
return;
|
|
238
239
|
}
|
|
239
240
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
JSObject contactData = options.getJSObject("contact");
|
|
241
|
+
String contactId = call.getString("id");
|
|
242
|
+
JSObject contactData = call.getObject("contact");
|
|
243
243
|
|
|
244
244
|
if (contactId == null || contactData == null) {
|
|
245
245
|
call.reject("Missing contact identifier or data.");
|
|
@@ -261,8 +261,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
261
261
|
return;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
|
|
265
|
-
String contactId = options.getString("id");
|
|
264
|
+
String contactId = call.getString("id");
|
|
266
265
|
|
|
267
266
|
if (contactId == null) {
|
|
268
267
|
call.reject("Missing contact identifier.");
|
|
@@ -327,8 +326,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
327
326
|
return;
|
|
328
327
|
}
|
|
329
328
|
|
|
330
|
-
|
|
331
|
-
String groupId = options.getString("id");
|
|
329
|
+
String groupId = call.getString("id");
|
|
332
330
|
|
|
333
331
|
if (groupId == null) {
|
|
334
332
|
call.reject("Missing group identifier.");
|
|
@@ -368,8 +366,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
368
366
|
return;
|
|
369
367
|
}
|
|
370
368
|
|
|
371
|
-
JSObject
|
|
372
|
-
JSObject groupData = options.getJSObject("group");
|
|
369
|
+
JSObject groupData = call.getObject("group");
|
|
373
370
|
|
|
374
371
|
if (groupData == null) {
|
|
375
372
|
call.reject("Missing group data.");
|
|
@@ -411,8 +408,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
411
408
|
return;
|
|
412
409
|
}
|
|
413
410
|
|
|
414
|
-
|
|
415
|
-
String groupId = options.getString("id");
|
|
411
|
+
String groupId = call.getString("id");
|
|
416
412
|
|
|
417
413
|
if (groupId == null) {
|
|
418
414
|
call.reject("Missing group identifier.");
|
|
@@ -462,8 +458,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
462
458
|
|
|
463
459
|
@PluginMethod
|
|
464
460
|
public void displayContactById(PluginCall call) {
|
|
465
|
-
|
|
466
|
-
String contactId = options.getString("id");
|
|
461
|
+
String contactId = call.getString("id");
|
|
467
462
|
|
|
468
463
|
if (contactId == null) {
|
|
469
464
|
call.reject("Missing contact identifier.");
|
|
@@ -485,12 +480,9 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
485
480
|
currentPickerCall = call;
|
|
486
481
|
Intent intent = new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);
|
|
487
482
|
|
|
488
|
-
JSObject
|
|
489
|
-
if (
|
|
490
|
-
|
|
491
|
-
if (contactData != null) {
|
|
492
|
-
populateIntent(intent, contactData);
|
|
493
|
-
}
|
|
483
|
+
JSObject contactData = call.getObject("contact");
|
|
484
|
+
if (contactData != null) {
|
|
485
|
+
populateIntent(intent, contactData);
|
|
494
486
|
}
|
|
495
487
|
|
|
496
488
|
startActivityForResult(call, intent, CREATE_CONTACT_REQUEST);
|
|
@@ -498,8 +490,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
498
490
|
|
|
499
491
|
@PluginMethod
|
|
500
492
|
public void displayUpdateContactById(PluginCall call) {
|
|
501
|
-
|
|
502
|
-
String contactId = options.getString("id");
|
|
493
|
+
String contactId = call.getString("id");
|
|
503
494
|
|
|
504
495
|
if (contactId == null) {
|
|
505
496
|
call.reject("Missing contact identifier.");
|
|
@@ -542,10 +533,10 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
542
533
|
if (data != null && data.getData() != null) {
|
|
543
534
|
String contactId = getContactIdFromUri(data.getData());
|
|
544
535
|
if (contactId != null) {
|
|
545
|
-
ContactBuilder builder = fetchContact(contactId);
|
|
536
|
+
ContactBuilder builder = fetchContact(contactId, null);
|
|
546
537
|
if (builder != null) {
|
|
547
538
|
JSArray contacts = new JSArray();
|
|
548
|
-
contacts.put(builder.toJSObject());
|
|
539
|
+
contacts.put(builder.toJSObject(null));
|
|
549
540
|
call.resolve(new JSObject().put("contacts", contacts));
|
|
550
541
|
} else {
|
|
551
542
|
call.resolve(new JSObject().put("contacts", new JSArray()));
|
|
@@ -1061,8 +1052,8 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1061
1052
|
|
|
1062
1053
|
// MARK: - Contact access helpers
|
|
1063
1054
|
|
|
1064
|
-
private List<ContactBuilder> fetchContacts(Integer limit, Integer offset) {
|
|
1065
|
-
|
|
1055
|
+
private List<ContactBuilder> fetchContacts(Integer limit, Integer offset, Set<String> fields) {
|
|
1056
|
+
Map<String, ContactBuilder> builderMap = new java.util.LinkedHashMap<>();
|
|
1066
1057
|
ContentResolver resolver = getContext().getContentResolver();
|
|
1067
1058
|
|
|
1068
1059
|
Uri queryUri = ContactsContract.Contacts.CONTENT_URI;
|
|
@@ -1086,163 +1077,189 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1086
1077
|
)
|
|
1087
1078
|
) {
|
|
1088
1079
|
if (cursor == null) {
|
|
1089
|
-
return
|
|
1080
|
+
return new ArrayList<>();
|
|
1090
1081
|
}
|
|
1091
1082
|
|
|
1092
1083
|
while (cursor.moveToNext()) {
|
|
1093
1084
|
String id = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1085
|
+
String displayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY));
|
|
1086
|
+
ContactBuilder builder = new ContactBuilder(id);
|
|
1087
|
+
builder.fullName = displayName;
|
|
1088
|
+
builderMap.put(id, builder);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
if (!builderMap.isEmpty()) {
|
|
1093
|
+
List<String> allIds = new ArrayList<>(builderMap.keySet());
|
|
1094
|
+
|
|
1095
|
+
for (int i = 0; i < allIds.size(); i += BATCH_SIZE) {
|
|
1096
|
+
List<String> batchIds = allIds.subList(i, Math.min(i + BATCH_SIZE, allIds.size()));
|
|
1097
|
+
fillContactData(builderMap, batchIds, fields);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
if (fields == null || fields.contains("account")) {
|
|
1101
|
+
for (int i = 0; i < allIds.size(); i += BATCH_SIZE) {
|
|
1102
|
+
List<String> batchIds = allIds.subList(i, Math.min(i + BATCH_SIZE, allIds.size()));
|
|
1103
|
+
fillAccountInfo(builderMap, batchIds);
|
|
1098
1104
|
}
|
|
1099
1105
|
}
|
|
1100
1106
|
}
|
|
1101
1107
|
|
|
1102
|
-
return
|
|
1108
|
+
return new ArrayList<>(builderMap.values());
|
|
1103
1109
|
}
|
|
1104
1110
|
|
|
1105
|
-
private
|
|
1111
|
+
private void fillContactData(Map<String, ContactBuilder> builderMap, List<String> batchIds, Set<String> fields) {
|
|
1106
1112
|
ContentResolver resolver = getContext().getContentResolver();
|
|
1107
|
-
|
|
1113
|
+
List<String> selectionArgs = new ArrayList<>(batchIds);
|
|
1114
|
+
StringBuilder selection = new StringBuilder();
|
|
1115
|
+
|
|
1116
|
+
selection.append(ContactsContract.Data.CONTACT_ID + " IN (");
|
|
1117
|
+
for (int i = 0; i < batchIds.size(); i++) {
|
|
1118
|
+
if (i > 0) selection.append(",");
|
|
1119
|
+
selection.append("?");
|
|
1120
|
+
}
|
|
1121
|
+
selection.append(")");
|
|
1122
|
+
|
|
1123
|
+
if (fields != null) {
|
|
1124
|
+
List<String> mimeTypes = getMimeTypesForFields(fields);
|
|
1125
|
+
|
|
1126
|
+
if (!mimeTypes.isEmpty()) {
|
|
1127
|
+
StringBuilder mimeSelection = new StringBuilder();
|
|
1128
|
+
mimeSelection.append(" AND " + ContactsContract.Data.MIMETYPE + " IN (");
|
|
1129
|
+
for (int i = 0; i < mimeTypes.size(); i++) {
|
|
1130
|
+
if (i > 0) mimeSelection.append(",");
|
|
1131
|
+
mimeSelection.append("?");
|
|
1132
|
+
selectionArgs.add(mimeTypes.get(i));
|
|
1133
|
+
}
|
|
1134
|
+
mimeSelection.append(")");
|
|
1135
|
+
selection.append(mimeSelection.toString());
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1108
1138
|
|
|
1109
|
-
// Structured name, emails, phones, etc.
|
|
1110
1139
|
try (
|
|
1111
1140
|
Cursor dataCursor = resolver.query(
|
|
1112
1141
|
ContactsContract.Data.CONTENT_URI,
|
|
1113
1142
|
null,
|
|
1114
|
-
|
|
1115
|
-
new String[]
|
|
1143
|
+
selection.toString(),
|
|
1144
|
+
selectionArgs.toArray(new String[0]),
|
|
1116
1145
|
null
|
|
1117
1146
|
)
|
|
1118
1147
|
) {
|
|
1119
|
-
if (dataCursor
|
|
1120
|
-
|
|
1148
|
+
if (dataCursor != null) {
|
|
1149
|
+
while (dataCursor.moveToNext()) {
|
|
1150
|
+
String contactId = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.Data.CONTACT_ID));
|
|
1151
|
+
ContactBuilder builder = builderMap.get(contactId);
|
|
1152
|
+
if (builder != null) {
|
|
1153
|
+
processDataRow(builder, dataCursor);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1121
1156
|
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1122
1159
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.LABEL)),
|
|
1156
|
-
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.IS_PRIMARY)) == 1
|
|
1157
|
-
);
|
|
1158
|
-
break;
|
|
1159
|
-
case ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE:
|
|
1160
|
-
builder.addPostalAddress(
|
|
1161
|
-
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)),
|
|
1162
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.LABEL)),
|
|
1163
|
-
dataCursor.getString(
|
|
1164
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.STREET)
|
|
1165
|
-
),
|
|
1166
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.CITY)),
|
|
1167
|
-
dataCursor.getString(
|
|
1168
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.REGION)
|
|
1169
|
-
),
|
|
1170
|
-
dataCursor.getString(
|
|
1171
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)
|
|
1172
|
-
),
|
|
1173
|
-
dataCursor.getString(
|
|
1174
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)
|
|
1175
|
-
),
|
|
1176
|
-
dataCursor.getString(
|
|
1177
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD)
|
|
1178
|
-
),
|
|
1179
|
-
dataCursor.getInt(
|
|
1180
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.IS_PRIMARY)
|
|
1181
|
-
) ==
|
|
1182
|
-
1
|
|
1183
|
-
);
|
|
1184
|
-
break;
|
|
1185
|
-
case ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE:
|
|
1186
|
-
builder.addUrlAddress(
|
|
1187
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.URL)),
|
|
1188
|
-
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.TYPE)),
|
|
1189
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.LABEL))
|
|
1190
|
-
);
|
|
1191
|
-
break;
|
|
1192
|
-
case ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE:
|
|
1193
|
-
builder.organizationName = dataCursor.getString(
|
|
1194
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.COMPANY)
|
|
1195
|
-
);
|
|
1196
|
-
builder.jobTitle = dataCursor.getString(
|
|
1197
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.TITLE)
|
|
1198
|
-
);
|
|
1199
|
-
break;
|
|
1200
|
-
case ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE:
|
|
1201
|
-
builder.note = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Note.NOTE));
|
|
1202
|
-
break;
|
|
1203
|
-
case ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE:
|
|
1204
|
-
int eventType = dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.TYPE));
|
|
1205
|
-
if (eventType == ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) {
|
|
1206
|
-
builder.setBirthday(
|
|
1207
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.START_DATE))
|
|
1208
|
-
);
|
|
1209
|
-
}
|
|
1210
|
-
break;
|
|
1211
|
-
case ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE:
|
|
1212
|
-
long groupId = dataCursor.getLong(
|
|
1213
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID)
|
|
1160
|
+
private void fillAccountInfo(Map<String, ContactBuilder> builderMap, List<String> batchIds) {
|
|
1161
|
+
ContentResolver resolver = getContext().getContentResolver();
|
|
1162
|
+
List<String> selectionArgs = new ArrayList<>(batchIds);
|
|
1163
|
+
StringBuilder selection = new StringBuilder();
|
|
1164
|
+
|
|
1165
|
+
selection.append(ContactsContract.RawContacts.CONTACT_ID + " IN (");
|
|
1166
|
+
for (int i = 0; i < batchIds.size(); i++) {
|
|
1167
|
+
if (i > 0) selection.append(",");
|
|
1168
|
+
selection.append("?");
|
|
1169
|
+
}
|
|
1170
|
+
selection.append(")");
|
|
1171
|
+
|
|
1172
|
+
try (
|
|
1173
|
+
Cursor rawCursor = resolver.query(
|
|
1174
|
+
ContactsContract.RawContacts.CONTENT_URI,
|
|
1175
|
+
new String[] {
|
|
1176
|
+
ContactsContract.RawContacts.CONTACT_ID,
|
|
1177
|
+
ContactsContract.RawContacts.ACCOUNT_NAME,
|
|
1178
|
+
ContactsContract.RawContacts.ACCOUNT_TYPE
|
|
1179
|
+
},
|
|
1180
|
+
selection.toString(),
|
|
1181
|
+
selectionArgs.toArray(new String[0]),
|
|
1182
|
+
null
|
|
1183
|
+
)
|
|
1184
|
+
) {
|
|
1185
|
+
if (rawCursor != null) {
|
|
1186
|
+
while (rawCursor.moveToNext()) {
|
|
1187
|
+
String contactId = rawCursor.getString(rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.CONTACT_ID));
|
|
1188
|
+
ContactBuilder builder = builderMap.get(contactId);
|
|
1189
|
+
if (builder != null && builder.accountName == null) {
|
|
1190
|
+
builder.accountName = rawCursor.getString(
|
|
1191
|
+
rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_NAME)
|
|
1214
1192
|
);
|
|
1215
|
-
builder.
|
|
1216
|
-
|
|
1217
|
-
case ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE:
|
|
1218
|
-
byte[] photoData = dataCursor.getBlob(
|
|
1219
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Photo.PHOTO)
|
|
1193
|
+
builder.accountType = rawCursor.getString(
|
|
1194
|
+
rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_TYPE)
|
|
1220
1195
|
);
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
private ContactBuilder fetchContact(@NonNull String contactId, Set<String> fields) {
|
|
1203
|
+
ContentResolver resolver = getContext().getContentResolver();
|
|
1204
|
+
ContactBuilder builder = new ContactBuilder(contactId);
|
|
1205
|
+
|
|
1206
|
+
// Build selection based on fields
|
|
1207
|
+
String selection = ContactsContract.Data.CONTACT_ID + " = ?";
|
|
1208
|
+
List<String> selectionArgs = new ArrayList<>();
|
|
1209
|
+
selectionArgs.add(contactId);
|
|
1210
|
+
|
|
1211
|
+
if (fields != null) {
|
|
1212
|
+
List<String> mimeTypes = getMimeTypesForFields(fields);
|
|
1213
|
+
|
|
1214
|
+
if (!mimeTypes.isEmpty()) {
|
|
1215
|
+
StringBuilder mimeSelection = new StringBuilder();
|
|
1216
|
+
mimeSelection.append(" AND " + ContactsContract.Data.MIMETYPE + " IN (");
|
|
1217
|
+
for (int i = 0; i < mimeTypes.size(); i++) {
|
|
1218
|
+
if (i > 0) mimeSelection.append(",");
|
|
1219
|
+
mimeSelection.append("?");
|
|
1220
|
+
selectionArgs.add(mimeTypes.get(i));
|
|
1227
1221
|
}
|
|
1222
|
+
mimeSelection.append(")");
|
|
1223
|
+
selection += mimeSelection.toString();
|
|
1228
1224
|
}
|
|
1229
1225
|
}
|
|
1230
1226
|
|
|
1231
|
-
//
|
|
1227
|
+
// Structured name, emails, phones, etc.
|
|
1232
1228
|
try (
|
|
1233
|
-
Cursor
|
|
1234
|
-
ContactsContract.
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
new String[]
|
|
1229
|
+
Cursor dataCursor = resolver.query(
|
|
1230
|
+
ContactsContract.Data.CONTENT_URI,
|
|
1231
|
+
null,
|
|
1232
|
+
selection,
|
|
1233
|
+
selectionArgs.toArray(new String[0]),
|
|
1238
1234
|
null
|
|
1239
1235
|
)
|
|
1240
1236
|
) {
|
|
1241
|
-
if (
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1237
|
+
if (dataCursor == null) {
|
|
1238
|
+
return null;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
while (dataCursor.moveToNext()) {
|
|
1242
|
+
processDataRow(builder, dataCursor);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// Account information (only if fields allow)
|
|
1247
|
+
if (fields == null || fields.contains("account")) {
|
|
1248
|
+
try (
|
|
1249
|
+
Cursor rawCursor = resolver.query(
|
|
1250
|
+
ContactsContract.RawContacts.CONTENT_URI,
|
|
1251
|
+
new String[] { ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE },
|
|
1252
|
+
ContactsContract.RawContacts.CONTACT_ID + " = ?",
|
|
1253
|
+
new String[] { contactId },
|
|
1254
|
+
null
|
|
1255
|
+
)
|
|
1256
|
+
) {
|
|
1257
|
+
if (rawCursor != null && rawCursor.moveToFirst()) {
|
|
1258
|
+
String accountName = rawCursor.getString(rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_NAME));
|
|
1259
|
+
String accountType = rawCursor.getString(rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_TYPE));
|
|
1260
|
+
builder.accountName = accountName;
|
|
1261
|
+
builder.accountType = accountType;
|
|
1262
|
+
}
|
|
1246
1263
|
}
|
|
1247
1264
|
}
|
|
1248
1265
|
|
|
@@ -1253,6 +1270,98 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1253
1270
|
return builder;
|
|
1254
1271
|
}
|
|
1255
1272
|
|
|
1273
|
+
private void processDataRow(ContactBuilder builder, Cursor dataCursor) {
|
|
1274
|
+
String mimeType = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE));
|
|
1275
|
+
switch (mimeType) {
|
|
1276
|
+
case ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
|
|
1277
|
+
builder.givenName = dataCursor.getString(
|
|
1278
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)
|
|
1279
|
+
);
|
|
1280
|
+
builder.familyName = dataCursor.getString(
|
|
1281
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME)
|
|
1282
|
+
);
|
|
1283
|
+
builder.middleName = dataCursor.getString(
|
|
1284
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME)
|
|
1285
|
+
);
|
|
1286
|
+
builder.namePrefix = dataCursor.getString(
|
|
1287
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.PREFIX)
|
|
1288
|
+
);
|
|
1289
|
+
builder.nameSuffix = dataCursor.getString(
|
|
1290
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.SUFFIX)
|
|
1291
|
+
);
|
|
1292
|
+
break;
|
|
1293
|
+
case ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE:
|
|
1294
|
+
builder.addEmail(
|
|
1295
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.ADDRESS)),
|
|
1296
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.TYPE)),
|
|
1297
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.LABEL)),
|
|
1298
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.IS_PRIMARY)) == 1
|
|
1299
|
+
);
|
|
1300
|
+
break;
|
|
1301
|
+
case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
|
|
1302
|
+
builder.addPhone(
|
|
1303
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)),
|
|
1304
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.TYPE)),
|
|
1305
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.LABEL)),
|
|
1306
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.IS_PRIMARY)) == 1
|
|
1307
|
+
);
|
|
1308
|
+
break;
|
|
1309
|
+
case ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE:
|
|
1310
|
+
builder.addPostalAddress(
|
|
1311
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)),
|
|
1312
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.LABEL)),
|
|
1313
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.STREET)),
|
|
1314
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.CITY)),
|
|
1315
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.REGION)),
|
|
1316
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)),
|
|
1317
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)),
|
|
1318
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD)),
|
|
1319
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.IS_PRIMARY)) == 1
|
|
1320
|
+
);
|
|
1321
|
+
break;
|
|
1322
|
+
case ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE:
|
|
1323
|
+
builder.addUrlAddress(
|
|
1324
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.URL)),
|
|
1325
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.TYPE)),
|
|
1326
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.LABEL))
|
|
1327
|
+
);
|
|
1328
|
+
break;
|
|
1329
|
+
case ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE:
|
|
1330
|
+
builder.organizationName = dataCursor.getString(
|
|
1331
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.COMPANY)
|
|
1332
|
+
);
|
|
1333
|
+
builder.jobTitle = dataCursor.getString(
|
|
1334
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.TITLE)
|
|
1335
|
+
);
|
|
1336
|
+
break;
|
|
1337
|
+
case ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE:
|
|
1338
|
+
builder.note = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Note.NOTE));
|
|
1339
|
+
break;
|
|
1340
|
+
case ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE:
|
|
1341
|
+
int eventType = dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.TYPE));
|
|
1342
|
+
if (eventType == ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) {
|
|
1343
|
+
builder.setBirthday(
|
|
1344
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.START_DATE))
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
break;
|
|
1348
|
+
case ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE:
|
|
1349
|
+
long groupId = dataCursor.getLong(
|
|
1350
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID)
|
|
1351
|
+
);
|
|
1352
|
+
builder.addGroupId(String.valueOf(groupId));
|
|
1353
|
+
break;
|
|
1354
|
+
case ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE:
|
|
1355
|
+
byte[] photoData = dataCursor.getBlob(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Photo.PHOTO));
|
|
1356
|
+
if (photoData != null) {
|
|
1357
|
+
builder.photoBase64 = Base64.encodeToString(photoData, Base64.NO_WRAP);
|
|
1358
|
+
}
|
|
1359
|
+
break;
|
|
1360
|
+
default:
|
|
1361
|
+
break;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1256
1365
|
private String resolveDisplayName(String contactId) {
|
|
1257
1366
|
ContentResolver resolver = getContext().getContentResolver();
|
|
1258
1367
|
try (
|
|
@@ -1271,6 +1380,65 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1271
1380
|
return null;
|
|
1272
1381
|
}
|
|
1273
1382
|
|
|
1383
|
+
private Set<String> parseFieldsArray(PluginCall call) {
|
|
1384
|
+
JSArray fieldsArray = call.getArray("fields", null);
|
|
1385
|
+
if (fieldsArray == null) {
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
Set<String> fields = new HashSet<>();
|
|
1389
|
+
try {
|
|
1390
|
+
List<Object> list = fieldsArray.toList();
|
|
1391
|
+
for (Object item : list) {
|
|
1392
|
+
if (item instanceof String) {
|
|
1393
|
+
fields.add((String) item);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
} catch (Exception e) {
|
|
1397
|
+
// Return empty set if parsing fails
|
|
1398
|
+
}
|
|
1399
|
+
return fields.isEmpty() ? null : fields;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
private List<String> getMimeTypesForFields(Set<String> fields) {
|
|
1403
|
+
List<String> mimeTypes = new ArrayList<>();
|
|
1404
|
+
// Always fetch structured name for basic display
|
|
1405
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
|
|
1406
|
+
|
|
1407
|
+
if (fields == null) {
|
|
1408
|
+
return mimeTypes;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
if (fields.contains("organizationName") || fields.contains("jobTitle")) {
|
|
1412
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
|
|
1413
|
+
}
|
|
1414
|
+
if (fields.contains("emailAddresses")) {
|
|
1415
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
|
|
1416
|
+
}
|
|
1417
|
+
if (fields.contains("phoneNumbers")) {
|
|
1418
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
|
|
1419
|
+
}
|
|
1420
|
+
if (fields.contains("postalAddresses")) {
|
|
1421
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
|
|
1422
|
+
}
|
|
1423
|
+
if (fields.contains("urlAddresses")) {
|
|
1424
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
|
|
1425
|
+
}
|
|
1426
|
+
if (fields.contains("note")) {
|
|
1427
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
|
|
1428
|
+
}
|
|
1429
|
+
if (fields.contains("birthday")) {
|
|
1430
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
|
|
1431
|
+
}
|
|
1432
|
+
if (fields.contains("groupIds")) {
|
|
1433
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
|
|
1434
|
+
}
|
|
1435
|
+
if (fields.contains("photo")) {
|
|
1436
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
return mimeTypes;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1274
1442
|
// MARK: - Contact builder helper
|
|
1275
1443
|
|
|
1276
1444
|
private static class ContactBuilder {
|
|
@@ -1381,36 +1549,50 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1381
1549
|
if (startDate == null || startDate.isEmpty()) {
|
|
1382
1550
|
return;
|
|
1383
1551
|
}
|
|
1384
|
-
|
|
1385
|
-
if (
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1552
|
+
// Handle yearless dates: --MM-DD
|
|
1553
|
+
if (startDate.startsWith("--")) {
|
|
1554
|
+
String[] parts = startDate.substring(2).split("-");
|
|
1555
|
+
if (parts.length >= 2) {
|
|
1556
|
+
birthdayMonth = safeParse(parts[0]);
|
|
1557
|
+
birthdayDay = safeParse(parts[1]);
|
|
1558
|
+
}
|
|
1559
|
+
} else {
|
|
1560
|
+
// Standard format: YYYY-MM-DD
|
|
1561
|
+
String[] parts = startDate.split("-");
|
|
1562
|
+
if (parts.length >= 3) {
|
|
1563
|
+
birthdayYear = safeParse(parts[0]);
|
|
1564
|
+
birthdayMonth = safeParse(parts[1]);
|
|
1565
|
+
birthdayDay = safeParse(parts[2]);
|
|
1566
|
+
}
|
|
1391
1567
|
}
|
|
1392
1568
|
}
|
|
1393
1569
|
|
|
1394
1570
|
JSObject toJSObject() {
|
|
1571
|
+
return toJSObject(null);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
JSObject toJSObject(Set<String> fields) {
|
|
1575
|
+
boolean includeAll = fields == null;
|
|
1395
1576
|
JSObject contact = new JSObject();
|
|
1396
|
-
|
|
1397
|
-
contact.put("
|
|
1398
|
-
contact.put("
|
|
1399
|
-
contact.put("
|
|
1400
|
-
contact.put("
|
|
1401
|
-
contact.put("
|
|
1402
|
-
contact.put("
|
|
1403
|
-
contact.put("
|
|
1404
|
-
contact.put("
|
|
1405
|
-
contact.put("
|
|
1406
|
-
contact.put("
|
|
1407
|
-
contact.put("
|
|
1408
|
-
contact.put("
|
|
1409
|
-
contact.put("
|
|
1410
|
-
contact.put("
|
|
1411
|
-
contact.put("
|
|
1412
|
-
|
|
1413
|
-
|
|
1577
|
+
|
|
1578
|
+
if (includeAll || fields.contains("id")) contact.put("id", id);
|
|
1579
|
+
if (includeAll || fields.contains("givenName")) contact.put("givenName", givenName);
|
|
1580
|
+
if (includeAll || fields.contains("familyName")) contact.put("familyName", familyName);
|
|
1581
|
+
if (includeAll || fields.contains("middleName")) contact.put("middleName", middleName);
|
|
1582
|
+
if (includeAll || fields.contains("namePrefix")) contact.put("namePrefix", namePrefix);
|
|
1583
|
+
if (includeAll || fields.contains("nameSuffix")) contact.put("nameSuffix", nameSuffix);
|
|
1584
|
+
if (includeAll || fields.contains("organizationName")) contact.put("organizationName", organizationName);
|
|
1585
|
+
if (includeAll || fields.contains("jobTitle")) contact.put("jobTitle", jobTitle);
|
|
1586
|
+
if (includeAll || fields.contains("note")) contact.put("note", note);
|
|
1587
|
+
if (includeAll || fields.contains("fullName")) contact.put("fullName", fullName);
|
|
1588
|
+
if (includeAll || fields.contains("photo")) contact.put("photo", photoBase64);
|
|
1589
|
+
if (includeAll || fields.contains("groupIds")) contact.put("groupIds", groupIds);
|
|
1590
|
+
if (includeAll || fields.contains("emailAddresses")) contact.put("emailAddresses", emailAddresses);
|
|
1591
|
+
if (includeAll || fields.contains("phoneNumbers")) contact.put("phoneNumbers", phoneNumbers);
|
|
1592
|
+
if (includeAll || fields.contains("postalAddresses")) contact.put("postalAddresses", postalAddresses);
|
|
1593
|
+
if (includeAll || fields.contains("urlAddresses")) contact.put("urlAddresses", urlAddresses);
|
|
1594
|
+
|
|
1595
|
+
if ((includeAll || fields.contains("birthday")) && (birthdayYear != null || birthdayMonth != null || birthdayDay != null)) {
|
|
1414
1596
|
JSObject birthday = new JSObject();
|
|
1415
1597
|
if (birthdayDay != null) birthday.put("day", birthdayDay);
|
|
1416
1598
|
if (birthdayMonth != null) birthday.put("month", birthdayMonth);
|
|
@@ -1418,13 +1600,15 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1418
1600
|
contact.put("birthday", birthday);
|
|
1419
1601
|
}
|
|
1420
1602
|
|
|
1421
|
-
if (
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1603
|
+
if (includeAll || fields.contains("account")) {
|
|
1604
|
+
if (accountName != null || accountType != null) {
|
|
1605
|
+
JSObject account = new JSObject();
|
|
1606
|
+
account.put("name", accountName);
|
|
1607
|
+
account.put("type", accountType);
|
|
1608
|
+
contact.put("account", account);
|
|
1609
|
+
} else {
|
|
1610
|
+
contact.put("account", null);
|
|
1611
|
+
}
|
|
1428
1612
|
}
|
|
1429
1613
|
|
|
1430
1614
|
return contact;
|
|
@@ -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.5"
|
|
9
9
|
public let identifier = "CapacitorContactsPlugin"
|
|
10
10
|
public let jsName = "CapacitorContacts"
|
|
11
11
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -54,10 +54,9 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
54
54
|
|
|
55
55
|
@objc func getContacts(_ call: CAPPluginCall) {
|
|
56
56
|
ensureAuthorized(call) {
|
|
57
|
-
let
|
|
58
|
-
let
|
|
59
|
-
let
|
|
60
|
-
let offset = options["offset"] as? Int ?? 0
|
|
57
|
+
let fields = (call.options["fields"] as? [String]).map { Set($0) }
|
|
58
|
+
let limit = call.options["limit"] as? Int
|
|
59
|
+
let offset = call.options["offset"] as? Int ?? 0
|
|
61
60
|
|
|
62
61
|
let keysToFetch = self.keysToFetch(for: fields)
|
|
63
62
|
let request = CNContactFetchRequest(keysToFetch: keysToFetch)
|
|
@@ -95,13 +94,13 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
@objc func getContactById(_ call: CAPPluginCall) {
|
|
98
|
-
guard let
|
|
97
|
+
guard let identifier = call.options["id"] as? String else {
|
|
99
98
|
call.reject("Missing contact identifier.")
|
|
100
99
|
return
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
ensureAuthorized(call) {
|
|
104
|
-
let fields = (options["fields"] as? [String]).map { Set($0) }
|
|
103
|
+
let fields = (call.options["fields"] as? [String]).map { Set($0) }
|
|
105
104
|
let keysToFetch = self.keysToFetch(for: fields)
|
|
106
105
|
|
|
107
106
|
do {
|
|
@@ -164,7 +163,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
@objc override public func requestPermissions(_ call: CAPPluginCall) {
|
|
167
|
-
let requested = (call.options["
|
|
166
|
+
let requested = (call.options["permissions"] as? [String]) ?? ["readContacts", "writeContacts"]
|
|
168
167
|
let needsRequest = requested.contains { _ in mapAuthorizationStatus(CNContactStore.authorizationStatus(for: .contacts)) != "granted" }
|
|
169
168
|
|
|
170
169
|
if !needsRequest {
|
|
@@ -187,8 +186,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
187
186
|
// MARK: - Write operations
|
|
188
187
|
|
|
189
188
|
@objc func createContact(_ call: CAPPluginCall) {
|
|
190
|
-
guard let
|
|
191
|
-
let contactData = options["contact"] as? JSObject else {
|
|
189
|
+
guard let contactData = call.options["contact"] as? JSObject else {
|
|
192
190
|
call.reject("Missing contact data.")
|
|
193
191
|
return
|
|
194
192
|
}
|
|
@@ -210,16 +208,15 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
210
208
|
}
|
|
211
209
|
|
|
212
210
|
@objc func updateContactById(_ call: CAPPluginCall) {
|
|
213
|
-
guard let
|
|
214
|
-
let
|
|
215
|
-
let contactData = options["contact"] as? JSObject else {
|
|
211
|
+
guard let identifier = call.options["id"] as? String,
|
|
212
|
+
let contactData = call.options["contact"] as? JSObject else {
|
|
216
213
|
call.reject("Missing contact identifier or data.")
|
|
217
214
|
return
|
|
218
215
|
}
|
|
219
216
|
|
|
220
217
|
ensureAuthorized(call) {
|
|
221
218
|
do {
|
|
222
|
-
|
|
219
|
+
var keysToFetch: [CNKeyDescriptor] = [
|
|
223
220
|
CNContactIdentifierKey as CNKeyDescriptor,
|
|
224
221
|
CNContactGivenNameKey as CNKeyDescriptor,
|
|
225
222
|
CNContactFamilyNameKey as CNKeyDescriptor,
|
|
@@ -233,10 +230,13 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
233
230
|
CNContactPostalAddressesKey as CNKeyDescriptor,
|
|
234
231
|
CNContactUrlAddressesKey as CNKeyDescriptor,
|
|
235
232
|
CNContactBirthdayKey as CNKeyDescriptor,
|
|
236
|
-
CNContactNoteKey as CNKeyDescriptor,
|
|
237
233
|
CNContactImageDataKey as CNKeyDescriptor
|
|
238
234
|
]
|
|
239
235
|
|
|
236
|
+
if contactData["note"] != nil {
|
|
237
|
+
keysToFetch.append(CNContactNoteKey as CNKeyDescriptor)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
240
|
let contact = try self.contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keysToFetch)
|
|
241
241
|
let mutableContact = contact.mutableCopy() as! CNMutableContact
|
|
242
242
|
|
|
@@ -254,8 +254,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
@objc func deleteContactById(_ call: CAPPluginCall) {
|
|
257
|
-
guard let
|
|
258
|
-
let identifier = options["id"] as? String else {
|
|
257
|
+
guard let identifier = call.options["id"] as? String else {
|
|
259
258
|
call.reject("Missing contact identifier.")
|
|
260
259
|
return
|
|
261
260
|
}
|
|
@@ -297,8 +296,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
297
296
|
}
|
|
298
297
|
|
|
299
298
|
@objc func getGroupById(_ call: CAPPluginCall) {
|
|
300
|
-
guard let
|
|
301
|
-
let identifier = options["id"] as? String else {
|
|
299
|
+
guard let identifier = call.options["id"] as? String else {
|
|
302
300
|
call.reject("Missing group identifier.")
|
|
303
301
|
return
|
|
304
302
|
}
|
|
@@ -321,8 +319,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
321
319
|
}
|
|
322
320
|
|
|
323
321
|
@objc func createGroup(_ call: CAPPluginCall) {
|
|
324
|
-
guard let
|
|
325
|
-
let groupData = options["group"] as? JSObject,
|
|
322
|
+
guard let groupData = call.options["group"] as? JSObject,
|
|
326
323
|
let name = groupData["name"] as? String else {
|
|
327
324
|
call.reject("Missing group name.")
|
|
328
325
|
return
|
|
@@ -345,8 +342,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
345
342
|
}
|
|
346
343
|
|
|
347
344
|
@objc func deleteGroupById(_ call: CAPPluginCall) {
|
|
348
|
-
guard let
|
|
349
|
-
let identifier = options["id"] as? String else {
|
|
345
|
+
guard let identifier = call.options["id"] as? String else {
|
|
350
346
|
call.reject("Missing group identifier.")
|
|
351
347
|
return
|
|
352
348
|
}
|
|
@@ -392,8 +388,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
392
388
|
}
|
|
393
389
|
|
|
394
390
|
@objc func displayContactById(_ call: CAPPluginCall) {
|
|
395
|
-
guard let
|
|
396
|
-
let identifier = options["id"] as? String else {
|
|
391
|
+
guard let identifier = call.options["id"] as? String else {
|
|
397
392
|
call.reject("Missing contact identifier.")
|
|
398
393
|
return
|
|
399
394
|
}
|
|
@@ -420,8 +415,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
420
415
|
DispatchQueue.main.async {
|
|
421
416
|
let newContact = CNMutableContact()
|
|
422
417
|
|
|
423
|
-
if let
|
|
424
|
-
let contactData = options["contact"] as? JSObject {
|
|
418
|
+
if let contactData = call.options["contact"] as? JSObject {
|
|
425
419
|
self.populateContact(newContact, from: contactData)
|
|
426
420
|
}
|
|
427
421
|
|
|
@@ -436,8 +430,7 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
436
430
|
}
|
|
437
431
|
|
|
438
432
|
@objc func displayUpdateContactById(_ call: CAPPluginCall) {
|
|
439
|
-
guard let
|
|
440
|
-
let identifier = options["id"] as? String else {
|
|
433
|
+
guard let identifier = call.options["id"] as? String else {
|
|
441
434
|
call.reject("Missing contact identifier.")
|
|
442
435
|
return
|
|
443
436
|
}
|
|
@@ -515,29 +508,35 @@ public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
515
508
|
|
|
516
509
|
private func keysToFetch(for fields: Set<String>?) -> [CNKeyDescriptor] {
|
|
517
510
|
var keys: [CNKeyDescriptor] = [
|
|
518
|
-
CNContactIdentifierKey as CNKeyDescriptor
|
|
519
|
-
CNContactGivenNameKey as CNKeyDescriptor,
|
|
520
|
-
CNContactFamilyNameKey as CNKeyDescriptor,
|
|
521
|
-
CNContactMiddleNameKey as CNKeyDescriptor,
|
|
522
|
-
CNContactNamePrefixKey as CNKeyDescriptor,
|
|
523
|
-
CNContactNameSuffixKey as CNKeyDescriptor,
|
|
524
|
-
CNContactOrganizationNameKey as CNKeyDescriptor,
|
|
525
|
-
CNContactJobTitleKey as CNKeyDescriptor,
|
|
526
|
-
CNContactEmailAddressesKey as CNKeyDescriptor,
|
|
527
|
-
CNContactPhoneNumbersKey as CNKeyDescriptor,
|
|
528
|
-
CNContactPostalAddressesKey as CNKeyDescriptor,
|
|
529
|
-
CNContactUrlAddressesKey as CNKeyDescriptor,
|
|
530
|
-
CNContactBirthdayKey as CNKeyDescriptor,
|
|
531
|
-
CNContactNoteKey as CNKeyDescriptor,
|
|
532
|
-
CNContactImageDataAvailableKey as CNKeyDescriptor,
|
|
533
|
-
CNContactImageDataKey as CNKeyDescriptor
|
|
511
|
+
CNContactIdentifierKey as CNKeyDescriptor
|
|
534
512
|
]
|
|
535
513
|
|
|
514
|
+
let shouldFetchAll = fields == nil
|
|
515
|
+
|
|
516
|
+
if shouldFetchAll || fields!.contains("givenName") { keys.append(CNContactGivenNameKey as CNKeyDescriptor) }
|
|
517
|
+
if shouldFetchAll || fields!.contains("familyName") { keys.append(CNContactFamilyNameKey as CNKeyDescriptor) }
|
|
518
|
+
if shouldFetchAll || fields!.contains("middleName") { keys.append(CNContactMiddleNameKey as CNKeyDescriptor) }
|
|
519
|
+
if shouldFetchAll || fields!.contains("namePrefix") { keys.append(CNContactNamePrefixKey as CNKeyDescriptor) }
|
|
520
|
+
if shouldFetchAll || fields!.contains("nameSuffix") { keys.append(CNContactNameSuffixKey as CNKeyDescriptor) }
|
|
521
|
+
if shouldFetchAll || fields!.contains("organizationName") { keys.append(CNContactOrganizationNameKey as CNKeyDescriptor) }
|
|
522
|
+
if shouldFetchAll || fields!.contains("jobTitle") { keys.append(CNContactJobTitleKey as CNKeyDescriptor) }
|
|
523
|
+
if shouldFetchAll || fields!.contains("emailAddresses") { keys.append(CNContactEmailAddressesKey as CNKeyDescriptor) }
|
|
524
|
+
if shouldFetchAll || fields!.contains("phoneNumbers") { keys.append(CNContactPhoneNumbersKey as CNKeyDescriptor) }
|
|
525
|
+
if shouldFetchAll || fields!.contains("postalAddresses") { keys.append(CNContactPostalAddressesKey as CNKeyDescriptor) }
|
|
526
|
+
if shouldFetchAll || fields!.contains("urlAddresses") { keys.append(CNContactUrlAddressesKey as CNKeyDescriptor) }
|
|
527
|
+
if shouldFetchAll || fields!.contains("birthday") { keys.append(CNContactBirthdayKey as CNKeyDescriptor) }
|
|
528
|
+
if shouldFetchAll || fields!.contains("note") { keys.append(CNContactNoteKey as CNKeyDescriptor) }
|
|
529
|
+
|
|
530
|
+
if shouldFetchAll || fields!.contains("photo") {
|
|
531
|
+
keys.append(CNContactImageDataAvailableKey as CNKeyDescriptor)
|
|
532
|
+
keys.append(CNContactImageDataKey as CNKeyDescriptor)
|
|
533
|
+
}
|
|
534
|
+
|
|
536
535
|
if let fields, fields.contains("groupIds") {
|
|
537
536
|
// No additional keys required, but this preserves the behaviour if custom keys are needed later.
|
|
538
537
|
}
|
|
539
538
|
|
|
540
|
-
if
|
|
539
|
+
if shouldFetchAll || fields!.contains("fullName") {
|
|
541
540
|
keys.append(CNContactFormatter.descriptorForRequiredKeys(for: .fullName))
|
|
542
541
|
}
|
|
543
542
|
|