element-ios/matrixConsole/API/ContactManager.m
ylecollen 92f1e2f602 -> use the new MXRestClient::lookup3pids method
The matrix IDs are retrieved in one time instead of getting them one by one

-> ConsoleEmail and ConsolePhoneNumber inherit of ConsoleContactField.
ConsoleContactField manages the matrix part (id + thumbnail download...)

-> the unknown room members are added into the contacts list.
Thus, it would easier to start a chat.
2015-01-22 12:01:12 +01:00

279 lines
13 KiB
Objective-C

/*
Copyright 2014 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "ContactManager.h"
#import "ConsoleContact.h"
#import "ConsolePhoneNumber.h"
#import "ConsoleEmail.h"
#import "MatrixHandler.h"
// warn when there is a contacts list refresh
NSString *const kContactManagerRefreshNotification = @"kContactManagerRefreshNotification";
@implementation ContactManager
@synthesize contacts;
#pragma mark Singleton Methods
static ContactManager* sharedContactManager = nil;
+ (id)sharedManager {
@synchronized(self) {
if(sharedContactManager == nil)
sharedContactManager = [[self alloc] init];
}
return sharedContactManager;
}
#pragma mark -
-(ContactManager *)init {
if (self = [super init]) {
NSString *label = [NSString stringWithFormat:@"ConsoleMatrix.%@.Contacts", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]];
processingQueue = dispatch_queue_create([label UTF8String], NULL);
// put an empty array instead of nil
contacts = [[NSMutableArray alloc] init];
// check if the application is allowed to list the contacts
ABAuthorizationStatus cbStatus = ABAddressBookGetAuthorizationStatus();
// did not yet request the access
if (cbStatus == kABAuthorizationStatusNotDetermined) {
// request address book access
ABAddressBookRef ab = ABAddressBookCreateWithOptions(nil, nil);
if (ab) {
ABAddressBookRequestAccessWithCompletion(ab, ^(bool granted, CFErrorRef error) {
dispatch_async(dispatch_get_main_queue(), ^{
[self refresh];
});
});
CFRelease(ab);
}
}
}
return self;
}
-(void)dealloc {
}
- (void)refresh
{
// did not yet request the access
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
// wait that the user gives the Authorization
return;
}
//
matrixIDBy3PID = [[NSMutableDictionary alloc] init];
dispatch_async(processingQueue, ^{
ABAddressBookRef ab = ABAddressBookCreateWithOptions(nil, nil);
ABRecordRef contactRecord;
int index;
//CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
CFMutableArrayRef people = (CFMutableArrayRef)ABAddressBookCopyArrayOfAllPeople(ab);
NSMutableArray* contactsList = [[NSMutableArray alloc] init];
if (nil != people) {
int peopleCount = CFArrayGetCount(people);
for (index = 0; index < peopleCount; index++) {
contactRecord = (ABRecordRef)CFArrayGetValueAtIndex(people, index);
[contactsList addObject:[[ConsoleContact alloc] initWithABRecord:contactRecord]];
}
CFRelease(people);
}
if (ab) {
CFRelease(ab);
}
contacts = contactsList;
dispatch_async(dispatch_get_main_queue(), ^{
[self refreshMatrixIDs];
[[NSNotificationCenter defaultCenter] postNotificationName:kContactManagerRefreshNotification object:nil userInfo:nil];
});
});
}
- (void)refreshMatrixIDs {
// build the request parameters
NSMutableArray* pids = [[NSMutableArray alloc] init];
NSMutableArray* medias = [[NSMutableArray alloc] init];
for(ConsoleContact* contact in contacts) {
// the phonenumbers are not managed
/*for(ConsolePhoneNumber* pn in contact.phoneNumbers) {
if (pn.textNumber.length > 0) {
// not yet added
if ([pids indexOfObject:pn.textNumber] == NSNotFound) {
[pids addObject:pn.textNumber];
[medias addObject:@"msisdn"];
}
}
}*/
for(ConsoleEmail* email in contact.emailAddresses) {
if (email.emailAddress.length > 0) {
// not yet added
if ([pids indexOfObject:email.emailAddress] == NSNotFound) {
[pids addObject:email.emailAddress];
[medias addObject:@"email"];
}
}
}
}
// get some pids
if (pids.count > 0) {
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
if (mxHandler.mxRestClient) {
[mxHandler.mxRestClient lookup3pids:pids
forMedia:medias
success:^(NSArray *userIds) {
// sanity check
if (userIds.count == pids.count) {
matrixIDBy3PID = [[NSMutableDictionary alloc] initWithObjects:userIds forKeys:pids];
for(ConsoleContact* contact in contacts) {
// the phonenumbers wil be managed later
/*for(ConsolePhoneNumber* pn in contact.phoneNumbers) {
if (pn.textNumber.length > 0) {
// not yet added
if ([pids indexOfObject:pn.textNumber] == NSNotFound) {
[pids addObject:pn.textNumber];
[medias addObject:@"msisdn"];
}
}
}*/
for(ConsoleEmail* email in contact.emailAddresses) {
if (email.emailAddress.length > 0) {
id matrixID = [matrixIDBy3PID valueForKey:email.emailAddress];
if ([matrixID isKindOfClass:[NSString class]]) {
dispatch_async(dispatch_get_main_queue(), ^{
[email setMatrixID:matrixID];
});
}
}
}
}
// check if the some room users are not defined in the local contacts book
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
// check if the user is already known
NSArray* users = [mxHandler.mxSession users];
NSMutableArray* unknownRoomContacts = [[NSMutableArray alloc] init];
for(MXUser* user in users) {
if ([userIds indexOfObject:user.userId] == NSNotFound) {
NSString* dummyContactID = [NSString stringWithFormat:@"%lu", (unsigned long)user.userId.hash];
// with the current API, there is no way to get the email from the matrxID
ConsoleEmail* email = [[ConsoleEmail alloc] initWithEmailAddress:user.userId type:@"" contactID:dummyContactID matrixID:user.userId];
ConsoleContact* contact = [[ConsoleContact alloc] initWithDisplayName:(user.displayname ? user.displayname : user.userId) contactID:dummyContactID emails:@[email] phonenumbers:nil];
[unknownRoomContacts addObject:contact];
}
}
// some members are not listed in the contacts
if (unknownRoomContacts.count > 0) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.contacts addObjectsFromArray:unknownRoomContacts];
[[NSNotificationCenter defaultCenter] postNotificationName:kContactManagerRefreshNotification object:nil userInfo:nil];
});
}
}
}
failure:^(NSError *error) {
// try later
dispatch_after(dispatch_walltime(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self refreshMatrixIDs];
});
}
];
}
}
}
- (SectionedContacts *)getSectionedContacts:(NSArray*)contactsList {
UILocalizedIndexedCollation *collation = [UILocalizedIndexedCollation currentCollation];
int indexOffset = 0;
NSInteger index, sectionTitlesCount = [[collation sectionTitles] count];
NSMutableArray *tmpSectionsArray = [[NSMutableArray alloc] initWithCapacity:(sectionTitlesCount)];
sectionTitlesCount += indexOffset;
for (index = 0; index < sectionTitlesCount; index++) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[tmpSectionsArray addObject:array];
}
int contactsCount = 0;
for (ConsoleContact *aContact in contactsList)
{
NSInteger section = [collation sectionForObject:aContact collationStringSelector:@selector(displayName)] + indexOffset;
[[tmpSectionsArray objectAtIndex:section] addObject:aContact];
++contactsCount;
}
NSMutableArray *tmpSectionedContactsTitle = [[NSMutableArray alloc] initWithCapacity:sectionTitlesCount];
NSMutableArray *shortSectionsArray = [[NSMutableArray alloc] initWithCapacity:sectionTitlesCount];
for (index = indexOffset; index < sectionTitlesCount; index++) {
NSMutableArray *usersArrayForSection = [tmpSectionsArray objectAtIndex:index];
if ([usersArrayForSection count] != 0) {
NSArray* sortedUsersArrayForSection = [collation sortedArrayFromArray:usersArrayForSection collationStringSelector:@selector(displayName)];
[shortSectionsArray addObject:sortedUsersArrayForSection];
[tmpSectionedContactsTitle addObject:[[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:(index - indexOffset)]];
}
}
return [[SectionedContacts alloc] initWithContacts:shortSectionsArray andTitles:tmpSectionedContactsTitle andCount:contactsCount];
}
@end