diff --git a/Classes/Base.lproj/ContactDetailsView.xib b/Classes/Base.lproj/ContactDetailsView.xib index 513c57641..f58448469 100644 --- a/Classes/Base.lproj/ContactDetailsView.xib +++ b/Classes/Base.lproj/ContactDetailsView.xib @@ -72,7 +72,7 @@ - + @@ -126,7 +126,7 @@ - + diff --git a/Classes/ContactDetailsTableView.m b/Classes/ContactDetailsTableView.m index 352652f25..ee376a013 100644 --- a/Classes/ContactDetailsTableView.m +++ b/Classes/ContactDetailsTableView.m @@ -572,13 +572,12 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { [cell setAddress:value]; if (contactSections[[indexPath section]] == ContactSections_Number) { [cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad]; - [cell.editTextfield setPlaceholder:NSLocalizedString(@"Phone number", nil)]; } else if (contactSections[[indexPath section]] == ContactSections_Sip) { [cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable]; - [cell.editTextfield setPlaceholder:NSLocalizedString(@"SIP address", nil)]; } else if (contactSections[[indexPath section]] == ContactSections_Email) { [cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable]; - [cell.editTextfield setPlaceholder:NSLocalizedString(@"Email address", nil)]; + } else { + [cell.editTextfield setKeyboardType:UIKeyboardTypeDefault]; } return cell; } @@ -591,7 +590,8 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { NSString *key = nil; ABPropertyID property = [self propertyIDForSection:contactSections[indexPath.section]]; - if (property != kABInvalidPropertyType) { + if (property != kABInvalidPropertyType && property != kABPersonFirstNameProperty && + property != kABPersonLastNameProperty) { ABMultiValueRef lMap = ABRecordCopyValue(contact, property); NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]); NSString *labelRef = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(lMap, index)); @@ -625,8 +625,30 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; - if (!editing) { + BOOL showEmails = [[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"]; + if (editing) { + // add phone/SIP/email entries so that the user can add new data + for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) { + if (contactSections[section] == ContactSections_Number || contactSections[section] == ContactSections_Sip || + (showEmails && contactSections[section] == ContactSections_Email)) { + [self addEntry:self.tableView section:section animated:animated]; + } + } + } else { [LinphoneUtils findAndResignFirstResponder:[self tableView]]; + // remove empty phone numbers + for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) { + // remove phony entries that were not filled by the user + if (contactSections[section] == ContactSections_Number || contactSections[section] == ContactSections_Sip || + (showEmails && contactSections[section] == ContactSections_Email)) { + + [self removeEmptyEntry:self.tableView section:section animated:animated]; + if ([[self getSectionData:section] count] == 0 && animated) { // the section is empty -> remove titles + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] + withRowAnimation:UITableViewRowAnimationFade]; + } + } + } } [self loadData]; if (contactDetailsDelegate != nil) { @@ -642,6 +664,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { NSString *text = nil; BOOL canAddEntry = self.tableView.isEditing; + NSString *addEntryName = nil; if (contactSections[section] == ContactSections_First_Name && self.tableView.isEditing) { text = NSLocalizedString(@"First name", nil); canAddEntry = NO; @@ -651,11 +674,14 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { } else if ([self getSectionData:section].count > 0 || self.tableView.isEditing) { if (contactSections[section] == ContactSections_Number) { text = NSLocalizedString(@"Phone numbers", nil); + addEntryName = NSLocalizedString(@"Add new phone number", nil); } else if (contactSections[section] == ContactSections_Sip) { text = NSLocalizedString(@"SIP addresses", nil); + addEntryName = NSLocalizedString(@"Add new SIP address", nil); } else if (contactSections[section] == ContactSections_Email && [LinphoneManager.instance lpConfigBoolForKey:@"show_contacts_emails_preference"]) { text = NSLocalizedString(@"Email addresses", nil); + addEntryName = NSLocalizedString(@"Add new email", nil); } } @@ -683,6 +709,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { [tempAddButton setImage:[UIImage imageNamed:@"add_field_over.png"] forState:UIControlStateSelected]; [tempAddButton addTarget:self action:@selector(onAddClick:) forControlEvents:UIControlEventTouchUpInside]; tempAddButton.tag = section; + tempAddButton.accessibilityLabel = addEntryName; [tempView addSubview:tempAddButton]; } @@ -744,6 +771,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { - (BOOL)textFieldShouldEndEditing:(UITextField *)textField { UIView *view = [textField superview]; + // Find TableViewCell while (view != nil && ![view isKindOfClass:[UIContactDetailsCell class]]) view = [view superview]; @@ -757,18 +785,36 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { ABPropertyID property = [self propertyIDForSection:sect]; NSString *value = [textField text]; - if (sect == ContactSections_Sip) { - [self setSipContactEntry:entry withValue:value]; - } else if (property != kABInvalidPropertyType) { - ABMultiValueRef lcMap = ABRecordCopyValue(contact, property); - ABMutableMultiValueRef lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]); - ABMultiValueReplaceValueAtIndex(lMap, (__bridge CFStringRef)value, index); - ABRecordSetValue(contact, property, lMap, nil); - CFRelease(lMap); + switch (sect) { + case ContactSections_First_Name: + case ContactSections_Last_Name: { + // [cell.detailTextLabel setText:[textField text]]; + CFErrorRef error = NULL; + ABRecordSetValue(contact, property, (__bridge CFTypeRef)([textField text]), (CFErrorRef *)&error); + if (error != NULL) { + LOGE(@"Error when saving property %i in contact %p: Fail(%@)", property, contact, + [(__bridge NSError *)error localizedDescription]); + } + break; + } + case ContactSections_Sip: + [self setSipContactEntry:entry withValue:value]; + break; + case ContactSections_Email: + case ContactSections_Number: { + ABMultiValueRef lcMap = ABRecordCopyValue(contact, property); + ABMutableMultiValueRef lMap = ABMultiValueCreateMutableCopy(lcMap); + CFRelease(lcMap); + NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]); + ABMultiValueReplaceValueAtIndex(lMap, (__bridge CFStringRef)value, index); + ABRecordSetValue(contact, property, lMap, nil); + CFRelease(lMap); + break; + } + case ContactSections_MAX: + case ContactSections_None: + break; } - cell.editTextfield.text = value; } else { LOGE(@"Not valid UIEditableTableViewCell"); @@ -779,7 +825,11 @@ static const ContactSections_e contactSections[ContactSections_MAX] = { return TRUE; } - (BOOL)isValid { - return true; + NSString *firstName = + (__bridge NSString *)(ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_First_Name])); + NSString *lastName = + (__bridge NSString *)(ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_Last_Name])); + return firstName.length > 0 || lastName.length > 0; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { diff --git a/Classes/ContactDetailsView.m b/Classes/ContactDetailsView.m index fe2d410f4..e0816193a 100644 --- a/Classes/ContactDetailsView.m +++ b/Classes/ContactDetailsView.m @@ -119,7 +119,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info [_tableController setContact:_contact]; if (reload) { - [self setEditing:FALSE]; + [self setEditing:TRUE animated:FALSE]; [[_tableController tableView] reloadData]; } } @@ -141,7 +141,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info if (linphoneAddress) { linphone_address_destroy(linphoneAddress); } - [self setEditing:FALSE]; + [self setEditing:TRUE]; [[_tableController tableView] reloadData]; } @@ -172,8 +172,10 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - [_editButton setBackgroundImage:[UIImage imageNamed:@"valid_disabled.png"] - forState:(UIControlStateDisabled | UIControlStateSelected)]; + _tableController.tableView.accessibilityIdentifier = @"Contact table"; + + [_editButton setImage:[UIImage imageNamed:@"valid_disabled.png"] + forState:(UIControlStateDisabled | UIControlStateSelected)]; if ([ContactSelection getSelectionMode] == ContactSelectionModeEdit || [ContactSelection getSelectionMode] == ContactSelectionModeNone) { @@ -226,6 +228,7 @@ static UICompositeViewDescription *compositeDescription = nil; _cancelButton.hidden = !editing; _backButton.hidden = editing; _nameLabel.hidden = editing; + [ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact]; CGRect frame = self.contentView.frame; frame.size.height -= _avatarImage.frame.origin.y + _avatarImage.frame.size.height; diff --git a/Classes/ContactsListView.m b/Classes/ContactsListView.m index ff11b1a8b..9fbb1c4a4 100644 --- a/Classes/ContactsListView.m +++ b/Classes/ContactsListView.m @@ -108,22 +108,14 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - ViewController Functions -//- (void)relayoutTableView { -// CGRect subViewFrame = self.view.frame; -// // let the top bar be visible -// subViewFrame.origin.y += self.topBar.frame.size.height + self.searchBar.frame.size.height; -// subViewFrame.size.height -= self.topBar.frame.size.height + self.searchBar.frame.size.height; -// [UIView animateWithDuration:0.2 -// animations:^{ -// self.tableController.tableView.frame = subViewFrame; -// }]; -//} - - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; _searchBar.showsCancelButton = (_searchBar.text.length > 0); + if (tableController.isEditing) { + tableController.editing = NO; + } [self update]; } diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index dc26ca5c4..d964a6006 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -2336,7 +2336,7 @@ static void audioRouteChangeListenerCallback(void *inUserData, // 1 const MSList *it = linphone_core_get_proxy_config_list([LinphoneManager getLc]); while (it) { - if (linphone_address_equal(addr, linphone_proxy_config_get_identity_address(it->data))) { + if (linphone_address_weak_equal(addr, linphone_proxy_config_get_identity_address(it->data))) { return YES; } it = it->next; diff --git a/TestsUI/ContactsTester.m b/TestsUI/ContactsTester.m index 7d07fcdb7..70706942d 100644 --- a/TestsUI/ContactsTester.m +++ b/TestsUI/ContactsTester.m @@ -14,6 +14,10 @@ #pragma mark - Setup +- (void)beforeAll { + [self switchToValidAccountIfNeeded]; +} + - (void)beforeEach { [super beforeEach]; if ([tester tryFindingTappableViewWithAccessibilityLabel:@"Back" error:nil]) { @@ -24,15 +28,9 @@ #pragma mark - Utils -- (void)setText:(NSString *)text forContactHeaderIndex:(NSInteger)idx { - [tester tapRowAtIndexPath:[NSIndexPath indexPathForRow:idx inSection:0] - inTableViewWithAccessibilityIdentifier:@"Contact Name Table"]; - [tester enterTextIntoCurrentFirstResponder:text]; -} - -- (void)setText:(NSString *)text forContactNumbersIndex:(NSInteger)idx inSection:(NSInteger)section { +- (void)setText:(NSString *)text forIndex:(NSInteger)idx inSection:(NSInteger)section { [tester tapRowAtIndexPath:[NSIndexPath indexPathForRow:idx inSection:section] - inTableViewWithAccessibilityIdentifier:@"Contact numbers table"]; + inTableViewWithAccessibilityIdentifier:@"Contact table"]; [tester enterTextIntoCurrentFirstResponder:text]; } @@ -49,30 +47,31 @@ traits:UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled | UIAccessibilityTraitSelected]; - [self setText:firstName forContactHeaderIndex:0]; + [self setText:firstName forIndex:0 inSection:ContactSections_First_Name]; // entering text should enable the "edit" button [tester waitForViewWithAccessibilityLabel:@"Edit" traits:UIAccessibilityTraitButton | UIAccessibilityTraitSelected]; - if (lastName) - [self setText:lastName forContactHeaderIndex:1]; + if (lastName) { + [self setText:lastName forIndex:0 inSection:ContactSections_Last_Name]; + } if (phone) { - [self setText:phone forContactNumbersIndex:0 inSection:ContactSections_Number]; + [self setText:phone forIndex:0 inSection:ContactSections_Number]; } if (sip) { - [self setText:sip forContactNumbersIndex:0 inSection:ContactSections_Sip]; + [self setText:sip forIndex:0 inSection:ContactSections_Sip]; } [tester tapViewWithAccessibilityLabel:@"Edit"]; } - (void)tapCellForRowAtIndexPath:(NSInteger)idx inSection:(NSInteger)section atX:(CGFloat)x { - UITableView *tv = [self findTableView:@"Contact numbers table"]; + UITableView *tv = [self findTableView:@"Contact table"]; NSIndexPath *path = [NSIndexPath indexPathForRow:idx inSection:section]; UITableViewCell *last = - [tester waitForCellAtIndexPath:path inTableViewWithAccessibilityIdentifier:@"Contact numbers table"]; + [tester waitForCellAtIndexPath:path inTableViewWithAccessibilityIdentifier:@"Contact table"]; XCTAssertNotNil(last); CGRect cellFrame = [last.contentView convertRect:last.contentView.frame toView:tv]; @@ -84,25 +83,19 @@ [self tapCellForRowAtIndexPath:idx inSection:section atX:-10]; } -- (void)tapEditButtonForRowAtIndexPath:(NSInteger)idx inSection:(NSInteger)section { - // tap the "+" to add a new item (or "-" to delete it).... WOW, this code is ugly! - // the thing is: we don't handle the "+" button ourself (system stuff) - // so it is not present in the tableview cell... so we tap on a fixed position of screen :) - [self tapCellForRowAtIndexPath:idx inSection:section atX:10]; -} - - (void)addEntries:(NSArray *)numbers inSection:(NSInteger)section { [tester tapViewWithAccessibilityLabel:@"Edit"]; - [self setText:[numbers objectAtIndex:0] forContactNumbersIndex:0 inSection:section]; + NSString *name = (section == ContactSections_Sip) ? @"Add new SIP address" : @"Add new phone number"; + [self setText:[numbers objectAtIndex:0] forIndex:0 inSection:section]; for (NSInteger i = 1; i < numbers.count; i++) { - [self tapEditButtonForRowAtIndexPath:i - 1 inSection:section]; - [self setText:[numbers objectAtIndex:i] forContactNumbersIndex:i inSection:section]; + [tester tapViewWithAccessibilityLabel:name traits:UIAccessibilityTraitButton]; + [self setText:[numbers objectAtIndex:i] forIndex:i inSection:section]; } [tester tapViewWithAccessibilityLabel:@"Edit"]; for (NSInteger i = 0; i < numbers.count; i++) { - [tester waitForViewWithAccessibilityLabel:[@"Linphone, " stringByAppendingString:[numbers objectAtIndex:i]] - traits:UIAccessibilityTraitStaticText]; + [tester waitForViewWithAccessibilityLabel:[@"Call " stringByAppendingString:[numbers objectAtIndex:i]] + traits:UIAccessibilityTraitButton]; } } @@ -121,7 +114,7 @@ NSString *contactName = [self getUUID]; NSString *phone = @"+5 15 #0664;447*46"; [self createContact:contactName lastName:@"dummy" phoneNumber:phone SIPAddress:nil]; - [tester tapViewWithAccessibilityLabel:[@"Linphone, " stringByAppendingString:phone]]; + [tester tapViewWithAccessibilityLabel:[@"Call " stringByAppendingString:phone]]; [tester waitForViewWithAccessibilityLabel:[phone stringByAppendingString:@" is not registered."]]; [tester tapViewWithAccessibilityLabel:@"Cancel"]; } @@ -136,18 +129,14 @@ [tester tapViewWithAccessibilityLabel:fullName traits:UIAccessibilityTraitStaticText]; [tester tapViewWithAccessibilityLabel:@"Edit"]; - [tester scrollViewWithAccessibilityIdentifier:@"Contact numbers table" byFractionOfSizeHorizontal:0 vertical:-0.9]; + [tester scrollViewWithAccessibilityIdentifier:@"Contact table" byFractionOfSizeHorizontal:0 vertical:-0.9]; - [tester tapViewWithAccessibilityLabel:@"Remove"]; - - [tester waitForAbsenceOfViewWithAccessibilityLabel:@"Firstname, Lastname" - value:fullName - traits:UIAccessibilityTraitStaticText]; + [tester tapViewWithAccessibilityLabel:@"Delete"]; + [tester tapViewWithAccessibilityLabel:@"DELETE"]; } - (void)testEditContact { NSString *contactName = [self getUUID]; - NSString *fullName = [contactName stringByAppendingString:@" dummy"]; [self createContact:contactName lastName:@"dummy" phoneNumber:nil SIPAddress:nil]; /* Phone number */ @@ -159,24 +148,21 @@ [tester tapViewWithAccessibilityLabel:@"Edit"]; // remove all numbers for (NSInteger i = 0; i < phones.count; i++) { - [self tapEditButtonForRowAtIndexPath:0 inSection:ContactSections_Number]; - [self deleteContactEntryForRowAtIndexPath:0 inSection:ContactSections_Number]; + [self tapRemoveButtonForRowAtIndexPath:0 inSection:ContactSections_Number]; } // remove all SIPs for (NSInteger i = 0; i < SIPs.count; i++) { - [self tapEditButtonForRowAtIndexPath:0 inSection:ContactSections_Sip]; - [self deleteContactEntryForRowAtIndexPath:0 inSection:ContactSections_Sip]; + [self tapRemoveButtonForRowAtIndexPath:0 inSection:ContactSections_Sip]; } [tester tapViewWithAccessibilityLabel:@"Edit"]; // then remove the contact [tester tapViewWithAccessibilityLabel:@"Edit"]; - [tester scrollViewWithAccessibilityIdentifier:@"Contact numbers table" byFractionOfSizeHorizontal:0 vertical:-0.9]; + [tester scrollViewWithAccessibilityIdentifier:@"Contact table" byFractionOfSizeHorizontal:0 vertical:-0.9]; - [tester tapViewWithAccessibilityLabel:@"Remove"]; - - [tester waitForAbsenceOfViewWithAccessibilityLabel:fullName traits:UIAccessibilityTraitStaticText]; + [tester tapViewWithAccessibilityLabel:@"Delete"]; + [tester tapViewWithAccessibilityLabel:@"DELETE"]; } @end