mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-31 18:29:29 +00:00
contact: factorize lots of lowlevel code in a single class (in progress)
This commit is contained in:
parent
0342e7b0cc
commit
5041ef3882
14 changed files with 474 additions and 609 deletions
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
|
|
@ -510,7 +510,7 @@
|
|||
</view>
|
||||
<view tag="47" contentMode="scaleToFill" id="mga-O5-mUn" userLabel="bottomBar">
|
||||
<rect key="frame" x="0.0" y="499" width="375" height="126"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<view tag="48" contentMode="scaleToFill" id="OIH-ek-VgL" userLabel="higherBar">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="63"/>
|
||||
|
|
@ -601,7 +601,7 @@
|
|||
<subviews>
|
||||
<button opaque="NO" tag="57" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="SRu-dB-r3e" userLabel="numpadButton" customClass="UIToggleButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="94" height="63"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<state key="normal" image="footer_dialer_default.png" backgroundImage="color_C.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
@ -624,7 +624,7 @@
|
|||
</button>
|
||||
<button opaque="NO" tag="59" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="t7u-65-OPV" userLabel="chatButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="281" y="0.0" width="94" height="63"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Hangup"/>
|
||||
<state key="normal" image="footer_chat_default.png" backgroundImage="color_C.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
@ -656,6 +656,7 @@
|
|||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.2666666667" green="0.2666666667" blue="0.2666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
|
|
@ -1196,7 +1197,7 @@
|
|||
<subviews>
|
||||
<button opaque="NO" tag="57" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Fyf-if-w6d" userLabel="numpadButton" customClass="UIToggleButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="83" height="63"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<state key="normal" image="footer_dialer_default.png" backgroundImage="color_C.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
@ -1219,7 +1220,7 @@
|
|||
</button>
|
||||
<button opaque="NO" tag="59" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Dh2-iA-2NB" userLabel="chatButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="250" y="0.0" width="84" height="63"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Hangup"/>
|
||||
<state key="normal" image="footer_chat_default.png" backgroundImage="color_C.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
|
|
@ -281,7 +281,7 @@
|
|||
<tableViewController id="20" userLabel="tableController" customClass="ContactDetailsTableView">
|
||||
<extendedEdge key="edgesForExtendedLayout"/>
|
||||
<connections>
|
||||
<outlet property="contactDetailsDelegate" destination="-1" id="53"/>
|
||||
<outlet property="editButton" destination="8" id="wZf-wX-YIu"/>
|
||||
<outlet property="view" destination="19" id="26"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
|
|
|
|||
34
Classes/Contact.h
Normal file
34
Classes/Contact.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Contact.h
|
||||
// linphone
|
||||
//
|
||||
// Created by Gautier Pelloux-Prayer on 12/01/16.
|
||||
//
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AddressBook/AddressBook.h>
|
||||
|
||||
@interface Contact : NSObject
|
||||
|
||||
@property(nonatomic, assign) NSString *firstName;
|
||||
@property(nonatomic, assign) NSString *lastName;
|
||||
@property(nonatomic, strong) NSMutableArray *sipAddresses;
|
||||
@property(nonatomic, strong) NSMutableArray *emails;
|
||||
@property(nonatomic, strong) NSMutableArray *phoneNumbers;
|
||||
|
||||
- (instancetype)initWithPerson:(ABRecordRef)person;
|
||||
|
||||
- (BOOL)setSipAddress:(NSString *)sip atIndex:(NSInteger)index;
|
||||
- (BOOL)setEmail:(NSString *)email atIndex:(NSInteger)index;
|
||||
- (BOOL)setPhoneNumber:(NSString *)phone atIndex:(NSInteger)index;
|
||||
|
||||
- (BOOL)addSipAddress:(NSString *)sip;
|
||||
- (BOOL)addEmail:(NSString *)email;
|
||||
- (BOOL)addPhoneNumber:(NSString *)phone;
|
||||
|
||||
- (BOOL)removeSipAddressAtIndex:(NSInteger)index;
|
||||
- (BOOL)removePhoneNumberAtIndex:(NSInteger)index;
|
||||
- (BOOL)removeEmailAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
270
Classes/Contact.m
Normal file
270
Classes/Contact.m
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
//
|
||||
// Contact.m
|
||||
// linphone
|
||||
//
|
||||
// Created by Gautier Pelloux-Prayer on 12/01/16.
|
||||
//
|
||||
//
|
||||
|
||||
#import "Contact.h"
|
||||
|
||||
@implementation Contact {
|
||||
ABRecordRef person;
|
||||
}
|
||||
|
||||
- (instancetype)initWithPerson:(ABRecordRef)aperson {
|
||||
self = [super init];
|
||||
person = aperson;
|
||||
|
||||
[self loadFields];
|
||||
|
||||
LOGI(@"Contact %@ %@ initialized with %d phones, %d sip, %d emails", self.firstName ?: @"", self.lastName ?: @"",
|
||||
self.phoneNumbers.count, self.sipAddresses.count, self.emails.count);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (person != nil && ABRecordGetRecordID(person) == kABRecordInvalidID) {
|
||||
CFRelease(person);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadFields {
|
||||
// First and Last name
|
||||
{
|
||||
_firstName = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
|
||||
_lastName = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
|
||||
}
|
||||
|
||||
// Phone numbers
|
||||
{
|
||||
NSMutableArray *phones = [[NSMutableArray alloc] init];
|
||||
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));
|
||||
if (valueRef != NULL) {
|
||||
[phones addObject:[FastAddressBook localizedLabel:valueRef]];
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(map);
|
||||
}
|
||||
_phoneNumbers = phones;
|
||||
}
|
||||
|
||||
// SIP (IM)
|
||||
{
|
||||
NSMutableArray *sip = [[NSMutableArray alloc] init];
|
||||
ABMultiValueRef map = ABRecordCopyValue(person, kABPersonInstantMessageProperty);
|
||||
if (map) {
|
||||
for (int i = 0; i < ABMultiValueGetCount(map); ++i) {
|
||||
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(map, i);
|
||||
if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
|
||||
if (CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField,
|
||||
CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey),
|
||||
kCFCompareCaseInsensitive) == 0) {
|
||||
NSString *value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey));
|
||||
CFRelease(lDict);
|
||||
if (value != NULL) {
|
||||
[sip addObject:value];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(map);
|
||||
}
|
||||
_sipAddresses = sip;
|
||||
}
|
||||
|
||||
// Email
|
||||
{
|
||||
NSMutableArray *emails = [[NSMutableArray alloc] init];
|
||||
ABMultiValueRef map = ABRecordCopyValue(person, kABPersonEmailProperty);
|
||||
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));
|
||||
if (valueRef != NULL) {
|
||||
[emails addObject:valueRef];
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(map);
|
||||
}
|
||||
_emails = emails;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
- (void)setFirstName:(NSString *)firstName {
|
||||
if ([self replaceInProperty:kABPersonFirstNameProperty value:(__bridge CFTypeRef)(firstName)]) {
|
||||
_firstName = firstName;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setLastName:(NSString *)lastName {
|
||||
if ([self replaceInProperty:kABPersonLastNameProperty value:(__bridge CFTypeRef)(lastName)]) {
|
||||
_lastName = lastName;
|
||||
}
|
||||
}
|
||||
|
||||
- (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);
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)replaceInProperty:(ABPropertyID)property value:(CFTypeRef)value atIndex:(NSInteger)index {
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(person, property);
|
||||
ABMutableMultiValueRef lMap;
|
||||
if (lcMap != NULL) {
|
||||
lMap = ABMultiValueCreateMutableCopy(lcMap);
|
||||
CFRelease(lcMap);
|
||||
} else {
|
||||
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
|
||||
}
|
||||
|
||||
BOOL ret = ABMultiValueReplaceValueAtIndex(lMap, value, index);
|
||||
if (ret) {
|
||||
ret = [self replaceInProperty:property value:lMap];
|
||||
} else {
|
||||
LOGW(@"Could not replace %@ at index %d from property %d", value, index, property);
|
||||
}
|
||||
|
||||
CFRelease(lMap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)addInProperty:(ABPropertyID)property value:(CFTypeRef)value {
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(person, property);
|
||||
ABMutableMultiValueRef lMap;
|
||||
if (lcMap != NULL) {
|
||||
lMap = ABMultiValueCreateMutableCopy(lcMap);
|
||||
CFRelease(lcMap);
|
||||
} else {
|
||||
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
|
||||
}
|
||||
|
||||
// will display this field with our application name
|
||||
CFStringRef label = (__bridge CFStringRef)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
||||
BOOL ret = ABMultiValueAddValueAndLabel(lMap, value, label, nil);
|
||||
if (ret) {
|
||||
ret = [self replaceInProperty:property value:lMap];
|
||||
} else {
|
||||
LOGW(@"Could not add %@ to property %d", value, property);
|
||||
}
|
||||
CFRelease(lMap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)removeInProperty:(ABPropertyID)property atIndex:(NSInteger)index {
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(person, property);
|
||||
ABMutableMultiValueRef lMap;
|
||||
if (lcMap != NULL) {
|
||||
lMap = ABMultiValueCreateMutableCopy(lcMap);
|
||||
CFRelease(lcMap);
|
||||
} else {
|
||||
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
|
||||
}
|
||||
|
||||
BOOL ret = ABMultiValueRemoveValueAndLabelAtIndex(lMap, index);
|
||||
if (ret) {
|
||||
ret = [self replaceInProperty:property value:lMap];
|
||||
} else {
|
||||
LOGW(@"Could not remove at index %d from property %d", index, property);
|
||||
}
|
||||
|
||||
CFRelease(lMap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)setSipAddress:(NSString *)sip atIndex:(NSInteger)index {
|
||||
NSDictionary *lDict = @{
|
||||
(NSString *) kABPersonInstantMessageUsernameKey : sip, (NSString *)
|
||||
kABPersonInstantMessageServiceKey : LinphoneManager.instance.contactSipField
|
||||
};
|
||||
|
||||
BOOL ret = [self replaceInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict) atIndex:index];
|
||||
if (ret) {
|
||||
_sipAddresses[index] = sip;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)setPhoneNumber:(NSString *)phone atIndex:(NSInteger)index {
|
||||
BOOL ret = [self replaceInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone) atIndex:index];
|
||||
if (ret) {
|
||||
_phoneNumbers[index] = phone;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)addSipAddress:(NSString *)sip {
|
||||
NSDictionary *lDict = @{
|
||||
(NSString *) kABPersonInstantMessageUsernameKey : sip, (NSString *)
|
||||
kABPersonInstantMessageServiceKey : [LinphoneManager instance].contactSipField
|
||||
};
|
||||
|
||||
BOOL ret = [self addInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict)];
|
||||
if (ret) {
|
||||
[_sipAddresses addObject:sip];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)removeSipAddressAtIndex:(NSInteger)index {
|
||||
BOOL ret = [self removeInProperty:kABPersonInstantMessageProperty atIndex:index];
|
||||
if (ret) {
|
||||
[_sipAddresses removeObjectAtIndex:index];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
- (BOOL)addPhoneNumber:(NSString *)phone {
|
||||
BOOL ret = [self addInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone)];
|
||||
if (ret) {
|
||||
[_phoneNumbers addObject:phone];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)removePhoneNumberAtIndex:(NSInteger)index {
|
||||
BOOL ret = [self removeInProperty:kABPersonPhoneProperty atIndex:index];
|
||||
if (ret) {
|
||||
[_phoneNumbers removeObjectAtIndex:index];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)setEmail:(NSString *)email atIndex:(NSInteger)index {
|
||||
BOOL ret = [self replaceInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email) atIndex:index];
|
||||
if (ret) {
|
||||
_emails[index] = email;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)addEmail:(NSString *)email {
|
||||
BOOL ret = [self addInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email)];
|
||||
if (ret) {
|
||||
[_emails addObject:email];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)removeEmailAtIndex:(NSInteger)index {
|
||||
BOOL ret = [self removeInProperty:kABPersonEmailProperty atIndex:index];
|
||||
if (ret) {
|
||||
[_emails removeObjectAtIndex:index];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/* ContactDetailsDelegate.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@protocol ContactDetailsDelegate <NSObject>
|
||||
|
||||
- (void)onModification:(id)event;
|
||||
|
||||
@end
|
||||
|
|
@ -20,7 +20,8 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import <AddressBook/AddressBook.h>
|
||||
|
||||
#import "ContactDetailsDelegate.h"
|
||||
#import "Contact.h"
|
||||
#import "LinphoneUI/UIToggleButton.h"
|
||||
|
||||
typedef enum _ContactSections {
|
||||
ContactSections_None = 0, // first section is empty because we cannot set header for first section
|
||||
|
|
@ -32,19 +33,14 @@ typedef enum _ContactSections {
|
|||
ContactSections_MAX
|
||||
} ContactSections;
|
||||
|
||||
@interface ContactDetailsTableView : UITableViewController <UITextFieldDelegate> {
|
||||
@private
|
||||
NSMutableArray *dataCache;
|
||||
NSMutableArray *labelArray;
|
||||
}
|
||||
@interface ContactDetailsTableView : UITableViewController <UITextFieldDelegate>
|
||||
|
||||
@property(nonatomic, assign, setter=setContact:) ABRecordRef contact;
|
||||
@property(nonatomic, strong) IBOutlet id<ContactDetailsDelegate> contactDetailsDelegate;
|
||||
@property(strong, nonatomic) Contact *contact;
|
||||
@property(weak, nonatomic) IBOutlet UIToggleButton *editButton;
|
||||
|
||||
- (BOOL)isValid;
|
||||
- (void)addPhoneField:(NSString *)number;
|
||||
- (void)addSipField:(NSString *)address;
|
||||
- (void)addEmailField:(NSString *)address;
|
||||
- (void)setContact:(ABRecordRef)contact;
|
||||
- (void)setContact:(Contact *)contact;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -24,413 +24,72 @@
|
|||
#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
|
||||
|
||||
INIT_WITH_COMMON_C {
|
||||
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];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (contact != nil && ABRecordGetRecordID(contact) == kABRecordInvalidID) {
|
||||
CFRelease(contact);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark - Property Functions
|
||||
|
||||
- (NSMutableArray *)getSectionData:(NSInteger)section {
|
||||
if (section == ContactSections_Number) {
|
||||
return [dataCache objectAtIndex:0];
|
||||
return _contact.phoneNumbers;
|
||||
} else if (section == ContactSections_Sip) {
|
||||
return [dataCache objectAtIndex:1];
|
||||
return _contact.sipAddresses;
|
||||
} else if (section == ContactSections_Email) {
|
||||
if ([[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"] == true) {
|
||||
return [dataCache objectAtIndex:2];
|
||||
} else {
|
||||
return nil;
|
||||
return _contact.emails;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (ABPropertyID)propertyIDForSection:(ContactSections)section {
|
||||
switch (section) {
|
||||
case ContactSections_FirstName:
|
||||
return kABPersonFirstNameProperty;
|
||||
case ContactSections_LastName:
|
||||
return kABPersonLastNameProperty;
|
||||
case ContactSections_Sip:
|
||||
return kABPersonInstantMessageProperty;
|
||||
case ContactSections_Number:
|
||||
return kABPersonPhoneProperty;
|
||||
case ContactSections_Email:
|
||||
return kABPersonEmailProperty;
|
||||
default:
|
||||
return kABInvalidPropertyType;
|
||||
- (void)removeEmptyEntry:(UITableView *)tableview section:(NSInteger)section animated:(BOOL)animated {
|
||||
NSMutableArray *sectionDict = [self getSectionData:section];
|
||||
for (NSInteger i = sectionDict.count - 1; i >= 0; i--) {
|
||||
NSString *value = sectionDict[i];
|
||||
if (value.length == 0) {
|
||||
[self removeEntry:tableview indexPath:[NSIndexPath indexPathForRow:i inSection:section] animated:animated];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (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);
|
||||
- (void)removeEntry:(UITableView *)tableview indexPath:(NSIndexPath *)path animated:(BOOL)animated {
|
||||
bool rmed = YES;
|
||||
if (path.section == ContactSections_Number) {
|
||||
rmed = [_contact removePhoneNumberAtIndex:path.row];
|
||||
} else if (path.section == ContactSections_Sip) {
|
||||
rmed = [_contact removeSipAddressAtIndex:path.row];
|
||||
} else if (path.section == ContactSections_Email) {
|
||||
rmed = [_contact removeEmailAtIndex:path.row];
|
||||
} 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);
|
||||
rmed = NO;
|
||||
}
|
||||
|
||||
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);
|
||||
if (rmed) {
|
||||
[tableview deleteRowsAtIndexPaths:@[ path ]
|
||||
withRowAnimation:animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
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;
|
||||
bool added = FALSE;
|
||||
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);
|
||||
added = [_contact addPhoneNumber:value];
|
||||
} 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);
|
||||
}
|
||||
added = [_contact addSipAddress: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);
|
||||
added = [_contact addEmail:value];
|
||||
}
|
||||
|
||||
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];
|
||||
NSUInteger count = [self getSectionData:section].count;
|
||||
[tableview insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:count - 1 inSection:section] ]
|
||||
withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
}
|
||||
|
||||
- (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)
|
||||
- (void)setContact:(Contact *)acontact {
|
||||
if (acontact == _contact)
|
||||
return;
|
||||
|
||||
if (contact != nil && ABRecordGetRecordID(contact) == kABRecordInvalidID) {
|
||||
CFRelease(contact);
|
||||
}
|
||||
contact = acontact;
|
||||
_contact = acontact;
|
||||
[self loadData];
|
||||
}
|
||||
|
||||
|
|
@ -455,18 +114,32 @@ INIT_WITH_COMMON_C {
|
|||
[self addEntry:[self tableView] section:i animated:FALSE value:address];
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
return _contact.firstName.length + _contact.lastName.length > 0;
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource Functions
|
||||
|
||||
- (void)loadData {
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return ContactSections_MAX;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (section == ContactSections_FirstName || section == ContactSections_LastName) {
|
||||
return (self.tableView.isEditing) ? 1 : 0 /*no first and last name when not editting */;
|
||||
} else {
|
||||
return [[self getSectionData:section] count];
|
||||
/*first and last name only when editting */
|
||||
return (self.tableView.isEditing) ? 1 : 0;
|
||||
} else if (section == ContactSections_Sip) {
|
||||
return _contact.sipAddresses.count;
|
||||
} else if (section == ContactSections_Number) {
|
||||
return _contact.phoneNumbers.count;
|
||||
} else if (section == ContactSections_Email) {
|
||||
return _contact.emails.count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -476,73 +149,37 @@ INIT_WITH_COMMON_C {
|
|||
cell = [[UIContactDetailsCell alloc] initWithIdentifier:kCellId];
|
||||
[cell.editTextfield setDelegate:self];
|
||||
}
|
||||
|
||||
cell.indexPath = indexPath;
|
||||
|
||||
NSMutableArray *sectionDict = [self getSectionData:[indexPath section]];
|
||||
Entry *entry = [sectionDict objectAtIndex:[indexPath row]];
|
||||
|
||||
NSString *value = @"";
|
||||
[cell hideDeleteButton:NO];
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeDefault];
|
||||
NSString *value = @"";
|
||||
if (indexPath.section == ContactSections_FirstName) {
|
||||
value = (NSString *)CFBridgingRelease(
|
||||
ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_FirstName]));
|
||||
value = _contact.firstName;
|
||||
[cell hideDeleteButton:YES];
|
||||
} else if (indexPath.section == ContactSections_LastName) {
|
||||
value = (NSString *)CFBridgingRelease(
|
||||
ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_LastName]));
|
||||
value = _contact.lastName;
|
||||
[cell hideDeleteButton:YES];
|
||||
} else if ([indexPath section] == ContactSections_Number) {
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
|
||||
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
|
||||
if (index != -1) {
|
||||
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]);
|
||||
if (index != -1) {
|
||||
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, index);
|
||||
value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey));
|
||||
CFRelease(lDict);
|
||||
}
|
||||
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(lMap);
|
||||
} else if ([indexPath section] == ContactSections_Email) {
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
|
||||
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
|
||||
if (index != -1) {
|
||||
NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(lMap, index));
|
||||
if (valueRef != NULL) {
|
||||
value = [FastAddressBook localizedLabel:valueRef];
|
||||
}
|
||||
}
|
||||
CFRelease(lMap);
|
||||
}
|
||||
[cell setAddress:value];
|
||||
if ([indexPath section] == ContactSections_Number) {
|
||||
value = _contact.phoneNumbers[indexPath.row];
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad];
|
||||
} else if ([indexPath section] == ContactSections_Sip) {
|
||||
value = _contact.sipAddresses[indexPath.row];
|
||||
LinphoneAddress *addr = NULL;
|
||||
if ([[LinphoneManager instance] lpConfigBoolForKey:@"contact_display_username_only"] &&
|
||||
(addr = linphone_address_new([value UTF8String]))) {
|
||||
value = [NSString stringWithCString:linphone_address_get_username(addr)
|
||||
encoding:[NSString defaultCStringEncoding]];
|
||||
linphone_address_destroy(addr);
|
||||
}
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
|
||||
} else if ([indexPath section] == ContactSections_Email) {
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
|
||||
} else {
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeDefault];
|
||||
value = _contact.emails[indexPath.row];
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress];
|
||||
}
|
||||
|
||||
[cell setAddress:value];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
|
@ -552,11 +189,11 @@ INIT_WITH_COMMON_C {
|
|||
[LinphoneUtils findAndResignFirstResponder:[self tableView]];
|
||||
if (editingStyle == UITableViewCellEditingStyleInsert) {
|
||||
[tableView beginUpdates];
|
||||
[self addEntry:tableView section:[indexPath section] animated:TRUE];
|
||||
[self addEntry:tableView section:[indexPath section] animated:TRUE value:@""];
|
||||
[tableView endUpdates];
|
||||
} else if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
[tableView beginUpdates];
|
||||
[self removeEntry:tableView path:indexPath animated:TRUE];
|
||||
[self removeEntry:tableView indexPath:indexPath animated:TRUE];
|
||||
[tableView endUpdates];
|
||||
}
|
||||
}
|
||||
|
|
@ -564,16 +201,16 @@ INIT_WITH_COMMON_C {
|
|||
#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];
|
||||
[self addEntry:self.tableView section:section animated:animated value:@""];
|
||||
}
|
||||
}
|
||||
_editButton.enabled = [self isValid];
|
||||
} else {
|
||||
[LinphoneUtils findAndResignFirstResponder:[self tableView]];
|
||||
// remove empty phone numbers
|
||||
|
|
@ -582,23 +219,21 @@ INIT_WITH_COMMON_C {
|
|||
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 removeEmptyEntry:self.tableView section:section animated:NO];
|
||||
// the section is empty -> remove titles
|
||||
if ([[self getSectionData:section] count] == 0 && animated) {
|
||||
[self.tableView
|
||||
reloadSections:[NSIndexSet indexSetWithIndex:section]
|
||||
withRowAnimation:animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
}
|
||||
_editButton.enabled = YES;
|
||||
}
|
||||
[self loadData];
|
||||
if (contactDetailsDelegate != nil) {
|
||||
[contactDetailsDelegate onModification:nil];
|
||||
}
|
||||
}
|
||||
// order is imported here: empty rows must be deleted before table change editing mode
|
||||
[super setEditing:editing animated:animated];
|
||||
|
||||
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
|
||||
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return UITableViewCellEditingStyleNone;
|
||||
[self loadData];
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
||||
|
|
@ -668,82 +303,9 @@ INIT_WITH_COMMON_C {
|
|||
forRowAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate Functions
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField
|
||||
shouldChangeCharactersInRange:(NSRange)range
|
||||
replacementString:(NSString *)string {
|
||||
if (contactDetailsDelegate != nil) {
|
||||
[contactDetailsDelegate onModification:nil];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
|
||||
UIView *view = [textField superview];
|
||||
while (view != nil && ![view isKindOfClass:[UIContactDetailsCell class]])
|
||||
view = [view superview];
|
||||
if (view != nil) {
|
||||
UIContactDetailsCell *cell = (UIContactDetailsCell *)view;
|
||||
// we cannot use indexPathForCell method here because if the cell is not visible anymore,
|
||||
// it will return nil..
|
||||
NSIndexPath *path = cell.indexPath; // [self.tableView indexPathForCell:cell];
|
||||
ContactSections sect = (ContactSections)[path section];
|
||||
ABPropertyID property = [self propertyIDForSection:sect];
|
||||
NSString *value = [textField text];
|
||||
|
||||
NSMutableArray *sectionDict = [self getSectionData:[path section]];
|
||||
Entry *entry = [sectionDict objectAtIndex:[path row]];
|
||||
|
||||
switch (sect) {
|
||||
case ContactSections_FirstName:
|
||||
case ContactSections_LastName: {
|
||||
CFErrorRef error = NULL;
|
||||
ABRecordSetValue(contact, property, (__bridge CFTypeRef)value, (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) {
|
||||
[contactDetailsDelegate onModification:nil];
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
- (BOOL)isValid {
|
||||
NSString *firstName = (NSString *)CFBridgingRelease(
|
||||
ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_FirstName]));
|
||||
NSString *lastName =
|
||||
(NSString *)CFBridgingRelease(ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_LastName]));
|
||||
return firstName.length > 0 || lastName.length > 0;
|
||||
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
|
||||
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return UITableViewCellEditingStyleNone;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -765,4 +327,49 @@ INIT_WITH_COMMON_C {
|
|||
return [self tableView:tableView viewForHeaderInSection:section].frame.size.height;
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate Functions
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
|
||||
UIView *view = [textField superview];
|
||||
while (view != nil && ![view isKindOfClass:[UIContactDetailsCell class]])
|
||||
view = [view superview];
|
||||
if (view != nil) {
|
||||
UIContactDetailsCell *cell = (UIContactDetailsCell *)view;
|
||||
// we cannot use indexPathForCell method here because if the cell is not visible anymore,
|
||||
// it will return nil..
|
||||
NSIndexPath *path = cell.indexPath; // [self.tableView indexPathForCell:cell];
|
||||
ContactSections sect = (ContactSections)[path section];
|
||||
NSString *value = [textField text];
|
||||
|
||||
switch (sect) {
|
||||
case ContactSections_FirstName:
|
||||
_contact.firstName = value;
|
||||
break;
|
||||
case ContactSections_LastName:
|
||||
_contact.lastName = value;
|
||||
break;
|
||||
case ContactSections_Sip:
|
||||
[_contact setSipAddress:value atIndex:path.row];
|
||||
break;
|
||||
case ContactSections_Email:
|
||||
[_contact setEmail:value atIndex:path.row];
|
||||
break;
|
||||
case ContactSections_Number:
|
||||
[_contact setPhoneNumber:value atIndex:path.row];
|
||||
break;
|
||||
case ContactSections_MAX:
|
||||
case ContactSections_None:
|
||||
break;
|
||||
}
|
||||
cell.editTextfield.text = value;
|
||||
_editButton.enabled = [self isValid];
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AddressBook/AddressBook.h>
|
||||
|
||||
#import "UICompositeView.h"
|
||||
#import "UIToggleButton.h"
|
||||
|
|
@ -26,8 +25,7 @@
|
|||
#import "UIRoundedImageView.h"
|
||||
#import "ImagePickerView.h"
|
||||
|
||||
@interface ContactDetailsView
|
||||
: TPMultiLayoutViewController <UICompositeViewDelegate, ContactDetailsDelegate, ImagePickerDelegate> {
|
||||
@interface ContactDetailsView : TPMultiLayoutViewController <UICompositeViewDelegate, ImagePickerDelegate> {
|
||||
ABAddressBookRef addressBook;
|
||||
BOOL inhibUpdate;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
return;
|
||||
}
|
||||
|
||||
LOGI(@"Reset data to contact %p", _contact);
|
||||
ABRecordID recordID = ABRecordGetRecordID(_contact);
|
||||
ABAddressBookRevert(addressBook);
|
||||
_contact = ABAddressBookGetPersonWithRecordID(addressBook, recordID);
|
||||
|
|
@ -60,8 +59,10 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
[PhoneMainView.instance popCurrentView];
|
||||
return;
|
||||
}
|
||||
LOGI(@"Reset data to contact %p", _contact);
|
||||
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact thumbnail:NO] bordered:NO withRoundedRadius:YES];
|
||||
[_tableController setContact:_contact];
|
||||
[_tableController setContact:[[Contact alloc] initWithPerson:_contact]];
|
||||
}
|
||||
|
||||
static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) {
|
||||
|
|
@ -118,11 +119,10 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
_contact = acontact;
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact thumbnail:NO] bordered:NO withRoundedRadius:YES];
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:acontact];
|
||||
[_tableController setContact:_contact];
|
||||
[_tableController setContact:[[Contact alloc] initWithPerson:_contact]];
|
||||
|
||||
if (reload) {
|
||||
[self setEditing:TRUE animated:FALSE];
|
||||
[[_tableController tableView] reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,10 +274,8 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (IBAction)onEditClick:(id)event {
|
||||
if (_tableController.isEditing) {
|
||||
if ([_tableController isValid]) {
|
||||
[self setEditing:FALSE];
|
||||
[self saveData];
|
||||
}
|
||||
[self setEditing:FALSE];
|
||||
[self saveData];
|
||||
} else {
|
||||
[self setEditing:TRUE];
|
||||
}
|
||||
|
|
@ -303,14 +301,6 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)onModification:(id)event {
|
||||
if (!_tableController.isEditing || [_tableController isValid]) {
|
||||
[_editButton setEnabled:TRUE];
|
||||
} else {
|
||||
[_editButton setEnabled:FALSE];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Image picker delegate
|
||||
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSDictionary *)info {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (tableController.isEditing) {
|
||||
tableController.editing = NO;
|
||||
}
|
||||
[self update];
|
||||
[self refreshButtons];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
|
|
@ -144,20 +144,20 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)changeView:(ContactsCategory)view {
|
||||
CGRect frame = _selectedButtonImage.frame;
|
||||
if (view == ContactsAll) {
|
||||
if (view == ContactsAll && !allButton.selected) {
|
||||
frame.origin.x = allButton.frame.origin.x;
|
||||
[ContactSelection setSipFilter:nil];
|
||||
[ContactSelection enableEmailFilter:FALSE];
|
||||
[tableController loadData];
|
||||
allButton.selected = TRUE;
|
||||
linphoneButton.selected = FALSE;
|
||||
} else {
|
||||
[tableController loadData];
|
||||
} else if (view == ContactsLinphone && !linphoneButton.selected) {
|
||||
frame.origin.x = linphoneButton.frame.origin.x;
|
||||
[ContactSelection setSipFilter:LinphoneManager.instance.contactFilter];
|
||||
[ContactSelection enableEmailFilter:FALSE];
|
||||
[tableController loadData];
|
||||
linphoneButton.selected = TRUE;
|
||||
allButton.selected = FALSE;
|
||||
[tableController loadData];
|
||||
}
|
||||
_selectedButtonImage.frame = frame;
|
||||
}
|
||||
|
|
@ -167,11 +167,6 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[self changeView:[ContactSelection getSipFilter] ? ContactsLinphone : ContactsAll];
|
||||
}
|
||||
|
||||
- (void)update {
|
||||
[self refreshButtons];
|
||||
[tableController loadData];
|
||||
}
|
||||
|
||||
#pragma mark - Action Functions
|
||||
|
||||
- (IBAction)onAllClick:(id)event {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="UIContactDetailsCell">
|
||||
|
|
@ -28,16 +28,14 @@
|
|||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" minimumFontSize="17" id="dTn-Hc-bGM" userLabel="editTextField">
|
||||
<rect key="frame" x="8" y="7" width="326" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.90588235289999997" green="0.90588235289999997" blue="0.90588235289999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<rect key="contentStretch" x="1.3877787807814457e-17" y="0.0" width="1" height="1"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
<textInputTraits key="textInputTraits" returnKeyType="done"/>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="C2f-aP-xjR" userLabel="deleteButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="340" y="7" width="30" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<state key="normal" image="delete_field_default.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
|
|
@ -48,7 +46,6 @@
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="SR2-3m-6t5" userLabel="defaultView">
|
||||
|
|
@ -58,7 +55,6 @@
|
|||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="ZbV-2Z-b4y" userLabel="callButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="135" y="40" width="44" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<animations/>
|
||||
<accessibility key="accessibilityConfiguration" label="Call"/>
|
||||
<state key="normal" image="call_start_body_default.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
@ -72,7 +68,6 @@
|
|||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="FDT-HY-OQZ" userLabel="chatButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="195" y="40" width="44" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<animations/>
|
||||
<accessibility key="accessibilityConfiguration" label="Chat"/>
|
||||
<state key="normal" image="chat_start_body_default.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
@ -86,16 +81,13 @@
|
|||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="john.doe@sip.linphone.org" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="frB-ep-LWi" userLabel="addressLabel">
|
||||
<rect key="frame" x="8" y="0.0" width="359" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
</view>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
|
|
|
|||
|
|
@ -356,7 +356,8 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void
|
|||
error = NULL;
|
||||
ABAddressBookSave(addressBook, (CFErrorRef *)&error);
|
||||
|
||||
[self reload];
|
||||
// TODO: stop reloading the whole address book but just clear the removed entries!
|
||||
[self loadData];
|
||||
|
||||
if (error != NULL) {
|
||||
LOGE(@"Save AddressBook: Fail(%@)", [(__bridge NSError *)error localizedDescription]);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@
|
|||
633888451BFB2C49001D5E7B /* HPGrowingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 633888421BFB2C49001D5E7B /* HPGrowingTextView.m */; };
|
||||
633888461BFB2C49001D5E7B /* HPTextViewInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = 633888441BFB2C49001D5E7B /* HPTextViewInternal.m */; };
|
||||
6341807C1BBC103100F71761 /* ChatConversationCreateTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6341807B1BBC103100F71761 /* ChatConversationCreateTableView.m */; };
|
||||
63423C0A1C4501D000D9A050 /* Contact.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423C091C4501D000D9A050 /* Contact.m */; };
|
||||
634610061B61330300548952 /* UILabel+Boldify.m in Sources */ = {isa = PBXBuildFile; fileRef = 634610051B61330300548952 /* UILabel+Boldify.m */; };
|
||||
6346100F1B61409800548952 /* CallOutgoingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6346100E1B61409800548952 /* CallOutgoingView.m */; };
|
||||
634610121B6140A500548952 /* CallOutgoingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 634610101B6140A500548952 /* CallOutgoingView.xib */; };
|
||||
|
|
@ -905,6 +906,8 @@
|
|||
633E388219FFB0F400936D1C /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
6341807A1BBC103100F71761 /* ChatConversationCreateTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatConversationCreateTableView.h; sourceTree = "<group>"; };
|
||||
6341807B1BBC103100F71761 /* ChatConversationCreateTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatConversationCreateTableView.m; sourceTree = "<group>"; };
|
||||
63423C081C4501D000D9A050 /* Contact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Contact.h; sourceTree = "<group>"; };
|
||||
63423C091C4501D000D9A050 /* Contact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Contact.m; sourceTree = "<group>"; };
|
||||
634610041B61330300548952 /* UILabel+Boldify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UILabel+Boldify.h"; sourceTree = "<group>"; };
|
||||
634610051B61330300548952 /* UILabel+Boldify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UILabel+Boldify.m"; sourceTree = "<group>"; };
|
||||
6346100D1B61409800548952 /* CallOutgoingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallOutgoingView.h; sourceTree = "<group>"; };
|
||||
|
|
@ -1378,7 +1381,6 @@
|
|||
C9B3A6FD15B485DB006F52EE /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = Utils/Utils.h; sourceTree = "<group>"; };
|
||||
D306459C1611EC2900BB571E /* UILoadingImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UILoadingImageView.h; sourceTree = "<group>"; };
|
||||
D306459D1611EC2900BB571E /* UILoadingImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UILoadingImageView.m; sourceTree = "<group>"; };
|
||||
D30BBD1215D3EFEB000F93DD /* ContactDetailsDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsDelegate.h; sourceTree = "<group>"; };
|
||||
D30BF33216A427BC00AF0026 /* libtunnel.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtunnel.a; path = "liblinphone-sdk/apple-darwin/lib/libtunnel.a"; sourceTree = "<group>"; };
|
||||
D3128FDE15AABC7E00A2147A /* ContactDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsView.h; sourceTree = "<group>"; };
|
||||
D3128FDF15AABC7E00A2147A /* ContactDetailsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactDetailsView.m; sourceTree = "<group>"; };
|
||||
|
|
@ -1760,7 +1762,6 @@
|
|||
D35E7594159460560066B1C1 /* ChatsListView.h */,
|
||||
D35E7595159460560066B1C1 /* ChatsListView.m */,
|
||||
D38187B415FE340500C3EDCA /* ChatsListView.xib */,
|
||||
D30BBD1215D3EFEB000F93DD /* ContactDetailsDelegate.h */,
|
||||
D37C639915AADEF4009D0BAC /* ContactDetailsTableView.h */,
|
||||
D37C639A15AADEF5009D0BAC /* ContactDetailsTableView.m */,
|
||||
D3128FDE15AABC7E00A2147A /* ContactDetailsView.h */,
|
||||
|
|
@ -2571,6 +2572,8 @@
|
|||
D3554EC515CA79A900478841 /* XMLRPC.xcodeproj */,
|
||||
63D11C521C3D501200E8FCEE /* Log.m */,
|
||||
63D11C541C3D503A00E8FCEE /* Log.h */,
|
||||
63423C081C4501D000D9A050 /* Contact.h */,
|
||||
63423C091C4501D000D9A050 /* Contact.m */,
|
||||
);
|
||||
name = Utils;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -3414,6 +3417,7 @@
|
|||
22AA8B0113D83F6300B30535 /* UICamSwitch.m in Sources */,
|
||||
63B8D6A21BCBF43100C12B09 /* UIChatCreateCell.m in Sources */,
|
||||
636BC9971B5F921B00C754CE /* UIIconButton.m in Sources */,
|
||||
63423C0A1C4501D000D9A050 /* Contact.m in Sources */,
|
||||
340751E7150F38FD00B89C47 /* UIVideoButton.m in Sources */,
|
||||
34216F401547EBCD00EA9777 /* VideoZoomHandler.m in Sources */,
|
||||
D3F83EEC1582021700336684 /* CallView.m in Sources */,
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@
|
|||
#import "Log.h"
|
||||
#import "Utils.h"
|
||||
|
||||
#import "UIToggleButton.h"
|
||||
#import "UISpeakerButton.h"
|
||||
#import "UIBluetoothButton.h"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue