react-native-contacts 7.0.7 → 8.0.0

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.
@@ -3,6 +3,11 @@
3
3
  #import "RCTContacts.h"
4
4
  #import <AssetsLibrary/AssetsLibrary.h>
5
5
  #import <React/RCTLog.h>
6
+ #import <Photos/Photos.h>
7
+
8
+ // #ifdef RCT_NEW_ARCH_ENABLED
9
+ // #import "RNContactsSpec.h"
10
+ // #endif
6
11
 
7
12
  @implementation RCTContacts {
8
13
  CNContactStore * contactStore;
@@ -43,6 +48,13 @@ RCT_EXPORT_MODULE();
43
48
  };
44
49
  }
45
50
 
51
+ RCT_REMAP_METHOD(getAll, withResolver:(RCTPromiseResolveBlock) resolve
52
+ withRejecter:(RCTPromiseRejectBlock) reject)
53
+ {
54
+ [self getAll:resolve reject:reject];
55
+ }
56
+
57
+
46
58
  RCT_EXPORT_METHOD(checkPermission:(RCTPromiseResolveBlock) resolve
47
59
  rejecter:(RCTPromiseRejectBlock) __unused reject)
48
60
  {
@@ -533,7 +545,7 @@ RCT_EXPORT_METHOD(getCount:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromise
533
545
 
534
546
  - (NSString *)getPathForDirectory:(int)directory
535
547
  {
536
- NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
548
+ NSArray *paths = NSSearchPathForDirectoriesInDomains((NSSearchPathDirectory)directory, NSUserDomainMask, YES);
537
549
  return [paths firstObject];
538
550
  }
539
551
 
@@ -597,7 +609,7 @@ RCT_EXPORT_METHOD(getContactById:(nonnull NSString *)recordID resolver:(RCTPromi
597
609
  }
598
610
  }
599
611
 
600
- -(NSString *) getContact:(NSString *)recordID
612
+ -(NSDictionary *) getContact:(NSString *)recordID
601
613
  addressBook:(CNContactStore*)addressBook
602
614
  withThumbnails:(BOOL) withThumbnails
603
615
  {
@@ -623,7 +635,7 @@ RCT_EXPORT_METHOD(getContactById:(nonnull NSString *)recordID resolver:(RCTPromi
623
635
  CNContact* contact = [addressBook unifiedContactWithIdentifier:recordID keysToFetch:keysToFetch error:&contactError];
624
636
 
625
637
  if(!contact)
626
- return [NSNull null];
638
+ return nil;
627
639
 
628
640
  return [self contactToDictionary: contact withThumbnails:withThumbnails];
629
641
  }
@@ -720,7 +732,8 @@ RCT_EXPORT_METHOD(openExistingContact:(NSDictionary *)contactData resolver:(RCTP
720
732
  currentViewController = currentViewController.presentedViewController;
721
733
  }
722
734
 
723
- UIActivityIndicatorViewStyle *activityIndicatorStyle;
735
+ UIActivityIndicatorViewStyle activityIndicatorStyle;
736
+ UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
724
737
  UIColor *activityIndicatorBackgroundColor;
725
738
  if (@available(iOS 13, *)) {
726
739
  activityIndicatorStyle = UIActivityIndicatorViewStyleMedium;
@@ -792,7 +805,7 @@ RCT_EXPORT_METHOD(viewExistingContact:(NSDictionary *)contactData resolver:(RCTP
792
805
  CNContactViewController *contactViewController = [CNContactViewController viewControllerForContact:contact];
793
806
 
794
807
  // Add a cancel button which will close the view
795
- contactViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backTitle == nil ? @"Cancel" : backTitle style:UIBarButtonSystemItemCancel target:self action:@selector(cancelContactForm)];
808
+ contactViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backTitle == nil ? @"Cancel" : backTitle style:UIBarButtonItemStylePlain target:self action:@selector(cancelContactForm)];
796
809
  contactViewController.delegate = self;
797
810
 
798
811
 
@@ -881,7 +894,7 @@ RCT_EXPORT_METHOD(editExistingContact:(NSDictionary *)contactData resolver:(RCTP
881
894
  //[controller presentViewController:alert animated:YES completion:nil];
882
895
 
883
896
  // Add a cancel button which will close the view
884
- controller.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonSystemItemCancel target:self action:@selector(doneContactForm)];
897
+ controller.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(doneContactForm)];
885
898
 
886
899
  controller.delegate = self;
887
900
  controller.allowsEditing = true;
@@ -1160,38 +1173,33 @@ RCT_EXPORT_METHOD(updateContact:(NSDictionary *)contactData resolver:(RCTPromise
1160
1173
 
1161
1174
  enum { WDASSETURL_PENDINGREADS = 1, WDASSETURL_ALLFINISHED = 0};
1162
1175
 
1163
- + (NSData*) loadImageAsset:(NSURL*)assetURL {
1164
- //thanks to http://www.codercowboy.com/code-synchronous-alassetlibrary-asset-existence-check/
1165
-
1166
- __block NSData *data = nil;
1167
- __block NSConditionLock * albumReadLock = [[NSConditionLock alloc] initWithCondition:WDASSETURL_PENDINGREADS];
1168
- //this *MUST* execute on a background thread, ALAssetLibrary tries to use the main thread and will hang if you're on the main thread.
1169
- dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
1170
- ALAssetsLibrary * assetLibrary = [[ALAssetsLibrary alloc] init];
1171
- [assetLibrary assetForURL:assetURL
1172
- resultBlock:^(ALAsset *asset) {
1173
- ALAssetRepresentation *rep = [asset defaultRepresentation];
1174
-
1175
- Byte *buffer = (Byte*)malloc(rep.size);
1176
- NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
1177
- data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
1178
-
1179
- [albumReadLock lock];
1180
- [albumReadLock unlockWithCondition:WDASSETURL_ALLFINISHED];
1181
- } failureBlock:^(NSError *error) {
1182
- RCTLog(@"asset error: %@", [error localizedDescription]);
1183
-
1184
- [albumReadLock lock];
1185
- [albumReadLock unlockWithCondition:WDASSETURL_ALLFINISHED];
1186
- }];
1176
+ + (NSData *)loadImageAsset:(NSURL *)assetURL {
1177
+ __block NSData *imageData = nil;
1178
+
1179
+ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
1180
+
1181
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
1182
+ PHFetchResult<PHAsset *> *result = [PHAsset fetchAssetsWithALAssetURLs:@[assetURL] options:nil];
1183
+ if (result.count > 0) {
1184
+ PHAsset *asset = result.firstObject;
1185
+ PHImageManager *imageManager = [PHImageManager defaultManager];
1186
+ PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
1187
+ options.synchronous = YES; // Load image synchronously
1188
+
1189
+ [imageManager requestImageDataForAsset:asset
1190
+ options:options
1191
+ resultHandler:^(NSData * _Nullable data, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
1192
+ imageData = data;
1193
+ dispatch_semaphore_signal(semaphore);
1194
+ }];
1195
+ } else {
1196
+ dispatch_semaphore_signal(semaphore);
1197
+ }
1187
1198
  });
1188
-
1189
- [albumReadLock lockWhenCondition:WDASSETURL_ALLFINISHED];
1190
- [albumReadLock unlock];
1191
-
1192
- RCTLog(@"asset lookup finished: %@ %@", [assetURL absoluteString], (data ? @"exists" : @"does not exist"));
1193
-
1194
- return data;
1199
+
1200
+ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
1201
+
1202
+ return imageData;
1195
1203
  }
1196
1204
 
1197
1205
  RCT_EXPORT_METHOD(deleteContact:(NSDictionary *)contactData resolver:(RCTPromiseResolveBlock) resolve
@@ -1221,9 +1229,13 @@ RCT_EXPORT_METHOD(deleteContact:(NSDictionary *)contactData resolver:(RCTPromise
1221
1229
  }
1222
1230
  }
1223
1231
 
1224
- RCT_EXPORT_METHOD(writePhotoToPath:(RCTResponseSenderBlock) rejecter:(RCTPromiseRejectBlock) reject)
1232
+ RCT_EXPORT_METHOD(writePhotoToPath:(nonnull NSString *)path resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject)
1225
1233
  {
1226
- reject(@"Error", @"not implemented", nil);
1234
+ @try {
1235
+ //Nothing is implemented here
1236
+ } @catch (NSException *exception) {
1237
+ reject(@"Error", @"not implemented", nil);
1238
+ }
1227
1239
  }
1228
1240
 
1229
1241
  -(CNContactStore*) contactsStore: (RCTPromiseRejectBlock) reject {
@@ -1253,4 +1265,472 @@ RCT_EXPORT_METHOD(writePhotoToPath:(RCTResponseSenderBlock) rejecter:(RCTPromise
1253
1265
  return YES;
1254
1266
  }
1255
1267
 
1268
+ // Thanks to this guard, we won't compile this code when we build for the old architecture.
1269
+ #ifdef RCT_NEW_ARCH_ENABLED
1270
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
1271
+ (const facebook::react::ObjCTurboModule::InitParams &)params
1272
+ {
1273
+ return std::make_shared<facebook::react::NativeContactsSpecJSI>(params);
1274
+ }
1275
+
1276
+ #endif
1277
+
1278
+ - (void)getAll:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1279
+ [self getAllContacts:resolve reject:reject withThumbnails:true];
1280
+ }
1281
+
1282
+ - (void)checkPermission:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1283
+ CNAuthorizationStatus authStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
1284
+ if (authStatus == CNAuthorizationStatusDenied || authStatus == CNAuthorizationStatusRestricted){
1285
+ resolve(@"denied");
1286
+ } else if (authStatus == CNAuthorizationStatusAuthorized){
1287
+ resolve(@"authorized");
1288
+ } else {
1289
+ resolve(@"undefined");
1290
+ }
1291
+ }
1292
+
1293
+
1294
+ - (void)deleteContact:(NSDictionary *)contactData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1295
+ if(!contactStore) {
1296
+ contactStore = [[CNContactStore alloc] init];
1297
+ }
1298
+
1299
+ NSString* recordID = [contactData valueForKey:@"recordID"];
1300
+
1301
+ NSArray *keys = @[CNContactIdentifierKey];
1302
+
1303
+
1304
+ @try {
1305
+
1306
+ CNMutableContact *contact = [[contactStore unifiedContactWithIdentifier:recordID keysToFetch:keys error:nil] mutableCopy];
1307
+ NSError *error;
1308
+ CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init];
1309
+ [saveRequest deleteContact:contact];
1310
+ [contactStore executeSaveRequest:saveRequest error:&error];
1311
+
1312
+ resolve(recordID);
1313
+ }
1314
+ @catch (NSException *exception) {
1315
+ reject(@"Error", [exception reason], nil);
1316
+ }
1317
+ }
1318
+
1319
+
1320
+ - (void)editExistingContact:(NSDictionary *)contactData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1321
+ CNContactStore* contactStore = [self contactsStore:reject];
1322
+ if(!contactStore)
1323
+ return;
1324
+
1325
+ NSError* contactError;
1326
+ selectedContact = nil;
1327
+ NSString* recordID = [contactData valueForKey:@"recordID"];
1328
+ NSArray * keysToFetch =@[
1329
+ CNContactEmailAddressesKey,
1330
+ CNContactPhoneNumbersKey,
1331
+ CNContactFamilyNameKey,
1332
+ CNContactGivenNameKey,
1333
+ CNContactMiddleNameKey,
1334
+ CNContactPostalAddressesKey,
1335
+ CNContactOrganizationNameKey,
1336
+ CNContactJobTitleKey,
1337
+ CNContactImageDataAvailableKey,
1338
+ CNContactThumbnailImageDataKey,
1339
+ CNContactImageDataKey,
1340
+ CNContactUrlAddressesKey,
1341
+ CNContactBirthdayKey,
1342
+ CNContactIdentifierKey,
1343
+ [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName],
1344
+ [CNContactViewController descriptorForRequiredKeys]];
1345
+
1346
+ @try {
1347
+ CNMutableContact* record = [[contactStore unifiedContactWithIdentifier:recordID keysToFetch:keysToFetch error:&contactError] mutableCopy];
1348
+
1349
+ NSMutableArray *phoneNumbers = [[NSMutableArray alloc]init];
1350
+ phoneNumbers = [NSMutableArray arrayWithArray:record.phoneNumbers];
1351
+
1352
+ for (id phoneData in [contactData valueForKey:@"phoneNumbers"]) {
1353
+ NSString *number = [phoneData valueForKey:@"number"];
1354
+
1355
+ CNLabeledValue *contactPhoneNumber = [CNLabeledValue labeledValueWithLabel:CNLabelOther value:[CNPhoneNumber phoneNumberWithStringValue:number]];
1356
+ //record.phoneNumbers = @[contactPhoneNumber];
1357
+ [phoneNumbers addObject:contactPhoneNumber];
1358
+ }
1359
+
1360
+ NSArray *phoneNumbersNew = [[NSArray alloc]init];
1361
+ phoneNumbersNew = [NSArray arrayWithArray:phoneNumbers];
1362
+
1363
+
1364
+ record.phoneNumbers = phoneNumbersNew;
1365
+
1366
+ CNSaveRequest *request = [[CNSaveRequest alloc] init];
1367
+ [request updateContact:record];
1368
+
1369
+ selectedContact = record;
1370
+
1371
+ [contactStore executeSaveRequest:request error:nil];
1372
+
1373
+ CNContactViewController *controller = [CNContactViewController viewControllerForContact:record];
1374
+ //controller.title = @"Saved!";
1375
+ UIAlertController *alert= [UIAlertController
1376
+ alertControllerWithTitle:@"Saved!"
1377
+ message:@"Number added to contact"
1378
+ preferredStyle:UIAlertControllerStyleAlert];
1379
+ //[controller presentViewController:alert animated:YES completion:nil];
1380
+
1381
+ // Add a cancel button which will close the view
1382
+ controller.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(doneContactForm)];
1383
+
1384
+ controller.delegate = self;
1385
+ controller.allowsEditing = true;
1386
+ controller.allowsActions = true;
1387
+
1388
+ dispatch_async(dispatch_get_main_queue(), ^{
1389
+ UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:controller];
1390
+ UIViewController *viewController = (UIViewController*)[[[[UIApplication sharedApplication] delegate] window] rootViewController];
1391
+
1392
+ //navigation.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor redColor]};
1393
+
1394
+ while (viewController.presentedViewController)
1395
+ {
1396
+ viewController = viewController.presentedViewController;
1397
+ }
1398
+ [viewController presentViewController:navigation animated:YES completion:nil];
1399
+ [controller presentViewController:alert animated:YES completion:nil];
1400
+
1401
+ self->updateContactPromise = resolve;
1402
+ });
1403
+
1404
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
1405
+
1406
+ [alert dismissViewControllerAnimated:YES completion:^{
1407
+
1408
+ //Dismissed
1409
+ }];
1410
+
1411
+ });
1412
+ }
1413
+ @catch (NSException *exception) {
1414
+ reject(@"Error", [exception reason], nil);
1415
+ }
1416
+ }
1417
+
1418
+
1419
+ - (void)getAllWithoutPhotos:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1420
+ [self getAllContacts:resolve reject:reject withThumbnails:false];
1421
+ }
1422
+
1423
+
1424
+ - (void)getContactById:(nonnull NSString *)recordID resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1425
+ CNContactStore* contactStore = [self contactsStore:reject];
1426
+ if(!contactStore)
1427
+ return;
1428
+
1429
+ CNEntityType entityType = CNEntityTypeContacts;
1430
+ if([CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusNotDetermined)
1431
+ {
1432
+ [contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) {
1433
+ if(granted){
1434
+ resolve([self getContact:recordID addressBook:contactStore withThumbnails:false]);
1435
+ }
1436
+ }];
1437
+ }
1438
+ else if( [CNContactStore authorizationStatusForEntityType:entityType]== CNAuthorizationStatusAuthorized)
1439
+ {
1440
+ resolve([self getContact:recordID addressBook:contactStore withThumbnails:false]);
1441
+ }
1442
+ }
1443
+
1444
+
1445
+ - (void)getContactsByEmailAddress:(NSString *)string resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1446
+ CNContactStore *contactStore = [[CNContactStore alloc] init];
1447
+ if (!contactStore)
1448
+ return;
1449
+ [self getContactsFromAddressBook:contactStore byEmailAddress:string resolve:resolve];
1450
+ }
1451
+
1452
+
1453
+ - (void)getContactsByPhoneNumber:(NSString *)string resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1454
+ CNContactStore *contactStore = [[CNContactStore alloc] init];
1455
+ if (!contactStore)
1456
+ return;
1457
+ [self getContactsFromAddressBook:contactStore byPhoneNumber:string resolve:resolve];
1458
+ }
1459
+
1460
+
1461
+ - (void)getContactsMatchingString:(NSString *)string resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1462
+ CNContactStore *contactStore = [[CNContactStore alloc] init];
1463
+ if (!contactStore)
1464
+ return;
1465
+ [self getContactsFromAddressBook:contactStore matchingString:string resolve:resolve];
1466
+ }
1467
+
1468
+
1469
+ - (void)getCount:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1470
+ [self getAllContactsCount:resolve reject:reject];
1471
+ }
1472
+
1473
+
1474
+ - (void)getPhotoForId:(nonnull NSString *)recordID resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1475
+ CNContactStore* contactStore = [self contactsStore:reject];
1476
+ if(!contactStore)
1477
+ return;
1478
+
1479
+ CNEntityType entityType = CNEntityTypeContacts;
1480
+ if([CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusNotDetermined)
1481
+ {
1482
+ [contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) {
1483
+ if(granted){
1484
+ resolve([self getFilePathForThumbnailImage:recordID addressBook:contactStore]);
1485
+ }
1486
+ }];
1487
+ }
1488
+ else if( [CNContactStore authorizationStatusForEntityType:entityType]== CNAuthorizationStatusAuthorized)
1489
+ {
1490
+ resolve([self getFilePathForThumbnailImage:recordID addressBook:contactStore]);
1491
+ }
1492
+ }
1493
+
1494
+
1495
+ - (void)openContactForm:(NSDictionary *)contactData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1496
+ CNMutableContact * contact = [[CNMutableContact alloc] init];
1497
+
1498
+ [self updateRecord:contact withData:contactData];
1499
+
1500
+ CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:contact];
1501
+
1502
+
1503
+ controller.delegate = self;
1504
+
1505
+ dispatch_async(dispatch_get_main_queue(), ^{
1506
+ UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:controller];
1507
+ UIViewController *viewController = (UIViewController*)[[[[UIApplication sharedApplication] delegate] window] rootViewController];
1508
+ while (viewController.presentedViewController)
1509
+ {
1510
+ viewController = viewController.presentedViewController;
1511
+ }
1512
+ [viewController presentViewController:navigation animated:YES completion:nil];
1513
+
1514
+ self->updateContactPromise = resolve;
1515
+ });
1516
+ }
1517
+
1518
+
1519
+ - (void)openExistingContact:(NSDictionary *)contactData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1520
+ if(!contactStore) {
1521
+ contactStore = [[CNContactStore alloc] init];
1522
+ }
1523
+
1524
+ NSString* recordID = [contactData valueForKey:@"recordID"];
1525
+ NSString* backTitle = [contactData valueForKey:@"backTitle"];
1526
+
1527
+ NSArray *keys = @[CNContactIdentifierKey,
1528
+ CNContactEmailAddressesKey,
1529
+ CNContactBirthdayKey,
1530
+ CNContactImageDataKey,
1531
+ CNContactPhoneNumbersKey,
1532
+ [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName],
1533
+ [CNContactViewController descriptorForRequiredKeys]];
1534
+
1535
+ @try {
1536
+
1537
+ CNContact *contact = [contactStore unifiedContactWithIdentifier:recordID keysToFetch:keys error:nil];
1538
+
1539
+ CNContactViewController *contactViewController = [CNContactViewController viewControllerForContact:contact];
1540
+
1541
+ // Add a cancel button which will close the view
1542
+ contactViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backTitle == nil ? @"Cancel" : backTitle style:UIBarButtonItemStyleDone target:self action:@selector(cancelContactForm)];
1543
+ contactViewController.delegate = self;
1544
+
1545
+
1546
+ dispatch_async(dispatch_get_main_queue(), ^{
1547
+ UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:contactViewController];
1548
+
1549
+ UIViewController *currentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
1550
+
1551
+ while (currentViewController.presentedViewController)
1552
+ {
1553
+ currentViewController = currentViewController.presentedViewController;
1554
+ }
1555
+
1556
+ UIActivityIndicatorViewStyle activityIndicatorStyle;
1557
+ UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
1558
+ UIColor *activityIndicatorBackgroundColor;
1559
+ if (@available(iOS 13, *)) {
1560
+ activityIndicatorStyle = UIActivityIndicatorViewStyleMedium;
1561
+ activityIndicatorBackgroundColor = [UIColor secondarySystemGroupedBackgroundColor];
1562
+ } else {
1563
+ activityIndicatorStyle = UIActivityIndicatorViewStyleGray;
1564
+ activityIndicatorBackgroundColor = [UIColor whiteColor];;
1565
+ }
1566
+
1567
+ // Cover the contact view with an activity indicator so we can put it in edit mode without user seeing the transition
1568
+ UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:activityIndicatorStyle];
1569
+ activityIndicatorView.frame = UIApplication.sharedApplication.keyWindow.frame;
1570
+ [activityIndicatorView startAnimating];
1571
+ activityIndicatorView.backgroundColor = activityIndicatorBackgroundColor;
1572
+ [navigation.view addSubview:activityIndicatorView];
1573
+
1574
+ [currentViewController presentViewController:navigation animated:YES completion:nil];
1575
+
1576
+
1577
+ // TODO should this 'fake click' method be used? For a brief instance
1578
+ // Fake click edit button to enter edit mode
1579
+ // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
1580
+ // SEL selector = contactViewController.navigationItem.rightBarButtonItem.action;
1581
+ // NSLog(@"!!!!!!!!!!!!!!!!!! FAKE CLICK!!! %@", NSStringFromSelector(selector));
1582
+ // id target = contactViewController.navigationItem.rightBarButtonItem.target;
1583
+ // [target performSelector:selector];
1584
+ // });
1585
+
1586
+
1587
+ // We need to wait for a short while otherwise contactViewController will not respond to the selector (it has not initialized)
1588
+ [contactViewController performSelector:@selector(toggleEditing:) withObject:nil afterDelay:0.1];
1589
+
1590
+ // remove the activity indicator after a delay so the underlying transition will have time to complete
1591
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
1592
+ [activityIndicatorView removeFromSuperview];
1593
+ });
1594
+
1595
+ updateContactPromise = resolve;
1596
+ });
1597
+
1598
+ }
1599
+ @catch (NSException *exception) {
1600
+ reject(@"Error", [exception reason], nil);
1601
+ }
1602
+ }
1603
+
1604
+
1605
+ - (void)requestPermission:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1606
+ CNContactStore* contactStore = [[CNContactStore alloc] init];
1607
+
1608
+ [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
1609
+ [self checkPermission:resolve rejecter:reject];
1610
+ }];
1611
+ }
1612
+
1613
+
1614
+ - (void)updateContact:(NSDictionary *)contactData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1615
+ CNContactStore* contactStore = [self contactsStore:reject];
1616
+ if(!contactStore)
1617
+ return;
1618
+
1619
+ NSError* contactError;
1620
+ NSString* recordID = [contactData valueForKey:@"recordID"];
1621
+ NSMutableArray * keysToFetch = [NSMutableArray arrayWithArray: @[
1622
+ CNContactEmailAddressesKey,
1623
+ CNContactPhoneNumbersKey,
1624
+ CNContactFamilyNameKey,
1625
+ CNContactGivenNameKey,
1626
+ CNContactMiddleNameKey,
1627
+ CNContactPostalAddressesKey,
1628
+ CNContactOrganizationNameKey,
1629
+ CNContactJobTitleKey,
1630
+ CNContactImageDataAvailableKey,
1631
+ CNContactThumbnailImageDataKey,
1632
+ CNContactImageDataKey,
1633
+ CNContactUrlAddressesKey,
1634
+ CNContactBirthdayKey,
1635
+ CNContactInstantMessageAddressesKey
1636
+ ]];
1637
+ if(notesUsageEnabled) {
1638
+ [keysToFetch addObject: CNContactNoteKey];
1639
+ }
1640
+
1641
+ @try {
1642
+ CNMutableContact* record = [[contactStore unifiedContactWithIdentifier:recordID keysToFetch:keysToFetch error:&contactError] mutableCopy];
1643
+ [self updateRecord:record withData:contactData];
1644
+ CNSaveRequest *request = [[CNSaveRequest alloc] init];
1645
+ [request updateContact:record];
1646
+
1647
+ [contactStore executeSaveRequest:request error:nil];
1648
+
1649
+ NSDictionary *contactDict = [self contactToDictionary:record withThumbnails:false];
1650
+
1651
+ resolve(contactDict);
1652
+ }
1653
+ @catch (NSException *exception) {
1654
+ reject(@"Error", [exception reason], nil);
1655
+ }
1656
+ }
1657
+
1658
+
1659
+ - (void)viewExistingContact:(NSDictionary *)contactData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1660
+ if(!contactStore) {
1661
+ contactStore = [[CNContactStore alloc] init];
1662
+ }
1663
+
1664
+ NSString* recordID = [contactData valueForKey:@"recordID"];
1665
+ NSString* backTitle = [contactData valueForKey:@"backTitle"];
1666
+
1667
+ NSArray *keys = @[CNContactIdentifierKey,
1668
+ CNContactEmailAddressesKey,
1669
+ CNContactBirthdayKey,
1670
+ CNContactImageDataKey,
1671
+ CNContactPhoneNumbersKey,
1672
+ [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName],
1673
+ [CNContactViewController descriptorForRequiredKeys]];
1674
+
1675
+ @try {
1676
+
1677
+ CNContact *contact = [contactStore unifiedContactWithIdentifier:recordID keysToFetch:keys error:nil];
1678
+
1679
+ CNContactViewController *contactViewController = [CNContactViewController viewControllerForContact:contact];
1680
+
1681
+ // Add a cancel button which will close the view
1682
+ contactViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backTitle == nil ? @"Cancel" : backTitle style:UIBarButtonItemStylePlain target:self action:@selector(cancelContactForm)];
1683
+ contactViewController.delegate = self;
1684
+
1685
+
1686
+ dispatch_async(dispatch_get_main_queue(), ^{
1687
+ UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:contactViewController];
1688
+
1689
+ UIViewController *currentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
1690
+
1691
+ while (currentViewController.presentedViewController)
1692
+ {
1693
+ currentViewController = currentViewController.presentedViewController;
1694
+ }
1695
+
1696
+ [currentViewController presentViewController:navigation animated:YES completion:nil];
1697
+
1698
+ updateContactPromise = resolve;
1699
+ });
1700
+
1701
+ }
1702
+ @catch (NSException *exception) {
1703
+ reject(@"Error", [exception reason], nil);
1704
+ }
1705
+ }
1706
+
1707
+
1708
+ - (void)writePhotoToPath:(NSString *)contactId file:(NSString *)file resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1709
+ reject(@"Error", @"not implemented", nil);
1710
+ }
1711
+
1712
+ - (void)addContact:(NSDictionary *)contactData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
1713
+ CNContactStore* contactStore = [self contactsStore:reject];
1714
+ if(!contactStore)
1715
+ return;
1716
+
1717
+ CNMutableContact * contact = [[CNMutableContact alloc] init];
1718
+
1719
+ [self updateRecord:contact withData:contactData];
1720
+
1721
+ @try {
1722
+ CNSaveRequest *request = [[CNSaveRequest alloc] init];
1723
+ [request addContact:contact toContainerWithIdentifier:nil];
1724
+
1725
+ [contactStore executeSaveRequest:request error:nil];
1726
+
1727
+ NSDictionary *contactDict = [self contactToDictionary:contact withThumbnails:false];
1728
+
1729
+ resolve(contactDict);
1730
+ }
1731
+ @catch (NSException *exception) {
1732
+ reject(@"Error", [exception reason], nil);
1733
+ }
1734
+ }
1735
+
1256
1736
  @end
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/rt2zz/react-native-contacts.git"
6
6
  },
7
- "version": "7.0.7",
7
+ "version": "8.0.0",
8
8
  "description": "React Native Contacts (android & ios)",
9
9
  "nativePackage": true,
10
10
  "keywords": [
@@ -19,9 +19,18 @@
19
19
  "bugs": {
20
20
  "url": "https://github.com/rt2zz/react-native-contacts/issues"
21
21
  },
22
+ "@react-native-community/bob": {
23
+ "source": "src",
24
+ "output": "lib",
25
+ "targets": [
26
+ "commonjs",
27
+ "module",
28
+ "typescript"
29
+ ]
30
+ },
22
31
  "homepage": "https://github.com/rt2zz/react-native-contacts",
23
- "main": "index.js",
24
- "types": "index.d.ts",
32
+ "main": "index.ts",
33
+ "types": "index.ts",
25
34
  "scripts": {
26
35
  "test": "echo \"Error: no test specified\" && exit 1"
27
36
  },
@@ -43,7 +52,13 @@
43
52
  "devDependencies": {
44
53
  "react-native-cli": "^2.0.1"
45
54
  },
55
+ "codegenConfig": {
56
+ "name": "RNContactsSpec",
57
+ "type": "modules",
58
+ "jsSrcsDir": "src"
59
+ },
46
60
  "peerDependencies": {
47
- "react-native": ">=0.64.0"
61
+ "react-native": "*",
62
+ "react": "*"
48
63
  }
49
64
  }