diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m index 3dd075073..818776705 100644 --- a/Classes/ChatRoomTableViewController.m +++ b/Classes/ChatRoomTableViewController.m @@ -21,6 +21,8 @@ #import "UIChatRoomCell.h" #import "UIChatRoomHeader.h" +#import + @implementation ChatRoomTableViewController @synthesize remoteContact; @@ -33,13 +35,18 @@ [self.tableView setBackgroundColor:[UIColor clearColor]]; // Can't do it in Xib: issue with ios4 } +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [TUNinePatchCache flushCache]; // Clear cache +} #pragma mark - -- (void)reloadData { +- (void)loadData { if(data != nil) [data release]; data = [[ChatModel listMessages:remoteContact] retain]; + [[self tableView] reloadData]; } @@ -47,7 +54,9 @@ - (void)setRemoteContact:(NSString *)aremoteContact { self->remoteContact = aremoteContact; - [[self tableView] reloadData]; + [ChatModel readConversation:aremoteContact]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"LinphoneTextReceived" object:self]; + [self loadData]; } #pragma mark - UITableViewDataSource Functions @@ -57,7 +66,6 @@ } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - [self reloadData]; return [data count]; } diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index 4d34bbc4e..28c6b6632 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -108,10 +108,12 @@ - (void)textReceivedEvent:(NSNotification *)notif { //LinphoneChatRoom *room = [[[notif userInfo] objectForKey:@"room"] pointerValue]; LinphoneAddress *from = [[[notif userInfo] objectForKey:@"from"] pointerValue]; - //NSString *message = [[notif userInfo] objectForKey:@"message"]; - if([[NSString stringWithUTF8String:linphone_address_get_username(from)] - caseInsensitiveCompare:remoteContact] == NSOrderedSame) { - [[tableController tableView] reloadData]; + if(from != NULL) { + //NSString *message = [[notif userInfo] objectForKey:@"message"]; + if([[NSString stringWithUTF8String:linphone_address_get_username(from)] + caseInsensitiveCompare:remoteContact] == NSOrderedSame) { + [[tableController tableView] reloadData]; + } } } diff --git a/Classes/ChatTableViewController.h b/Classes/ChatTableViewController.h index 91965b7f6..9dfa4e7ef 100644 --- a/Classes/ChatTableViewController.h +++ b/Classes/ChatTableViewController.h @@ -21,7 +21,7 @@ @interface ChatTableViewController : UITableViewController { @private - NSArray *data; + NSMutableArray *data; } @end diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index 47ea4ebc5..da927f422 100644 --- a/Classes/ChatTableViewController.m +++ b/Classes/ChatTableViewController.m @@ -37,12 +37,21 @@ } +#pragma mark - ViewController Functions + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [self loadData]; +} + + #pragma mark - -- (void)reloadData { +- (void)loadData { if(data != nil) [data release]; data = [[ChatModel listConversations] retain]; + [[self tableView] reloadData]; } #pragma mark - UITableViewDataSource Functions @@ -52,7 +61,6 @@ } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - [self reloadData]; return [data count]; } @@ -89,4 +97,15 @@ push:TRUE]; } +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if(editingStyle == UITableViewCellEditingStyleDelete) { + [tableView beginUpdates]; + ChatModel *chat = [data objectAtIndex:[indexPath row]]; + [data removeObjectAtIndex:[indexPath row]]; + [ChatModel removeConversation:[chat remoteContact]]; + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; + [tableView endUpdates]; + } +} + @end diff --git a/Classes/ContactDetailsTableViewController.m b/Classes/ContactDetailsTableViewController.m index d8cdd335e..3264ba4a7 100644 --- a/Classes/ContactDetailsTableViewController.m +++ b/Classes/ContactDetailsTableViewController.m @@ -24,6 +24,7 @@ #import "UACellBackgroundView.h" #import "UILinphone.h" #import "OrderedDictionary.h" +#import "FastAddressBook.h" @interface Entry : NSObject @@ -450,15 +451,13 @@ CFRelease(lMap); } if(dest != nil) { - CFStringRef lDisplayName = ABRecordCopyCompositeName(contact); - NSString *displayName = [NSString stringWithString:(NSString*) lDisplayName]; - CFRelease(lDisplayName); + NSString *displayName = [FastAddressBook getContactDisplayName:contact]; // Go to dialer view [[PhoneMainView instance] changeView:PhoneView_Dialer calls:[NSArray arrayWithObjects: [AbstractCall abstractCall:@"call:displayName:", dest, displayName], - nil]]; + nil]]; } } else { NSString *key = nil; @@ -496,13 +495,13 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { [ContactDetailsTableViewController findAndResignFirstResponder:[self tableView]]; if (editingStyle == UITableViewCellEditingStyleInsert) { - [self.tableView beginUpdates]; - [self addEntry:self.tableView section:[indexPath section] animated:TRUE]; - [self.tableView endUpdates]; + [tableView beginUpdates]; + [self addEntry:tableView section:[indexPath section] animated:TRUE]; + [tableView endUpdates]; } else if (editingStyle == UITableViewCellEditingStyleDelete) { - [self.tableView beginUpdates]; - [self removeEntry:self.tableView path:indexPath animated:TRUE]; - [self.tableView endUpdates]; + [tableView beginUpdates]; + [self removeEntry:tableView path:indexPath animated:TRUE]; + [tableView endUpdates]; } } diff --git a/Classes/ContactDetailsViewController.m b/Classes/ContactDetailsViewController.m index 3d664932e..3e376fdfd 100644 --- a/Classes/ContactDetailsViewController.m +++ b/Classes/ContactDetailsViewController.m @@ -58,6 +58,7 @@ - (void)resetData { if(contact == NULL) { + ABAddressBookRevert(addressBook); return; } @@ -139,6 +140,7 @@ static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef inf } - (void)newContact { + NSLog(@"New contact"); self->contact = ABPersonCreate(); [tableController setContact:self->contact]; [self enableEdit:FALSE]; @@ -146,6 +148,7 @@ static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef inf } - (void)newContact:(NSString*)address { + NSLog(@"New contact"); self->contact = ABPersonCreate(); [tableController setContact:self->contact]; [tableController addSipField:address]; @@ -154,6 +157,7 @@ static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef inf } - (void)editContact:(ABRecordRef)acontact { + NSLog(@"Edit contact %p", acontact); self->contact = ABAddressBookGetPersonWithRecordID(addressBook, ABRecordGetRecordID(acontact)); [tableController setContact:self->contact]; [self enableEdit:FALSE]; @@ -161,6 +165,7 @@ static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef inf } - (void)editContact:(ABRecordRef)acontact address:(NSString*)address { + NSLog(@"Edit contact %p", acontact); self->contact = ABAddressBookGetPersonWithRecordID(addressBook, ABRecordGetRecordID(acontact)); [tableController setContact:self->contact]; [tableController addSipField:address]; @@ -172,6 +177,7 @@ static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef inf #pragma mark - Property Functions - (void)setContact:(ABRecordRef)acontact { + NSLog(@"set contact %p", acontact); self->contact = ABAddressBookGetPersonWithRecordID(addressBook, ABRecordGetRecordID(acontact)); [tableController setContact:self->contact]; [self disableEdit:FALSE]; @@ -206,6 +212,7 @@ static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef inf [tableController viewWillDisappear:NO]; } [self disableEdit:FALSE]; + self->contact = NULL; [self resetData]; } diff --git a/Classes/ContactsViewController.m b/Classes/ContactsViewController.m index 3ce634fe0..28bb9e252 100644 --- a/Classes/ContactsViewController.m +++ b/Classes/ContactsViewController.m @@ -122,7 +122,6 @@ typedef enum _HistoryView { - (void)changeView: (HistoryView) view { if(view == History_All) { - [tableController setSipFilter:FALSE]; allButton.selected = TRUE; } else { diff --git a/Classes/DialerViewController.m b/Classes/DialerViewController.m index 35c986982..0630ca319 100644 --- a/Classes/DialerViewController.m +++ b/Classes/DialerViewController.m @@ -194,13 +194,19 @@ } - (void)call:(NSString*)address { - [self call:address displayName:nil]; + NSString *displayName = nil; + ABRecordRef contact = [[[LinphoneManager instance] fastAddressBook] getContact:address]; + if(contact) { + displayName = [FastAddressBook getContactDisplayName:contact]; + } + [self call:address displayName:displayName]; } - (void)call:(NSString*)address displayName:(NSString *)displayName { [[LinphoneManager instance] call:address displayName:displayName transfer:transferMode]; } + #pragma mark - UITextFieldDelegate Functions - (BOOL)textFieldShouldReturn:(UITextField *)textField { diff --git a/Classes/HistoryDetailsViewController.h b/Classes/HistoryDetailsViewController.h index 61902b6f6..c3e3b3e93 100644 --- a/Classes/HistoryDetailsViewController.h +++ b/Classes/HistoryDetailsViewController.h @@ -34,6 +34,8 @@ UILabel *typeLabel; UILabel *typeHeaderLabel; UIButton *addressButton; + UIButton *addContactButton; + ABRecordRef contact; } @property (nonatomic, retain) IBOutlet UIImageView *avatarImage; @property (nonatomic, retain) IBOutlet UILabel *addressLabel; @@ -44,13 +46,14 @@ @property (nonatomic, retain) IBOutlet UILabel *typeLabel; @property (nonatomic, retain) IBOutlet UILabel *typeHeaderLabel; @property (nonatomic, retain) IBOutlet UIButton *addressButton; - +@property (nonatomic, retain) IBOutlet UIButton *addContactButton; @property (nonatomic, assign) LinphoneCallLog *callLog; - (void)setCallLogValue:(NSValue*)vcallLog; - (IBAction)onBackClick:(id)event; - (IBAction)onContactClick:(id)event; +- (IBAction)onAddContactClick:(id)event; - (IBAction)onAddressClick:(id)event; @end diff --git a/Classes/HistoryDetailsViewController.m b/Classes/HistoryDetailsViewController.m index cdf42aada..30b58ebd9 100644 --- a/Classes/HistoryDetailsViewController.m +++ b/Classes/HistoryDetailsViewController.m @@ -33,11 +33,13 @@ @synthesize typeLabel; @synthesize typeHeaderLabel; @synthesize addressButton; - +@synthesize addContactButton; #pragma mark - LifeCycle Functions - (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [avatarImage release]; [addressLabel release]; [dateLabel release]; @@ -47,8 +49,9 @@ [typeLabel release]; [typeHeaderLabel release]; [addressButton release]; + [addContactButton release]; - [super dealloc]; + [super dealloc]; } @@ -78,16 +81,168 @@ } +#pragma mark - ViewController Functions + +- (void)viewDidLoad { + [super viewDidLoad]; + [HistoryDetailsViewController adaptSize:dateHeaderLabel field:dateLabel]; + [HistoryDetailsViewController adaptSize:durationHeaderLabel field:durationLabel]; + [HistoryDetailsViewController adaptSize:typeHeaderLabel field:typeLabel]; + [addressButton.titleLabel setAdjustsFontSizeToFitWidth:TRUE]; // Auto shrink: IB lack! +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(update:) + name:@"LinphoneAddressBookUpdate" + object:nil]; + [self update]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneAddressBookUpdate" + object:nil]; +} + + #pragma mark - ++ (void)adaptSize:(UILabel*)label field:(UIView*)field { + // + // Adapt size + // + 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]; +} + - (void)update { - // Set up the cell... - LinphoneAddress* partyToDisplay; + // Don't update if callLog is null + if(callLog==NULL) { + return; + } + + LinphoneAddress* addr; if (callLog->dir == LinphoneCallIncoming) { - partyToDisplay = callLog->from; + addr = callLog->from; } else { - partyToDisplay = callLog->to; + addr = callLog->to; } + + UIImage *image = nil; + NSString* address = nil; + if(addr != NULL) { + BOOL useLinphoneAddress = true; + // contact name + const char* lAddress = linphone_address_as_string_uri_only(addr); + if(lAddress) { + NSString *normalizedSipAddress = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:lAddress]]; + contact = [[[LinphoneManager instance] fastAddressBook] getContact:normalizedSipAddress]; + if(contact) { + image = [FastAddressBook getContactImage:contact thumbnail:false]; + address = [FastAddressBook getContactDisplayName:contact]; + useLinphoneAddress = false; + } + } + if(useLinphoneAddress) { + const char* lDisplayName = linphone_address_get_display_name(addr); + const char* lUserName = linphone_address_get_username(addr); + if (lDisplayName) + address = [NSString stringWithUTF8String:lDisplayName]; + 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 = @"Unknown"; + } + [addressLabel setText:address]; + + // Hide/Show add button + if(contact) { + [addContactButton setHidden:TRUE]; + } else { + [addContactButton setHidden:FALSE]; + } + + // State + NSMutableString *state = [NSMutableString string]; + if (callLog->dir == LinphoneCallIncoming) { + [state setString:@"Incoming call"]; + } else { + [state setString:@"Outgoing call"]; + } + switch (callLog->status) { + case LinphoneCallSuccess: + break; + case LinphoneCallAborted: + [state appendString:@" (Aborted)"]; + break; + case LinphoneCallMissed: + [state appendString:@" (Missed)"]; + break; + case LinphoneCallDeclined : + [state appendString:@" (Declined)"]; + break; + } + [typeLabel setText:state]; + + // Date + NSDate *startData = [NSDate dateWithTimeIntervalSince1970:callLog->start_date_time]; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; + NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + [dateFormatter setLocale:locale]; + [dateLabel setText:[dateFormatter stringFromDate:startData]]; + [locale release]; + [dateFormatter release]; + + // Duration + int duration = callLog->duration; + [durationLabel setText:[NSString stringWithFormat:@"%02i:%02i", (duration/60), duration - 60 * (duration / 60), nil]]; + + if (addr != NULL) { + // contact name + const char* lAddress = linphone_address_as_string_uri_only(addr); + if(lAddress != NULL) { + [addressButton setTitle:[NSString stringWithUTF8String:lAddress] forState:UIControlStateNormal]; + [addressButton setHidden:FALSE]; + } else { + [addressButton setHidden:TRUE]; + } + } else { + [addressButton setHidden:TRUE]; + } + } @@ -98,11 +253,54 @@ } - (IBAction)onContactClick:(id)event { - + if(contact) { + [[PhoneMainView instance] changeView:PhoneView_ContactDetails + calls:[NSArray arrayWithObject:[AbstractCall abstractCall:@"setContact:", contact]] + push:TRUE]; + } +} + +- (IBAction)onAddContactClick:(id)event { + [[PhoneMainView instance] changeView:PhoneView_Contacts + calls:[NSArray arrayWithObject:[AbstractCall abstractCall:@"setAddress:", [[addressButton titleLabel] text]]] + push:TRUE]; } - (IBAction)onAddressClick:(id)event { - + LinphoneAddress* addr; + if (callLog->dir == LinphoneCallIncoming) { + addr = callLog->from; + } else { + addr = callLog->to; + } + + const char* lAddress = linphone_address_as_string_uri_only(addr); + + NSString *displayName = nil; + if(contact != nil) { + displayName = [FastAddressBook getContactDisplayName:contact]; + } else { + const char* lDisplayName = linphone_address_get_display_name(addr); + const char* lUserName = linphone_address_get_username(addr); + if (lDisplayName) + displayName = [NSString stringWithUTF8String:lDisplayName]; + else if(lUserName) + displayName = [NSString stringWithUTF8String:lUserName]; + } + + if(displayName != nil) { + // Go to dialer view + [[PhoneMainView instance] changeView:PhoneView_Dialer + calls:[NSArray arrayWithObjects: + [AbstractCall abstractCall:@"call:displayName:", [NSString stringWithUTF8String:lAddress], displayName], + nil]]; + } else { + // Go to dialer view + [[PhoneMainView instance] changeView:PhoneView_Dialer + calls:[NSArray arrayWithObjects: + [AbstractCall abstractCall:@"call:", [NSString stringWithUTF8String:lAddress]], + nil]]; + } } @end diff --git a/Classes/HistoryDetailsViewController.xib b/Classes/HistoryDetailsViewController.xib index 206d6c9c4..ef9273c73 100644 --- a/Classes/HistoryDetailsViewController.xib +++ b/Classes/HistoryDetailsViewController.xib @@ -2,10 +2,10 @@ 1296 - 11D50 + 11E53 2182 - 1138.32 - 568.00 + 1138.47 + 569.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 1181 @@ -41,13 +41,28 @@ 290 + + + 292 + {320, 58} + + + + _NS:9 + NO + IBCocoaTouchFramework + + NSImage + contact_bar_background.png + + 292 {160, 58} - + _NS:9 NO @@ -63,11 +78,11 @@ NSImage - contact_back_over.png + history_back_over.png NSImage - contact_back_default.png + history_back_default.png 2 @@ -79,7 +94,7 @@ 16 - + 292 {{160, 0}, {160, 58}} @@ -87,18 +102,31 @@ _NS:9 - NO - IBCocoaTouchFramework - - NSImage - contact_bar_background.png + NO + + Add contact + IBCocoaTouchFramework + 0 + 0 + NO + + + NSImage + history_add_over.png + + + NSImage + history_add_default.png + + + {320, 58} - + _NS:9 3 @@ -389,13 +417,17 @@ {{33, 273}, {255, 50}} - _NS:9 NO IBCocoaTouchFramework 0 0 NO + NO + 10 + 10 + 10 + 10 0102030405 @@ -509,6 +541,14 @@ 49 + + + addContactButton + + + + 52 + onBackClick: @@ -536,6 +576,15 @@ 40 + + + onAddContactClick: + + + 7 + + 53 + @@ -573,8 +622,9 @@ 6 - + + navigationBar @@ -699,6 +749,12 @@ headerButton + + 50 + + + backButton + @@ -723,16 +779,18 @@ com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - + - 49 + 53 @@ -740,11 +798,16 @@ HistoryDetailsViewController UIViewController + id id id id + + onAddContactClick: + id + onAddressClick: id @@ -759,6 +822,7 @@ + UIButton UIButton UILabel UIImageView @@ -770,6 +834,10 @@ UILabel + + addContactButton + UIButton + addressButton UIButton @@ -827,9 +895,11 @@ {131, 131} {550, 101} {550, 101} - {320, 117} - {320, 117} {5, 117} + {320, 117} + {320, 117} + {320, 117} + {320, 117} 1181 diff --git a/Classes/HistoryTableViewController.m b/Classes/HistoryTableViewController.m index 45a588252..c0b6d33cb 100644 --- a/Classes/HistoryTableViewController.m +++ b/Classes/HistoryTableViewController.m @@ -57,10 +57,19 @@ } +#pragma mark - ViewController Functions + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [self loadData]; +} + + #pragma mark - Property Functions - (void)setMissedFilter:(BOOL)amissedFilter { self->missedFilter = amissedFilter; + [self loadData]; [[self tableView] reloadData]; } @@ -88,7 +97,6 @@ } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - [self loadData]; return [callLogs count]; } @@ -149,5 +157,16 @@ [dispName release]; } +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if(editingStyle == UITableViewCellEditingStyleDelete) { + [tableView beginUpdates]; + LinphoneCallLog *callLog = [[callLogs objectAtIndex:[indexPath row]] pointerValue]; + [callLogs removeObjectAtIndex:[indexPath row]]; + linphone_core_remove_call_log([LinphoneManager getLc], callLog); + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; + [tableView endUpdates]; + } +} + @end diff --git a/Classes/IncomingCallViewController.m b/Classes/IncomingCallViewController.m index db6c97d75..251a94f84 100644 --- a/Classes/IncomingCallViewController.m +++ b/Classes/IncomingCallViewController.m @@ -91,25 +91,30 @@ - (void)update { [self view]; //Force view load - UIImage *image; - NSString* address; + UIImage *image = nil; + NSString* address = nil; const LinphoneAddress* addr = linphone_call_get_remote_address(call); if (addr != NULL) { + BOOL useLinphoneAddress = true; // contact name const char* lAddress = linphone_address_as_string_uri_only(addr); - const char* lDisplayName = linphone_address_get_display_name(addr); - const char* lUserName = linphone_address_get_username(addr); - if (lDisplayName) - address = [NSString stringWithUTF8String:lDisplayName]; - else if(lUserName) - address = [NSString stringWithUTF8String:lUserName]; if(lAddress) { - NSString *address = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:lAddress]]; - ABRecordRef contact = [[[LinphoneManager instance] fastAddressBook] getContact:address]; - image = [FastAddressBook getContactImage:contact thumbnail:false]; + NSString *normalizedSipAddress = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:lAddress]]; + ABRecordRef contact = [[[LinphoneManager instance] fastAddressBook] getContact:normalizedSipAddress]; + if(contact) { + image = [FastAddressBook getContactImage:contact thumbnail:false]; + address = [FastAddressBook getContactDisplayName:contact]; + useLinphoneAddress = false; + } + } + if(useLinphoneAddress) { + const char* lDisplayName = linphone_address_get_display_name(addr); + const char* lUserName = linphone_address_get_username(addr); + if (lDisplayName) + address = [NSString stringWithUTF8String:lDisplayName]; + else if(lUserName) + address = [NSString stringWithUTF8String:lUserName]; } - } else { - [addressLabel setText:@"Unknown"]; } // Set Image diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 240091550..f26854c1d 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -26,6 +26,7 @@ #import "IASKSettingsReader.h" #import "IASKSettingsStore.h" #import "IASKAppSettingsViewController.h" +#import "FastAddressBook.h" #include "linphonecore.h" diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 219cb1bfa..fed5147d7 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -28,7 +28,6 @@ #import #import "LinphoneManager.h" -#import "FastAddressBook.h" #import "LinphoneCoreSettingsStore.h" #import "ChatModel.h" @@ -166,34 +165,6 @@ struct codec_name_pref_table codec_pref_table[]={ return theLinphoneManager; } --(void) updateCallWithAddressBookData:(LinphoneCall*) call {/* - //1 copy adress book - LinphoneCallLog* lLog = linphone_call_get_call_log(call); - LinphoneAddress* lAddress; - if (lLog->dir == LinphoneCallIncoming) { - lAddress=lLog->from; - } else { - lAddress=lLog->to; - } - const char* lUserName = linphone_address_get_username(lAddress); - if (!lUserName) { - //just return - return; - } - - NSString* lE164Number = [[NSString alloc] initWithCString:lUserName encoding:[NSString defaultCStringEncoding]]; - NSString* lDisplayName = [self getDisplayNameFromAddressBook:lE164Number andUpdateCallLog:lLog]; - - if(lDisplayName) { - linphone_address_set_display_name(lAddress, [lDisplayName cStringUsingEncoding:[NSString defaultCStringEncoding]]); - } else { - ms_message("No contact entry found for [%s] in address book",lUserName); - } - - [lE164Number release]; - return;*/ -} - - (void)onCall:(LinphoneCall*)call StateChanged:(LinphoneCallState)state withMessage:(const char *)message { // Handling wrapper if(state == LinphoneCallReleased) { @@ -209,10 +180,6 @@ struct codec_name_pref_table codec_pref_table[]={ linphone_call_set_user_pointer(call, data); } - if (state == LinphoneCallIncomingReceived) { - [self updateCallWithAddressBookData:call]; // display name is updated - } - if ((state == LinphoneCallEnd || state == LinphoneCallError)) { if(linphone_core_get_calls_nb([LinphoneManager getLc]) == 0) [self enableSpeaker:FALSE]; @@ -324,6 +291,7 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo [chat setMessage:[NSString stringWithUTF8String:message]]; [chat setDirection:[NSNumber numberWithInt:1]]; [chat setTime:[NSDate date]]; + [chat setRead:[NSNumber numberWithInt:0]]; [chat create]; // Post event @@ -826,7 +794,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach linphone_core_invite_address_with_params([LinphoneManager getLc], linphoneAddress, lcallParams); } linphone_address_destroy(linphoneAddress); - } else if ( proxyCfg==nil){ + } else if (proxyCfg==nil){ UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid sip address",nil) message:NSLocalizedString(@"Either configure a SIP proxy server from settings prior to place a call or use a valid sip address (I.E sip:john@example.net)",nil) delegate:nil @@ -840,7 +808,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach linphone_proxy_config_normalize_number(proxyCfg,[address cStringUsingEncoding:[NSString defaultCStringEncoding]],normalizedUserName,sizeof(normalizedUserName)); linphone_address_set_username(linphoneAddress, normalizedUserName); if(displayName!=nil) { - linphone_address_set_display_name(linphoneAddress,[displayName cStringUsingEncoding:[NSString defaultCStringEncoding]]); + linphone_address_set_display_name(linphoneAddress, [displayName cStringUsingEncoding:[NSString defaultCStringEncoding]]); } if(transfer) { linphone_core_transfer_call([LinphoneManager getLc], linphone_core_get_current_call([LinphoneManager getLc]), normalizedUserName); diff --git a/Classes/LinphoneUI/UICallButton.m b/Classes/LinphoneUI/UICallButton.m index b34ff5e1b..48bd02962 100644 --- a/Classes/LinphoneUI/UICallButton.m +++ b/Classes/LinphoneUI/UICallButton.m @@ -26,6 +26,7 @@ @synthesize addressField; + #pragma mark - Lifecycle Functions - (void)initUICallButton { @@ -66,7 +67,13 @@ #pragma mark - - (void)touchUp:(id) sender { - [[LinphoneManager instance] call:[addressField text] displayName:nil transfer:FALSE]; + NSString *address = [addressField text]; + NSString *displayName = nil; + ABRecordRef contact = [[[LinphoneManager instance] fastAddressBook] getContact:address]; + if(contact) { + displayName = [FastAddressBook getContactDisplayName:contact]; + } + [[LinphoneManager instance] call:address displayName:displayName transfer:FALSE]; } @end diff --git a/Classes/LinphoneUI/UICallCell.m b/Classes/LinphoneUI/UICallCell.m index 9ce420dca..ef3ea1747 100644 --- a/Classes/LinphoneUI/UICallCell.m +++ b/Classes/LinphoneUI/UICallCell.m @@ -151,24 +151,30 @@ if(data != nil && data->call != NULL) { call = data->call; const LinphoneAddress* addr = linphone_call_get_remote_address(call); - UIImage *image; - NSString* address; - if (addr != NULL) { + + UIImage *image = nil; + NSString* address = nil; + if(addr != NULL) { + BOOL useLinphoneAddress = true; // contact name const char* lAddress = linphone_address_as_string_uri_only(addr); - const char* lDisplayName = linphone_address_get_display_name(addr); - const char* lUserName = linphone_address_get_username(addr); - if (lDisplayName) - address = [NSString stringWithUTF8String:lDisplayName]; - else if(lUserName) - address = [NSString stringWithUTF8String:lUserName]; if(lAddress) { - NSString *address = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:lAddress]]; - ABRecordRef contact = [[[LinphoneManager instance] fastAddressBook] getContact:address]; - image = [FastAddressBook getContactImage:contact thumbnail:false]; + NSString *normalizedSipAddress = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:lAddress]]; + ABRecordRef contact = [[[LinphoneManager instance] fastAddressBook] getContact:normalizedSipAddress]; + if(contact) { + image = [FastAddressBook getContactImage:contact thumbnail:false]; + address = [FastAddressBook getContactDisplayName:contact]; + useLinphoneAddress = false; + } + } + if(useLinphoneAddress) { + const char* lDisplayName = linphone_address_get_display_name(addr); + const char* lUserName = linphone_address_get_username(addr); + if (lDisplayName) + address = [NSString stringWithUTF8String:lDisplayName]; + else if(lUserName) + address = [NSString stringWithUTF8String:lUserName]; } - } else { - [addressLabel setText:@"Unknown"]; } // Set Image @@ -184,7 +190,6 @@ [addressLabel setText:address]; LinphoneCallState state = linphone_call_get_state(call); - if(!conferenceCell) { if(state == LinphoneCallOutgoingRinging) { [stateImage setImage:[UIImage imageNamed:@"call_state_ringing_default.png"]]; @@ -214,11 +219,8 @@ [headerBackgroundImage setImage:[UIImage imageNamed:@"cell_conference.png"]]; } - NSMutableString* msDuration = [[NSMutableString alloc] init]; int duration = linphone_call_get_duration(call); - [msDuration appendFormat:@"%02i:%02i", (duration/60), duration - 60 * (duration / 60), nil]; - [stateLabel setText:msDuration]; - [msDuration release]; + [stateLabel setText:[NSString stringWithFormat:@"%02i:%02i", (duration/60), duration - 60 * (duration / 60), nil]]; if(!data->minimize) { CGRect frame = [self frame]; diff --git a/Classes/LinphoneUI/UIChatCell.m b/Classes/LinphoneUI/UIChatCell.m index c00994736..4ce25c3d7 100644 --- a/Classes/LinphoneUI/UIChatCell.m +++ b/Classes/LinphoneUI/UIChatCell.m @@ -134,9 +134,14 @@ - (IBAction)onDeleteClick: (id) event { if(chat != NULL) { - [ChatModel removeConversation:[chat remoteContact]]; - UITableView *parentTable = (UITableView *)self.superview; - [parentTable reloadData]; + UIView *view = [self superview]; + // Find TableViewCell + if(view != nil && ![view isKindOfClass:[UITableView class]]) view = [view superview]; + if(view != nil) { + UITableView *tableView = (UITableView*) view; + NSIndexPath *indexPath = [tableView indexPathForCell:self]; + [[tableView dataSource] tableView:tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:indexPath]; + } } } diff --git a/Classes/LinphoneUI/UIHistoryCell.h b/Classes/LinphoneUI/UIHistoryCell.h index e4d15b1fd..2ce131462 100644 --- a/Classes/LinphoneUI/UIHistoryCell.h +++ b/Classes/LinphoneUI/UIHistoryCell.h @@ -23,7 +23,7 @@ @interface UIHistoryCell : UITableViewCell { UIImageView* imageView; - UILabel* displayNameLabel; + UILabel* addressLabel; UIButton* detailsButton; UIButton* deleteButton; @private @@ -33,7 +33,7 @@ @property (nonatomic, assign) LinphoneCallLog *callLog; @property (nonatomic, retain) IBOutlet UIImageView* imageView; -@property (nonatomic, retain) IBOutlet UILabel* displayNameLabel; +@property (nonatomic, retain) IBOutlet UILabel* addressLabel; @property (nonatomic, retain) IBOutlet UIButton* detailsButton; @property (nonatomic, retain) IBOutlet UIButton* deleteButton; diff --git a/Classes/LinphoneUI/UIHistoryCell.m b/Classes/LinphoneUI/UIHistoryCell.m index a1944bf45..9e4aae335 100644 --- a/Classes/LinphoneUI/UIHistoryCell.m +++ b/Classes/LinphoneUI/UIHistoryCell.m @@ -24,7 +24,7 @@ @implementation UIHistoryCell @synthesize callLog; -@synthesize displayNameLabel; +@synthesize addressLabel; @synthesize imageView; @synthesize deleteButton; @synthesize detailsButton; @@ -49,7 +49,7 @@ - (void) dealloc { [detailsButton release]; [deleteButton release]; - [displayNameLabel release]; + [addressLabel release]; [imageView release]; [super dealloc]; @@ -79,9 +79,14 @@ - (IBAction)onDelete:(id)event { if(callLog != NULL) { - linphone_core_remove_call_log([LinphoneManager getLc], callLog); - UITableView *parentTable = (UITableView *)self.superview; - [parentTable reloadData]; + UIView *view = [self superview]; + // Find TableViewCell + if(view != nil && ![view isKindOfClass:[UITableView class]]) view = [view superview]; + if(view != nil) { + UITableView *tableView = (UITableView*) view; + NSIndexPath *indexPath = [tableView indexPathForCell:self]; + [[tableView dataSource] tableView:tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:indexPath]; + } } } @@ -91,7 +96,7 @@ - (void)update { // Set up the cell... - LinphoneAddress* partyToDisplay; + LinphoneAddress* addr; UIImage *image; if (callLog->dir == LinphoneCallIncoming) { if (callLog->status == LinphoneCallSuccess) { @@ -99,15 +104,36 @@ } else { image = [UIImage imageNamed:@"call_status_missed.png"]; } - partyToDisplay = callLog->from; + addr = callLog->from; } else { image = [UIImage imageNamed:@"call_status_outgoing.png"]; - partyToDisplay = callLog->to; + addr = callLog->to; } - const char* username = (linphone_address_get_display_name(partyToDisplay) != 0)? linphone_address_get_display_name(partyToDisplay):linphone_address_get_username(partyToDisplay); + NSString* address = nil; + if(addr != NULL) { + BOOL useLinphoneAddress = true; + // contact name + const char* lAddress = linphone_address_as_string_uri_only(addr); + if(lAddress) { + NSString *normalizedSipAddress = [FastAddressBook normalizeSipURI:[NSString stringWithUTF8String:lAddress]]; + ABRecordRef contact = [[[LinphoneManager instance] fastAddressBook] getContact:normalizedSipAddress]; + if(contact) { + address = [FastAddressBook getContactDisplayName:contact]; + useLinphoneAddress = false; + } + } + if(useLinphoneAddress) { + const char* lDisplayName = linphone_address_get_display_name(addr); + const char* lUserName = linphone_address_get_username(addr); + if (lDisplayName) + address = [NSString stringWithUTF8String:lDisplayName]; + else if(lUserName) + address = [NSString stringWithUTF8String:lUserName]; + } + } - [displayNameLabel setText:[NSString stringWithUTF8String: username]]; + [addressLabel setText:address]; [imageView setImage: image]; } diff --git a/Classes/LinphoneUI/UIHistoryCell.xib b/Classes/LinphoneUI/UIHistoryCell.xib index cfca19597..20b98f889 100644 --- a/Classes/LinphoneUI/UIHistoryCell.xib +++ b/Classes/LinphoneUI/UIHistoryCell.xib @@ -174,14 +174,6 @@ 11 - - - displayNameLabel - - - - 14 - deleteButton @@ -198,6 +190,14 @@ 17 + + + addressLabel + + + + 25 + onDetails: @@ -292,7 +292,7 @@ - 24 + 25 @@ -314,12 +314,16 @@ + UILabel UIButton UIButton - UILabel UIImageView + + addressLabel + UILabel + deleteButton UIButton @@ -328,10 +332,6 @@ detailsButton UIButton - - displayNameLabel - UILabel - imageView UIImageView diff --git a/Classes/LinphoneUI/UIMainBar.h b/Classes/LinphoneUI/UIMainBar.h index 783a29074..a53638cab 100644 --- a/Classes/LinphoneUI/UIMainBar.h +++ b/Classes/LinphoneUI/UIMainBar.h @@ -27,6 +27,8 @@ UIButton *chatButton; UIView *historyNotificationView; UILabel *historyNotificationLabel; + UIView *chatNotificationView; + UILabel *chatNotificationLabel; } @property (nonatomic, retain) IBOutlet UIButton* historyButton; @@ -36,6 +38,8 @@ @property (nonatomic, retain) IBOutlet UIButton* chatButton; @property (nonatomic, retain) IBOutlet UIView *historyNotificationView; @property (nonatomic, retain) IBOutlet UILabel *historyNotificationLabel; +@property (nonatomic, retain) IBOutlet UIView *chatNotificationView; +@property (nonatomic, retain) IBOutlet UILabel *chatNotificationLabel; -(IBAction) onHistoryClick: (id) event; -(IBAction) onContactsClick: (id) event; diff --git a/Classes/LinphoneUI/UIMainBar.m b/Classes/LinphoneUI/UIMainBar.m index 1cfb7d105..b6c3237a3 100644 --- a/Classes/LinphoneUI/UIMainBar.m +++ b/Classes/LinphoneUI/UIMainBar.m @@ -19,6 +19,7 @@ #import "UIMainBar.h" #import "PhoneMainView.h" +#import "ChatModel.h" @implementation UIMainBar @@ -29,6 +30,8 @@ @synthesize chatButton; @synthesize historyNotificationView; @synthesize historyNotificationLabel; +@synthesize chatNotificationView; +@synthesize chatNotificationLabel; #pragma mark - Lifecycle Functions @@ -46,6 +49,8 @@ [chatButton release]; [historyNotificationView release]; [historyNotificationLabel release]; + [chatNotificationView release]; + [chatNotificationLabel release]; [super dealloc]; } @@ -64,12 +69,19 @@ selector:@selector(callUpdate:) name:@"LinphoneCallUpdate" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(textReceived:) + name:@"LinphoneTextReceived" + object:nil]; + + // Update current view [self updateView:[[PhoneMainView instance] currentView]]; if([LinphoneManager isLcReady]) { - [self updateMissed:linphone_core_get_missed_calls_count([LinphoneManager getLc])]; + [self updateMissedCall:linphone_core_get_missed_calls_count([LinphoneManager getLc])]; } else { - [self updateMissed:0]; + [self updateMissedCall:0]; } + [self updateUnreadMessage:[ChatModel unreadMessages]]; } - (void)viewWillDisappear:(BOOL)animated { @@ -81,6 +93,9 @@ [[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneCallUpdate" object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneTextReceived" + object:nil]; } @@ -89,7 +104,7 @@ - (void)callUpdate: (NSNotification*) notif { //LinphoneCall *call = [[notif.userInfo objectForKey: @"call"] pointerValue]; //LinphoneCallState state = [[notif.userInfo objectForKey: @"state"] intValue]; - [self updateMissed:linphone_core_get_missed_calls_count([LinphoneManager getLc])]; + [self updateMissedCall:linphone_core_get_missed_calls_count([LinphoneManager getLc])]; } - (void)changeViewEvent: (NSNotification*) notif { @@ -98,20 +113,50 @@ [self updateView:[viewNumber intValue]]; } +- (void)textReceived: (NSNotification*) notif { + [self updateUnreadMessage:[ChatModel unreadMessages]]; +} + #pragma mark - -- (void)updateMissed:(int)missedCall { +- (void)updateUnreadMessage:(int)unreadMessage { + if (unreadMessage > 0) { + if([chatNotificationView isHidden]) { + chatNotificationView.transform = CGAffineTransformIdentity; + [self startBounceAnimation:@"Bounce" target:chatNotificationView]; + [chatNotificationView setHidden:FALSE]; + } + [chatNotificationLabel setText:[NSString stringWithFormat:@"%i", unreadMessage]]; + } else { + if(![chatNotificationView isHidden]) { + [self stopBounceAnimation:@"Bounce" target:chatNotificationView]; + CGAffineTransform startCGA = [chatNotificationView transform]; + [UIView animateWithDuration:0.4 + delay:0 + options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction + animations:^{ + chatNotificationView.transform = CGAffineTransformConcat(startCGA, CGAffineTransformMakeScale(0.01f, 0.01f)); + } + completion:^(BOOL finished){ + [chatNotificationView setHidden:TRUE]; + } + ]; + } + } +} + +- (void)updateMissedCall:(int)missedCall { if (missedCall > 0) { if([historyNotificationView isHidden]) { historyNotificationView.transform = CGAffineTransformIdentity; - [self startShakeAnimation:@"Shake" target:historyNotificationView]; + [self startBounceAnimation:@"Bounce" target:historyNotificationView]; [historyNotificationView setHidden:FALSE]; } [historyNotificationLabel setText:[NSString stringWithFormat:@"%i", missedCall]]; } else { if(![historyNotificationView isHidden]) { - [self stopShakeAnimation:@"Shake" target:historyNotificationView]; + [self stopBounceAnimation:@"Bounce" target:historyNotificationView]; CGAffineTransform startCGA = [historyNotificationView transform]; [UIView animateWithDuration:0.4 delay:0 @@ -127,7 +172,7 @@ } } -- (void)startShakeAnimation:(NSString *)animationID target:(UIView *)target { +- (void)startBounceAnimation:(NSString *)animationID target:(UIView *)target { [target setTransform:CGAffineTransformMakeTranslation(0, -4)]; [UIView animateWithDuration: 0.3 delay: 0 @@ -143,7 +188,7 @@ } -- (void)stopShakeAnimation:(NSString *)animationID target:(UIView *)target { +- (void)stopBounceAnimation:(NSString *)animationID target:(UIView *)target { [target.layer removeAnimationForKey:animationID]; } @@ -151,7 +196,7 @@ // Reset missed call if(view == PhoneView_History) { linphone_core_reset_missed_calls_count([LinphoneManager getLc]); - [self updateMissed:0]; + [self updateMissedCall:0]; } // Update buttons diff --git a/Classes/LinphoneUI/UIMainBar.xib b/Classes/LinphoneUI/UIMainBar.xib index a861b8642..6330d597c 100644 --- a/Classes/LinphoneUI/UIMainBar.xib +++ b/Classes/LinphoneUI/UIMainBar.xib @@ -112,7 +112,7 @@ _NS:9 NO IBCocoaTouchFramework - + NSImage history_notification.png @@ -131,7 +131,7 @@ NO IBCocoaTouchFramework 99 - + 3 MQA @@ -139,11 +139,11 @@ 0 10 1 - + 1 14 - + Helvetica 14 16 @@ -155,7 +155,7 @@ _NS:9 - + 3 MCAwAA @@ -265,6 +265,7 @@ {{256, 0}, {64, 77}} + _NS:9 NO @@ -290,6 +291,54 @@ + + + -2147483356 + + + + 274 + {21, 21} + + + + _NS:9 + NO + IBCocoaTouchFramework + + + + + 292 + {21, 21} + + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + 99 + + + 0 + 10 + 1 + + + + + {{261, 5}, {21, 21}} + + + + _NS:9 + + NO + NO + IBCocoaTouchFramework + {320, 77} @@ -370,6 +419,22 @@ 36 + + + chatNotificationLabel + + + + 40 + + + + chatNotificationView + + + + 41 + onChatClick: @@ -446,6 +511,7 @@ + mainTabBar @@ -509,6 +575,28 @@ historyNotificationLabel + + 37 + + + + + + + chatNotificationView + + + 38 + + + chatNotificationLabel + + + 39 + + + chatNotificationImage + @@ -521,6 +609,9 @@ com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin @@ -537,7 +628,7 @@ - 36 + 41 @@ -575,6 +666,8 @@ UIButton + UILabel + UIView UIButton UIButton UIButton @@ -587,6 +680,14 @@ chatButton UIButton + + chatNotificationLabel + UILabel + + + chatNotificationView + UIView + contactsButton UIButton diff --git a/Classes/Model/ChatModel.h b/Classes/Model/ChatModel.h index 1d5139b18..f1258ba80 100644 --- a/Classes/Model/ChatModel.h +++ b/Classes/Model/ChatModel.h @@ -27,22 +27,26 @@ NSNumber *direction; //0 outgoing 1 incoming NSString *message; NSDate *time; + NSNumber *read; } -@property (nonatomic, readonly) NSNumber *chatId; -@property (nonatomic, copy) NSString *localContact; -@property (nonatomic, copy) NSString *remoteContact; -@property (nonatomic, copy) NSNumber *direction; -@property (nonatomic, copy) NSString *message; -@property (nonatomic, copy) NSDate *time; +@property (readonly) NSNumber *chatId; +@property (copy) NSString *localContact; +@property (copy) NSString *remoteContact; +@property (copy) NSNumber *direction; +@property (copy) NSString *message; +@property (copy) NSDate *time; +@property (copy) NSNumber *read; -- (void) create; -+ (ChatModel*) read:(NSNumber*)id; -- (void) update; -- (void) delete; +- (void)create; ++ (ChatModel*)read:(NSNumber*)id; +- (void)update; +- (void)delete; -+ (NSArray *) listConversations; -+ (NSArray *) listMessages:(NSString *)contact; -+ (void) removeConversation:(NSString *)contact; ++ (NSMutableArray *)listConversations; ++ (NSMutableArray *)listMessages:(NSString *)contact; ++ (void)removeConversation:(NSString *)contact; ++ (int)unreadMessages; ++ (void)readConversation:(NSString *)contact; @end diff --git a/Classes/Model/ChatModel.m b/Classes/Model/ChatModel.m index 45e553b30..fbd949149 100644 --- a/Classes/Model/ChatModel.m +++ b/Classes/Model/ChatModel.m @@ -28,6 +28,7 @@ @synthesize message; @synthesize direction; @synthesize time; +@synthesize read; #pragma mark - Lifecycle Functions @@ -41,6 +42,7 @@ self.direction = [NSNumber numberWithInt:sqlite3_column_int(sqlStatement, 3)]; self.message = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(sqlStatement, 4)]; self.time = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_int(sqlStatement, 5)]; + self.read = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_int(sqlStatement, 6)]; } return self; } @@ -52,6 +54,7 @@ [message release]; [direction release]; [time release]; + [read release]; [super dealloc]; } @@ -65,8 +68,8 @@ NSLog(@"Database not ready"); return; } - const char *sql = [[NSString stringWithFormat:@"INSERT INTO chat (localContact, remoteContact, direction, message, time) VALUES (\"%@\", \"%@\", %i, \"%@\", %i)", - localContact, remoteContact, [direction intValue], message, [time timeIntervalSince1970]] UTF8String]; + const char *sql = [[NSString stringWithFormat:@"INSERT INTO chat (localContact, remoteContact, direction, message, time, read) VALUES (\"%@\", \"%@\", %i, \"%@\", %f, %i)", + localContact, remoteContact, [direction intValue], message, [time timeIntervalSince1970], [read intValue]] UTF8String]; sqlite3_stmt *sqlStatement; if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); @@ -86,7 +89,7 @@ return nil; } - const char *sql = [[NSString stringWithFormat:@"SELECT id, localContact, remoteContact, direction, message, time FROM chat WHERE id=%@", + const char *sql = [[NSString stringWithFormat:@"SELECT id, localContact, remoteContact, direction, message, time, read FROM chat WHERE id=%@", chatId] UTF8String]; sqlite3_stmt *sqlStatement; if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { @@ -115,8 +118,8 @@ return; } - const char *sql = [[NSString stringWithFormat:@"UPDATE chat SET localContact=\"%@\", remoteContact=\"%@\", direction=%i, message=\"%@\", time=%i WHERE id=%@", - localContact, remoteContact, [direction intValue], message, [time timeIntervalSince1970], chatId] UTF8String]; + const char *sql = [[NSString stringWithFormat:@"UPDATE chat SET localContact=\"%@\", remoteContact=\"%@\", direction=%i, message=\"%@\", time=%f, read=%i WHERE id=%@", + localContact, remoteContact, [direction intValue], message, [time timeIntervalSince1970], read, [chatId intValue]] UTF8String]; sqlite3_stmt *sqlStatement; if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); @@ -159,21 +162,21 @@ #pragma mark - -+ (NSArray *)listConversations { ++ (NSMutableArray *)listConversations { + NSMutableArray *array = [NSMutableArray array]; sqlite3* database = [[LinphoneManager instance] database]; if(database == NULL) { NSLog(@"Database not ready"); - return [[[NSArray alloc] init] autorelease]; + return array; } - const char *sql = "SELECT id, localContact, remoteContact, direction, message, time FROM chat GROUP BY remoteContact ORDER BY time DESC"; + const char *sql = "SELECT id, localContact, remoteContact, direction, message, time, read FROM chat GROUP BY remoteContact ORDER BY time DESC"; sqlite3_stmt *sqlStatement; if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { NSLog(@"Can't execute the query: %s (%s)", sql, sqlite3_errmsg(database)); - return [[[NSArray alloc] init] autorelease]; + return array; } - NSMutableArray *array = [[NSMutableArray alloc] init]; int err; while ((err = sqlite3_step(sqlStatement)) == SQLITE_ROW) { ChatModel *line = [[ChatModel alloc] initWithData:sqlStatement]; @@ -182,32 +185,30 @@ if (err != SQLITE_DONE) { NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); - return [[[NSArray alloc] init] autorelease]; + return array; } sqlite3_finalize(sqlStatement); - NSArray *fArray = [NSArray arrayWithArray: array]; - [array release]; - return fArray; + return array; } -+ (NSArray *)listMessages:(NSString *)contact { ++ (NSMutableArray *)listMessages:(NSString *)contact { + NSMutableArray *array = [NSMutableArray array]; sqlite3* database = [[LinphoneManager instance] database]; if(database == NULL) { NSLog(@"Database not ready"); - return [[[NSArray alloc] init] autorelease]; + return array; } - const char *sql = [[NSString stringWithFormat:@"SELECT id, localContact, remoteContact, direction, message, time FROM chat WHERE remoteContact=\"%@\" ORDER BY time DESC", + const char *sql = [[NSString stringWithFormat:@"SELECT id, localContact, remoteContact, direction, message, time, read FROM chat WHERE remoteContact=\"%@\" ORDER BY time DESC", contact] UTF8String]; sqlite3_stmt *sqlStatement; if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { NSLog(@"Can't execute the query: %s (%s)", sql, sqlite3_errmsg(database)); - return [[[NSArray alloc] init] autorelease]; + return array; } - NSMutableArray *array = [[NSMutableArray alloc] init]; int err; while ((err = sqlite3_step(sqlStatement)) == SQLITE_ROW) { ChatModel *line = [[ChatModel alloc] initWithData:sqlStatement]; @@ -216,17 +217,15 @@ if (err != SQLITE_DONE) { NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); - return [[[NSArray alloc] init] autorelease]; + return array; } sqlite3_finalize(sqlStatement); - NSArray *fArray = [NSArray arrayWithArray: array]; - [array release]; - return fArray; + return array; } -+ (void) removeConversation:(NSString *)contact { ++ (void)removeConversation:(NSString *)contact { sqlite3* database = [[LinphoneManager instance] database]; if(database == NULL) { NSLog(@"Database not ready"); @@ -250,4 +249,55 @@ sqlite3_finalize(sqlStatement); } ++ (int)unreadMessages { + int count = -1; + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return count; + } + + const char *sql = [[NSString stringWithFormat:@"SELECT count(*) FROM chat WHERE read=0"] UTF8String]; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); + return count; + } + + if (sqlite3_step(sqlStatement) != SQLITE_ROW) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + sqlite3_finalize(sqlStatement); + return count; + } + + count = sqlite3_column_int(sqlStatement, 0); + + sqlite3_finalize(sqlStatement); + return count; +} + ++ (void)readConversation:(NSString *)contact { + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return; + } + + const char *sql = [[NSString stringWithFormat:@"UPDATE chat SET read=1 WHERE remoteContact=\"%@\"", + contact] UTF8String]; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); + return; + } + + if (sqlite3_step(sqlStatement) != SQLITE_DONE) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + sqlite3_finalize(sqlStatement); + return; + } + + sqlite3_finalize(sqlStatement); +} + @end diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index d8b83fbac..d7dcb9114 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -347,6 +347,7 @@ static PhoneMainView* phoneMainViewInstance=nil; } - (void)_changeView:(PhoneView)view calls:(NSArray *)calls transition:(CATransition*)transition { + NSLog(@"PhoneMainView: change view %d", view); UICompositeViewDescription* description = [viewDescriptions objectForKey:[NSNumber numberWithInt: view]]; if(description == nil) return; @@ -375,6 +376,7 @@ static PhoneMainView* phoneMainViewInstance=nil; } - (void)popView:(NSArray *)calls { + NSLog(@"PhoneMainView: Pop!"); if([viewStack count] > 0) { PhoneView view = [[viewStack lastObject] intValue]; [viewStack removeLastObject]; diff --git a/Classes/Utils/FastAddressBook.h b/Classes/Utils/FastAddressBook.h index 3e0f89a6c..fa737ae52 100644 --- a/Classes/Utils/FastAddressBook.h +++ b/Classes/Utils/FastAddressBook.h @@ -21,7 +21,7 @@ #import @interface FastAddressBook : NSObject { - NSMutableDictionary* mAddressBookMap; + NSMutableDictionary* addressBookMap; ABAddressBookRef addressBook; } diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index b2441ca7b..3ec6488a7 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -46,8 +46,8 @@ } - (ABRecordRef)getContact:(NSString*)address { - @synchronized (mAddressBookMap){ - return (ABRecordRef)[mAddressBookMap objectForKey:address]; + @synchronized (addressBookMap){ + return (ABRecordRef)[addressBookMap objectForKey:address]; } } @@ -87,10 +87,20 @@ return [FastAddressBook appendCountryCodeIfPossible:lNormalizedAddress]; } -void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void *context) { - NSMutableDictionary* lAddressBookMap = (NSMutableDictionary*)context; - @synchronized (lAddressBookMap) { - [lAddressBookMap removeAllObjects]; +- (FastAddressBook*)init { + if ((self = [super init]) != nil) { + addressBookMap = [[NSMutableDictionary alloc] init]; + addressBook = ABAddressBookCreate(); + ABAddressBookRegisterExternalChangeCallback (addressBook, sync_address_book, self); + [self loadData]; + } + return self; +} + +- (void)loadData { + ABAddressBookRevert(addressBook); + @synchronized (addressBookMap) { + [addressBookMap removeAllObjects]; NSArray *lContacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook); for (id lPerson in lContacts) { @@ -103,7 +113,7 @@ void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void CFStringRef lLabel = ABMultiValueCopyLabelAtIndex(lMap, i); CFStringRef lLocalizedLabel = ABAddressBookCopyLocalizedLabel(lLabel); NSString* lNormalizedKey = [FastAddressBook normalizePhoneNumber:(NSString*)lValue]; - [lAddressBookMap setObject:lPerson forKey:lNormalizedKey]; + [addressBookMap setObject:lPerson forKey:lNormalizedKey]; CFRelease(lValue); if (lLabel) CFRelease(lLabel); if (lLocalizedLabel) CFRelease(lLocalizedLabel); @@ -118,12 +128,18 @@ void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void if(lMap) { for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) { CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i); + BOOL add = false; if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) { if(CFStringCompare((CFStringRef)CONTACT_SIP_FIELD, CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), kCFCompareCaseInsensitive) == 0) { - CFStringRef lValue = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey); - NSString* lNormalizedKey = [FastAddressBook normalizeSipURI:(NSString*)lValue]; - [lAddressBookMap setObject:lPerson forKey:lNormalizedKey]; + add = true; } + } else { + add = true; + } + if(add) { + CFStringRef lValue = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey); + NSString* lNormalizedKey = [FastAddressBook normalizeSipURI:(NSString*)lValue]; + [addressBookMap setObject:lPerson forKey:lNormalizedKey]; } CFRelease(lDict); } @@ -133,20 +149,16 @@ void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void } CFRelease(lContacts); } + [[NSNotificationCenter defaultCenter] postNotificationName:@"LinphoneAddressBookUpdate" object:self]; } -- (FastAddressBook*)init { - if ((self = [super init]) != nil) { - mAddressBookMap = [[NSMutableDictionary alloc] init]; - addressBook = ABAddressBookCreate(); - ABAddressBookRegisterExternalChangeCallback (addressBook, sync_address_book, mAddressBookMap); - sync_address_book(addressBook,nil,mAddressBookMap); - } - return self; +void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void *context) { + FastAddressBook* fastAddressBook = (FastAddressBook*)context; + [fastAddressBook loadData]; } - (void)dealloc { - ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, mAddressBookMap); + ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self); CFRelease(addressBook); [super dealloc]; } diff --git a/Resources/database.sqlite b/Resources/database.sqlite index d52fcbd6e..1469b4df1 100644 Binary files a/Resources/database.sqlite and b/Resources/database.sqlite differ diff --git a/Resources/history_add_default.png b/Resources/history_add_default.png new file mode 100644 index 000000000..125c8f0f1 Binary files /dev/null and b/Resources/history_add_default.png differ diff --git a/Resources/history_add_over.png b/Resources/history_add_over.png new file mode 100644 index 000000000..fdb40bbf5 Binary files /dev/null and b/Resources/history_add_over.png differ diff --git a/Resources/history_back_default.png b/Resources/history_back_default.png new file mode 100644 index 000000000..3c90a7bb6 Binary files /dev/null and b/Resources/history_back_default.png differ diff --git a/Resources/history_back_over.png b/Resources/history_back_over.png new file mode 100644 index 000000000..ce56ede38 Binary files /dev/null and b/Resources/history_back_over.png differ diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 088237180..cf09ecf6a 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -181,6 +181,14 @@ D3128FF415AABE4E00A2147A /* contact_edit_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3128FE915AABE4E00A2147A /* contact_edit_default.png */; }; D3128FF515AABE4E00A2147A /* contact_edit_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3128FEA15AABE4E00A2147A /* contact_edit_over.png */; }; D3128FF615AABE4E00A2147A /* contact_edit_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3128FEA15AABE4E00A2147A /* contact_edit_over.png */; }; + D3157A8A15B4466F00DD8C4C /* history_add_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8815B4466F00DD8C4C /* history_add_default.png */; }; + D3157A8B15B4466F00DD8C4C /* history_add_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8815B4466F00DD8C4C /* history_add_default.png */; }; + D3157A8C15B4466F00DD8C4C /* history_add_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8915B4466F00DD8C4C /* history_add_over.png */; }; + D3157A8D15B4466F00DD8C4C /* history_add_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8915B4466F00DD8C4C /* history_add_over.png */; }; + D3157A9015B446CB00DD8C4C /* history_back_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8E15B446CB00DD8C4C /* history_back_default.png */; }; + D3157A9115B446CB00DD8C4C /* history_back_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8E15B446CB00DD8C4C /* history_back_default.png */; }; + D3157A9215B446CB00DD8C4C /* history_back_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8F15B446CB00DD8C4C /* history_back_over.png */; }; + D3157A9315B446CB00DD8C4C /* history_back_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3157A8F15B446CB00DD8C4C /* history_back_over.png */; }; D3196D3415A321E3007FEEBA /* options_add_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3196D3015A321E2007FEEBA /* options_add_default.png */; }; D3196D3515A321E3007FEEBA /* options_add_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3196D3015A321E2007FEEBA /* options_add_default.png */; }; D3196D3615A321E3007FEEBA /* options_add_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3196D3115A321E2007FEEBA /* options_add_over.png */; }; @@ -1093,6 +1101,10 @@ D3128FE815AABE4E00A2147A /* contact_back_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = contact_back_over.png; path = Resources/contact_back_over.png; sourceTree = ""; }; D3128FE915AABE4E00A2147A /* contact_edit_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = contact_edit_default.png; path = Resources/contact_edit_default.png; sourceTree = ""; }; D3128FEA15AABE4E00A2147A /* contact_edit_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = contact_edit_over.png; path = Resources/contact_edit_over.png; sourceTree = ""; }; + D3157A8815B4466F00DD8C4C /* history_add_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = history_add_default.png; path = Resources/history_add_default.png; sourceTree = ""; }; + D3157A8915B4466F00DD8C4C /* history_add_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = history_add_over.png; path = Resources/history_add_over.png; sourceTree = ""; }; + D3157A8E15B446CB00DD8C4C /* history_back_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = history_back_default.png; path = Resources/history_back_default.png; sourceTree = ""; }; + D3157A8F15B446CB00DD8C4C /* history_back_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = history_back_over.png; path = Resources/history_back_over.png; sourceTree = ""; }; D3196D3015A321E2007FEEBA /* options_add_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = options_add_default.png; path = Resources/options_add_default.png; sourceTree = ""; }; D3196D3115A321E2007FEEBA /* options_add_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = options_add_over.png; path = Resources/options_add_over.png; sourceTree = ""; }; D3196D3215A321E3007FEEBA /* options_transfer_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = options_transfer_default.png; path = Resources/options_transfer_default.png; sourceTree = ""; }; @@ -2192,8 +2204,12 @@ D3F83EFB158205A100336684 /* hangup_over.png */, D36C43CE158F2F370048BA40 /* header_conference.png */, D3F26BFB15987083005F9CAB /* header_incoming.png */, + D3157A8815B4466F00DD8C4C /* history_add_default.png */, + D3157A8915B4466F00DD8C4C /* history_add_over.png */, D3ED3E9315872EF1006C0DE4 /* history_all_default.png */, D3ED3E9215872EF1006C0DE4 /* history_all_selected.png */, + D3157A8E15B446CB00DD8C4C /* history_back_default.png */, + D3157A8F15B446CB00DD8C4C /* history_back_over.png */, D347347C1580E5F8003C7B8C /* history_default.png */, D3ED3E9415872EF1006C0DE4 /* history_edit_default.png */, D3ED3E9515872EF1006C0DE4 /* history_edit_over.png */, @@ -2814,6 +2830,10 @@ D3E84F2A15B00F4100420DAC /* dialer_alt_background.png in Resources */, D3E84F3815B011AF00420DAC /* contact_cancel_default.png in Resources */, D3E84F3A15B011AF00420DAC /* contact_cancel_over.png in Resources */, + D3157A8A15B4466F00DD8C4C /* history_add_default.png in Resources */, + D3157A8C15B4466F00DD8C4C /* history_add_over.png in Resources */, + D3157A9015B446CB00DD8C4C /* history_back_default.png in Resources */, + D3157A9215B446CB00DD8C4C /* history_back_over.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3061,6 +3081,10 @@ D3E84F2B15B00F4100420DAC /* dialer_alt_background.png in Resources */, D3E84F3915B011AF00420DAC /* contact_cancel_default.png in Resources */, D3E84F3B15B011AF00420DAC /* contact_cancel_over.png in Resources */, + D3157A8B15B4466F00DD8C4C /* history_add_default.png in Resources */, + D3157A8D15B4466F00DD8C4C /* history_add_over.png in Resources */, + D3157A9115B446CB00DD8C4C /* history_back_default.png in Resources */, + D3157A9315B446CB00DD8C4C /* history_back_over.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; };