react-native-contacts 7.0.2 → 7.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.
package/README.md CHANGED
@@ -29,10 +29,14 @@ PermissionsAndroid.request(
29
29
  'buttonPositive': 'Please accept bare mortal'
30
30
  }
31
31
  )
32
- .then(Contacts.getAll)
33
- .then(contacts => {
34
- ...
35
- })
32
+ .then(Contacts.getAll()
33
+ .then((contacts) => {
34
+ // work with contacts
35
+ console.log(contacts)
36
+ })
37
+ .catch((e) => {
38
+ console.log(e)
39
+ }))
36
40
  ```
37
41
 
38
42
  ## Installation
@@ -56,7 +60,7 @@ react-native unlink react-native-contacts
56
60
  npm install latest version of react-native-contacts
57
61
  Your good to go!
58
62
  ```
59
- ### react native version 60 and above
63
+ ### react native version 60 and above
60
64
 
61
65
  If you are using react native version 0.60 or above you do not have to link this library.
62
66
 
@@ -175,7 +179,8 @@ If you'd like to read/write the contact's notes, call the `iosEnableNotesUsage(t
175
179
  * `getPhotoForId(contactId)`: Promise<string> - returns a URI (or null) for a contacts photo
176
180
  * `addContact(contact)`: Promise<Contact> - adds a contact to the AddressBook.
177
181
  * `openContactForm(contact)` - create a new contact and display in contactsUI.
178
- * `openExistingContact(contact)` - where contact is an object with a valid recordID
182
+ * `openExistingContact(contact)` - open existing contact (edit mode), where contact is an object with a valid recordID
183
+ * `viewExistingContact(contact)` - open existing contact (view mode), where contact is an object with a valid recordID
179
184
  * `editExistingContact(contact)`: Promise<Contact> - add numbers to the contact, where the contact is an object with a valid recordID and an array of phoneNumbers
180
185
  * `updateContact(contact)`: Promise<Contact> - where contact is an object with a valid recordID
181
186
  * `deleteContact(contact)` - where contact is an object with a valid recordID
@@ -221,15 +226,25 @@ If you'd like to read/write the contact's notes, call the `iosEnableNotesUsage(t
221
226
  prefix: 'MR',
222
227
  suffix: '',
223
228
  department: '',
224
- birthday: {'year': 1988, 'month': 0, 'day': 1 },
229
+ birthday: {'year': 1988, 'month': 1, 'day': 1 },
225
230
  imAddresses: [
226
231
  { username: '0123456789', service: 'ICQ'},
227
232
  { username: 'johndoe123', service: 'Facebook'}
228
- ]
233
+ ],
234
+ isStarred: false,
229
235
  }
230
236
  ```
231
- **NOTE**
237
+
238
+ ### Android only
239
+
232
240
  * on Android versions below 8 the entire display name is passed in the `givenName` field. `middleName` and `familyName` will be `""`.
241
+ * isStarred field
242
+ * writePhotoToPath() - writes the contact photo to a given path
243
+
244
+ ## iOS only
245
+
246
+ checkPermission(): Promise - checks permission to access Contacts
247
+ requestPermission(): Promise - request permission to access Contacts
233
248
 
234
249
  ## Adding Contacts
235
250
  Currently all fields from the contact record except for thumbnailPath are supported for writing
@@ -110,10 +110,15 @@ public class ContactsManager extends ReactContextBaseJavaModule implements Activ
110
110
  ContentResolver cr = context.getContentResolver();
111
111
 
112
112
  ContactsProvider contactsProvider = new ContactsProvider(cr);
113
- Integer contacts = contactsProvider.getContactsCount();
113
+ try {
114
+ Integer contacts = contactsProvider.getContactsCount();
115
+ promise.resolve(contacts);
116
+ } catch (Exception e) {
117
+ promise.reject(e);
118
+ }
114
119
 
115
- promise.resolve(contacts);
116
120
  return null;
121
+
117
122
  }
118
123
  };
119
124
  myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
@@ -519,6 +524,28 @@ public class ContactsManager extends ReactContextBaseJavaModule implements Activ
519
524
  promise.reject(e.toString());
520
525
  }
521
526
  }
527
+
528
+ /*
529
+ * View contact in native app
530
+ */
531
+ @ReactMethod
532
+ public void viewExistingContact(ReadableMap contact, Promise promise) {
533
+
534
+ String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;
535
+
536
+ try {
537
+ Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, recordID);
538
+ Intent intent = new Intent(Intent.ACTION_VIEW);
539
+ intent.setDataAndType(uri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
540
+ intent.putExtra("finishActivityOnSaveCompleted", true);
541
+
542
+ updateContactPromise = promise;
543
+ getReactApplicationContext().startActivityForResult(intent, REQUEST_OPEN_EXISTING_CONTACT, Bundle.EMPTY);
544
+
545
+ } catch (Exception e) {
546
+ promise.reject(e.toString());
547
+ }
548
+ }
522
549
 
523
550
  /*
524
551
  * Edit contact in native app
@@ -37,6 +37,7 @@ public class ContactsProvider {
37
37
  add(ContactsContract.Data.CONTACT_ID);
38
38
  add(ContactsContract.Data.RAW_CONTACT_ID);
39
39
  add(ContactsContract.Data.LOOKUP_KEY);
40
+ add(ContactsContract.Data.STARRED);
40
41
  add(ContactsContract.Contacts.Data.MIMETYPE);
41
42
  add(ContactsContract.Profile.DISPLAY_NAME);
42
43
  add(Contactables.PHOTO_URI);
@@ -344,10 +345,13 @@ public class ContactsProvider {
344
345
  Contact contact = map.get(contactId);
345
346
  String mimeType = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.MIMETYPE));
346
347
  String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
348
+ int starred = cursor.getInt(cursor.getColumnIndex(ContactsContract.Data.STARRED));
349
+ Boolean isStarred = starred == 1;
347
350
  contact.rawContactId = rawContactId;
348
351
  if (!TextUtils.isEmpty(name) && TextUtils.isEmpty(contact.displayName)) {
349
352
  contact.displayName = name;
350
353
  }
354
+ contact.isStarred = isStarred;
351
355
 
352
356
  if (TextUtils.isEmpty(contact.photoUri)) {
353
357
  String rawPhotoURI = cursor.getString(cursor.getColumnIndex(Contactables.PHOTO_URI));
@@ -599,6 +603,7 @@ public class ContactsProvider {
599
603
  private List<Item> urls = new ArrayList<>();
600
604
  private List<Item> instantMessengers = new ArrayList<>();
601
605
  private boolean hasPhoto = false;
606
+ private boolean isStarred = false;
602
607
  private String photoUri;
603
608
  private List<Item> emails = new ArrayList<>();
604
609
  private List<Item> phones = new ArrayList<>();
@@ -626,6 +631,7 @@ public class ContactsProvider {
626
631
  contact.putString("note", note);
627
632
  contact.putBoolean("hasThumbnail", this.hasPhoto);
628
633
  contact.putString("thumbnailPath", photoUri == null ? "" : photoUri);
634
+ contact.putBoolean("isStarred", this.isStarred);
629
635
 
630
636
  WritableArray phoneNumbers = Arguments.createArray();
631
637
  for (Item item : phones) {
package/foo.js ADDED
@@ -0,0 +1 @@
1
+ console.log('hello')
package/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export function getPhotoForId(contactId: string): Promise<string>;
6
6
  export function addContact(contact: Contact): Promise<void>;
7
7
  export function openContactForm(contact: Partial<Contact>): Promise<Contact>;
8
8
  export function openExistingContact(contact: Contact): Promise<Contact>;
9
+ export function viewExistingContact(contact: { recordID: string }): Promise<Contact | void>
9
10
  export function editExistingContact(contact: Contact): Promise<Contact>;
10
11
  export function updateContact(contact: Contact): Promise<void>;
11
12
  export function deleteContact(contact: Contact): Promise<void>;
@@ -64,6 +65,7 @@ export interface Contact {
64
65
  phoneNumbers: PhoneNumber[];
65
66
  hasThumbnail: boolean;
66
67
  thumbnailPath: string;
68
+ isStarred: boolean;
67
69
  postalAddresses: PostalAddress[];
68
70
  prefix: string;
69
71
  suffix: string;
@@ -347,9 +347,9 @@ RCT_EXPORT_METHOD(getCount:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromise
347
347
  if (birthday.month != NSDateComponentUndefined && birthday.day != NSDateComponentUndefined) {
348
348
  //months are indexed to 0 in JavaScript (0 = January) so we subtract 1 from NSDateComponents.month
349
349
  if (birthday.year != NSDateComponentUndefined) {
350
- [output setObject:@{@"year": @(birthday.year), @"month": @(birthday.month - 1), @"day": @(birthday.day)} forKey:@"birthday"];
350
+ [output setObject:@{@"year": @(birthday.year), @"month": @(birthday.month), @"day": @(birthday.day)} forKey:@"birthday"];
351
351
  } else {
352
- [output setObject:@{@"month": @(birthday.month - 1), @"day":@(birthday.day)} forKey:@"birthday"];
352
+ [output setObject:@{@"month": @(birthday.month), @"day":@(birthday.day)} forKey:@"birthday"];
353
353
  }
354
354
  }
355
355
  }
@@ -676,18 +676,8 @@ RCT_EXPORT_METHOD(openContactForm:(NSDictionary *)contactData
676
676
  viewController = viewController.presentedViewController;
677
677
  }
678
678
  [viewController presentViewController:navigation animated:YES completion:nil];
679
-
680
- if (@available(iOS 13, *)) {
681
- viewController.view.window.backgroundColor=[UIColor blackColor];
682
- navigation.navigationBar.topItem.title = @"";
683
- UIView *statusBar = [[UIView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager.statusBarFrame];
684
- statusBar.backgroundColor = [UIColor blackColor];
685
- statusBar.tag=1;
686
- controller.navigationController.navigationBar.tintColor = [UIColor blackColor];
687
- [[UIApplication sharedApplication].keyWindow addSubview:statusBar];
688
- }
689
679
 
690
- updateContactPromise = resolve;
680
+ self->updateContactPromise = resolve;
691
681
  });
692
682
  }
693
683
 
@@ -716,7 +706,7 @@ RCT_EXPORT_METHOD(openExistingContact:(NSDictionary *)contactData resolver:(RCTP
716
706
  CNContactViewController *contactViewController = [CNContactViewController viewControllerForContact:contact];
717
707
 
718
708
  // Add a cancel button which will close the view
719
- contactViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backTitle == nil ? @"Cancel" : backTitle style:UIBarButtonSystemItemCancel target:self action:@selector(cancelContactForm)];
709
+ contactViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backTitle == nil ? @"Cancel" : backTitle style:UIBarButtonItemStyleDone target:self action:@selector(cancelContactForm)];
720
710
  contactViewController.delegate = self;
721
711
 
722
712
 
@@ -777,6 +767,56 @@ RCT_EXPORT_METHOD(openExistingContact:(NSDictionary *)contactData resolver:(RCTP
777
767
  }
778
768
  }
779
769
 
770
+ RCT_EXPORT_METHOD(viewExistingContact:(NSDictionary *)contactData resolver:(RCTPromiseResolveBlock) resolve
771
+ rejecter:(RCTPromiseRejectBlock) reject)
772
+ {
773
+ if(!contactStore) {
774
+ contactStore = [[CNContactStore alloc] init];
775
+ }
776
+
777
+ NSString* recordID = [contactData valueForKey:@"recordID"];
778
+ NSString* backTitle = [contactData valueForKey:@"backTitle"];
779
+
780
+ NSArray *keys = @[CNContactIdentifierKey,
781
+ CNContactEmailAddressesKey,
782
+ CNContactBirthdayKey,
783
+ CNContactImageDataKey,
784
+ CNContactPhoneNumbersKey,
785
+ [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName],
786
+ [CNContactViewController descriptorForRequiredKeys]];
787
+
788
+ @try {
789
+
790
+ CNContact *contact = [contactStore unifiedContactWithIdentifier:recordID keysToFetch:keys error:nil];
791
+
792
+ CNContactViewController *contactViewController = [CNContactViewController viewControllerForContact:contact];
793
+
794
+ // 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)];
796
+ contactViewController.delegate = self;
797
+
798
+
799
+ dispatch_async(dispatch_get_main_queue(), ^{
800
+ UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:contactViewController];
801
+
802
+ UIViewController *currentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
803
+
804
+ while (currentViewController.presentedViewController)
805
+ {
806
+ currentViewController = currentViewController.presentedViewController;
807
+ }
808
+
809
+ [currentViewController presentViewController:navigation animated:YES completion:nil];
810
+
811
+ updateContactPromise = resolve;
812
+ });
813
+
814
+ }
815
+ @catch (NSException *exception) {
816
+ reject(@"Error", [exception reason], nil);
817
+ }
818
+ }
819
+
780
820
  RCT_EXPORT_METHOD(editExistingContact:(NSDictionary *)contactData resolver:(RCTPromiseResolveBlock) resolve
781
821
  rejecter:(RCTPromiseRejectBlock) reject)
782
822
  {
@@ -860,17 +900,7 @@ RCT_EXPORT_METHOD(editExistingContact:(NSDictionary *)contactData resolver:(RCTP
860
900
  [viewController presentViewController:navigation animated:YES completion:nil];
861
901
  [controller presentViewController:alert animated:YES completion:nil];
862
902
 
863
- if (@available(iOS 13, *)) {
864
- viewController.view.window.backgroundColor=[UIColor blackColor];
865
- navigation.navigationBar.topItem.title = @"";
866
- UIView *statusBar = [[UIView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager.statusBarFrame];
867
- statusBar.backgroundColor = [UIColor blackColor];
868
- statusBar.tag=1;
869
- controller.navigationController.navigationBar.tintColor = [UIColor blackColor];
870
- [[UIApplication sharedApplication].keyWindow addSubview:statusBar];
871
- }
872
-
873
- updateContactPromise = resolve;
903
+ self->updateContactPromise = resolve;
874
904
  });
875
905
 
876
906
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@@ -903,6 +933,10 @@ RCT_EXPORT_METHOD(editExistingContact:(NSDictionary *)contactData resolver:(RCTP
903
933
  {
904
934
  if (updateContactPromise != nil) {
905
935
  UIViewController *rootViewController = (UIViewController*)[[[[UIApplication sharedApplication] delegate] window] rootViewController];
936
+ while (rootViewController.presentedViewController)
937
+ {
938
+ rootViewController = rootViewController.presentedViewController;
939
+ }
906
940
  [rootViewController dismissViewControllerAnimated:YES completion:nil];
907
941
 
908
942
  updateContactPromise(nil);
@@ -925,12 +959,6 @@ RCT_EXPORT_METHOD(editExistingContact:(NSDictionary *)contactData resolver:(RCTP
925
959
 
926
960
  updateContactPromise = nil;
927
961
  }
928
-
929
- UIView *statusBar = [[UIApplication sharedApplication].keyWindow viewWithTag:1];
930
-
931
- if(statusBar) {
932
- [statusBar removeFromSuperview];
933
- }
934
962
  }
935
963
 
936
964
  RCT_EXPORT_METHOD(updateContact:(NSDictionary *)contactData resolver:(RCTPromiseResolveBlock) resolve
@@ -1011,8 +1039,7 @@ RCT_EXPORT_METHOD(updateContact:(NSDictionary *)contactData resolver:(RCTPromise
1011
1039
  if (birthday[@"year"]) {
1012
1040
  components.year = [birthday[@"year"] intValue];
1013
1041
  }
1014
- //months are indexed to 0 in JavaScript so we add 1 when assigning the month to DateComponent
1015
- components.month = [birthday[@"month"] intValue] + 1;
1042
+ components.month = [birthday[@"month"] intValue];
1016
1043
  components.day = [birthday[@"day"] intValue];
1017
1044
  }
1018
1045
 
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.2",
7
+ "version": "7.0.5",
8
8
  "description": "React Native Contacts (android & ios)",
9
9
  "nativePackage": true,
10
10
  "keywords": [