linphone-iphone/Classes/ContactDetailsTableViewController.m
Guillaume BIENKOWSKI b6d8afe22e Migrate to ARC \o/
2015-06-02 11:54:48 +02:00

860 lines
35 KiB
Objective-C

/* ContactDetailsTableViewController.m
*
* Copyright (C) 2012 Belledonne Comunications, Grenoble, France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import "ContactDetailsTableViewController.h"
#import "PhoneMainView.h"
#import "UIEditableTableViewCell.h"
#import "UACellBackgroundView.h"
#import "UILinphone.h"
#import "OrderedDictionary.h"
#import "FastAddressBook.h"
#import "Utils.h"
@interface Entry : NSObject
@property (assign) ABMultiValueIdentifier identifier;
@end
@implementation Entry
@synthesize identifier;
#pragma mark - Lifecycle Functions
- (id)initWithData:(ABMultiValueIdentifier)aidentifier {
self = [super init];
if (self != NULL) {
[self setIdentifier:aidentifier];
}
return self;
}
@end
@implementation ContactDetailsTableViewController
static const ContactSections_e contactSections[ContactSections_MAX] = {ContactSections_None, ContactSections_Number, ContactSections_Sip, ContactSections_Email};
@synthesize footerController;
@synthesize headerController;
@synthesize contactDetailsDelegate;
@synthesize contact;
#pragma mark - Lifecycle Functions
- (void)initContactDetailsTableViewController {
dataCache = [[NSMutableArray alloc] init];
// pre-fill the data-cache with empty arrays
for(int i=ContactSections_Number; i< ContactSections_MAX; i++){
[dataCache addObject:@[]];
}
labelArray = [[NSMutableArray alloc] initWithObjects:
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"],
[NSString stringWithString:(NSString*)kABPersonPhoneMobileLabel],
[NSString stringWithString:(NSString*)kABPersonPhoneIPhoneLabel],
[NSString stringWithString:(NSString*)kABPersonPhoneMainLabel], nil];
editingIndexPath = nil;
}
- (id)init {
self = [super init];
if (self) {
[self initContactDetailsTableViewController];
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (self) {
[self initContactDetailsTableViewController];
}
return self;
}
- (void)dealloc {
if(contact != nil && ABRecordGetRecordID(contact) == kABRecordInvalidID) {
CFRelease(contact);
}
}
#pragma mark - ViewController Functions
- (void)viewDidLoad {
[super viewDidLoad];
[headerController view]; // Force view load
[footerController view]; // Force view load
self.tableView.accessibilityIdentifier = @"Contact numbers table";
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
#pragma mark -
- (BOOL)isValid {
return [headerController isValid];
}
- (void)updateModification {
[contactDetailsDelegate onModification:nil];
}
- (NSMutableArray*)getSectionData:(NSInteger)section {
if(contactSections[section] == ContactSections_Number) {
return [dataCache objectAtIndex:0];
} else if(contactSections[section] == ContactSections_Sip) {
return [dataCache objectAtIndex:1];
} else if(contactSections[section] == ContactSections_Email) {
if ([[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"] == true) {
return [dataCache objectAtIndex:2];
} else {
return nil;
}
}
return nil;
}
- (ABPropertyID)propertyIDForSection:(ContactSections_e)section {
switch (section) {
case ContactSections_Sip: return kABPersonInstantMessageProperty;
case ContactSections_Number: return kABPersonPhoneProperty;
case ContactSections_Email: return kABPersonEmailProperty;
default: return kABInvalidPropertyType;
}
}
+ (NSString*)localizeLabel:(NSString*)str {
return (NSString*) CFBridgingRelease(ABAddressBookCopyLocalizedLabel((__bridge CFStringRef) str));
}
- (NSDictionary*)getLocalizedLabels {
OrderedDictionary *dict = [[OrderedDictionary alloc] initWithCapacity:[labelArray count]];
for(NSString *str in labelArray) {
[dict setObject:[ContactDetailsTableViewController localizeLabel:str] forKey:str];
}
return dict;
}
- (void)loadData {
[dataCache removeAllObjects];
if(contact == NULL)
return;
LOGI(@"Load data from contact %p", contact);
// Phone numbers
{
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
NSMutableArray *subArray = [NSMutableArray array];
if(lMap) {
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(lMap, i);
Entry *entry = [[Entry alloc] initWithData:identifier];
[subArray addObject: entry];
}
CFRelease(lMap);
}
[dataCache addObject:subArray];
}
// SIP (IM)
{
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
NSMutableArray *subArray = [NSMutableArray array];
if(lMap) {
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(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 {
//check domain
LinphoneAddress* address = linphone_address_new([(NSString*)CFDictionaryGetValue(lDict,kABPersonInstantMessageUsernameKey) UTF8String]);
if (address) {
if ([[ContactSelection getSipFilter] compare:@"*" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
add = true;
} else {
NSString* domain = [NSString stringWithCString:linphone_address_get_domain(address)
encoding:[NSString defaultCStringEncoding]];
add = [domain compare:[ContactSelection getSipFilter] options:NSCaseInsensitiveSearch] == NSOrderedSame;
}
linphone_address_destroy(address);
} else {
add = false;
}
}
if(add) {
Entry *entry = [[Entry alloc] initWithData:identifier];
[subArray addObject: entry];
}
CFRelease(lDict);
}
CFRelease(lMap);
}
[dataCache addObject:subArray];
}
// Email
if ([[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"] == true)
{
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
NSMutableArray *subArray = [NSMutableArray array];
if(lMap) {
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(lMap, i);
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i);
Entry *entry = [[Entry alloc] initWithData:identifier];
[subArray addObject: entry];
CFRelease(lDict);
}
CFRelease(lMap);
}
[dataCache addObject:subArray];
}
if(contactDetailsDelegate != nil) {
[contactDetailsDelegate onModification:nil];
}
[self.tableView reloadData];
}
-(Entry *) setOrCreateSipContactEntry:(Entry *)entry withValue:(NSString*)value {
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
ABMutableMultiValueRef lMap;
if(lcMap != NULL) {
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
} else {
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
}
ABMultiValueIdentifier index;
CFErrorRef error = NULL;
CFStringRef keys[] = { kABPersonInstantMessageUsernameKey, kABPersonInstantMessageServiceKey};
CFTypeRef values[] = { CFBridgingRetain([value copy]), (__bridge CFTypeRef)([LinphoneManager instance].contactSipField) };
CFDictionaryRef lDict = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
if (entry) {
index = (int)ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
ABMultiValueReplaceValueAtIndex(lMap, lDict, index);
} else {
CFStringRef label = (__bridge CFStringRef)[labelArray objectAtIndex:0];
ABMultiValueAddValueAndLabel(lMap, lDict, label, &index);
}
if (!ABRecordSetValue(contact, kABPersonInstantMessageProperty, lMap, &error)) {
LOGI(@"Can't set contact with value [%@] cause [%@]", value,[(__bridge NSError*)error localizedDescription]);
CFRelease(lMap);
} else {
if (entry == nil) {
entry = [[Entry alloc] initWithData:index];
}
CFRelease(lDict);
CFRelease(lMap);
/*check if message type is kept or not*/
lcMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
index = (int)ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
lDict = ABMultiValueCopyValueAtIndex(lMap,index);
if(!CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
/*too bad probably a gtalk number, storing uri*/
NSString* username = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
LinphoneAddress* address = linphone_core_interpret_url([LinphoneManager getLc]
,[username UTF8String]);
if(address){
char* uri = linphone_address_as_string_uri_only(address);
CFStringRef keys[] = { kABPersonInstantMessageUsernameKey, kABPersonInstantMessageServiceKey};
CFTypeRef values[] = { (__bridge CFTypeRef)([NSString stringWithCString:uri encoding:[NSString defaultCStringEncoding]]), (__bridge CFTypeRef)([LinphoneManager instance].contactSipField) };
CFDictionaryRef lDict2 = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
ABMultiValueReplaceValueAtIndex(lMap, lDict2, index);
if (!ABRecordSetValue(contact, kABPersonInstantMessageProperty, lMap, &error)) {
LOGI(@"Can't set contact with value [%@] cause [%@]", value,[(__bridge NSError*)error localizedDescription]);
}
CFRelease(lDict2);
linphone_address_destroy(address);
ms_free(uri);
}
}
CFRelease(lMap);
}
CFRelease(lDict);
return entry;
}
-(void) setSipContactEntry:(Entry *)entry withValue:(NSString*)value {
[self setOrCreateSipContactEntry:entry withValue:value];
}
- (void)addEntry:(UITableView*)tableview section:(NSInteger)section animated:(BOOL)animated {
[self addEntry:tableview section:section animated:animated value:@""];
}
- (void)addEntry:(UITableView*)tableview section:(NSInteger)section animated:(BOOL)animated value:(NSString *)value{
NSMutableArray *sectionArray = [self getSectionData:section];
NSUInteger count = [sectionArray count];
CFErrorRef error = NULL;
bool added = TRUE;
if(contactSections[section] == ContactSections_Number) {
ABMultiValueIdentifier identifier;
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
ABMutableMultiValueRef lMap;
if(lcMap != NULL) {
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
} else {
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
}
CFStringRef label = (__bridge CFStringRef)[labelArray objectAtIndex:0];
if(!ABMultiValueAddValueAndLabel(lMap, CFBridgingRetain([value copy]), label, &identifier)) {
added = false;
}
if(added && ABRecordSetValue(contact, kABPersonPhoneProperty, lMap, &error)) {
Entry *entry = [[Entry alloc] initWithData:identifier];
[sectionArray addObject:entry];
} else {
added = false;
LOGI(@"Can't add entry: %@", [(__bridge NSError*)error localizedDescription]);
}
CFRelease(lMap);
} else if(contactSections[section] == ContactSections_Sip) {
Entry *entry = [self setOrCreateSipContactEntry:nil withValue:value];
if (entry) {
[sectionArray addObject:entry];
added=true;
} else {
added=false;
LOGE(@"Can't add entry for value: %@", value);
}
} else if(contactSections[section] == ContactSections_Email) {
ABMultiValueIdentifier identifier;
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
ABMutableMultiValueRef lMap;
if(lcMap != NULL) {
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
} else {
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
}
CFStringRef label = (__bridge CFStringRef)[labelArray objectAtIndex:0];
if(!ABMultiValueAddValueAndLabel(lMap, CFBridgingRetain([value copy]), label, &identifier)) {
added = false;
}
if(added && ABRecordSetValue(contact, kABPersonEmailProperty, lMap, &error)) {
Entry *entry = [[Entry alloc] initWithData:identifier];
[sectionArray addObject:entry];
} else {
added = false;
LOGI(@"Can't add entry: %@", [(__bridge NSError*)error localizedDescription]);
}
CFRelease(lMap);
}
if (added && animated) {
// Update accessory
if (count > 0) {
[tableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:count -1 inSection:section]] withRowAnimation:FALSE];
}
[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:count inSection:section]] withRowAnimation:UITableViewRowAnimationFade];
}
if(contactDetailsDelegate != nil) {
[contactDetailsDelegate onModification:nil];
}
}
- (void)removeEmptyEntry:(UITableView*)tableview section:(NSInteger)section animated:(BOOL)animated {
NSMutableArray *sectionDict = [self getSectionData:section];
NSInteger row = [sectionDict count] - 1;
if(row >= 0) {
Entry *entry = [sectionDict objectAtIndex:row];
ABPropertyID property = [self propertyIDForSection:contactSections[section]];
if( property != kABInvalidPropertyType ){
ABMultiValueRef lMap = ABRecordCopyValue(contact, property);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFTypeRef valueRef = ABMultiValueCopyValueAtIndex(lMap, index);
CFTypeRef toRelease = valueRef;
if (property == kABPersonInstantMessageProperty ) {
// when we query the instanteMsg property we get a dictionary instead of a value
valueRef = CFDictionaryGetValue(valueRef, kABPersonInstantMessageUsernameKey);
}
if(![(__bridge NSString*) valueRef length]) {
[self removeEntry:tableview path:[NSIndexPath indexPathForRow:row inSection:section] animated:animated];
}
CFRelease(toRelease);
CFRelease(lMap);
}
}
if(contactDetailsDelegate != nil) {
[contactDetailsDelegate onModification:nil];
}
}
- (void)removeEntry:(UITableView*)tableview path:(NSIndexPath*)indexPath animated:(BOOL)animated {
NSMutableArray *sectionArray = [self getSectionData:[indexPath section]];
Entry *entry = [sectionArray objectAtIndex:[indexPath row]];
ABPropertyID property = [self propertyIDForSection:contactSections[indexPath.section]];
if( property != kABInvalidPropertyType ){
ABMultiValueRef lcMap = ABRecordCopyValue(contact, property);
ABMutableMultiValueRef lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
ABMultiValueRemoveValueAndLabelAtIndex(lMap, index);
ABRecordSetValue(contact, property, lMap, nil);
CFRelease(lMap);
}
[sectionArray removeObjectAtIndex:[indexPath row]];
NSArray *tagInsertIndexPath = [NSArray arrayWithObject:indexPath];
if (animated) {
[tableview deleteRowsAtIndexPaths:tagInsertIndexPath withRowAnimation:UITableViewRowAnimationFade];
}
}
#pragma mark - Property Functions
- (void)setContact:(ABRecordRef)acontact {
if(contact != nil && ABRecordGetRecordID(contact) == kABRecordInvalidID) {
CFRelease(contact);
}
contact = acontact;
[self loadData];
[headerController setContact:contact];
}
- (void)addPhoneField:(NSString*)number {
int i = 0;
while(i < ContactSections_MAX && contactSections[i] != ContactSections_Number) ++i;
[self addEntry:[self tableView] section:i animated:FALSE value:number];
}
- (void)addSipField:(NSString*)address {
int i = 0;
while(i < ContactSections_MAX && contactSections[i] != ContactSections_Sip) ++i;
[self addEntry:[self tableView] section:i animated:FALSE value:address];
}
- (void)addEmailField:(NSString*)address {
int i = 0;
while(i < ContactSections_MAX && contactSections[i] != ContactSections_Email) ++i;
[self addEntry:[self tableView] section:i animated:FALSE value:address];
}
#pragma mark - UITableViewDataSource Functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return ContactSections_MAX;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self getSectionData:section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellId = @"ContactDetailsCell";
UIEditableTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId];
if (cell == nil) {
cell = [[UIEditableTableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:kCellId];
[cell.detailTextField setDelegate:self];
[cell.detailTextField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[cell.detailTextField setAutocorrectionType:UITextAutocorrectionTypeNo];
[cell setBackgroundColor:[UIColor whiteColor]];
// Background View
UACellBackgroundView *selectedBackgroundView = [[UACellBackgroundView alloc] initWithFrame:CGRectZero];
cell.selectedBackgroundView = selectedBackgroundView;
[selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR];
}
NSMutableArray *sectionDict = [self getSectionData:[indexPath section]];
Entry *entry = [sectionDict objectAtIndex:[indexPath row]];
NSString *value = @"";
// default label is our app name
NSString *label = [ContactDetailsTableViewController localizeLabel:[labelArray objectAtIndex:0]];
if(contactSections[[indexPath section]] == ContactSections_Number) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFStringRef labelRef = ABMultiValueCopyLabelAtIndex(lMap, index);
if(labelRef != NULL) {
label = [ContactDetailsTableViewController localizeLabel:(NSString*) CFBridgingRelease(labelRef)];
}
NSString* valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(lMap, index));
if(valueRef != NULL) {
value = [ContactDetailsTableViewController localizeLabel:valueRef];
}
CFRelease(lMap);
} else if(contactSections[[indexPath section]] == ContactSections_Sip) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFStringRef labelRef = ABMultiValueCopyLabelAtIndex(lMap, index);
if(labelRef != NULL) {
label = [ContactDetailsTableViewController localizeLabel:(NSString*) CFBridgingRelease(labelRef)];
}
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, index);
CFStringRef valueRef = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
if(valueRef != NULL) {
LinphoneAddress* addr=NULL;
if ([[LinphoneManager instance] lpConfigBoolForKey:@"contact_display_username_only"]
&& (addr=linphone_address_new([(NSString *)CFBridgingRelease(valueRef) UTF8String]))) {
if (linphone_address_get_username(addr)) {
value = [NSString stringWithCString:linphone_address_get_username(addr)
encoding:[NSString defaultCStringEncoding]];
} /*else value=@""*/
} else {
value = (NSString*) CFBridgingRelease(valueRef);
}
if (addr) linphone_address_destroy(addr);
}
CFRelease(lDict);
CFRelease(lMap);
} else if(contactSections[[indexPath section]] == ContactSections_Email) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFStringRef labelRef = ABMultiValueCopyLabelAtIndex(lMap, index);
if(labelRef != NULL) {
label = [ContactDetailsTableViewController localizeLabel:(NSString*) CFBridgingRelease(labelRef)];
}
CFStringRef valueRef = ABMultiValueCopyValueAtIndex(lMap, index);
if(valueRef != NULL) {
value = [ContactDetailsTableViewController localizeLabel:(NSString*) CFBridgingRelease(valueRef)];
}
CFRelease(lMap);
}
[cell.textLabel setText:label];
[cell.detailTextLabel setText:value];
[cell.detailTextField setText:value];
if (contactSections[[indexPath section]] == ContactSections_Number) {
[cell.detailTextField setKeyboardType:UIKeyboardTypePhonePad];
[cell.detailTextField setPlaceholder:NSLocalizedString(@"Phone number", nil)];
} else if(contactSections[[indexPath section]] == ContactSections_Sip){
[cell.detailTextField setKeyboardType:UIKeyboardTypeASCIICapable];
[cell.detailTextField setPlaceholder:NSLocalizedString(@"SIP address", nil)];
} else if(contactSections[[indexPath section]] == ContactSections_Email) {
[cell.detailTextField setKeyboardType:UIKeyboardTypeASCIICapable];
[cell.detailTextField setPlaceholder:NSLocalizedString(@"Email address", nil)];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSMutableArray *sectionDict = [self getSectionData:[indexPath section]];
Entry *entry = [sectionDict objectAtIndex:[indexPath row]];
if (![self isEditing]) {
NSString *dest=NULL;;
if(contactSections[[indexPath section]] == ContactSections_Number) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFStringRef valueRef = ABMultiValueCopyValueAtIndex(lMap, index);
if(valueRef != NULL) {
dest = [ContactDetailsTableViewController localizeLabel:(NSString*) CFBridgingRelease(valueRef)];
}
CFRelease(lMap);
} else if(contactSections[[indexPath section]] == ContactSections_Sip) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, index);
CFStringRef valueRef = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
dest = [FastAddressBook normalizeSipURI:(NSString*) CFBridgingRelease(valueRef)];
CFRelease(lDict);
CFRelease(lMap);
} else if(contactSections[[indexPath section]] == ContactSections_Email) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFStringRef valueRef = ABMultiValueCopyValueAtIndex(lMap, index);
if(valueRef != NULL) {
dest = [FastAddressBook normalizeSipURI:(NSString*) CFBridgingRelease(valueRef)];
}
CFRelease(lMap);
}
if(dest != nil) {
NSString *displayName = [FastAddressBook getContactDisplayName:contact];
if([ContactSelection getSelectionMode] != ContactSelectionModeMessage) {
// Go to dialer view
DialerViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[DialerViewController compositeViewDescription]], DialerViewController);
if(controller != nil) {
[controller call:dest displayName:displayName];
}
} else {
// Go to Chat room view
[[PhoneMainView instance] popToView:[ChatViewController compositeViewDescription]]; // Got to Chat and push ChatRoom
ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController);
if(controller != nil) {
LinphoneChatRoom* room = linphone_core_get_or_create_chat_room([LinphoneManager getLc], [dest UTF8String]);
[controller setChatRoom:room];
}
}
}
} else {
NSString *key = nil;
ABPropertyID property = [self propertyIDForSection:contactSections[indexPath.section]];
if( property != kABInvalidPropertyType ){
ABMultiValueRef lMap = ABRecordCopyValue(contact, property);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFTypeRef labelRef = ABMultiValueCopyLabelAtIndex(lMap, index);
if(labelRef != NULL) {
key = (NSString*) CFBridgingRelease(labelRef);
}
CFRelease(lMap);
}
if(key != nil) {
editingIndexPath = [indexPath copy];
ContactDetailsLabelViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactDetailsLabelViewController compositeViewDescription] push:TRUE], ContactDetailsLabelViewController);
if(controller != nil) {
[controller setDataList:[self getLocalizedLabels]];
[controller setSelectedData:key];
[controller setDelegate:self];
}
}
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[LinphoneUtils findAndResignFirstResponder:[self tableView]];
if (editingStyle == UITableViewCellEditingStyleInsert) {
[tableView beginUpdates];
[self addEntry:tableView section:[indexPath section] animated:TRUE];
[tableView endUpdates];
} else if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView beginUpdates];
[self removeEntry:tableView path:indexPath animated:TRUE];
[tableView endUpdates];
}
}
#pragma mark - UITableViewDelegate Functions
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
bool_t showEmails = [[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"];
// Resign keyboard
if(!editing) {
[LinphoneUtils findAndResignFirstResponder:[self tableView]];
}
[headerController setEditing:editing animated:animated];
[footerController setEditing:editing animated:animated];
if(animated) {
[self.tableView beginUpdates];
}
if(editing) {
// add phony entries so that the user can add new data
for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) {
if(contactSections[section] == ContactSections_Number ||
contactSections[section] == ContactSections_Sip ||
(showEmails && contactSections[section] == ContactSections_Email)) {
[self addEntry:self.tableView section:section animated:animated];
}
}
} else {
for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) {
// remove phony entries that were not filled by the user
if(contactSections[section] == ContactSections_Number ||
contactSections[section] == ContactSections_Sip ||
(showEmails && contactSections[section] == ContactSections_Email)) {
[self removeEmptyEntry:self.tableView section:section animated:animated];
if( [[self getSectionData:section] count] == 0 && animated ) { // the section is empty -> remove titles
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section]
withRowAnimation:UITableViewRowAnimationFade];
}
}
}
}
if(animated) {
[self.tableView endUpdates];
}
[super setEditing:editing animated:animated];
if(contactDetailsDelegate != nil) {
[contactDetailsDelegate onModification:nil];
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger last_index = [[self getSectionData:[indexPath section]] count] - 1;
if (indexPath.row == last_index) {
return UITableViewCellEditingStyleInsert;
}
return UITableViewCellEditingStyleDelete;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if(section == ContactSections_None) {
return [headerController view];
} else {
return nil;
}
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
if(section == (ContactSections_MAX - 1)) {
if(ABRecordGetRecordID(contact) != kABRecordInvalidID) {
return [footerController view];
}
}
return nil;
}
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if( [[self getSectionData:section] count] == 0) return nil;
if(contactSections[section] == ContactSections_Number) {
return NSLocalizedString(@"Phone numbers", nil);
} else if(contactSections[section] == ContactSections_Sip) {
return NSLocalizedString(@"SIP addresses", nil);
} else if(contactSections[section] == ContactSections_Email) {
return NSLocalizedString(@"Email addresses", nil);
}
return nil;
}
- (NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if(section == ContactSections_None) {
return [UIContactDetailsHeader height:[headerController isEditing]];
} else {
// Hide section if nothing in it
if([[self getSectionData:section] count] > 0)
return 22;
else
return 0.000001f; // Hack UITableView = 0
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
if(section == (ContactSections_MAX - 1)) {
if(ABRecordGetRecordID(contact) != kABRecordInvalidID) {
return [UIContactDetailsFooter height:[footerController isEditing]];
} else {
return 0.000001f; // Hack UITableView = 0
}
} else if(section == ContactSections_None) {
return 0.000001f; // Hack UITableView = 0
}
return 10.0f;
}
#pragma mark - ContactDetailsLabelDelegate Functions
- (void)changeContactDetailsLabel:(NSString *)value {
if(value != nil) {
NSInteger section = editingIndexPath.section;
NSMutableArray *sectionDict = [self getSectionData:section];
ABPropertyID property = [self propertyIDForSection:(int)section];
Entry *entry = [sectionDict objectAtIndex:editingIndexPath.row];
if( property != kABInvalidPropertyType ){
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
ABMutableMultiValueRef lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
ABMultiValueReplaceLabelAtIndex(lMap, (__bridge CFStringRef)(value), index);
ABRecordSetValue(contact, kABPersonPhoneProperty, lMap, nil);
CFRelease(lMap);
}
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject: editingIndexPath] withRowAnimation:FALSE];
[self.tableView reloadSectionIndexTitles];
[self.tableView endUpdates];
}
editingIndexPath = nil;
}
#pragma mark - UITextFieldDelegate Functions
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if(contactDetailsDelegate != nil) {
[self performSelector:@selector(updateModification) withObject:nil afterDelay:0];
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
UIView *view = [textField superview];
// Find TableViewCell
while(view != nil && ![view isKindOfClass:[UIEditableTableViewCell class]]) view = [view superview];
if(view != nil) {
UIEditableTableViewCell *cell = (UIEditableTableViewCell*)view;
NSIndexPath *path = [self.tableView indexPathForCell:cell];
NSMutableArray *sectionDict = [self getSectionData:[path section]];
Entry *entry = [sectionDict objectAtIndex:[path row]];
ContactSections_e sect = contactSections[[path section]];
ABPropertyID property = [self propertyIDForSection:sect];
NSString *value = [textField text];
if(sect == ContactSections_Sip) {
[self setSipContactEntry:entry withValue:value];
} else if( property != kABInvalidPropertyType ){
ABMultiValueRef lcMap = ABRecordCopyValue(contact, property);
ABMutableMultiValueRef lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
ABMultiValueReplaceValueAtIndex(lMap, (__bridge CFStringRef)value, index);
ABRecordSetValue(contact, property, lMap, nil);
CFRelease(lMap);
}
[cell.detailTextLabel setText:value];
} else {
LOGE(@"Not valid UIEditableTableViewCell");
}
if(contactDetailsDelegate != nil) {
[self performSelector:@selector(updateModification) withObject:nil afterDelay:0];
}
return TRUE;
}
@end