mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 02:58:07 +00:00
Contact: factorize code to handle either native contacts and/or LinphoneFriends
This commit is contained in:
parent
6a1faf8dbf
commit
e5f2d89847
20 changed files with 311 additions and 309 deletions
|
|
@ -35,8 +35,7 @@
|
|||
|
||||
[_allContacts enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
|
||||
NSString *address = (NSString *)key;
|
||||
ABRecordRef person = (__bridge ABRecordRef)(value);
|
||||
NSString *name = [FastAddressBook displayNameForContact:person];
|
||||
NSString *name = [FastAddressBook displayNameForContact:value];
|
||||
if ((filter.length == 0) || ([name.lowercaseString containsSubstring:filter.lowercaseString]) ||
|
||||
([address.lowercaseString containsSubstring:filter.lowercaseString])) {
|
||||
_contacts[address] = name;
|
||||
|
|
|
|||
|
|
@ -13,12 +13,18 @@
|
|||
|
||||
@interface Contact : NSObject
|
||||
|
||||
@property(nonatomic, assign) NSString *firstName;
|
||||
@property(nonatomic, assign) NSString *lastName;
|
||||
@property(nonatomic, readonly) ABRecordRef person;
|
||||
@property(nonatomic, readonly) LinphoneFriend *friend;
|
||||
|
||||
@property(nonatomic, retain) NSString *firstName;
|
||||
@property(nonatomic, retain) NSString *lastName;
|
||||
@property(nonatomic, strong) NSMutableArray *sipAddresses;
|
||||
@property(nonatomic, strong) NSMutableArray *emails;
|
||||
@property(nonatomic, strong) NSMutableArray *phoneNumbers;
|
||||
|
||||
- (UIImage *)avatar:(BOOL)thumbnail;
|
||||
- (NSString *)displayName;
|
||||
|
||||
- (instancetype)initWithPerson:(ABRecordRef)person;
|
||||
- (instancetype)initWithFriend:(LinphoneFriend *) friend;
|
||||
|
||||
|
|
@ -33,5 +39,4 @@
|
|||
- (BOOL)removeSipAddressAtIndex:(NSInteger)index;
|
||||
- (BOOL)removePhoneNumberAtIndex:(NSInteger)index;
|
||||
- (BOOL)removeEmailAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@
|
|||
|
||||
#import "Contact.h"
|
||||
|
||||
@implementation Contact {
|
||||
ABRecordRef person;
|
||||
LinphoneFriend *friend;
|
||||
}
|
||||
@implementation Contact
|
||||
|
||||
- (instancetype)initWithPerson:(ABRecordRef)aperson {
|
||||
return [self initWithPerson:aperson andFriend:NULL];
|
||||
|
|
@ -23,12 +20,12 @@
|
|||
|
||||
- (instancetype)initWithPerson:(ABRecordRef)aperson andFriend:(LinphoneFriend *)afriend {
|
||||
self = [super init];
|
||||
person = aperson;
|
||||
friend = afriend;
|
||||
_person = aperson;
|
||||
_friend = afriend ? linphone_friend_ref(afriend) : NULL;
|
||||
|
||||
if (person) {
|
||||
if (_person) {
|
||||
[self loadProperties];
|
||||
} else if (friend) {
|
||||
} else if (_friend) {
|
||||
[self loadFriend];
|
||||
} else {
|
||||
LOGE(@"Contact cannot be initialized");
|
||||
|
|
@ -41,20 +38,72 @@
|
|||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (person != nil && ABRecordGetRecordID(person) == kABRecordInvalidID) {
|
||||
CFRelease(person);
|
||||
if (_person != nil && ABRecordGetRecordID(_person) == kABRecordInvalidID) {
|
||||
CFRelease(_person);
|
||||
}
|
||||
person = nil;
|
||||
friend = NULL;
|
||||
if (_friend) {
|
||||
linphone_friend_unref(_friend);
|
||||
}
|
||||
_person = nil;
|
||||
_friend = NULL;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
- (UIImage *)avatar:(BOOL)thumbnail {
|
||||
if (_person && ABPersonHasImageData(_person)) {
|
||||
NSData *imgData = CFBridgingRelease(ABPersonCopyImageDataWithFormat(
|
||||
_person, thumbnail ? kABPersonImageFormatThumbnail : kABPersonImageFormatOriginalSize));
|
||||
return [UIImage imageWithData:imgData];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)displayName {
|
||||
if (_person != nil) {
|
||||
NSString *lFirstName = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonFirstNameProperty));
|
||||
NSString *lLocalizedFirstName = [FastAddressBook localizedLabel:lFirstName];
|
||||
NSString *compositeName = CFBridgingRelease(ABRecordCopyCompositeName(_person));
|
||||
|
||||
NSString *lLastName = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonLastNameProperty));
|
||||
NSString *lLocalizedLastName = [FastAddressBook localizedLabel:lLastName];
|
||||
|
||||
NSString *lOrganization = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonOrganizationProperty));
|
||||
NSString *lLocalizedOrganization = [FastAddressBook localizedLabel:lOrganization];
|
||||
|
||||
if (compositeName) {
|
||||
return compositeName;
|
||||
} else if (lLocalizedFirstName || lLocalizedLastName) {
|
||||
return [NSString stringWithFormat:@"%@ %@", lLocalizedFirstName, lLocalizedLastName];
|
||||
} else {
|
||||
return (NSString *)lLocalizedOrganization;
|
||||
}
|
||||
} else if (_friend) {
|
||||
const char *dp = linphone_address_get_display_name(linphone_friend_get_address(_friend));
|
||||
if (dp)
|
||||
return [NSString stringWithUTF8String:dp];
|
||||
}
|
||||
|
||||
if (_lastName || _firstName) {
|
||||
NSMutableString *str;
|
||||
if (_firstName)
|
||||
[str appendString:_firstName];
|
||||
if (_firstName && _lastName)
|
||||
[str appendString:@" "];
|
||||
if (_lastName)
|
||||
[str appendString:_lastName];
|
||||
}
|
||||
|
||||
return NSLocalizedString(@"Unknown", nil);
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setFirstName:(NSString *)firstName {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = ([self replaceInProperty:kABPersonFirstNameProperty value:(__bridge CFTypeRef)(firstName)]);
|
||||
} else {
|
||||
ret = (linphone_friend_set_name(friend, firstName.UTF8String) == 0);
|
||||
ret = (linphone_friend_set_name(_friend, firstName.UTF8String) == 0);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
|
|
@ -64,7 +113,7 @@
|
|||
|
||||
- (void)setLastName:(NSString *)lastName {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = ([self replaceInProperty:kABPersonLastNameProperty value:(__bridge CFTypeRef)(lastName)]);
|
||||
} else {
|
||||
LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__);
|
||||
|
|
@ -77,7 +126,7 @@
|
|||
|
||||
- (BOOL)setSipAddress:(NSString *)sip atIndex:(NSInteger)index {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
NSDictionary *lDict = @{
|
||||
(NSString *) kABPersonInstantMessageUsernameKey : sip, (NSString *)
|
||||
kABPersonInstantMessageServiceKey : LinphoneManager.instance.contactSipField
|
||||
|
|
@ -96,7 +145,7 @@
|
|||
|
||||
- (BOOL)setPhoneNumber:(NSString *)phone atIndex:(NSInteger)index {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = [self replaceInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone) atIndex:index];
|
||||
} else {
|
||||
LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__);
|
||||
|
|
@ -109,7 +158,7 @@
|
|||
|
||||
- (BOOL)setEmail:(NSString *)email atIndex:(NSInteger)index {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = [self replaceInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email) atIndex:index];
|
||||
} else {
|
||||
}
|
||||
|
|
@ -121,7 +170,7 @@
|
|||
|
||||
- (BOOL)addSipAddress:(NSString *)sip {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
NSDictionary *lDict = @{
|
||||
(NSString *) kABPersonInstantMessageUsernameKey : sip, (NSString *)
|
||||
kABPersonInstantMessageServiceKey : LinphoneManager.instance.contactSipField
|
||||
|
|
@ -129,13 +178,13 @@
|
|||
|
||||
ret = [self addInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict)];
|
||||
} else {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, sip.UTF8String);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, sip.UTF8String) ?: linphone_address_new(sip.UTF8String);
|
||||
if (addr) {
|
||||
ret = TRUE;
|
||||
linphone_friend_add_address(friend, addr);
|
||||
linphone_friend_add_address(_friend, addr);
|
||||
linphone_address_destroy(addr);
|
||||
// ensure that it was added by checking list size
|
||||
ret = (ms_list_size(linphone_friend_get_addresses(friend)) == _sipAddresses.count + 1);
|
||||
ret = (ms_list_size(linphone_friend_get_addresses(_friend)) == _sipAddresses.count + 1);
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
|
|
@ -146,16 +195,17 @@
|
|||
|
||||
- (BOOL)addPhoneNumber:(NSString *)phone {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = [self addInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone)];
|
||||
} else {
|
||||
char *cphone = linphone_proxy_config_normalize_phone_number(NULL, phone.UTF8String);
|
||||
char *cphone =
|
||||
linphone_proxy_config_normalize_phone_number(NULL, phone.UTF8String) ?: ms_strdup(phone.UTF8String);
|
||||
if (cphone) {
|
||||
linphone_friend_add_phone_number(friend, cphone);
|
||||
linphone_friend_add_phone_number(_friend, cphone);
|
||||
phone = [NSString stringWithUTF8String:cphone];
|
||||
ms_free(cphone);
|
||||
// ensure that it was added by checking list size
|
||||
ret = (ms_list_size(linphone_friend_get_phone_numbers(friend)) == _phoneNumbers.count + 1);
|
||||
ret = (ms_list_size(linphone_friend_get_phone_numbers(_friend)) == _phoneNumbers.count + 1);
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
|
|
@ -166,7 +216,7 @@
|
|||
|
||||
- (BOOL)addEmail:(NSString *)email {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = [self addInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email)];
|
||||
} else {
|
||||
LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__);
|
||||
|
|
@ -179,15 +229,15 @@
|
|||
|
||||
- (BOOL)removeSipAddressAtIndex:(NSInteger)index {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = [self removeInProperty:kABPersonInstantMessageProperty atIndex:index];
|
||||
} else {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, ((NSString *)_sipAddresses[index]).UTF8String);
|
||||
if (addr) {
|
||||
linphone_friend_remove_address(friend, addr);
|
||||
linphone_friend_remove_address(_friend, addr);
|
||||
linphone_address_destroy(addr);
|
||||
// ensure that it was destroyed by checking list size
|
||||
ret = (ms_list_size(linphone_friend_get_addresses(friend)) == _sipAddresses.count - 1);
|
||||
ret = (ms_list_size(linphone_friend_get_addresses(_friend)) == _sipAddresses.count - 1);
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
|
|
@ -198,13 +248,13 @@
|
|||
|
||||
- (BOOL)removePhoneNumberAtIndex:(NSInteger)index {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = [self removeInProperty:kABPersonPhoneProperty atIndex:index];
|
||||
} else {
|
||||
const char *phone = ((NSString *)_phoneNumbers[index]).UTF8String;
|
||||
linphone_friend_remove_phone_number(friend, phone);
|
||||
linphone_friend_remove_phone_number(_friend, phone);
|
||||
// ensure that it was destroyed by checking list size
|
||||
ret = (ms_list_size(linphone_friend_get_phone_numbers(friend)) == _phoneNumbers.count - 1);
|
||||
ret = (ms_list_size(linphone_friend_get_phone_numbers(_friend)) == _phoneNumbers.count - 1);
|
||||
}
|
||||
if (ret) {
|
||||
[_phoneNumbers removeObjectAtIndex:index];
|
||||
|
|
@ -214,7 +264,7 @@
|
|||
|
||||
- (BOOL)removeEmailAtIndex:(NSInteger)index {
|
||||
BOOL ret = FALSE;
|
||||
if (person) {
|
||||
if (_person) {
|
||||
ret = [self removeInProperty:kABPersonEmailProperty atIndex:index];
|
||||
} else {
|
||||
LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__);
|
||||
|
|
@ -230,23 +280,29 @@
|
|||
- (void)loadProperties {
|
||||
// First and Last name
|
||||
{
|
||||
_firstName = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
|
||||
_lastName = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
|
||||
_firstName = (NSString *)CFBridgingRelease(ABRecordCopyValue(_person, kABPersonFirstNameProperty));
|
||||
_lastName = (NSString *)CFBridgingRelease(ABRecordCopyValue(_person, kABPersonLastNameProperty));
|
||||
}
|
||||
|
||||
// Phone numbers
|
||||
{
|
||||
_phoneNumbers = [[NSMutableArray alloc] init];
|
||||
ABMultiValueRef map = ABRecordCopyValue(person, kABPersonPhoneProperty);
|
||||
ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonPhoneProperty);
|
||||
if (map) {
|
||||
for (int i = 0; i < ABMultiValueGetCount(map); ++i) {
|
||||
ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(map, i);
|
||||
NSInteger index = ABMultiValueGetIndexForIdentifier(map, identifier);
|
||||
if (index != -1) {
|
||||
NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(map, index));
|
||||
char *normalizedPhone = linphone_proxy_config_normalize_phone_number(
|
||||
linphone_core_get_default_proxy_config(LC), valueRef.UTF8String);
|
||||
NSString *name = [FastAddressBook
|
||||
normalizeSipURI:normalizedPhone ? [NSString stringWithUTF8String:normalizedPhone] : valueRef];
|
||||
if (valueRef != NULL) {
|
||||
[_phoneNumbers addObject:[FastAddressBook localizedLabel:valueRef]];
|
||||
[_phoneNumbers addObject:name ?: [FastAddressBook localizedLabel:valueRef]];
|
||||
}
|
||||
if (normalizedPhone)
|
||||
ms_free(normalizedPhone);
|
||||
}
|
||||
}
|
||||
CFRelease(map);
|
||||
|
|
@ -256,7 +312,7 @@
|
|||
// SIP (IM)
|
||||
{
|
||||
_sipAddresses = [[NSMutableArray alloc] init];
|
||||
ABMultiValueRef map = ABRecordCopyValue(person, kABPersonInstantMessageProperty);
|
||||
ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonInstantMessageProperty);
|
||||
if (map) {
|
||||
for (int i = 0; i < ABMultiValueGetCount(map); ++i) {
|
||||
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(map, i);
|
||||
|
|
@ -267,7 +323,7 @@
|
|||
NSString *value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey));
|
||||
CFRelease(lDict);
|
||||
if (value != NULL) {
|
||||
[_sipAddresses addObject:value];
|
||||
[_sipAddresses addObject:[FastAddressBook normalizeSipURI:value] ?: value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -279,7 +335,7 @@
|
|||
// Email
|
||||
{
|
||||
_emails = [[NSMutableArray alloc] init];
|
||||
ABMultiValueRef map = ABRecordCopyValue(person, kABPersonEmailProperty);
|
||||
ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonEmailProperty);
|
||||
if (map) {
|
||||
for (int i = 0; i < ABMultiValueGetCount(map); ++i) {
|
||||
ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(map, i);
|
||||
|
|
@ -298,15 +354,15 @@
|
|||
|
||||
- (BOOL)replaceInProperty:(ABPropertyID)property value:(CFTypeRef)value {
|
||||
CFErrorRef error = NULL;
|
||||
if (!ABRecordSetValue(person, property, value, &error)) {
|
||||
LOGE(@"Error when saving property %d in contact %p: Fail(%@)", property, person, error);
|
||||
if (!ABRecordSetValue(_person, property, value, &error)) {
|
||||
LOGE(@"Error when saving property %d in contact %p: Fail(%@)", property, _person, error);
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)replaceInProperty:(ABPropertyID)property value:(CFTypeRef)value atIndex:(NSInteger)index {
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(person, property);
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(_person, property);
|
||||
ABMutableMultiValueRef lMap;
|
||||
if (lcMap != NULL) {
|
||||
lMap = ABMultiValueCreateMutableCopy(lcMap);
|
||||
|
|
@ -327,7 +383,7 @@
|
|||
}
|
||||
|
||||
- (BOOL)addInProperty:(ABPropertyID)property value:(CFTypeRef)value {
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(person, property);
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(_person, property);
|
||||
ABMutableMultiValueRef lMap;
|
||||
if (lcMap != NULL) {
|
||||
lMap = ABMultiValueCreateMutableCopy(lcMap);
|
||||
|
|
@ -349,7 +405,7 @@
|
|||
}
|
||||
|
||||
- (BOOL)removeInProperty:(ABPropertyID)property atIndex:(NSInteger)index {
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(person, property);
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(_person, property);
|
||||
ABMutableMultiValueRef lMap;
|
||||
if (lcMap != NULL) {
|
||||
lMap = ABMultiValueCreateMutableCopy(lcMap);
|
||||
|
|
@ -373,12 +429,15 @@
|
|||
|
||||
- (void)loadFriend {
|
||||
// First and Last name
|
||||
{ _firstName = [NSString stringWithUTF8String:linphone_friend_get_name(friend) ?: ""]; }
|
||||
{
|
||||
_firstName = [NSString stringWithUTF8String:linphone_friend_get_name(_friend) ?: ""];
|
||||
_lastName = nil;
|
||||
}
|
||||
|
||||
// Phone numbers
|
||||
{
|
||||
_phoneNumbers = [[NSMutableArray alloc] init];
|
||||
MSList *numbers = linphone_friend_get_phone_numbers(friend);
|
||||
MSList *numbers = linphone_friend_get_phone_numbers(_friend);
|
||||
while (numbers) {
|
||||
NSString *phone = [NSString stringWithUTF8String:numbers->data];
|
||||
[_phoneNumbers addObject:[FastAddressBook localizedLabel:phone]];
|
||||
|
|
@ -389,7 +448,7 @@
|
|||
// SIP (IM)
|
||||
{
|
||||
_sipAddresses = [[NSMutableArray alloc] init];
|
||||
MSList *sips = linphone_friend_get_addresses(friend);
|
||||
MSList *sips = linphone_friend_get_addresses(_friend);
|
||||
while (sips) {
|
||||
LinphoneAddress *addr = sips->data;
|
||||
char *uri = linphone_address_as_string_uri_only(addr);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@
|
|||
if (rmed) {
|
||||
[tableview deleteRowsAtIndexPaths:@[ path ]
|
||||
withRowAnimation:animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone];
|
||||
} else {
|
||||
LOGW(@"Cannot remove entry at path %@, skipping", path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +85,8 @@
|
|||
NSUInteger count = [self getSectionData:section].count;
|
||||
[tableview insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:count - 1 inSection:section] ]
|
||||
withRowAnimation:animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone];
|
||||
} else {
|
||||
LOGW(@"Cannot add entry '%@' in section %d, skipping", value, section);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,10 @@
|
|||
#import "ImagePickerView.h"
|
||||
|
||||
@interface ContactDetailsView : TPMultiLayoutViewController <UICompositeViewDelegate, ImagePickerDelegate> {
|
||||
ABAddressBookRef addressBook;
|
||||
BOOL inhibUpdate;
|
||||
}
|
||||
|
||||
@property(nonatomic, assign, setter=setContact:) ABRecordRef contact;
|
||||
@property(nonatomic, assign, setter=setContact:) Contact *contact;
|
||||
@property(nonatomic, strong) IBOutlet ContactDetailsTableView *tableController;
|
||||
@property(nonatomic, strong) IBOutlet UIToggleButton *editButton;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *backButton;
|
||||
|
|
@ -49,7 +48,7 @@
|
|||
|
||||
- (void)newContact;
|
||||
- (void)newContact:(NSString *)address;
|
||||
- (void)editContact:(ABRecordRef)contact;
|
||||
- (void)editContact:(ABRecordRef)contact address:(NSString *)address;
|
||||
- (void)setContact:(ABRecordRef)contact;
|
||||
- (void)editContact:(Contact *)contact;
|
||||
- (void)editContact:(Contact *)contact address:(NSString *)address;
|
||||
- (void)setContact:(Contact *)contact;
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -22,46 +22,46 @@
|
|||
|
||||
@implementation ContactDetailsView
|
||||
|
||||
static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context);
|
||||
|
||||
#pragma mark - Lifecycle Functions
|
||||
|
||||
- (id)init {
|
||||
self = [super initWithNibName:NSStringFromClass(self.class) bundle:[NSBundle mainBundle]];
|
||||
if (self != nil) {
|
||||
inhibUpdate = FALSE;
|
||||
addressBook = ABAddressBookCreateWithOptions(nil, nil);
|
||||
ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self));
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(onAddressBookUpdate:)
|
||||
name:kLinphoneAddressBookUpdate
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self));
|
||||
CFRelease(addressBook);
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)onAddressBookUpdate:(NSNotification *)k {
|
||||
if (!inhibUpdate && ![_tableController isEditing]) {
|
||||
[self resetData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetData {
|
||||
if (self.isEditing) {
|
||||
[self setEditing:FALSE];
|
||||
}
|
||||
if (_contact == NULL) {
|
||||
ABAddressBookRevert(addressBook);
|
||||
return;
|
||||
}
|
||||
|
||||
ABRecordID recordID = ABRecordGetRecordID(_contact);
|
||||
ABAddressBookRevert(addressBook);
|
||||
_contact = ABAddressBookGetPersonWithRecordID(addressBook, recordID);
|
||||
|
||||
if (_contact != NULL) {
|
||||
LOGI(@"Reset data to contact %p", _contact);
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact thumbnail:NO]
|
||||
bordered:NO
|
||||
withRoundedRadius:YES];
|
||||
[_tableController setContact:[[Contact alloc] initWithPerson:_contact]];
|
||||
[_tableController setContact:_contact];
|
||||
_emptyLabel.hidden = YES;
|
||||
} else {
|
||||
_emptyLabel.hidden = NO;
|
||||
|
|
@ -71,13 +71,6 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
}
|
||||
}
|
||||
|
||||
static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) {
|
||||
ContactDetailsView *controller = (__bridge ContactDetailsView *)context;
|
||||
if (!controller->inhibUpdate && ![[controller tableController] isEditing]) {
|
||||
[controller resetData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeContact {
|
||||
if (_contact != NULL) {
|
||||
inhibUpdate = TRUE;
|
||||
|
|
@ -94,41 +87,20 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
}
|
||||
|
||||
// Add contact to book
|
||||
CFErrorRef error = NULL;
|
||||
if (ABRecordGetRecordID(_contact) == kABRecordInvalidID) {
|
||||
ABAddressBookAddRecord(addressBook, _contact, (CFErrorRef *)&error);
|
||||
if (error != NULL) {
|
||||
LOGE(@"Add contact %p: Fail(%@)", _contact, [(__bridge NSError *)error localizedDescription]);
|
||||
} else {
|
||||
LOGI(@"Add contact %p: Success!", _contact);
|
||||
}
|
||||
}
|
||||
|
||||
// Save address book
|
||||
error = NULL;
|
||||
inhibUpdate = TRUE;
|
||||
ABAddressBookSave(addressBook, &error);
|
||||
inhibUpdate = FALSE;
|
||||
if (error != NULL) {
|
||||
LOGE(@"Save AddressBook: Fail(%@)", [(__bridge NSError *)error localizedDescription]);
|
||||
} else {
|
||||
LOGI(@"Save AddressBook: Success!");
|
||||
}
|
||||
[LinphoneManager.instance.fastAddressBook reload];
|
||||
[LinphoneManager.instance.fastAddressBook saveContact:_contact];
|
||||
}
|
||||
|
||||
- (void)selectContact:(ABRecordRef)acontact andReload:(BOOL)reload {
|
||||
- (void)selectContact:(Contact *)acontact andReload:(BOOL)reload {
|
||||
if (self.isEditing) {
|
||||
[self setEditing:FALSE];
|
||||
}
|
||||
ABAddressBookRevert(addressBook);
|
||||
|
||||
_contact = acontact;
|
||||
_emptyLabel.hidden = (_contact != NULL);
|
||||
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact thumbnail:NO] bordered:NO withRoundedRadius:YES];
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:acontact];
|
||||
[_tableController setContact:[[Contact alloc] initWithPerson:_contact]];
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];
|
||||
[_tableController setContact:_contact];
|
||||
|
||||
if (reload) {
|
||||
[self setEditing:TRUE animated:FALSE];
|
||||
|
|
@ -157,25 +129,25 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
}
|
||||
|
||||
- (void)newContact {
|
||||
[self selectContact:ABPersonCreate() andReload:YES];
|
||||
[self selectContact:[[Contact alloc] initWithPerson:ABPersonCreate()] andReload:YES];
|
||||
}
|
||||
|
||||
- (void)newContact:(NSString *)address {
|
||||
[self selectContact:ABPersonCreate() andReload:NO];
|
||||
[self selectContact:[[Contact alloc] initWithPerson:ABPersonCreate()] andReload:NO];
|
||||
[self addCurrentContactContactField:address];
|
||||
}
|
||||
|
||||
- (void)editContact:(ABRecordRef)acontact {
|
||||
[self selectContact:ABAddressBookGetPersonWithRecordID(addressBook, ABRecordGetRecordID(acontact)) andReload:YES];
|
||||
- (void)editContact:(Contact *)acontact {
|
||||
[self selectContact:acontact andReload:YES];
|
||||
}
|
||||
|
||||
- (void)editContact:(ABRecordRef)acontact address:(NSString *)address {
|
||||
[self selectContact:ABAddressBookGetPersonWithRecordID(addressBook, ABRecordGetRecordID(acontact)) andReload:NO];
|
||||
- (void)editContact:(Contact *)acontact address:(NSString *)address {
|
||||
[self selectContact:acontact andReload:NO];
|
||||
[self addCurrentContactContactField:address];
|
||||
}
|
||||
|
||||
- (void)setContact:(ABRecordRef)acontact {
|
||||
[self selectContact:ABAddressBookGetPersonWithRecordID(addressBook, ABRecordGetRecordID(acontact)) andReload:NO];
|
||||
- (void)setContact:(Contact *)acontact {
|
||||
[self selectContact:acontact andReload:NO];
|
||||
}
|
||||
|
||||
#pragma mark - ViewController Functions
|
||||
|
|
@ -348,23 +320,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[VIEW(ImagePickerView).popoverController dismissPopoverAnimated:TRUE];
|
||||
}
|
||||
|
||||
FastAddressBook *fab = LinphoneManager.instance.fastAddressBook;
|
||||
CFErrorRef error = NULL;
|
||||
if (!ABPersonRemoveImageData(_contact, (CFErrorRef *)&error)) {
|
||||
LOGI(@"Can't remove entry: %@", [(__bridge NSError *)error localizedDescription]);
|
||||
}
|
||||
NSData *dataRef = UIImageJPEGRepresentation(image, 0.9f);
|
||||
CFDataRef cfdata = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);
|
||||
|
||||
[fab saveAddressBook];
|
||||
|
||||
if (!ABPersonSetImageData(_contact, cfdata, (CFErrorRef *)&error)) {
|
||||
LOGI(@"Can't add entry: %@", [(__bridge NSError *)error localizedDescription]);
|
||||
} else {
|
||||
[fab saveAddressBook];
|
||||
}
|
||||
|
||||
CFRelease(cfdata);
|
||||
[FastAddressBook setAvatar:image forContact:_contact];
|
||||
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact thumbnail:NO] bordered:NO withRoundedRadius:YES];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@
|
|||
@interface ContactsListTableView : UICheckBoxTableView {
|
||||
@private
|
||||
OrderedDictionary *addressBookMap;
|
||||
NSMutableDictionary *avatarMap;
|
||||
|
||||
ABAddressBookRef addressBook;
|
||||
}
|
||||
|
||||
- (void)loadData;
|
||||
|
|
|
|||
|
|
@ -25,17 +25,19 @@
|
|||
|
||||
@implementation ContactsListTableView
|
||||
|
||||
static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context);
|
||||
|
||||
#pragma mark - Lifecycle Functions
|
||||
|
||||
- (void)initContactsTableViewController {
|
||||
addressBookMap = [[OrderedDictionary alloc] init];
|
||||
avatarMap = [[NSMutableDictionary alloc] init];
|
||||
|
||||
addressBook = ABAddressBookCreateWithOptions(nil, nil);
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(onAddressBookUpdate:)
|
||||
name:kLinphoneAddressBookUpdate
|
||||
object:nil];
|
||||
}
|
||||
|
||||
ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self));
|
||||
- (void)onAddressBookUpdate:(NSNotification *)k {
|
||||
[self loadData];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
|
@ -65,9 +67,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (addressBook) {
|
||||
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self));
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
@ -92,7 +92,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) {
|
|||
return (int)(within_sentence != NULL ? 0 : fuzzy_word + strlen(fuzzy_word) - c);
|
||||
}
|
||||
|
||||
- (NSString *)displayNameForContact:(ABRecordRef)person {
|
||||
- (NSString *)displayNameForContact:(Contact *)person {
|
||||
NSString *name = [FastAddressBook displayNameForContact:person];
|
||||
if (name != nil && [name length] > 0 && ![name isEqualToString:NSLocalizedString(@"Unknown", nil)]) {
|
||||
// Add the contact only if it fuzzy match filter too (if any)
|
||||
|
|
@ -116,27 +116,24 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) {
|
|||
// Reset Address book
|
||||
[addressBookMap removeAllObjects];
|
||||
|
||||
NSArray *lContacts = (NSArray *)CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
|
||||
for (id lPerson in lContacts) {
|
||||
for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) {
|
||||
Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr];
|
||||
|
||||
BOOL add = true;
|
||||
ABRecordRef person = (__bridge ABRecordRef)lPerson;
|
||||
|
||||
// Do not add the contact directly if we set some filter
|
||||
if ([ContactSelection getSipFilter] || [ContactSelection emailFilterEnabled]) {
|
||||
add = false;
|
||||
}
|
||||
if ([FastAddressBook contactHasValidSipDomain:person]) {
|
||||
if ([FastAddressBook contactHasValidSipDomain:contact]) {
|
||||
add = true;
|
||||
}
|
||||
if (!add && [ContactSelection emailFilterEnabled]) {
|
||||
ABMultiValueRef personEmailAddresses = ABRecordCopyValue(person, kABPersonEmailProperty);
|
||||
// Add this contact if it has an email
|
||||
add = (ABMultiValueGetCount(personEmailAddresses) > 0);
|
||||
|
||||
CFRelease(personEmailAddresses);
|
||||
add = (contact.emails.count > 0);
|
||||
}
|
||||
|
||||
NSString *name = [self displayNameForContact:person];
|
||||
NSString *name = [self displayNameForContact:contact];
|
||||
if (add && name != nil) {
|
||||
NSString *firstChar = [[name substringToIndex:1] uppercaseString];
|
||||
|
||||
|
|
@ -149,7 +146,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) {
|
|||
subDic = [[OrderedDictionary alloc] init];
|
||||
[addressBookMap insertObject:subDic forKey:firstChar selector:@selector(caseInsensitiveCompare:)];
|
||||
}
|
||||
[subDic insertObject:lPerson forKey:name selector:@selector(caseInsensitiveCompare:)];
|
||||
[subDic insertObject:contact forKey:name selector:@selector(caseInsensitiveCompare:)];
|
||||
}
|
||||
}
|
||||
[super loadData];
|
||||
|
|
@ -166,13 +163,6 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) {
|
|||
}
|
||||
}
|
||||
|
||||
static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) {
|
||||
ContactsListTableView *controller = (__bridge ContactsListTableView *)context;
|
||||
ABAddressBookRevert(addressBook);
|
||||
[controller->avatarMap removeAllObjects];
|
||||
[controller loadData];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource Functions
|
||||
|
||||
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
|
||||
|
|
@ -200,14 +190,10 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
if (cell == nil) {
|
||||
cell = [[UIContactCell alloc] initWithIdentifier:kCellId];
|
||||
}
|
||||
ABRecordRef contact = [self contactForIndexPath:indexPath];
|
||||
Contact *contact = [self contactForIndexPath:indexPath];
|
||||
|
||||
// Cached avatar
|
||||
UIImage *image = [avatarMap objectForKey:[NSNumber numberWithInt:ABRecordGetRecordID(contact)]];
|
||||
if (image == nil) {
|
||||
image = [FastAddressBook imageForContact:contact thumbnail:true];
|
||||
[avatarMap setObject:image forKey:[NSNumber numberWithInt:ABRecordGetRecordID(contact)]];
|
||||
}
|
||||
UIImage *image = [FastAddressBook imageForContact:contact thumbnail:true];
|
||||
[cell.avatarImage setImage:image bordered:NO withRoundedRadius:YES];
|
||||
[cell setContact:contact];
|
||||
[super accessoryForCell:cell atPath:indexPath];
|
||||
|
|
@ -236,15 +222,15 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
|
||||
if (![self isEditing]) {
|
||||
OrderedDictionary *subDic = [addressBookMap objectForKey:[addressBookMap keyAtIndex:[indexPath section]]];
|
||||
ABRecordRef lPerson = (__bridge ABRecordRef)([subDic objectForKey:[subDic keyAtIndex:[indexPath row]]]);
|
||||
Contact *contact = [subDic objectForKey:[subDic keyAtIndex:[indexPath row]]];
|
||||
|
||||
// Go to Contact details view
|
||||
ContactDetailsView *view = VIEW(ContactDetailsView);
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
if (([ContactSelection getSelectionMode] != ContactSelectionModeEdit) || !([ContactSelection getAddAddress])) {
|
||||
[view setContact:lPerson];
|
||||
[view setContact:contact];
|
||||
} else {
|
||||
[view editContact:lPerson address:[ContactSelection getAddAddress]];
|
||||
[view editContact:contact address:[ContactSelection getAddAddress]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -253,39 +239,49 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
|
||||
forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self));
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
[tableView beginUpdates];
|
||||
|
||||
NSString *firstChar = [addressBookMap keyAtIndex:[indexPath section]];
|
||||
OrderedDictionary *subDic = [addressBookMap objectForKey:firstChar];
|
||||
NSString *key = [[subDic allKeys] objectAtIndex:[indexPath row]];
|
||||
ABRecordRef contact = (__bridge ABRecordRef)([subDic objectForKey:key]);
|
||||
Contact *contact = [subDic objectForKey:key];
|
||||
[[addressBookMap objectForKey:firstChar] removeObjectForKey:[self displayNameForContact:contact]];
|
||||
if ([tableView numberOfRowsInSection:indexPath.section] == 1) {
|
||||
[addressBookMap removeObjectForKey:firstChar];
|
||||
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
|
||||
withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
|
||||
[[LinphoneManager.instance fastAddressBook] removeContact:contact];
|
||||
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
|
||||
withRowAnimation:UITableViewRowAnimationFade];
|
||||
[tableView endUpdates];
|
||||
ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self));
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(onAddressBookUpdate:)
|
||||
name:kLinphoneAddressBookUpdate
|
||||
object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeSelectionUsing:(void (^)(NSIndexPath *))remover {
|
||||
[super removeSelectionUsing:^(NSIndexPath *indexPath) {
|
||||
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self));
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
|
||||
NSString *firstChar = [addressBookMap keyAtIndex:[indexPath section]];
|
||||
OrderedDictionary *subDic = [addressBookMap objectForKey:firstChar];
|
||||
NSString *key = [[subDic allKeys] objectAtIndex:[indexPath row]];
|
||||
ABRecordRef contact = (__bridge ABRecordRef)([subDic objectForKey:key]);
|
||||
Contact *contact = [subDic objectForKey:key];
|
||||
[[addressBookMap objectForKey:firstChar] removeObjectForKey:[self displayNameForContact:contact]];
|
||||
if ([self.tableView numberOfRowsInSection:indexPath.section] == 1) {
|
||||
[addressBookMap removeObjectForKey:firstChar];
|
||||
}
|
||||
[[LinphoneManager.instance fastAddressBook] removeContact:contact];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(onAddressBookUpdate:)
|
||||
name:kLinphoneAddressBookUpdate
|
||||
object:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (IBAction)onContactClick:(id)event {
|
||||
LinphoneAddress *addr = linphone_call_log_get_remote_address(callLog);
|
||||
ABRecordRef contact = [FastAddressBook getContactWithAddress:addr];
|
||||
Contact *contact = [FastAddressBook getContactWithAddress:addr];
|
||||
if (contact) {
|
||||
ContactDetailsView *view = VIEW(ContactDetailsView);
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
@property(nonatomic, strong) IBOutlet UILabel *nameLabel;
|
||||
@property(nonatomic, strong) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property(weak, nonatomic) IBOutlet UIImageView *linphoneImage;
|
||||
@property (nonatomic, assign) ABRecordRef contact;
|
||||
@property(nonatomic, assign) Contact *contact;
|
||||
|
||||
- (id)initWithIdentifier:(NSString*)identifier;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
#pragma mark - Property Functions
|
||||
|
||||
- (void)setContact:(ABRecordRef)acontact {
|
||||
- (void)setContact:(Contact *)acontact {
|
||||
_contact = acontact;
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];
|
||||
_linphoneImage.hidden = !([FastAddressBook contactHasValidSipDomain:_contact]);
|
||||
|
|
|
|||
|
|
@ -21,34 +21,35 @@
|
|||
#import <AddressBook/AddressBook.h>
|
||||
|
||||
#include "linphone/linphonecore.h"
|
||||
#include "Contact.h"
|
||||
|
||||
@interface FastAddressBook : NSObject {
|
||||
ABAddressBookRef addressBook;
|
||||
}
|
||||
@interface FastAddressBook : NSObject
|
||||
|
||||
@property(readonly, nonatomic) NSMutableDictionary *addressBookMap;
|
||||
|
||||
- (void)reload;
|
||||
- (void)saveAddressBook;
|
||||
- (int)removeContact:(ABRecordRef)contact;
|
||||
- (int)removeContact:(Contact *)contact;
|
||||
- (BOOL)saveContact:(Contact *)contact;
|
||||
|
||||
+ (BOOL)isAuthorized;
|
||||
|
||||
// TOOLS
|
||||
|
||||
+ (ABRecordRef)getContactWithAddress:(const LinphoneAddress *)address;
|
||||
+ (Contact *)getContactWithAddress:(const LinphoneAddress *)address;
|
||||
|
||||
+ (UIImage *)imageForContact:(ABRecordRef)contact thumbnail:(BOOL)thumbnail;
|
||||
+ (UIImage *)imageForContact:(Contact *)contact thumbnail:(BOOL)thumbnail;
|
||||
+ (UIImage *)imageForAddress:(const LinphoneAddress *)addr thumbnail:(BOOL)thumbnail;
|
||||
|
||||
+ (BOOL)contactHasValidSipDomain:(ABRecordRef)person;
|
||||
+ (BOOL)contactHasValidSipDomain:(Contact *)person;
|
||||
|
||||
+ (NSString *)displayNameForContact:(ABRecordRef)person;
|
||||
+ (NSString *)displayNameForContact:(Contact *)person;
|
||||
+ (NSString *)displayNameForAddress:(const LinphoneAddress *)addr;
|
||||
|
||||
+ (BOOL)isSipURI:(NSString *)address; // should be removed
|
||||
+ (NSString *)normalizeSipURI:(NSString *)address; // should be removed
|
||||
|
||||
+ (NSString *)localizedLabel:(NSString *)label;
|
||||
+ (void)setAvatar:(UIImage *)avatar forContact:(Contact *)contact;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -22,18 +22,14 @@
|
|||
#import "ContactsListView.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation FastAddressBook
|
||||
@implementation FastAddressBook {
|
||||
ABAddressBookRef addressBook;
|
||||
}
|
||||
|
||||
static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context);
|
||||
|
||||
+ (UIImage *)imageForContact:(ABRecordRef)contact thumbnail:(BOOL)thumbnail {
|
||||
UIImage *retImage = nil;
|
||||
if (contact && ABPersonHasImageData(contact)) {
|
||||
NSData *imgData = CFBridgingRelease(ABPersonCopyImageDataWithFormat(
|
||||
contact, thumbnail ? kABPersonImageFormatThumbnail : kABPersonImageFormatOriginalSize));
|
||||
|
||||
retImage = [UIImage imageWithData:imgData];
|
||||
}
|
||||
+ (UIImage *)imageForContact:(Contact *)contact thumbnail:(BOOL)thumbnail {
|
||||
UIImage *retImage = [contact avatar:thumbnail];
|
||||
if (retImage == nil) {
|
||||
retImage = [UIImage imageNamed:@"avatar.png"];
|
||||
}
|
||||
|
|
@ -50,17 +46,17 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
return [FastAddressBook imageForContact:[FastAddressBook getContactWithAddress:addr] thumbnail:thumbnail];
|
||||
}
|
||||
|
||||
+ (ABRecordRef)getContact:(NSString *)address {
|
||||
+ (Contact *)getContact:(NSString *)address {
|
||||
if (LinphoneManager.instance.fastAddressBook != nil) {
|
||||
@synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) {
|
||||
return (__bridge ABRecordRef)[LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:address];
|
||||
return [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:address];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (ABRecordRef)getContactWithAddress:(const LinphoneAddress *)address {
|
||||
ABRecordRef contact = nil;
|
||||
+ (Contact *)getContactWithAddress:(const LinphoneAddress *)address {
|
||||
Contact *contact = nil;
|
||||
if (address) {
|
||||
char *uri = linphone_address_as_string_uri_only(address);
|
||||
NSString *normalizedSipAddress = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:uri]];
|
||||
|
|
@ -135,67 +131,43 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
}
|
||||
}
|
||||
|
||||
- (void)registerAddrsFor:(Contact *)contact {
|
||||
for (NSString *phone in contact.phoneNumbers) {
|
||||
[_addressBookMap setObject:contact forKey:phone];
|
||||
}
|
||||
for (NSString *sip in contact.sipAddresses) {
|
||||
[_addressBookMap setObject:contact forKey:sip];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadData {
|
||||
@synchronized(_addressBookMap) {
|
||||
ABAddressBookRevert(addressBook);
|
||||
[_addressBookMap removeAllObjects];
|
||||
|
||||
// load native contacts
|
||||
CFArrayRef lContacts = ABAddressBookCopyArrayOfAllPeople(addressBook);
|
||||
CFIndex count = CFArrayGetCount(lContacts);
|
||||
for (CFIndex idx = 0; idx < count; idx++) {
|
||||
ABRecordRef lPerson = CFArrayGetValueAtIndex(lContacts, idx);
|
||||
// Phone
|
||||
{
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(lPerson, kABPersonPhoneProperty);
|
||||
if (lMap) {
|
||||
for (int i = 0; i < ABMultiValueGetCount(lMap); i++) {
|
||||
NSString *lValue = (__bridge NSString *)ABMultiValueCopyValueAtIndex(lMap, i);
|
||||
char *normalizedPhone = linphone_proxy_config_normalize_phone_number(
|
||||
linphone_core_get_default_proxy_config(LC), lValue.UTF8String);
|
||||
NSString *name = [FastAddressBook
|
||||
normalizeSipURI:normalizedPhone ? [NSString stringWithUTF8String:normalizedPhone] : lValue];
|
||||
[_addressBookMap setObject:(__bridge id)(lPerson) forKey:name ?: lValue];
|
||||
if (normalizedPhone)
|
||||
ms_free(normalizedPhone);
|
||||
CFRelease((CFStringRef)lValue);
|
||||
}
|
||||
CFRelease(lMap);
|
||||
}
|
||||
}
|
||||
|
||||
// SIP
|
||||
{
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(lPerson, kABPersonInstantMessageProperty);
|
||||
if (lMap) {
|
||||
for (int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
|
||||
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i);
|
||||
BOOL add = false;
|
||||
if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
|
||||
if (CFStringCompare((CFStringRef)LinphoneManager.instance.contactSipField,
|
||||
CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey),
|
||||
kCFCompareCaseInsensitive) == 0) {
|
||||
add = true;
|
||||
}
|
||||
} else {
|
||||
add = true;
|
||||
}
|
||||
if (add) {
|
||||
NSString *lValue =
|
||||
(__bridge NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
|
||||
NSString *lNormalizedKey = [FastAddressBook normalizeSipURI:lValue];
|
||||
if (lNormalizedKey != NULL) {
|
||||
[_addressBookMap setObject:(__bridge id)(lPerson) forKey:lNormalizedKey];
|
||||
} else {
|
||||
[_addressBookMap setObject:(__bridge id)(lPerson) forKey:lValue];
|
||||
}
|
||||
}
|
||||
CFRelease(lDict);
|
||||
}
|
||||
CFRelease(lMap);
|
||||
}
|
||||
}
|
||||
Contact *contact = [[Contact alloc] initWithPerson:lPerson];
|
||||
[self registerAddrsFor:contact];
|
||||
}
|
||||
CFRelease(lContacts);
|
||||
|
||||
// load Linphone friends
|
||||
const MSList *lists = linphone_core_get_friends_lists(LC);
|
||||
while (lists) {
|
||||
LinphoneFriendList *fl = lists->data;
|
||||
const MSList *friends = linphone_friend_list_get_friends(fl);
|
||||
while (friends) {
|
||||
LinphoneFriend *f = friends->data;
|
||||
Contact *contact = [[Contact alloc] initWithFriend:f];
|
||||
[self registerAddrsFor:contact];
|
||||
friends = friends->next;
|
||||
}
|
||||
lists = lists->next;
|
||||
}
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneAddressBookUpdate object:self];
|
||||
}
|
||||
|
|
@ -219,74 +191,39 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void
|
|||
return @"";
|
||||
}
|
||||
|
||||
+ (BOOL)contactHasValidSipDomain:(ABRecordRef)person {
|
||||
if (person == nil)
|
||||
+ (BOOL)contactHasValidSipDomain:(Contact *)contact {
|
||||
if (contact == nil)
|
||||
return NO;
|
||||
|
||||
// Check if one of the contact' sip URI matches the expected SIP filter
|
||||
ABMultiValueRef personSipAddresses = ABRecordCopyValue(person, kABPersonInstantMessageProperty);
|
||||
BOOL match = false;
|
||||
NSString *domain = LinphoneManager.instance.contactFilter;
|
||||
|
||||
for (int i = 0; i < ABMultiValueGetCount(personSipAddresses) && !match; ++i) {
|
||||
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(personSipAddresses, i);
|
||||
if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
|
||||
CFStringRef serviceKey = CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey);
|
||||
|
||||
if (CFStringCompare((CFStringRef)LinphoneManager.instance.contactSipField, serviceKey,
|
||||
kCFCompareCaseInsensitive) == 0) {
|
||||
match = true;
|
||||
}
|
||||
} else if (domain != nil) {
|
||||
// check domain
|
||||
LinphoneAddress *address = linphone_core_interpret_url(
|
||||
LC, [(NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey) UTF8String]);
|
||||
|
||||
if (address) {
|
||||
const char *dom = linphone_address_get_domain(address);
|
||||
if (dom != NULL) {
|
||||
NSString *contactDomain =
|
||||
[NSString stringWithCString:dom encoding:[NSString defaultCStringEncoding]];
|
||||
|
||||
match = (([domain compare:@"*" options:NSCaseInsensitiveSearch] == NSOrderedSame) ||
|
||||
([domain compare:contactDomain options:NSCaseInsensitiveSearch] == NSOrderedSame));
|
||||
}
|
||||
linphone_address_destroy(address);
|
||||
for (NSString *sip in contact.sipAddresses) {
|
||||
// check domain
|
||||
LinphoneAddress *address = linphone_core_interpret_url(LC, sip.UTF8String);
|
||||
if (address) {
|
||||
const char *dom = linphone_address_get_domain(address);
|
||||
BOOL match = false;
|
||||
if (dom != NULL) {
|
||||
NSString *contactDomain = [NSString stringWithCString:dom encoding:[NSString defaultCStringEncoding]];
|
||||
match = (([domain compare:@"*" options:NSCaseInsensitiveSearch] == NSOrderedSame) ||
|
||||
([domain compare:contactDomain options:NSCaseInsensitiveSearch] == NSOrderedSame));
|
||||
}
|
||||
linphone_address_destroy(address);
|
||||
if (match)
|
||||
return YES;
|
||||
}
|
||||
CFRelease(lDict);
|
||||
}
|
||||
CFRelease(personSipAddresses);
|
||||
return match;
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSString *)displayNameForContact:(ABRecordRef)contact {
|
||||
NSString *ret = NSLocalizedString(@"Unknown", nil);
|
||||
if (contact != nil) {
|
||||
NSString *lFirstName = CFBridgingRelease(ABRecordCopyValue(contact, kABPersonFirstNameProperty));
|
||||
NSString *lLocalizedFirstName = [FastAddressBook localizedLabel:lFirstName];
|
||||
NSString *compositeName = CFBridgingRelease(ABRecordCopyCompositeName(contact));
|
||||
|
||||
NSString *lLastName = CFBridgingRelease(ABRecordCopyValue(contact, kABPersonLastNameProperty));
|
||||
NSString *lLocalizedLastName = [FastAddressBook localizedLabel:lLastName];
|
||||
|
||||
NSString *lOrganization = CFBridgingRelease(ABRecordCopyValue(contact, kABPersonOrganizationProperty));
|
||||
NSString *lLocalizedOrganization = [FastAddressBook localizedLabel:lOrganization];
|
||||
|
||||
if (compositeName) {
|
||||
ret = compositeName;
|
||||
} else if (lLocalizedFirstName || lLocalizedLastName) {
|
||||
ret = [NSString stringWithFormat:@"%@ %@", lLocalizedFirstName, lLocalizedLastName];
|
||||
} else {
|
||||
ret = (NSString *)lLocalizedOrganization;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
+ (NSString *)displayNameForContact:(Contact *)contact {
|
||||
return contact.displayName;
|
||||
}
|
||||
|
||||
+ (NSString *)displayNameForAddress:(const LinphoneAddress *)addr {
|
||||
NSString *ret = NSLocalizedString(@"Unknown", nil);
|
||||
ABRecordRef contact = [FastAddressBook getContactWithAddress:addr];
|
||||
Contact *contact = [FastAddressBook getContactWithAddress:addr];
|
||||
if (contact) {
|
||||
ret = [FastAddressBook displayNameForContact:contact];
|
||||
} else {
|
||||
|
|
@ -301,11 +238,11 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void
|
|||
return ret;
|
||||
}
|
||||
|
||||
- (int)removeContact:(ABRecordRef)contact {
|
||||
- (int)removeContact:(Contact *)contact {
|
||||
// Remove contact from book
|
||||
if (contact && ABRecordGetRecordID(contact) != kABRecordInvalidID) {
|
||||
if (contact.person && ABRecordGetRecordID(contact.person) != kABRecordInvalidID) {
|
||||
CFErrorRef error = NULL;
|
||||
ABAddressBookRemoveRecord(addressBook, contact, (CFErrorRef *)&error);
|
||||
ABAddressBookRemoveRecord(addressBook, contact.person, (CFErrorRef *)&error);
|
||||
if (error != NULL) {
|
||||
LOGE(@"Remove contact %p: Fail(%@)", contact, [(__bridge NSError *)error localizedDescription]);
|
||||
} else {
|
||||
|
|
@ -328,4 +265,49 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void
|
|||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
- (BOOL)saveContact:(Contact *)contact {
|
||||
CFErrorRef error = NULL;
|
||||
if (ABRecordGetRecordID(contact.person) == kABRecordInvalidID) {
|
||||
ABAddressBookAddRecord(addressBook, contact.person, (CFErrorRef *)&error);
|
||||
if (error != NULL) {
|
||||
LOGE(@"Add contact %p: Fail(%@)", contact.person, [(__bridge NSError *)error localizedDescription]);
|
||||
} else {
|
||||
LOGI(@"Add contact %p: Success!", contact.person);
|
||||
}
|
||||
}
|
||||
|
||||
// Save address book
|
||||
error = NULL;
|
||||
ABAddressBookSave(addressBook, &error);
|
||||
if (error != NULL) {
|
||||
LOGE(@"Save AddressBook: Fail(%@)", [(__bridge NSError *)error localizedDescription]);
|
||||
} else {
|
||||
LOGI(@"Save AddressBook: Success!");
|
||||
}
|
||||
[self reload];
|
||||
|
||||
return error == NULL;
|
||||
}
|
||||
|
||||
+ (void)setAvatar:(UIImage *)avatar forContact:(Contact *)contact {
|
||||
FastAddressBook *fab = LinphoneManager.instance.fastAddressBook;
|
||||
CFErrorRef error = NULL;
|
||||
if (!ABPersonRemoveImageData(contact.person, (CFErrorRef *)&error)) {
|
||||
LOGI(@"Can't remove entry: %@", [(__bridge NSError *)error localizedDescription]);
|
||||
}
|
||||
NSData *dataRef = UIImageJPEGRepresentation(avatar, 0.9f);
|
||||
CFDataRef cfdata = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);
|
||||
|
||||
[fab saveAddressBook];
|
||||
|
||||
if (!ABPersonSetImageData(contact.person, cfdata, (CFErrorRef *)&error)) {
|
||||
LOGI(@"Can't add entry: %@", [(__bridge NSError *)error localizedDescription]);
|
||||
} else {
|
||||
[fab saveAddressBook];
|
||||
}
|
||||
|
||||
CFRelease(cfdata);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ typedef enum {
|
|||
@end
|
||||
|
||||
@interface ContactDisplay : NSObject
|
||||
+ (void)setDisplayNameLabel:(UILabel *)label forContact:(ABRecordRef)contact;
|
||||
+ (void)setDisplayNameLabel:(UILabel *)label forContact:(Contact *)contact;
|
||||
+ (void)setDisplayNameLabel:(UILabel *)label forAddress:(const LinphoneAddress *)addr;
|
||||
@end
|
||||
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@
|
|||
|
||||
@implementation ContactDisplay
|
||||
|
||||
+ (void)setDisplayNameLabel:(UILabel *)label forContact:(ABRecordRef)contact {
|
||||
+ (void)setDisplayNameLabel:(UILabel *)label forContact:(Contact *)contact {
|
||||
label.text = [FastAddressBook displayNameForContact:contact];
|
||||
#if 0
|
||||
NSString *lLastName = CFBridgingRelease(ABRecordCopyValue(contact, kABPersonLastNameProperty));
|
||||
|
|
@ -526,7 +526,7 @@
|
|||
}
|
||||
|
||||
+ (void)setDisplayNameLabel:(UILabel *)label forAddress:(const LinphoneAddress *)addr {
|
||||
const LinphoneFriend *contact = [FastAddressBook getContactWithAddress:addr];
|
||||
Contact *contact = [FastAddressBook getContactWithAddress:addr];
|
||||
if (contact) {
|
||||
[ContactDisplay setDisplayNameLabel:label forContact:contact];
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -27,3 +27,6 @@ ringer_dev_id=AQ: Audio Queue Device
|
|||
|
||||
[video]
|
||||
display_filter_auto_rotate=0
|
||||
|
||||
[friend_0]
|
||||
url="gautier.pelloux" <sip:gautier.pelloux@sip.linphone.org>
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#import "Log.h"
|
||||
#import "Utils.h"
|
||||
#import "Contact.h"
|
||||
|
||||
#import "UIToggleButton.h"
|
||||
#import "UISpeakerButton.h"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 0f29972001c023ead9041412c64d7f1ab46434f7
|
||||
Subproject commit e654c008283c942345ac20540981ba854d9138ba
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit d04ec58fa4c162634d32cce9ebcd3bdc3d07aa89
|
||||
Subproject commit e9664d1bf5a2898635c3b29d0fc9a04ede221fc0
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 62703c016c4a75755ba074eda9e4b7a58d1241cd
|
||||
Subproject commit 36fd57c45b9b6ebbafbe57e5be4c5e2120a281cf
|
||||
Loading…
Add table
Reference in a new issue