Add fuzzy search bar in Contacts view

This commit is contained in:
Gautier Pelloux-Prayer 2014-09-25 12:21:43 +02:00
parent 55a88095bd
commit 6065ac73c3
10 changed files with 645 additions and 538 deletions

View file

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment defaultVersion="1072" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ChatViewController">
@ -91,14 +90,11 @@
</textField>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
</view>
<tableViewController autoresizesArchivedViewToFullSize="NO" id="4" userLabel="tableController" customClass="ChatTableViewController">
<extendedEdge key="edgesForExtendedLayout"/>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<simulatedOrientationMetrics key="simulatedOrientationMetrics"/>
<nil key="simulatedDestinationMetrics"/>
<connections>
<outlet property="view" destination="6" id="13"/>
</connections>
@ -113,4 +109,9 @@
<image name="field_background.png" width="542" height="88"/>
<image name="toolsbar_background.png" width="5" height="88"/>
</resources>
</document>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment defaultVersion="1072" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
<deployment defaultVersion="1536" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ContactsViewController">
@ -11,6 +11,7 @@
<outlet property="allButton" destination="4" id="27"/>
<outlet property="backButton" destination="87" id="90"/>
<outlet property="linphoneButton" destination="5" id="31"/>
<outlet property="searchBar" destination="5jE-oF-d45" id="xfS-xo-2Bm"/>
<outlet property="toolBar" destination="3" id="n95-dF-EoN"/>
<outlet property="view" destination="2" id="16"/>
</connections>
@ -21,7 +22,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" id="3" userLabel="toolBar">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="88"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="toolsbar_background.png" id="92" userLabel="background">
@ -109,11 +110,21 @@
<action selector="onBackClick:" destination="-1" eventType="touchUpInside" id="89"/>
</connections>
</button>
<searchBar contentMode="redraw" id="5jE-oF-d45" userLabel="searchBar">
<rect key="frame" x="0.0" y="44" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<textInputTraits key="textInputTraits"/>
<connections>
<outlet property="delegate" destination="-1" id="4jL-Rv-dW7"/>
</connections>
</searchBar>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
</view>
</objects>
<resources>
@ -127,4 +138,9 @@
<image name="contacts_linphone_selected.png" width="213" height="88"/>
<image name="toolsbar_background.png" width="5" height="88"/>
</resources>
</document>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>

View file

@ -123,7 +123,8 @@ static UICompositeViewDescription *compositeDescription = nil;
[ContactSelection setSelectionMode:ContactSelectionModeMessage];
[ContactSelection setAddAddress:nil];
[ContactSelection setSipFilter: [LinphoneManager instance].contactFilter];
[ContactSelection setEmailFilter:FALSE];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection setNameOrEmailFilter:nil];
[[PhoneMainView instance] changeCurrentView:[ContactsViewController compositeViewDescription] push:TRUE];
} else {
[self startChatRoom];

View file

@ -207,7 +207,8 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {ContactSe
if(CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField, CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), kCFCompareCaseInsensitive) == 0) {
add = true;
}
} else { //check domain
} else {
//check domain
LinphoneAddress* address = linphone_address_new([(NSString*)CFDictionaryGetValue(lDict,kABPersonInstantMessageUsernameKey) UTF8String]);
if (address) {
if ([[ContactSelection getSipFilter] compare:@"*" options:NSCaseInsensitiveSearch] == NSOrderedSame) {

View file

@ -4,18 +4,18 @@
*
* 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
* 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 "ContactsTableViewController.h"
#import "UIContactCell.h"
@ -33,237 +33,273 @@ static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef inf
#pragma mark - Lifecycle Functions
- (void)initContactsTableViewController {
addressBookMap = [[OrderedDictionary alloc] init];
avatarMap = [[NSMutableDictionary alloc] init];
addressBook = ABAddressBookCreateWithOptions(nil, nil);
ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, self);
addressBookMap = [[OrderedDictionary alloc] init];
avatarMap = [[NSMutableDictionary alloc] init];
addressBook = ABAddressBookCreateWithOptions(nil, nil);
ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, self);
}
- (id)init {
self = [super init];
if (self) {
self = [super init];
if (self) {
[self initContactsTableViewController];
}
return self;
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (self) {
self = [super initWithCoder:decoder];
if (self) {
[self initContactsTableViewController];
}
return self;
}
return self;
}
- (void)dealloc {
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
CFRelease(addressBook);
[addressBookMap release];
[avatarMap release];
[super dealloc];
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
CFRelease(addressBook);
[addressBookMap release];
[avatarMap release];
[super dealloc];
}
#pragma mark -
#pragma mark -
- (BOOL)contactHasValidSipDomain:(ABRecordRef)person {
// Check if one of the contact' sip URI matches the expected SIP filter
ABMultiValueRef personSipAddresses = ABRecordCopyValue(person, kABPersonInstantMessageProperty);
BOOL match = false;
NSString * filter = [ContactSelection getSipFilter];
for(int i = 0; i < ABMultiValueGetCount(personSipAddresses) && !match; ++i) {
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(personSipAddresses, i);
if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
CFStringRef serviceKey = CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey);
if (CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField, serviceKey, kCFCompareCaseInsensitive) == 0) {
match = true;
}
} else {
//check domain
LinphoneAddress* address = linphone_address_new([(NSString*)CFDictionaryGetValue(lDict,kABPersonInstantMessageUsernameKey) UTF8String]);
if (address) {
NSString* domain = [NSString stringWithCString:linphone_address_get_domain(address)
encoding:[NSString defaultCStringEncoding]];
if (([filter compare:@"*" options:NSCaseInsensitiveSearch] == NSOrderedSame)
|| ([filter compare:domain options:NSCaseInsensitiveSearch] == NSOrderedSame)) {
match = true;
}
linphone_address_destroy(address);
}
}
CFRelease(lDict);
}
return match;
}
static int ms_strcmpfuz(const char * fuzzy_word, const char * sentence) {
if (! fuzzy_word || !sentence) {
return fuzzy_word == sentence;
}
const char * c = fuzzy_word;
const char * within_sentence = sentence;
for (; c != NULL && *c != '\0' && within_sentence != NULL; ++c) {
within_sentence = strchr(within_sentence, *c);
// Could not find c character in sentence. Abort.
if (within_sentence == NULL) {
break;
}
// since strchr returns the index of the matched char, move forward
within_sentence++;
}
// If the whole fuzzy was found, returns 0. Otherwise returns number of characters left.
return (within_sentence != NULL ? 0 : fuzzy_word + strlen(fuzzy_word) - c);
}
- (void)loadData {
[LinphoneLogger logc:LinphoneLoggerLog format:"Load contact list"];
@synchronized (addressBookMap) {
// Reset Address book
[addressBookMap removeAllObjects];
NSArray *lContacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
for (id lPerson in lContacts) {
BOOL add = true;
if([ContactSelection getSipFilter] || [ContactSelection getEmailFilter]) {
add = false;
}
if([ContactSelection getSipFilter]) {
ABMultiValueRef lMap = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonInstantMessageProperty);
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i);
if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
CFStringRef serviceKey = CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey);
CFStringRef username = username=CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
if(CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField, serviceKey, kCFCompareCaseInsensitive) == 0) {
add = true;
} else {
add=false;
[LinphoneLogger logc:LinphoneLoggerLog format:"Load contact list"];
@synchronized (addressBookMap) {
// Reset Address book
[addressBookMap removeAllObjects];
NSArray *lContacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
for (id lPerson in lContacts) {
BOOL add = true;
ABRecordRef person = (ABRecordRef)lPerson;
// Do not add the contact directly if we set some filter
if([ContactSelection getSipFilter] || [ContactSelection emailFilterEnabled]) {
add = false;
}
if([ContactSelection getSipFilter] && [self contactHasValidSipDomain:person]) {
add = true;
}
if (!add && [ContactSelection emailFilterEnabled]) {
ABMultiValueRef personEmailAddresses = ABRecordCopyValue(person, kABPersonEmailProperty);
// Add this contact if it has an email
add = (ABMultiValueGetCount(personEmailAddresses) > 0);
CFRelease(personEmailAddresses);
}
if(add) {
CFStringRef lFirstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFStringRef lLocalizedFirstName = (lFirstName != nil)? ABAddressBookCopyLocalizedLabel(lFirstName): nil;
CFStringRef lLastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
CFStringRef lLocalizedLastName = (lLastName != nil)? ABAddressBookCopyLocalizedLabel(lLastName): nil;
CFStringRef lOrganization = ABRecordCopyValue(person, kABPersonOrganizationProperty);
CFStringRef lLocalizedlOrganization = (lOrganization != nil)? ABAddressBookCopyLocalizedLabel(lOrganization): nil;
NSString *name = nil;
if(lLocalizedFirstName != nil && lLocalizedLastName != nil) {
name=[NSString stringWithFormat:@"%@ %@", [(NSString *)lLocalizedFirstName retain], [(NSString *)lLocalizedLastName retain]];
} else if(lLocalizedLastName != nil) {
name=[NSString stringWithFormat:@"%@",[(NSString *)lLocalizedLastName retain]];
} else if(lLocalizedFirstName != nil) {
name=[NSString stringWithFormat:@"%@",[(NSString *)lLocalizedFirstName retain]];
} else if(lLocalizedlOrganization != nil) {
name=[NSString stringWithFormat:@"%@",[(NSString *)lLocalizedlOrganization retain]];
}
if(name != nil && [name length] > 0) {
// Add the contact only if it fuzzy match filter too (if any)
if ([ContactSelection getNameOrEmailFilter] == nil ||
(ms_strcmpfuz([[[ContactSelection getNameOrEmailFilter] lowercaseString] UTF8String], [[name lowercaseString] UTF8String]) == 0)) {
// Put in correct subDic
NSString *firstChar = [[name substringToIndex:1] uppercaseString];
if([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') {
firstChar = @"#";
}
} 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;
}
}
CFRelease(lDict);
}
CFRelease(lMap);
}
if ((add == false) && [ContactSelection getEmailFilter]) {
ABMultiValueRef lMap = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonEmailProperty);
if (ABMultiValueGetCount(lMap) > 0) {
add = true;
}
CFRelease(lMap);
}
if(add) {
CFStringRef lFirstName = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonFirstNameProperty);
CFStringRef lLocalizedFirstName = (lFirstName != nil)? ABAddressBookCopyLocalizedLabel(lFirstName): nil;
CFStringRef lLastName = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonLastNameProperty);
CFStringRef lLocalizedLastName = (lLastName != nil)? ABAddressBookCopyLocalizedLabel(lLastName): nil;
CFStringRef lOrganization = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonOrganizationProperty);
CFStringRef lLocalizedlOrganization = (lOrganization != nil)? ABAddressBookCopyLocalizedLabel(lOrganization): nil;
NSString *name = nil;
if(lLocalizedFirstName != nil && lLocalizedLastName != nil) {
name=[NSString stringWithFormat:@"%@%@", [(NSString *)lLocalizedFirstName retain], [(NSString *)lLocalizedLastName retain]];
} else if(lLocalizedLastName != nil) {
name=[NSString stringWithFormat:@"%@",[(NSString *)lLocalizedLastName retain]];
} else if(lLocalizedFirstName != nil) {
name=[NSString stringWithFormat:@"%@",[(NSString *)lLocalizedFirstName retain]];
} else if(lLocalizedlOrganization != nil) {
name=[NSString stringWithFormat:@"%@",[(NSString *)lLocalizedlOrganization retain]];
}
if(name != nil && [name length] > 0) {
// Put in correct subDic
NSString *firstChar = [[name substringToIndex:1] uppercaseString];
if([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') {
firstChar = @"#";
}
OrderedDictionary *subDic =[addressBookMap objectForKey: firstChar];
if(subDic == nil) {
subDic = [[[OrderedDictionary alloc] init] autorelease];
[addressBookMap insertObject:subDic forKey:firstChar selector:@selector(caseInsensitiveCompare:)];
}
[subDic insertObject:lPerson forKey:name selector:@selector(caseInsensitiveCompare:)];
}
if(lLocalizedlOrganization != nil)
CFRelease(lLocalizedlOrganization);
if(lOrganization != nil)
CFRelease(lOrganization);
if(lLocalizedLastName != nil)
CFRelease(lLocalizedLastName);
if(lLastName != nil)
CFRelease(lLastName);
if(lLocalizedFirstName != nil)
CFRelease(lLocalizedFirstName);
if(lFirstName != nil)
CFRelease(lFirstName);
}
}
if (lContacts) CFRelease(lContacts);
}
[self.tableView reloadData];
OrderedDictionary *subDic =[addressBookMap objectForKey: firstChar];
if(subDic == nil) {
subDic = [[[OrderedDictionary alloc] init] autorelease];
[addressBookMap insertObject:subDic forKey:firstChar selector:@selector(caseInsensitiveCompare:)];
}
[subDic insertObject:lPerson forKey:name selector:@selector(caseInsensitiveCompare:)];
}
}
if(lLocalizedlOrganization != nil)
CFRelease(lLocalizedlOrganization);
if(lOrganization != nil)
CFRelease(lOrganization);
if(lLocalizedLastName != nil)
CFRelease(lLocalizedLastName);
if(lLastName != nil)
CFRelease(lLastName);
if(lLocalizedFirstName != nil)
CFRelease(lLocalizedFirstName);
if(lFirstName != nil)
CFRelease(lFirstName);
}
}
if (lContacts)
CFRelease(lContacts);
}
[self.tableView reloadData];
}
static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void *context) {
ContactsTableViewController* controller = (ContactsTableViewController*)context;
ABAddressBookRevert(addressBook);
[controller->avatarMap removeAllObjects];
[controller loadData];
ContactsTableViewController* controller = (ContactsTableViewController*)context;
ABAddressBookRevert(addressBook);
[controller->avatarMap removeAllObjects];
[controller loadData];
}
#pragma mark - ViewController Functions
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[super viewWillDisappear:animated];
}
#pragma mark - UITableViewDataSource Functions
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [addressBookMap allKeys];
return [addressBookMap allKeys];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [addressBookMap count];
return [addressBookMap count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [(OrderedDictionary *)[addressBookMap objectForKey: [addressBookMap keyAtIndex: section]] count];
return [(OrderedDictionary *)[addressBookMap objectForKey: [addressBookMap keyAtIndex: section]] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellId = @"UIContactCell";
UIContactCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId];
if (cell == nil) {
cell = [[[UIContactCell alloc] initWithIdentifier:kCellId] autorelease];
// Background View
UACellBackgroundView *selectedBackgroundView = [[[UACellBackgroundView alloc] initWithFrame:CGRectZero] autorelease];
cell.selectedBackgroundView = selectedBackgroundView;
[selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR];
}
OrderedDictionary *subDic = [addressBookMap objectForKey: [addressBookMap keyAtIndex: [indexPath section]]];
NSString *key = [[subDic allKeys] objectAtIndex:[indexPath row]];
ABRecordRef contact = [subDic objectForKey:key];
// Cached avatar
UIImage *image = nil;
id data = [avatarMap objectForKey:[NSNumber numberWithInt: ABRecordGetRecordID(contact)]];
if(data == nil) {
image = [FastAddressBook getContactImage:contact thumbnail:true];
if(image != nil) {
[avatarMap setObject:image forKey:[NSNumber numberWithInt: ABRecordGetRecordID(contact)]];
} else {
[avatarMap setObject:[NSNull null] forKey:[NSNumber numberWithInt: ABRecordGetRecordID(contact)]];
}
} else if(data != [NSNull null]) {
image = data;
}
if(image == nil) {
image = [UIImage imageNamed:@"avatar_unknown_small.png"];
}
[[cell avatarImage] setImage:image];
[cell setContact: contact];
return cell;
static NSString *kCellId = @"UIContactCell";
UIContactCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId];
if (cell == nil) {
cell = [[[UIContactCell alloc] initWithIdentifier:kCellId] autorelease];
// Background View
UACellBackgroundView *selectedBackgroundView = [[[UACellBackgroundView alloc] initWithFrame:CGRectZero] autorelease];
cell.selectedBackgroundView = selectedBackgroundView;
[selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR];
}
OrderedDictionary *subDic = [addressBookMap objectForKey: [addressBookMap keyAtIndex: [indexPath section]]];
NSString *key = [[subDic allKeys] objectAtIndex:[indexPath row]];
ABRecordRef contact = [subDic objectForKey:key];
// Cached avatar
UIImage *image = nil;
id data = [avatarMap objectForKey:[NSNumber numberWithInt: ABRecordGetRecordID(contact)]];
if(data == nil) {
image = [FastAddressBook getContactImage:contact thumbnail:true];
if(image != nil) {
[avatarMap setObject:image forKey:[NSNumber numberWithInt: ABRecordGetRecordID(contact)]];
} else {
[avatarMap setObject:[NSNull null] forKey:[NSNumber numberWithInt: ABRecordGetRecordID(contact)]];
}
} else if(data != [NSNull null]) {
image = data;
}
if(image == nil) {
image = [UIImage imageNamed:@"avatar_unknown_small.png"];
}
[[cell avatarImage] setImage:image];
[cell setContact: contact];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [addressBookMap keyAtIndex: section];
return [addressBookMap keyAtIndex: section];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
OrderedDictionary *subDic = [addressBookMap objectForKey: [addressBookMap keyAtIndex: [indexPath section]]];
ABRecordRef lPerson = [subDic objectForKey: [subDic keyAtIndex:[indexPath row]]];
// Go to Contact details view
ContactDetailsViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactDetailsViewController compositeViewDescription] push:TRUE], ContactDetailsViewController);
if(controller != nil) {
if([ContactSelection getSelectionMode] != ContactSelectionModeEdit) {
[controller setContact:lPerson];
} else {
[controller editContact:lPerson address:[ContactSelection getAddAddress]];
}
}
OrderedDictionary *subDic = [addressBookMap objectForKey: [addressBookMap keyAtIndex: [indexPath section]]];
ABRecordRef lPerson = [subDic objectForKey: [subDic keyAtIndex:[indexPath row]]];
// Go to Contact details view
ContactDetailsViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactDetailsViewController compositeViewDescription] push:TRUE], ContactDetailsViewController);
if(controller != nil) {
if([ContactSelection getSelectionMode] != ContactSelectionModeEdit) {
[controller setContact:lPerson];
} else {
[controller editContact:lPerson address:[ContactSelection getAddAddress]];
}
}
}
#pragma mark - UITableViewDelegate Functions
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
// Detemine if it's in editing mode
if (self.editing) {
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
// Detemine if it's in editing mode
if (self.editing) {
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
@end

View file

@ -4,18 +4,18 @@
*
* 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
* 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 <UIKit/UIKit.h>
#import <AddressBookUI/ABPeoplePickerNavigationController.h>
@ -30,18 +30,48 @@ typedef enum _ContactSelectionMode {
ContactSelectionModeMessage
} ContactSelectionMode;
@interface ContactSelection : NSObject {
@interface ContactSelection : NSObject <UISearchBarDelegate> {
}
+ (void)setSelectionMode:(ContactSelectionMode)selectionMode;
+ (ContactSelectionMode)getSelectionMode;
+ (void)setAddAddress:(NSString*)address;
+ (NSString*)getAddAddress;
/* define sip filter, can be * or sip domain*/
/*!
* Filters contacts by SIP domain.
* @param domain SIP domain to filter. Use @"*" or nil to disable it.
*/
+ (void)setSipFilter:(NSString*) domain;
/*!
* Weither contacts are filtered by SIP domain or not.
* @return the filter used, or nil if none.
*/
+ (NSString*)getSipFilter;
+ (void)setEmailFilter:(BOOL)enable;
+ (BOOL)getEmailFilter;
/*!
* Weither always keep contacts with an email address or not.
* @param enable TRUE if you want to always keep contacts with an email.
*/
+ (void)enableEmailFilter:(BOOL)enable;
/*!
* Weither always keep contacts with an email address or not.
* @return TRUE if this behaviour is enabled.
*/
+ (BOOL)emailFilterEnabled;
/*!
* Filters contacts by name and/or email fuzzy matching pattern.
* @param fuzzyName fuzzy word to match. Use nil to disable it.
*/
+ (void)setNameOrEmailFilter:(NSString*)fuzzyName;
/*!
* Weither contacts are filtered by name and/or email.
* @return the filter used, or nil if none.
*/
+ (NSString*)getNameOrEmailFilter;
@end
@ -57,10 +87,12 @@ typedef enum _ContactSelectionMode {
@property (nonatomic, retain) IBOutlet UIButton* linphoneButton;
@property (nonatomic, retain) IBOutlet UIButton *backButton;
@property (nonatomic, retain) IBOutlet UIButton *addButton;
@property (retain, nonatomic) IBOutlet UISearchBar *searchBar;
- (IBAction)onAllClick:(id)event;
- (IBAction)onLinphoneClick:(id)event;
- (IBAction)onAddContactClick:(id)event;
- (IBAction)onBackClick:(id)event;
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText;
@end

View file

@ -4,18 +4,18 @@
*
* 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
* 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 "ContactsViewController.h"
#import "PhoneMainView.h"
@ -28,47 +28,58 @@
static ContactSelectionMode sSelectionMode = ContactSelectionModeNone;
static NSString* sAddAddress = nil;
static NSString* sSipFilter = nil;
static BOOL sEmailFilter = FALSE;
static BOOL sEnableEmailFilter = FALSE;
static NSString* sNameOrEmailFilter;
+ (void)setSelectionMode:(ContactSelectionMode)selectionMode {
sSelectionMode = selectionMode;
sSelectionMode = selectionMode;
}
+ (ContactSelectionMode)getSelectionMode {
return sSelectionMode;
return sSelectionMode;
}
+ (void)setAddAddress:(NSString*)address {
if(sAddAddress != nil) {
[sAddAddress release];
sAddAddress= nil;
}
if(address != nil) {
sAddAddress = [address retain];
}
if(sAddAddress != nil) {
[sAddAddress release];
sAddAddress= nil;
}
if(address != nil) {
sAddAddress = [address retain];
}
}
+ (NSString*)getAddAddress {
return sAddAddress;
return sAddAddress;
}
+ (void)setSipFilter:(NSString*)domain {
[sSipFilter release];
[sSipFilter release];
sSipFilter = [domain retain];
}
+ (NSString*)getSipFilter {
return sSipFilter;
return sSipFilter;
}
+ (void)setEmailFilter:(BOOL)enable {
sEmailFilter = enable;
+ (void)enableEmailFilter:(BOOL)enable {
sEnableEmailFilter = enable;
}
+ (BOOL)getEmailFilter {
return sEmailFilter;
+ (BOOL)emailFilterEnabled {
return sEnableEmailFilter;
}
+ (void)setNameOrEmailFilter:(NSString*)fuzzyName {
[sNameOrEmailFilter release];
sNameOrEmailFilter = [fuzzyName retain];
}
+ (NSString*)getNameOrEmailFilter {
return sNameOrEmailFilter;
}
@end
@implementation ContactsViewController
@ -85,28 +96,30 @@ static BOOL sEmailFilter = FALSE;
@synthesize toolBar;
typedef enum _HistoryView {
History_All,
History_Linphone,
History_MAX
History_All,
History_Linphone,
History_Search,
History_MAX
} HistoryView;
#pragma mark - Lifecycle Functions
- (id)init {
return [super initWithNibName:@"ContactsViewController" bundle:[NSBundle mainBundle]];
return [super initWithNibName:@"ContactsViewController" bundle:[NSBundle mainBundle]];
}
- (void)dealloc {
[tableController release];
[tableView release];
[allButton release];
[linphoneButton release];
[backButton release];
[addButton release];
[super dealloc];
[tableController release];
[tableView release];
[allButton release];
[linphoneButton release];
[backButton release];
[addButton release];
[_searchBar release];
[super dealloc];
}
#pragma mark - UICompositeViewDelegate Functions
@ -114,181 +127,181 @@ typedef enum _HistoryView {
static UICompositeViewDescription *compositeDescription = nil;
+ (UICompositeViewDescription *)compositeViewDescription {
if(compositeDescription == nil) {
compositeDescription = [[UICompositeViewDescription alloc] init:@"Contacts"
content:@"ContactsViewController"
stateBar:nil
stateBarEnabled:false
tabBar:@"UIMainBar"
tabBarEnabled:true
fullscreen:false
landscapeMode:[LinphoneManager runningOnIpad]
portraitMode:true];
}
return compositeDescription;
if(compositeDescription == nil) {
compositeDescription = [[UICompositeViewDescription alloc] init:@"Contacts"
content:@"ContactsViewController"
stateBar:nil
stateBarEnabled:false
tabBar:@"UIMainBar"
tabBarEnabled:true
fullscreen:false
landscapeMode:[LinphoneManager runningOnIpad]
portraitMode:true];
}
return compositeDescription;
}
#pragma mark - ViewController Functions
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[super viewWillDisappear:animated];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
BOOL use_system = [[LinphoneManager instance] lpConfigBoolForKey:@"use_system_contacts"];
if( use_system && !self.sysViewController){// use system contacts
ABPeoplePickerNavigationController* picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
picker.view.frame = self.view.frame;
[super viewWillAppear:animated];
[self.view addSubview:picker.view];
BOOL use_system = [[LinphoneManager instance] lpConfigBoolForKey:@"use_system_contacts"];
if( use_system && !self.sysViewController){// use system contacts
ABPeoplePickerNavigationController* picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
picker.view.frame = self.view.frame;
self.sysViewController = picker;
[self.view addSubview:picker.view];
} else if( !use_system && !self.tableController ){
self.sysViewController = picker;
CGRect subViewFrame= self.view.frame;
// let the toolBar be visible
subViewFrame.origin.y += self.toolBar.frame.size.height;
subViewFrame.size.height -= self.toolBar.frame.size.height;
} else if( !use_system && !self.tableController ){
self.tableController = [[[ContactsTableViewController alloc] init] autorelease];
self.tableView = [[[UITableView alloc] init] autorelease];
CGRect subViewFrame= self.view.frame;
// let the toolBar be visible
subViewFrame.origin.y += self.toolBar.frame.size.height;
subViewFrame.size.height -= self.toolBar.frame.size.height;
self.tableController.view = self.tableView;
self.tableView.frame = subViewFrame;
self.tableController = [[[ContactsTableViewController alloc] init] autorelease];
self.tableView = [[[UITableView alloc] init] autorelease];
self.tableView.dataSource = self.tableController;
self.tableView.delegate = self.tableController;
self.tableController.view = self.tableView;
self.tableView.frame = subViewFrame;
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin;
self.tableView.dataSource = self.tableController;
self.tableView.delegate = self.tableController;
[self.view addSubview:tableView];
[self update];
}
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin;
[self.view addSubview:tableView];
[self update];
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if(![FastAddressBook isAuthorized]) {
UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Address book",nil)
[super viewDidAppear:animated];
if(![FastAddressBook isAuthorized]) {
UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Address book",nil)
message:NSLocalizedString(@"You must authorize the application to have access to address book.\n"
"Toggle the application in Settings > Privacy > Contacts",nil)
"Toggle the application in Settings > Privacy > Contacts",nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Continue",nil)
otherButtonTitles:nil];
[error show];
[error release];
[[PhoneMainView instance] changeCurrentView:[DialerViewController compositeViewDescription]];
}
[[PhoneMainView instance] changeCurrentView:[DialerViewController compositeViewDescription]];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[super viewDidDisappear:animated];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self changeView:History_All];
// Set selected+over background: IB lack !
[linphoneButton setBackgroundImage:[UIImage imageNamed:@"contacts_linphone_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[linphoneButton setTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]
[super viewDidLoad];
[self changeView:History_All];
// Set selected+over background: IB lack !
[linphoneButton setBackgroundImage:[UIImage imageNamed:@"contacts_linphone_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[linphoneButton setTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]
forState:UIControlStateNormal];
[LinphoneUtils buttonFixStates:linphoneButton];
// Set selected+over background: IB lack !
[allButton setBackgroundImage:[UIImage imageNamed:@"contacts_all_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[LinphoneUtils buttonFixStates:allButton];
[tableController.tableView setBackgroundColor:[UIColor clearColor]]; // Can't do it in Xib: issue with ios4
[tableController.tableView setBackgroundView:nil]; // Can't do it in Xib: issue with ios4
// Set selected+over background: IB lack !
[allButton setBackgroundImage:[UIImage imageNamed:@"contacts_all_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[LinphoneUtils buttonFixStates:allButton];
[tableController.tableView setBackgroundColor:[UIColor clearColor]]; // Can't do it in Xib: issue with ios4
[tableController.tableView setBackgroundView:nil]; // Can't do it in Xib: issue with ios4
}
#pragma mark -
- (void)changeView:(HistoryView)view {
if(view == History_All) {
[ContactSelection setSipFilter:nil];
[ContactSelection setEmailFilter:FALSE];
[tableController loadData];
allButton.selected = TRUE;
} else {
allButton.selected = FALSE;
}
if(view == History_All) {
[ContactSelection setSipFilter:nil];
[ContactSelection enableEmailFilter:FALSE];
[tableController loadData];
allButton.selected = TRUE;
} else {
allButton.selected = FALSE;
}
if(view == History_Linphone) {
[ContactSelection setSipFilter:[LinphoneManager instance].contactFilter];
[ContactSelection setEmailFilter:FALSE];
[tableController loadData];
linphoneButton.selected = TRUE;
} else {
linphoneButton.selected = FALSE;
}
if(view == History_Linphone) {
[ContactSelection setSipFilter:[LinphoneManager instance].contactFilter];
[ContactSelection enableEmailFilter:FALSE];
[tableController loadData];
linphoneButton.selected = TRUE;
} else {
linphoneButton.selected = FALSE;
}
}
- (void)update {
switch ([ContactSelection getSelectionMode]) {
case ContactSelectionModePhone:
case ContactSelectionModeMessage:
[addButton setHidden:TRUE];
[backButton setHidden:FALSE];
break;
default:
[addButton setHidden:FALSE];
[backButton setHidden:TRUE];
break;
}
if([ContactSelection getSipFilter]) {
allButton.selected = FALSE;
linphoneButton.selected = TRUE;
} else {
allButton.selected = TRUE;
linphoneButton.selected = FALSE;
}
[tableController loadData];
switch ([ContactSelection getSelectionMode]) {
case ContactSelectionModePhone:
case ContactSelectionModeMessage:
[addButton setHidden:TRUE];
[backButton setHidden:FALSE];
break;
default:
[addButton setHidden:FALSE];
[backButton setHidden:TRUE];
break;
}
if([ContactSelection getSipFilter]) {
allButton.selected = FALSE;
linphoneButton.selected = TRUE;
} else {
allButton.selected = TRUE;
linphoneButton.selected = FALSE;
}
[tableController loadData];
}
#pragma mark - Action Functions
- (IBAction)onAllClick:(id)event {
[self changeView: History_All];
[self changeView: History_All];
}
- (IBAction)onLinphoneClick:(id)event {
[self changeView: History_Linphone];
[self changeView: History_Linphone];
}
- (IBAction)onAddContactClick:(id)event {
// Go to Contact details view
ContactDetailsViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactDetailsViewController compositeViewDescription] push:TRUE], ContactDetailsViewController);
if(controller != nil) {
if([ContactSelection getAddAddress] == nil) {
[controller newContact];
} else {
[controller newContact:[ContactSelection getAddAddress]];
}
}
// Go to Contact details view
ContactDetailsViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactDetailsViewController compositeViewDescription] push:TRUE], ContactDetailsViewController);
if(controller != nil) {
if([ContactSelection getAddAddress] == nil) {
[controller newContact];
} else {
[controller newContact:[ContactSelection getAddAddress]];
}
}
}
- (IBAction)onBackClick:(id)event {
[[PhoneMainView instance] popCurrentView];
[[PhoneMainView instance] popCurrentView];
}
@ -296,8 +309,8 @@ static UICompositeViewDescription *compositeDescription = nil;
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
[[PhoneMainView instance] popCurrentView];
return;
[[PhoneMainView instance] popCurrentView];
return;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
@ -314,19 +327,23 @@ static UICompositeViewDescription *compositeDescription = nil;
CFTypeRef multiValue = ABRecordCopyValue(person, property);
CFIndex valueIdx = ABMultiValueGetIndexForIdentifier(multiValue,identifier);
NSString *phoneNumber = (NSString *)ABMultiValueCopyValueAtIndex(multiValue, valueIdx);
// Go to dialer view
DialerViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[DialerViewController compositeViewDescription]], DialerViewController);
if(controller != nil) {
[controller call:phoneNumber displayName:[(NSString*)ABRecordCopyCompositeName(person) autorelease]];
}
[phoneNumber release];
CFRelease(multiValue);
// Go to dialer view
DialerViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[DialerViewController compositeViewDescription]], DialerViewController);
if(controller != nil) {
[controller call:phoneNumber displayName:[(NSString*)ABRecordCopyCompositeName(person) autorelease]];
}
[phoneNumber release];
CFRelease(multiValue);
return false;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[ContactSelection setNameOrEmailFilter:searchText];
[tableController loadData];
}
- (void)viewDidUnload {
[self setToolBar:nil];
[super viewDidUnload];
[self setToolBar:nil];
[super viewDidUnload];
}
@end

View file

@ -4,18 +4,18 @@
*
* 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
* 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 <AVFoundation/AVAudioSession.h>
#import <AudioToolbox/AudioToolbox.h>
@ -76,7 +76,7 @@
[callButton release];
[addCallButton release];
[transferButton release];
[oneButton release];
[twoButton release];
[threeButton release];
@ -89,13 +89,13 @@
[starButton release];
[zeroButton release];
[sharpButton release];
[videoPreview release];
[videoCameraSwitch release];
// Remove all observers
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
@ -106,12 +106,12 @@ static UICompositeViewDescription *compositeDescription = nil;
+ (UICompositeViewDescription *)compositeViewDescription {
if(compositeDescription == nil) {
compositeDescription = [[UICompositeViewDescription alloc] init:@"Dialer"
content:@"DialerViewController"
stateBar:@"UIStateBar"
stateBarEnabled:true
tabBar:@"UIMainBar"
tabBarEnabled:true
compositeDescription = [[UICompositeViewDescription alloc] init:@"Dialer"
content:@"DialerViewController"
stateBar:@"UIStateBar"
stateBarEnabled:true
tabBar:@"UIMainBar"
tabBarEnabled:true
fullscreen:false
landscapeMode:[LinphoneManager runningOnIpad]
portraitMode:true];
@ -124,13 +124,13 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Set observer
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(callUpdateEvent:)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(callUpdateEvent:)
name:kLinphoneCallUpdate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(coreUpdateEvent:)
name:kLinphoneCoreUpdate
@ -178,16 +178,16 @@ static UICompositeViewDescription *compositeDescription = nil;
#endif
}
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kLinphoneCallUpdate
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kLinphoneCoreUpdate
object:nil];
@ -195,7 +195,7 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewDidLoad {
[super viewDidLoad];
[zeroButton setDigit:'0'];
[oneButton setDigit:'1'];
[twoButton setDigit:'2'];
@ -208,9 +208,9 @@ static UICompositeViewDescription *compositeDescription = nil;
[nineButton setDigit:'9'];
[starButton setDigit:'*'];
[sharpButton setDigit:'#'];
[addressField setAdjustsFontSizeToFitWidth:TRUE]; // Not put it in IB: issue with placeholder size
if([LinphoneManager runningOnIpad]) {
if ([LinphoneManager instance].frontCamId != nil) {
// only show camera switch button if we have more than 1 camera
@ -248,7 +248,7 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark - Event Functions
- (void)callUpdateEvent:(NSNotification*)notif {
- (void)callUpdateEvent:(NSNotification*)notif {
LinphoneCall *call = [[notif.userInfo objectForKey: @"call"] pointerValue];
LinphoneCallState state = [[notif.userInfo objectForKey: @"state"] intValue];
[self callUpdate:call state:state];
@ -283,7 +283,7 @@ static UICompositeViewDescription *compositeDescription = nil;
[transferButton setHidden:true];
}
[callButton setHidden:true];
[backButton setHidden:false];
[backButton setHidden:false];
[addContactButton setHidden:true];
} else {
[addCallButton setHidden:true];
@ -330,7 +330,7 @@ static UICompositeViewDescription *compositeDescription = nil;
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == addressField) {
[addressField resignFirstResponder];
}
}
return YES;
}
@ -341,10 +341,11 @@ static UICompositeViewDescription *compositeDescription = nil;
[ContactSelection setSelectionMode:ContactSelectionModeEdit];
[ContactSelection setAddAddress:[addressField text]];
[ContactSelection setSipFilter:nil];
[ContactSelection setEmailFilter:FALSE];
[ContactSelection setNameOrEmailFilter:nil];
[ContactSelection enableEmailFilter:FALSE];
ContactsViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactsViewController compositeViewDescription] push:TRUE], ContactsViewController);
if(controller != nil) {
}
}

View file

@ -4,18 +4,18 @@
*
* 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
* 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 "HistoryDetailsViewController.h"
#import "PhoneMainView.h"
@ -55,10 +55,10 @@
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[dateFormatter release];
[callLogId release];
[avatarImage release];
[addressLabel release];
[dateLabel release];
@ -72,7 +72,7 @@
[callButton release];
[messageButton release];
[addContactButton release];
[super dealloc];
}
@ -83,12 +83,12 @@ static UICompositeViewDescription *compositeDescription = nil;
+ (UICompositeViewDescription *)compositeViewDescription {
if(compositeDescription == nil) {
compositeDescription = [[UICompositeViewDescription alloc] init:@"HistoryDetails"
content:@"HistoryDetailsViewController"
stateBar:nil
stateBarEnabled:false
tabBar:@"UIMainBar"
tabBarEnabled:true
compositeDescription = [[UICompositeViewDescription alloc] init:@"HistoryDetails"
content:@"HistoryDetailsViewController"
stateBar:nil
stateBarEnabled:false
tabBar:@"UIMainBar"
tabBarEnabled:true
fullscreen:false
landscapeMode:[LinphoneManager runningOnIpad]
portraitMode:true];
@ -124,12 +124,12 @@ static UICompositeViewDescription *compositeDescription = nil;
if( use_system ){
[addContactButton setHidden:TRUE];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(update)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(update)
name:kLinphoneAddressBookUpdate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(coreUpdateEvent:)
name:kLinphoneCoreUpdate
@ -138,11 +138,11 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kLinphoneAddressBookUpdate
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kLinphoneCoreUpdate
object:nil];
@ -156,7 +156,7 @@ static UICompositeViewDescription *compositeDescription = nil;
}
#pragma mark -
#pragma mark -
+ (void)adaptSize:(UILabel*)label field:(UIView*)field {
//
@ -164,20 +164,20 @@ static UICompositeViewDescription *compositeDescription = nil;
//
CGRect labelFrame = [label frame];
CGRect fieldFrame = [field frame];
fieldFrame.origin.x -= labelFrame.size.width;
// Compute firstName size
CGSize contraints;
contraints.height = [label frame].size.height;
contraints.width = ([field frame].size.width + [field frame].origin.x) - [label frame].origin.x;
CGSize firstNameSize = [[label text] sizeWithFont:[label font] constrainedToSize: contraints];
labelFrame.size.width = firstNameSize.width;
// Compute lastName size & position
fieldFrame.origin.x += labelFrame.size.width;
fieldFrame.size.width = (contraints.width + [label frame].origin.x) - fieldFrame.origin.x;
[label setFrame: labelFrame];
[field setFrame: fieldFrame];
}
@ -186,7 +186,7 @@ static UICompositeViewDescription *compositeDescription = nil;
if(![LinphoneManager isLcReady]) {
return;
}
// Look for the call log
callLog = NULL;
const MSList *list = linphone_core_get_call_logs([LinphoneManager getLc]);
@ -199,20 +199,20 @@ static UICompositeViewDescription *compositeDescription = nil;
}
list = list->next;
}
// Pop if callLog is null
if(callLog == NULL) {
[[PhoneMainView instance] popCurrentView];
return;
}
LinphoneAddress* addr =linphone_call_log_get_remote_address(callLog);
UIImage *image = nil;
NSString* address = nil;
if(addr != NULL) {
BOOL useLinphoneAddress = true;
// contact name
// contact name
char* lAddress = linphone_address_as_string_uri_only(addr);
if(lAddress) {
NSString *normalizedSipAddress = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:lAddress]];
@ -227,25 +227,25 @@ static UICompositeViewDescription *compositeDescription = nil;
if(useLinphoneAddress) {
const char* lDisplayName = linphone_address_get_display_name(addr);
const char* lUserName = linphone_address_get_username(addr);
if (lDisplayName)
if (lDisplayName)
address = [NSString stringWithUTF8String:lDisplayName];
else if(lUserName)
else if(lUserName)
address = [NSString stringWithUTF8String:lUserName];
}
}
// Set Image
if(image == nil) {
image = [UIImage imageNamed:@"avatar_unknown.png"];
}
[avatarImage setImage:image];
// Set Address
if(address == nil) {
address = NSLocalizedString(@"Unknown", nil);
}
[addressLabel setText:address];
// Hide/Show add button
BOOL use_system = [[LinphoneManager instance] lpConfigBoolForKey:@"use_system_contacts"];
if(contact) {
@ -253,7 +253,7 @@ static UICompositeViewDescription *compositeDescription = nil;
} else if (!use_system) {
[addContactButton setHidden:FALSE];
}
// State
NSMutableString *state = [NSMutableString string];
if (linphone_call_log_get_dir(callLog) == LinphoneCallIncoming) {
@ -283,7 +283,7 @@ static UICompositeViewDescription *compositeDescription = nil;
// Duration
int duration = linphone_call_log_get_duration(callLog);
[durationLabel setText:[NSString stringWithFormat:@"%02i:%02i", (duration/60), duration - 60 * (duration / 60), nil]];
// contact name
[plainAddressLabel setText:@""];
if (addr != NULL) {
@ -297,7 +297,7 @@ static UICompositeViewDescription *compositeDescription = nil;
}
}
}
if (addr != NULL) {
[callButton setHidden:FALSE];
[messageButton setHidden:FALSE];
@ -305,7 +305,7 @@ static UICompositeViewDescription *compositeDescription = nil;
[callButton setHidden:TRUE];
[messageButton setHidden:TRUE];
}
}
@ -327,16 +327,17 @@ static UICompositeViewDescription *compositeDescription = nil;
- (IBAction)onAddContactClick:(id)event {
LinphoneAddress* addr;
addr=linphone_call_log_get_remote_address(callLog);
if (addr != NULL) {
char* lAddress = linphone_address_as_string_uri_only(addr);
if(lAddress != NULL) {
[ContactSelection setAddAddress:[NSString stringWithUTF8String:lAddress]];
[ContactSelection setSelectionMode:ContactSelectionModeEdit];
[ContactSelection setSipFilter:nil];
[ContactSelection setEmailFilter:FALSE];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection setNameOrEmailFilter:nil];
ContactsViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactsViewController compositeViewDescription] push:TRUE], ContactsViewController);
if(controller != nil) {
}
@ -346,26 +347,26 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (IBAction)onCallClick:(id)event {
LinphoneAddress* addr;
LinphoneAddress* addr;
addr=linphone_call_log_get_remote_address(callLog);
char* lAddress = linphone_address_as_string_uri_only(addr);
if(lAddress == NULL)
if(lAddress == NULL)
return;
NSString *displayName = nil;
if(contact != nil) {
displayName = [FastAddressBook getContactDisplayName:contact];
displayName = [FastAddressBook getContactDisplayName:contact];
} else {
const char* lDisplayName = linphone_address_get_display_name(addr);
const char* lUserName = linphone_address_get_username(addr);
if (lDisplayName)
if (lDisplayName)
displayName = [NSString stringWithUTF8String:lDisplayName];
else if(lUserName)
else if(lUserName)
displayName = [NSString stringWithUTF8String:lUserName];
}
DialerViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[DialerViewController compositeViewDescription]], DialerViewController);
if(controller != nil) {
if(displayName != nil) {
@ -380,11 +381,11 @@ static UICompositeViewDescription *compositeDescription = nil;
- (IBAction)onMessageClick:(id)event {
LinphoneAddress* addr;
addr=linphone_call_log_get_remote_address(callLog);
char* lAddress = linphone_address_as_string_uri_only(addr);
if(lAddress == NULL)
return;
NSString *displayName = nil;
if(contact != nil) {
displayName = [FastAddressBook getContactDisplayName:contact];
@ -396,7 +397,7 @@ static UICompositeViewDescription *compositeDescription = nil;
else if(lUserName)
displayName = [NSString stringWithUTF8String:lUserName];
}
// Go to ChatRoom view
[[PhoneMainView instance] changeCurrentView:[ChatViewController compositeViewDescription]];
ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController);

View file

@ -4,16 +4,16 @@
*
* 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 Library 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
* 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 Library 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.
*/
@ -46,7 +46,7 @@ static NSString * const kDisappearAnimation = @"disappear";
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[historyButton release];
[contactsButton release];
[dialerButton release];
@ -56,7 +56,7 @@ static NSString * const kDisappearAnimation = @"disappear";
[historyNotificationLabel release];
[chatNotificationView release];
[chatNotificationLabel release];
[super dealloc];
}
@ -65,17 +65,17 @@ static NSString * const kDisappearAnimation = @"disappear";
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(changeViewEvent:)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(changeViewEvent:)
name:kLinphoneMainViewChange
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(callUpdate:)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(callUpdate:)
name:kLinphoneCallUpdate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(textReceived:)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(textReceived:)
name:kLinphoneTextReceived
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
@ -87,14 +87,14 @@ static NSString * const kDisappearAnimation = @"disappear";
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kLinphoneMainViewChange
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kLinphoneCallUpdate
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kLinphoneTextReceived
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
@ -103,35 +103,35 @@ static NSString * const kDisappearAnimation = @"disappear";
}
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
{
UIButton *historyButtonLandscape = (UIButton*) [landscapeView viewWithTag:[historyButton tag]];
// Set selected+over background: IB lack !
[historyButton setBackgroundImage:[UIImage imageNamed:@"history_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
// Set selected+over background: IB lack !
[historyButtonLandscape setBackgroundImage:[UIImage imageNamed:@"history_selected_landscape.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[LinphoneUtils buttonFixStatesForTabs:historyButton];
[LinphoneUtils buttonFixStatesForTabs:historyButtonLandscape];
}
{
UIButton *contactsButtonLandscape = (UIButton*) [landscapeView viewWithTag:[contactsButton tag]];
// Set selected+over background: IB lack !
[contactsButton setBackgroundImage:[UIImage imageNamed:@"contacts_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
// Set selected+over background: IB lack !
[contactsButtonLandscape setBackgroundImage:[UIImage imageNamed:@"contacts_selected_landscape.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[LinphoneUtils buttonFixStatesForTabs:contactsButton];
[LinphoneUtils buttonFixStatesForTabs:contactsButtonLandscape];
}
@ -140,11 +140,11 @@ static NSString * const kDisappearAnimation = @"disappear";
// Set selected+over background: IB lack !
[dialerButton setBackgroundImage:[UIImage imageNamed:@"dialer_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
// Set selected+over background: IB lack !
[dialerButtonLandscape setBackgroundImage:[UIImage imageNamed:@"dialer_selected_landscape.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[LinphoneUtils buttonFixStatesForTabs:dialerButton];
[LinphoneUtils buttonFixStatesForTabs:dialerButtonLandscape];
}
@ -153,37 +153,37 @@ static NSString * const kDisappearAnimation = @"disappear";
// Set selected+over background: IB lack !
[settingsButton setBackgroundImage:[UIImage imageNamed:@"settings_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
// Set selected+over background: IB lack !
[settingsButtonLandscape setBackgroundImage:[UIImage imageNamed:@"settings_selected_landscape.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[LinphoneUtils buttonFixStatesForTabs:settingsButton];
[LinphoneUtils buttonFixStatesForTabs:settingsButtonLandscape];
}
{
UIButton *chatButtonLandscape = (UIButton*) [landscapeView viewWithTag:[chatButton tag]];
// Set selected+over background: IB lack !
[chatButton setBackgroundImage:[UIImage imageNamed:@"chat_selected.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
// Set selected+over background: IB lack !
[chatButtonLandscape setBackgroundImage:[UIImage imageNamed:@"chat_selected_landscape.png"]
forState:(UIControlStateHighlighted | UIControlStateSelected)];
[LinphoneUtils buttonFixStatesForTabs:chatButton];
[LinphoneUtils buttonFixStatesForTabs:chatButtonLandscape];
}
[super viewDidLoad]; // Have to be after due to TPMultiLayoutViewController
}
- (void)viewDidUnload {
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationWillEnterForegroundNotification
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
@ -203,8 +203,8 @@ static NSString * const kDisappearAnimation = @"disappear";
#pragma mark - Event Functions
- (void)applicationWillEnterForeground:(NSNotification*)notif {
// Force the animations
- (void)applicationWillEnterForeground:(NSNotification*)notif {
// Force the animations
[[self.view layer] removeAllAnimations];
[historyNotificationView.layer setTransform:CATransform3DIdentity];
[chatNotificationView.layer setTransform:CATransform3DIdentity];
@ -219,7 +219,7 @@ static NSString * const kDisappearAnimation = @"disappear";
[self updateMissedCall:linphone_core_get_missed_calls_count([LinphoneManager getLc]) appear:TRUE];
}
- (void)changeViewEvent:(NSNotification*)notif {
- (void)changeViewEvent:(NSNotification*)notif {
//UICompositeViewDescription *view = [notif.userInfo objectForKey: @"view"];
//if(view != nil)
[self updateView:[[PhoneMainView instance] firstView]];
@ -246,7 +246,7 @@ static NSString * const kDisappearAnimation = @"disappear";
}
#pragma mark -
#pragma mark -
- (void)update:(BOOL)appear{
[self updateView:[[PhoneMainView instance] firstView]];
@ -354,14 +354,14 @@ static NSString * const kDisappearAnimation = @"disappear";
bounce.autoreverses = TRUE;
bounce.repeatCount = HUGE_VALF;
[target.layer addAnimation:bounce forKey:animationID];
}
- (void)stopBounceAnimation:(NSString *)animationID target:(UIView *)target {
[target.layer removeAnimationForKey:animationID];
}
- (void)updateView:(UICompositeViewDescription*) view {
- (void)updateView:(UICompositeViewDescription*) view {
// Update buttons
if([view equal:[HistoryViewController compositeViewDescription]]) {
historyButton.selected = TRUE;
@ -401,7 +401,8 @@ static NSString * const kDisappearAnimation = @"disappear";
[ContactSelection setSelectionMode:ContactSelectionModeNone];
[ContactSelection setAddAddress:nil];
[ContactSelection setSipFilter:nil];
[ContactSelection setEmailFilter:FALSE];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection setNameOrEmailFilter:nil];
[[PhoneMainView instance] changeCurrentView:[ContactsViewController compositeViewDescription]];
}
@ -422,7 +423,7 @@ static NSString * const kDisappearAnimation = @"disappear";
- (NSDictionary*)attributesForView:(UIView*)view {
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
[attributes setObject:[NSValue valueWithCGRect:view.frame] forKey:@"frame"];
[attributes setObject:[NSValue valueWithCGRect:view.bounds] forKey:@"bounds"];
if([view isKindOfClass:[UIButton class]]) {
@ -430,7 +431,7 @@ static NSString * const kDisappearAnimation = @"disappear";
[LinphoneUtils buttonMultiViewAddAttributes:attributes button:button];
}
[attributes setObject:[NSNumber numberWithInteger:view.autoresizingMask] forKey:@"autoresizingMask"];
return attributes;
}