Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-20589] iOS: Allow editing contacts in iOS9 and above #7870

Merged
merged 3 commits into from
Apr 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion iphone/Classes/ContactsModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#import "KrollCallback.h"
#import "TiContactsPerson.h"

@interface ContactsModule : TiModule<ABPeoplePickerNavigationControllerDelegate, CNContactPickerDelegate,CNContactViewControllerDelegate> {
@interface ContactsModule : TiModule<ABPeoplePickerNavigationControllerDelegate, CNContactPickerDelegate,CNContactViewControllerDelegate, TiContactsPersonUpdateObserver> {
@private
ABAddressBookRef addressBook;
ABPeoplePickerNavigationController* picker;
Expand Down
48 changes: 29 additions & 19 deletions iphone/Classes/ContactsModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

static NSArray* contactKeysWithImage;
static NSArray* contactKeysWithoutImage;

@implementation ContactsModule

void CMExternalChangeCallback (ABAddressBookRef notifyAddressBook,CFDictionaryRef info,void *context)
Expand Down Expand Up @@ -151,7 +152,6 @@ -(void)dealloc
saveRequest = nil;
RELEASE_TO_NIL(contactPicker)
[[NSNotificationCenter defaultCenter] removeObserver:self name:CNContactStoreDidChangeNotification object:nil];

[super dealloc];
}

Expand Down Expand Up @@ -196,7 +196,6 @@ -(void)requestContactsPermissions:(id)args
NSString * error = nil;
int code = 0;
BOOL doPrompt = NO;

if ([TiUtils isIOS9OrGreater]) {
CNAuthorizationStatus permissions = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
switch (permissions) {
Expand Down Expand Up @@ -236,7 +235,7 @@ -(void)requestContactsPermissions:(id)args
}, NO);
return;
}

ABAuthorizationStatus permissions = ABAddressBookGetAuthorizationStatus();
switch (permissions) {
case kABAuthorizationStatusNotDetermined:
Expand Down Expand Up @@ -284,15 +283,14 @@ -(NSNumber*) contactsAuthorization
CNAuthorizationStatus result = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
return [NSNumber numberWithInt:result];
}

ABAuthorizationStatus result = ABAddressBookGetAuthorizationStatus();
return [NSNumber numberWithLong:result];
}

-(void)save:(id)unused
{
ENSURE_UI_THREAD(save, unused)

if ([TiUtils isIOS9OrGreater]) {
CNContactStore *ourContactStore = [self contactStore];
if (ourContactStore == NULL) {
Expand All @@ -308,10 +306,10 @@ -(void)save:(id)unused
subreason:nil
location:CODELOCATION];
};
saveRequest = nil;
RELEASE_TO_NIL(saveRequest)
return;
}

CFErrorRef error;
ABAddressBookRef ourAddressBook = [self addressBook];
if (ourAddressBook == NULL) {
Expand Down Expand Up @@ -348,11 +346,9 @@ -(void)showContacts:(id)args
RELEASE_TO_NIL(selectedPropertyCallback)
RELEASE_TO_NIL(picker)
RELEASE_TO_NIL(contactPicker)

cancelCallback = [[args objectForKey:@"cancel"] retain];
selectedPersonCallback = [[args objectForKey:@"selectedPerson"] retain];
selectedPropertyCallback = [[args objectForKey:@"selectedProperty"] retain];

if ([TiUtils isIOS9OrGreater]) {
contactPicker = [[CNContactPickerViewController alloc] init];
[contactPicker setDelegate:self];
Expand Down Expand Up @@ -383,7 +379,6 @@ -(void)showContacts:(id)args
return;

}

picker = [[ABPeoplePickerNavigationController alloc] init];
[picker setPeoplePickerDelegate:self];

Expand Down Expand Up @@ -498,7 +493,10 @@ -(TiContactsPerson*)getPersonByIdentifier:(id)arg
if (error) {
return nil;
}
return [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact *)contact module:self] autorelease];
return [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext]
contactId:(CNMutableContact *)contact
module:self
observer:self] autorelease];
}

//New in iOS9
Expand Down Expand Up @@ -557,7 +555,10 @@ -(NSArray*)getPeopleWithName:(id)arg
}
NSMutableArray* people = [NSMutableArray arrayWithCapacity:[contacts count]];
for (CNContact *personRef in contacts) {
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact *)personRef module:self] autorelease];
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext]
contactId:(CNMutableContact *)personRef
module:self
observer:self] autorelease];
[people addObject:person];
}
return people;
Expand Down Expand Up @@ -604,7 +605,7 @@ -(NSArray*)getAllPeople:(id)unused
//this fetch request takes all information. Not advised to use this method if addressbook is huge. May result in performance issues.
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:[ContactsModule contactKeysWithImage]];
BOOL success = [ourContactStore enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * __nonnull contact, BOOL * __nonnull stop) {
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contact module:self] autorelease];
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contact module:self observer:self] autorelease];
[peopleRefs addObject:person];
}];
RELEASE_TO_NIL(fetchRequest)
Expand Down Expand Up @@ -716,12 +717,16 @@ -(TiContactsPerson*)createPerson:(id)arg
}
NSError *error = nil;
CNMutableContact *newContact = [[CNMutableContact alloc] init];
TiContactsPerson* newPerson = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:newContact module:self] autorelease];
// We dont set observer here because we dont want to be notified when props are being added to a newly created contact.
TiContactsPerson* newPerson = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may should consider to leave the old initializer in place, because module developers might use the interface their modules. Also, we don't need to nil the observer on those.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats right. Retained old initialiser and made the new initialiser as the designated initialiser.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change removes the required arguments contactId:newContact module:self. Did you test the changes?

contactId:newContact
module:self] autorelease];
RELEASE_TO_NIL(newContact);
[newPerson setValuesForKeysWithDictionary:arg];
[newPerson updateiOS9ContactProperties];
saveRequest = [newPerson getSaveRequestForAddition:[ourContactStore defaultContainerIdentifier]];
[self save:nil];
newPerson.observer = self;
return newPerson;
}

Expand Down Expand Up @@ -770,14 +775,13 @@ -(void)removePerson:(id)arg
{
ENSURE_SINGLE_ARG(arg,TiContactsPerson)
ENSURE_UI_THREAD(removePerson,arg)

if([TiUtils isIOS9OrGreater]) {
TiContactsPerson *person = arg;
saveRequest = nil;
saveRequest = [person getSaveRequestForDeletion];
return;
}

[self removeRecord:[arg record]];
}

Expand Down Expand Up @@ -857,7 +861,6 @@ -(void)removeGroup:(id)arg
{
ENSURE_SINGLE_ARG(arg,TiContactsGroup)
ENSURE_UI_THREAD(removeGroup,arg)

if([TiUtils isIOS9OrGreater]) {
TiContactsGroup *group = arg;
saveRequest = nil;
Expand Down Expand Up @@ -1017,11 +1020,12 @@ - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)pe
{
[self peoplePickerNavigationController:peoplePicker shouldContinueAfterSelectingPerson:person property:property identifier:identifier];
}

//iOS9 delegates
- (void)contactPicker:(nonnull CNContactPickerViewController *)picker didSelectContact:(nonnull CNContact *)contact
{
if (selectedPersonCallback) {
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contact module:self] autorelease];
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contact module:self observer:self] autorelease];
[self _fireEventToListener:@"selectedPerson"
withObject:[NSDictionary dictionaryWithObject:person forKey:@"person"]
listener:selectedPersonCallback
Expand All @@ -1038,7 +1042,7 @@ - (void)contactPicker:(nonnull CNContactPickerViewController *)picker didSelectC
- (void)contactPicker:(nonnull CNContactPickerViewController *)picker didSelectContactProperty:(nonnull CNContactProperty *)contactProperty
{
if (selectedPropertyCallback) {
TiContactsPerson *personObject = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contactProperty.contact module:self] autorelease];
TiContactsPerson* personObject = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contactProperty.contact module:self observer:self] autorelease];

id value = contactProperty.value;
id result = [NSNull null];
Expand Down Expand Up @@ -1134,6 +1138,12 @@ - (void)contactViewController:(nonnull CNContactViewController *)viewController
{

}

#pragma mark - TiContactsPersonUpdateObserver
- (void)didUpdatePerson:(TiContactsPerson*)person {
saveRequest = saveRequest ? saveRequest : [CNSaveRequest new];
[saveRequest updateContact:person.nativePerson];
}
@end

#endif
12 changes: 9 additions & 3 deletions iphone/Classes/TiContactsGroup.m
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ -(NSArray*)members:(id)unused
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:[ContactsModule contactKeysWithImage]];
fetchRequest.predicate = [CNContact predicateForContactsInGroupWithIdentifier:[group identifier]];
BOOL success = [ourContactStore enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * __nonnull contact, BOOL * __nonnull stop) {
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contact module:module] autorelease];
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext]
contactId:(CNMutableContact*)contact
module:module
observer:module] autorelease];
[peopleRefs addObject:person];
}];
if (success) {
Expand Down Expand Up @@ -211,7 +214,11 @@ -(NSArray*)sortedMembers:(id)value
fetchRequest.sortOrder = sortOrder;
fetchRequest.mutableObjects = YES;
BOOL success = [ourContactStore enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * __nonnull contact, BOOL * __nonnull stop) {
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext] contactId:(CNMutableContact*)contact module:module] autorelease];
// Observer is module because we want all changes to be propagated and the respective CNSaveRequest is updated.
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[self executionContext]
contactId:(CNMutableContact*)contact
module:module
observer:module] autorelease];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the observer be module or self? Just want to make sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hansemannn observer is module because we want to propagate all changes to the ContactsModule where saveRequest is updated. Added a note in code to be clear.

[peopleRefs addObject:person];
}];
RELEASE_TO_NIL(fetchRequest)
Expand Down Expand Up @@ -259,7 +266,6 @@ -(void)add:(id)arg
{
ENSURE_SINGLE_ARG(arg,TiContactsPerson)
ENSURE_UI_THREAD(add,arg);

if ([TiUtils isIOS9OrGreater]) {
TiContactsPerson *person = arg;
CNContactStore *ourContactStore = [module contactStore];
Expand Down
17 changes: 16 additions & 1 deletion iphone/Classes/TiContactsPerson.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
#import <AddressBook/AddressBook.h>
#import <Contacts/Contacts.h>

@class TiContactsPerson;
@protocol TiContactsPersonUpdateObserver <NSObject>
@optional
- (void)didUpdatePerson:(TiContactsPerson*)person;
@end

@class ContactsModule;

@interface TiContactsPerson : TiProxy {
Expand All @@ -31,10 +37,19 @@

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the initializer I wanted to stay there (with no observer), so modules can still use it.

-(id)_initWithPageContext:(id<TiEvaluator>)context recordId:(ABRecordID)id_ module:(ContactsModule*)module_;
-(id)_initWithPageContext:(id<TiEvaluator>)context person:(ABRecordRef)person_ module:(ContactsModule*)module_;

@property(readonly,nonatomic) NSString* identifier;
@property(assign, nonatomic) id<TiContactsPersonUpdateObserver> observer;

+(NSDictionary*)iOS9multiValueLabels;
+(NSDictionary*)iOS9propertyKeys;
-(id)_initWithPageContext:(id<TiEvaluator>)context contactId:(CNMutableContact*)person_ module:(ContactsModule*)module_;
-(id)_initWithPageContext:(id<TiEvaluator>)context
contactId:(CNMutableContact*)person_
module:(ContactsModule*)module_;
-(id)_initWithPageContext:(id<TiEvaluator>)context
contactId:(CNMutableContact*)person_
module:(ContactsModule*)module_
observer:(id<TiContactsPersonUpdateObserver>) observer_;
-(CNSaveRequest*)getSaveRequestForDeletion;
-(CNSaveRequest*)getSaveRequestForAddition:(NSString*)containerIdentifier;
-(CNSaveRequest*)getSaveRequestForAddToGroup: (CNMutableGroup*) group;
Expand Down