linphone-ios/Classes/ContactDetailsTableView.m
Gautier Pelloux-Prayer 4a1f6ddacc UI: fix some minor icons
2015-12-22 14:14:34 +01:00

833 lines
30 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 "ContactDetailsTableView.h"
#import "PhoneMainView.h"
#import "UIContactDetailsCell.h"
#import "Utils.h"
#import "OrderedDictionary.h"
#import "FastAddressBook.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 ContactDetailsTableView
@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 -
- (void)updateModification {
[contactDetailsDelegate onModification:nil];
}
- (NSMutableArray *)getSectionData:(NSInteger)section {
if (section == ContactSections_Number) {
return [dataCache objectAtIndex:0];
} else if (section == ContactSections_Sip) {
return [dataCache objectAtIndex:1];
} else if (section == ContactSections_Email) {
if ([[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"] == true) {
return [dataCache objectAtIndex:2];
} else {
return nil;
}
}
return nil;
}
- (ABPropertyID)propertyIDForSection:(ContactSections)section {
switch (section) {
case ContactSections_First_Name:
return kABPersonFirstNameProperty;
case ContactSections_Last_Name:
return kABPersonLastNameProperty;
case ContactSections_Sip:
return kABPersonInstantMessageProperty;
case ContactSections_Number:
return kABPersonPhoneProperty;
case ContactSections_Email:
return kABPersonEmailProperty;
default:
return kABInvalidPropertyType;
}
}
- (NSDictionary *)getLocalizedLabels {
OrderedDictionary *dict = [[OrderedDictionary alloc] initWithCapacity:[labelArray count]];
for (NSString *str in labelArray) {
[dict setObject:[FastAddressBook localizedLabel: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;
NSDictionary *lDict = @{
(NSString *)kABPersonInstantMessageUsernameKey : value, (NSString *)
kABPersonInstantMessageServiceKey : [LinphoneManager instance].contactSipField
};
if (entry) {
index = (int)ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
ABMultiValueReplaceValueAtIndex(lMap, (__bridge CFTypeRef)(lDict), index);
} else {
CFStringRef label = (__bridge CFStringRef)[labelArray objectAtIndex:0];
ABMultiValueAddValueAndLabel(lMap, (__bridge CFTypeRef)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(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 = CFBridgingRelease(ABMultiValueCopyValueAtIndex(lMap, index));
if ([lDict objectForKey:(__bridge NSString *)kABPersonInstantMessageServiceKey] == nil) {
/*too bad probably a gtalk number, storing uri*/
NSString *username = [lDict objectForKey:(NSString *)kABPersonInstantMessageUsernameKey];
LinphoneAddress *address = linphone_core_interpret_url([LinphoneManager getLc], [username UTF8String]);
if (address) {
char *uri = linphone_address_as_string_uri_only(address);
NSDictionary *dict2 = @{
(NSString *)kABPersonInstantMessageUsernameKey :
[NSString stringWithCString:uri encoding:[NSString defaultCStringEncoding]],
(NSString *)
kABPersonInstantMessageServiceKey : [LinphoneManager instance].contactSipField
};
ABMultiValueReplaceValueAtIndex(lMap, (__bridge CFTypeRef)(dict2), index);
if (!ABRecordSetValue(contact, kABPersonInstantMessageProperty, lMap, &error)) {
LOGI(@"Can't set contact with value [%@] cause [%@]", value,
[(__bridge NSError *)error localizedDescription]);
}
linphone_address_destroy(address);
ms_free(uri);
}
}
CFRelease(lMap);
}
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 (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, (__bridge CFTypeRef)(value), 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 (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 (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, (__bridge CFTypeRef)(value), 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 i = [sectionDict count];
for (NSInteger row = i - 1; row >= 0; row--) {
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 = nil;
NSString *value = nil;
if (property == kABPersonInstantMessageProperty) {
// when we query the instanteMsg property we get a dictionary instead of a value
toRelease = valueRef;
value = CFDictionaryGetValue(valueRef, kABPersonInstantMessageUsernameKey);
} else {
value = CFBridgingRelease(valueRef);
}
if (value.length == 0) {
[self removeEntry:tableview path:[NSIndexPath indexPathForRow:row inSection:section] animated:animated];
}
if (toRelease != nil) {
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 (acontact == contact)
return;
if (contact != nil && ABRecordGetRecordID(contact) == kABRecordInvalidID) {
CFRelease(contact);
}
contact = acontact;
[self loadData];
}
- (void)addPhoneField:(NSString *)number {
ContactSections i = 0;
while (i != ContactSections_MAX && i != ContactSections_Number)
++i;
[self addEntry:[self tableView] section:i animated:FALSE value:number];
}
- (void)addSipField:(NSString *)address {
ContactSections i = 0;
while (i != ContactSections_MAX && i != ContactSections_Sip)
++i;
[self addEntry:[self tableView] section:i animated:FALSE value:address];
}
- (void)addEmailField:(NSString *)address {
ContactSections i = 0;
while (i != ContactSections_MAX && 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 {
if (section == ContactSections_First_Name || section == ContactSections_Last_Name) {
return (self.tableView.isEditing) ? 1 : 0 /*no first and last name when not editting */;
} else {
return [[self getSectionData:section] count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellId = @"UIContactDetailsCell";
UIContactDetailsCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId];
if (cell == nil) {
cell = [[UIContactDetailsCell alloc] initWithIdentifier:kCellId];
[cell.editTextfield setDelegate:self];
}
NSMutableArray *sectionDict = [self getSectionData:[indexPath section]];
Entry *entry = [sectionDict objectAtIndex:[indexPath row]];
NSString *value = @"";
[cell hideDeleteButton:NO];
if (indexPath.section == ContactSections_First_Name) {
value = (NSString *)CFBridgingRelease(
ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_First_Name]));
[cell hideDeleteButton:YES];
} else if (indexPath.section == ContactSections_Last_Name) {
value = (NSString *)CFBridgingRelease(
ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_Last_Name]));
[cell hideDeleteButton:YES];
} else if ([indexPath section] == ContactSections_Number) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(lMap, index));
if (valueRef != NULL) {
value = [FastAddressBook localizedLabel:valueRef];
}
CFRelease(lMap);
} else if ([indexPath section] == ContactSections_Sip) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, index);
value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey));
if (value != NULL) {
LinphoneAddress *addr = NULL;
if ([[LinphoneManager instance] lpConfigBoolForKey:@"contact_display_username_only"] &&
(addr = linphone_address_new([value UTF8String]))) {
if (linphone_address_get_username(addr)) {
value = [NSString stringWithCString:linphone_address_get_username(addr)
encoding:[NSString defaultCStringEncoding]];
}
}
if (addr)
linphone_address_destroy(addr);
}
CFRelease(lDict);
CFRelease(lMap);
} else if ([indexPath section] == ContactSections_Email) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(lMap, index));
if (valueRef != NULL) {
value = [FastAddressBook localizedLabel:valueRef];
}
CFRelease(lMap);
}
[cell setAddress:value];
if ([indexPath section] == ContactSections_Number) {
[cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad];
} else if ([indexPath section] == ContactSections_Sip) {
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
} else if ([indexPath section] == ContactSections_Email) {
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
} else {
[cell.editTextfield setKeyboardType:UIKeyboardTypeDefault];
}
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 *key = nil;
ABPropertyID property = [self propertyIDForSection:(ContactSections)indexPath.section];
if (property != kABInvalidPropertyType && property != kABPersonFirstNameProperty &&
property != kABPersonLastNameProperty) {
ABMultiValueRef lMap = ABRecordCopyValue(contact, property);
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
NSString *labelRef = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(lMap, index));
if (labelRef != NULL) {
key = (NSString *)(labelRef);
}
CFRelease(lMap);
}
if (key != nil) {
editingIndexPath = indexPath;
}
}
}
- (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 {
[super setEditing:editing animated:animated];
BOOL showEmails = [[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"];
if (editing) {
// add phone/SIP/email entries so that the user can add new data
for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) {
if (section == ContactSections_Number || section == ContactSections_Sip ||
(showEmails && section == ContactSections_Email)) {
[self addEntry:self.tableView section:section animated:animated];
}
}
} else {
[LinphoneUtils findAndResignFirstResponder:[self tableView]];
// remove empty phone numbers
for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) {
// remove phony entries that were not filled by the user
if (section == ContactSections_Number || section == ContactSections_Sip ||
(showEmails && 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];
}
}
}
}
[self loadData];
if (contactDetailsDelegate != nil) {
[contactDetailsDelegate onModification:nil];
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleNone;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSString *text = nil;
BOOL canAddEntry = self.tableView.isEditing;
NSString *addEntryName = nil;
if (section == ContactSections_First_Name && self.tableView.isEditing) {
text = NSLocalizedString(@"First name", nil);
canAddEntry = NO;
} else if (section == ContactSections_Last_Name && self.tableView.isEditing) {
text = NSLocalizedString(@"Last name", nil);
canAddEntry = NO;
} else if ([self getSectionData:section].count > 0 || self.tableView.isEditing) {
if (section == ContactSections_Number) {
text = NSLocalizedString(@"Phone numbers", nil);
addEntryName = NSLocalizedString(@"Add new phone number", nil);
} else if (section == ContactSections_Sip) {
text = NSLocalizedString(@"SIP addresses", nil);
addEntryName = NSLocalizedString(@"Add new SIP address", nil);
} else if (section == ContactSections_Email &&
[LinphoneManager.instance lpConfigBoolForKey:@"show_contacts_emails_preference"]) {
text = NSLocalizedString(@"Email addresses", nil);
addEntryName = NSLocalizedString(@"Add new email", nil);
}
}
if (!text) {
return nil;
}
CGRect frame = CGRectMake(0, 0, tableView.frame.size.width, 30);
UIView *tempView = [[UIView alloc] initWithFrame:frame];
tempView.backgroundColor = [UIColor whiteColor];
UILabel *tempLabel = [[UILabel alloc] initWithFrame:frame];
tempLabel.backgroundColor = [UIColor clearColor];
tempLabel.textColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"color_E.png"]];
tempLabel.text = text.uppercaseString;
tempLabel.textAlignment = NSTextAlignmentCenter;
tempLabel.font = [UIFont systemFontOfSize:15];
tempLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[tempView addSubview:tempLabel];
if (canAddEntry) {
frame.origin.x = tableView.frame.size.width / 2 - 28;
UIIconButton *tempAddButton = [[UIIconButton alloc] initWithFrame:frame];
[tempAddButton setImage:[UIImage imageNamed:@"add_field_default.png"] forState:UIControlStateNormal];
[tempAddButton setImage:[UIImage imageNamed:@"add_field_over.png"] forState:UIControlStateHighlighted];
[tempAddButton setImage:[UIImage imageNamed:@"add_field_over.png"] forState:UIControlStateSelected];
[tempAddButton addTarget:self action:@selector(onAddClick:) forControlEvents:UIControlEventTouchUpInside];
tempAddButton.tag = section;
tempAddButton.accessibilityLabel = addEntryName;
tempAddButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[tempView addSubview:tempAddButton];
}
return tempView;
}
- (void)onAddClick:(id)sender {
NSInteger section = ((UIButton *)sender).tag;
UITableView *tableView = VIEW(ContactDetailsView).tableController.tableView;
NSInteger count = [self.tableView numberOfRowsInSection:section];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:count inSection:section];
[tableView.dataSource tableView:tableView
commitEditingStyle:UITableViewCellEditingStyleInsert
forRowAtIndexPath:indexPath];
}
#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:[UIContactDetailsCell class]])
view = [view superview];
if (view != nil) {
UIContactDetailsCell *cell = (UIContactDetailsCell *)view;
NSIndexPath *path = [self.tableView indexPathForCell:cell];
NSMutableArray *sectionDict = [self getSectionData:[path section]];
Entry *entry = [sectionDict objectAtIndex:[path row]];
ContactSections sect = (ContactSections)[path section];
ABPropertyID property = [self propertyIDForSection:sect];
NSString *value = [textField text];
switch (sect) {
case ContactSections_First_Name:
case ContactSections_Last_Name: {
// [cell.detailTextLabel setText:[textField text]];
CFErrorRef error = NULL;
ABRecordSetValue(contact, property, (__bridge CFTypeRef)([textField text]), (CFErrorRef *)&error);
if (error != NULL) {
LOGE(@"Error when saving property %i in contact %p: Fail(%@)", property, contact,
[(__bridge NSError *)error localizedDescription]);
}
break;
}
case ContactSections_Sip:
[self setSipContactEntry:entry withValue:value];
break;
case ContactSections_Email:
case ContactSections_Number: {
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);
break;
}
case ContactSections_MAX:
case ContactSections_None:
break;
}
cell.editTextfield.text = value;
} else {
LOGE(@"Not valid UIEditableTableViewCell");
}
if (contactDetailsDelegate != nil) {
[self performSelector:@selector(updateModification) withObject:nil afterDelay:0];
}
return TRUE;
}
- (BOOL)isValid {
NSString *firstName = (NSString *)CFBridgingRelease(
ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_First_Name]));
NSString *lastName = (NSString *)CFBridgingRelease(
ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_Last_Name]));
return firstName.length > 0 || lastName.length > 0;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView.isEditing) {
return 44;
} else {
return 88;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 1e-5;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 0 || (!self.tableView.isEditing &&
(section == ContactSections_First_Name || section == ContactSections_Last_Name))) {
return 1e-5;
}
return [self tableView:tableView viewForHeaderInSection:section].frame.size.height;
}
@end