From 3ae85ce2d8dec6ddd70af290525cd01da7de85b8 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 1 Feb 2017 11:43:46 -0500 Subject: [PATCH 1/4] Add button to start a new conversation with non-contact based on phone number in search field. // FREEBIE --- .../MessageComposeTableViewController.m | 61 +++++++++++++++---- .../translations/en.lproj/Localizable.strings | 3 + 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/Signal/src/view controllers/MessageComposeTableViewController.m b/Signal/src/view controllers/MessageComposeTableViewController.m index 810bef22b..d2ff1bf04 100644 --- a/Signal/src/view controllers/MessageComposeTableViewController.m +++ b/Signal/src/view controllers/MessageComposeTableViewController.m @@ -1,9 +1,5 @@ // -// MessageComposeTableViewController.m -// -// -// Created by Dylan Bourgeois on 02/11/14. -// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // #import "MessageComposeTableViewController.h" @@ -24,24 +20,30 @@ NS_ASSUME_NONNULL_BEGIN UISearchResultsUpdating, MFMessageComposeViewControllerDelegate> -@property (nonatomic, strong) IBOutlet UITableViewCell *inviteCell; -@property (nonatomic, strong) IBOutlet OWSNoSignalContactsView *noSignalContactsView; +@property (nonatomic) IBOutlet UITableViewCell *inviteCell; +@property (nonatomic) UITableViewCell *conversationForNonContactCell; +@property (nonatomic) IBOutlet OWSNoSignalContactsView *noSignalContactsView; @property (nonatomic) UIButton *sendTextButton; -@property (nonatomic, strong) UISearchController *searchController; -@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator; -@property (nonatomic, strong) UIBarButtonItem *addGroup; -@property (nonatomic, strong) UIView *loadingBackgroundView; +@property (nonatomic) UISearchController *searchController; +@property (nonatomic) UIActivityIndicatorView *activityIndicator; +@property (nonatomic) UIBarButtonItem *addGroup; +@property (nonatomic) UIView *loadingBackgroundView; @property (nonatomic) NSString *currentSearchTerm; @property (copy) NSArray *contacts; @property (copy) NSArray *searchResults; @property (nonatomic, readonly) OWSContactsManager *contactsManager; +@property (nonatomic) BOOL showNewConversationForNonContactButton; +// This property should be set IFF showNewConversationForNonContactButton is YES. +@property (nonatomic) NSString *nonContactPhoneNumber; + @end NSInteger const MessageComposeTableViewControllerSectionInvite = 0; NSInteger const MessageComposeTableViewControllerSectionContacts = 1; +NSInteger const MessageComposeTableViewControllerSectionNewConversationForNonContact = 2; NSString *const MessageComposeTableViewControllerCellInvite = @"ContactTableInviteCell"; NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableViewCell"; @@ -87,6 +89,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.searchController.searchBar.backgroundColor = [UIColor whiteColor]; self.inviteCell.textLabel.text = NSLocalizedString( @"INVITE_FRIENDS_CONTACT_TABLE_BUTTON", @"Text for button at the top of the contact picker"); + + self.conversationForNonContactCell = [UITableViewCell new]; self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero]; [self createLoadingAndBackgroundViews]; @@ -201,6 +205,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.inviteCell.hidden = YES; + self.conversationForNonContactCell.hidden = YES; self.searchController.searchBar.hidden = YES; self.tableView.backgroundView = self.noSignalContactsView; self.tableView.backgroundView.opaque = YES; @@ -212,6 +217,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.searchController.searchBar.hidden = NO; self.tableView.backgroundView = nil; self.inviteCell.hidden = NO; + self.conversationForNonContactCell.hidden = NO; } } @@ -296,11 +302,24 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie [self.sendTextButton setTitle:sendTextTo forState:UIControlStateNormal]; self.sendTextButton.hidden = NO; self.currentSearchTerm = formattedNumber; + self.showNewConversationForNonContactButton = YES; + self.nonContactPhoneNumber = formattedNumber; } else { self.sendTextButton.hidden = YES; + self.showNewConversationForNonContactButton = NO; + _nonContactPhoneNumber = nil; } } +- (void)setShowNewConversationForNonContactButton:(BOOL)showNewConversationForNonContactButton { + if (_showNewConversationForNonContactButton == showNewConversationForNonContactButton) { + return; + } + + _showNewConversationForNonContactButton = showNewConversationForNonContactButton; + + [self.tableView reloadData]; +} #pragma mark - Send Normal Text to Unknown Contact @@ -407,7 +426,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie #pragma mark - Table View Data Source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return 2; + return 4; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { @@ -417,6 +436,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie return 0; } return 1; + } else if (section == MessageComposeTableViewControllerSectionNewConversationForNonContact) { + return _showNewConversationForNonContactButton ? 1 : 0; } else { if (self.searchController.active) { return (NSInteger)[self.searchResults count]; @@ -430,6 +451,13 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie { if (indexPath.section == MessageComposeTableViewControllerSectionInvite) { return self.inviteCell; + } else if (indexPath.section == MessageComposeTableViewControllerSectionNewConversationForNonContact) { + OWSAssert(self.nonContactPhoneNumber.length > 0); + + self.conversationForNonContactCell.textLabel.text = [NSString stringWithFormat:NSLocalizedString(@"NEW_CONVERSATION_FOR_NON_CONTACT_FORMAT", + @"Text for button to start a new conversation with a non-contact"), + self.nonContactPhoneNumber]; + return self.conversationForNonContactCell; } else { ContactTableViewCell *cell = (ContactTableViewCell *)[tableView dequeueReusableCellWithIdentifier:MessageComposeTableViewControllerCellContact]; @@ -461,6 +489,15 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } else { showInvite(); } + } else if (indexPath.section == MessageComposeTableViewControllerSectionNewConversationForNonContact) { + OWSAssert(self.nonContactPhoneNumber.length > 0); + + if (self.nonContactPhoneNumber.length > 0) { + [self dismissViewControllerAnimated:YES + completion:^() { + [Environment messageIdentifier:self.nonContactPhoneNumber withCompose:YES]; + }]; + } } else { NSString *identifier = [[[self contactForIndexPath:indexPath] textSecureIdentifiers] firstObject]; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 4527c079e..8fe4c9cd6 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -489,6 +489,9 @@ /* No comment provided by engineer. */ "NETWORK_STATUS_TEXT" = "You can check your network status by looking at the colored bar above your inbox."; +/* Text for button to start a new conversation with a non-contact */ +"NEW_CONVERSATION_FOR_NON_CONTACT_FORMAT" = "New conversation with %@"; + /* Action Sheet title prompting the user for a group avatar */ "NEW_GROUP_ADD_PHOTO_ACTION" = "Set Group Photo"; From 26b3be4ec55a83fc47379de3699aba8331dfe7d7 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 2 Feb 2017 11:48:41 -0500 Subject: [PATCH 2/4] Improve "new conversation" view. * Add "search by phone number" to "no contacts" mode. * Coordinate "invite flow", "invite by SMS" and "new conversation with non-contact" to ensure only one (at most) is shown. * Show "new conversation with non-contact" IFF phone number is known to correspond to a signal account. // FREEBIE --- .../MessageComposeTableViewController.m | 211 ++++++++++++------ .../translations/en.lproj/Localizable.strings | 6 +- 2 files changed, 151 insertions(+), 66 deletions(-) diff --git a/Signal/src/view controllers/MessageComposeTableViewController.m b/Signal/src/view controllers/MessageComposeTableViewController.m index d2ff1bf04..ca277354e 100644 --- a/Signal/src/view controllers/MessageComposeTableViewController.m +++ b/Signal/src/view controllers/MessageComposeTableViewController.m @@ -22,9 +22,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) IBOutlet UITableViewCell *inviteCell; @property (nonatomic) UITableViewCell *conversationForNonContactCell; +@property (nonatomic) UITableViewCell *inviteViaSMSCell; @property (nonatomic) IBOutlet OWSNoSignalContactsView *noSignalContactsView; -@property (nonatomic) UIButton *sendTextButton; @property (nonatomic) UISearchController *searchController; @property (nonatomic) UIActivityIndicatorView *activityIndicator; @property (nonatomic) UIBarButtonItem *addGroup; @@ -35,15 +35,29 @@ NS_ASSUME_NONNULL_BEGIN @property (copy) NSArray *searchResults; @property (nonatomic, readonly) OWSContactsManager *contactsManager; -@property (nonatomic) BOOL showNewConversationForNonContactButton; -// This property should be set IFF showNewConversationForNonContactButton is YES. -@property (nonatomic) NSString *nonContactPhoneNumber; +// This property should be set IFF the current search text can +// be parsed as a phone number. If set, it contains a E164 value. +@property (nonatomic) NSString *searchPhoneNumber; +// This dictionary is used to cache the set of phone numbers +// which are known to correspond to Signal accounts. +@property (nonatomic) NSMutableSet *phoneNumberAccountSet; + +@property (nonatomic) BOOL isBackgroundViewHidden; @end -NSInteger const MessageComposeTableViewControllerSectionInvite = 0; -NSInteger const MessageComposeTableViewControllerSectionContacts = 1; -NSInteger const MessageComposeTableViewControllerSectionNewConversationForNonContact = 2; +// The "special" sections are used to display (at most) one of three cells: +// +// * "New conversation for non-contact" if user has entered a phone +// number which corresponds to a signal account, or: +// * "Send invite via SMS" if user has entered a phone number +// which is not known to correspond to a signal account, or: +// * "Invite contacts" if the invite flow is available, or: +// * Nothing, otherwise. +NSInteger const MessageComposeTableViewControllerSectionInviteNonContactConversation = 0; +NSInteger const MessageComposeTableViewControllerSectionInviteViaSMS = 1; +NSInteger const MessageComposeTableViewControllerSectionInviteFlow = 2; +NSInteger const MessageComposeTableViewControllerSectionContacts = 3; NSString *const MessageComposeTableViewControllerCellInvite = @"ContactTableInviteCell"; NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableViewCell"; @@ -91,6 +105,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie @"INVITE_FRIENDS_CONTACT_TABLE_BUTTON", @"Text for button at the top of the contact picker"); self.conversationForNonContactCell = [UITableViewCell new]; + self.inviteViaSMSCell = [UITableViewCell new]; self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero]; [self createLoadingAndBackgroundViews]; @@ -160,9 +175,36 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie [_loadingBackgroundView addSubview:loadingProgressView]; [_loadingBackgroundView addSubview:loadingLabel]; - [self.noSignalContactsView.inviteButton addTarget:self - action:@selector(presentInviteFlow) - forControlEvents:UIControlEventTouchUpInside]; + UIButton *inviteButton = self.noSignalContactsView.inviteButton; + [inviteButton addTarget:self + action:@selector(presentInviteFlow) + forControlEvents:UIControlEventTouchUpInside]; + [inviteButton setTitleColor:[UIColor ows_materialBlueColor] + forState:UIControlStateNormal]; + [inviteButton.titleLabel setFont:[UIFont ows_regularFontWithSize:17.f]]; + + UIButton *searchByPhoneNumberButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [searchByPhoneNumberButton setTitle:NSLocalizedString(@"NO_CONTACTS_SEARCH_BY_PHONE_NUMBER", + @"Label for a button that lets users search for contacts by phone number") + forState:UIControlStateNormal]; + [searchByPhoneNumberButton setTitleColor:[UIColor ows_materialBlueColor] + forState:UIControlStateNormal]; + [searchByPhoneNumberButton.titleLabel setFont:[UIFont ows_regularFontWithSize:17.f]]; + [inviteButton.superview addSubview:searchByPhoneNumberButton]; + [searchByPhoneNumberButton autoHCenterInSuperview]; + [searchByPhoneNumberButton autoPinEdge:ALEdgeTop + toEdge:ALEdgeBottom + ofView:inviteButton + withOffset:20]; + [searchByPhoneNumberButton addTarget:self + action:@selector(hideBackgroundView) + forControlEvents:UIControlEventTouchUpInside]; +} + +- (void)hideBackgroundView { + self.isBackgroundViewHidden = YES; + + [self showEmptyBackgroundView:NO]; } - (void)presentInviteFlow @@ -172,9 +214,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie [self presentViewController:inviteFlow.actionSheetController animated:YES completion:nil]; } - - (void)showLoadingBackgroundView:(BOOL)show { - if (show) { + if (show && !self.isBackgroundViewHidden) { _addGroup = self.navigationItem.rightBarButtonItem != nil ? _addGroup : self.navigationItem.rightBarButtonItem; self.navigationItem.rightBarButtonItem = nil; self.searchController.searchBar.hidden = YES; @@ -206,6 +247,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.inviteCell.hidden = YES; self.conversationForNonContactCell.hidden = YES; + self.inviteViaSMSCell.hidden = YES; self.searchController.searchBar.hidden = YES; self.tableView.backgroundView = self.noSignalContactsView; self.tableView.backgroundView.opaque = YES; @@ -218,6 +260,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.tableView.backgroundView = nil; self.inviteCell.hidden = NO; self.conversationForNonContactCell.hidden = NO; + self.inviteViaSMSCell.hidden = NO; } } @@ -244,17 +287,6 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.searchController.searchBar.delegate = self; self.searchController.searchBar.placeholder = NSLocalizedString(@"SEARCH_BYNAMEORNUMBER_PLACEHOLDER_TEXT", @""); - self.sendTextButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [self.sendTextButton setBackgroundColor:[UIColor ows_materialBlueColor]]; - [self.sendTextButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - self.sendTextButton.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, - self.searchController.searchBar.frame.origin.y + 44.0f, - self.searchController.searchBar.frame.size.width, - 44.0); - [self.view addSubview:self.sendTextButton]; - self.sendTextButton.hidden = YES; - - [self.sendTextButton addTarget:self action:@selector(sendText) forControlEvents:UIControlEventTouchUpInside]; [self initializeRefreshControl]; } @@ -283,10 +315,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { - self.sendTextButton.hidden = YES; } - #pragma mark - Filter - (void)filterContentForSearchText:(NSString *)searchText @@ -297,26 +327,58 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie NSString *formattedNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:searchText].toE164; // text to a non-signal number if we have no results and a valid phone # if (self.searchResults.count == 0 && searchText.length > 8 && formattedNumber) { - NSString *sendTextTo = NSLocalizedString(@"SEND_SMS_BUTTON", @""); - sendTextTo = [sendTextTo stringByAppendingString:formattedNumber]; - [self.sendTextButton setTitle:sendTextTo forState:UIControlStateNormal]; - self.sendTextButton.hidden = NO; self.currentSearchTerm = formattedNumber; - self.showNewConversationForNonContactButton = YES; - self.nonContactPhoneNumber = formattedNumber; + self.searchPhoneNumber = formattedNumber; + // Kick off account lookup if necessary. + [self checkIsNonContactPhoneNumberSignalUser:formattedNumber]; } else { - self.sendTextButton.hidden = YES; - self.showNewConversationForNonContactButton = NO; - _nonContactPhoneNumber = nil; + _searchPhoneNumber = nil; } } -- (void)setShowNewConversationForNonContactButton:(BOOL)showNewConversationForNonContactButton { - if (_showNewConversationForNonContactButton == showNewConversationForNonContactButton) { - return; +- (BOOL)checkIsNonContactPhoneNumberSignalUser:(NSString *)phoneNumber +{ + DDLogWarn(@"isNonContactPhoneNumberSignalUser: %@", phoneNumber); + + if ([self.phoneNumberAccountSet containsObject:phoneNumber]) { + return YES; } - _showNewConversationForNonContactButton = showNewConversationForNonContactButton; + __weak MessageComposeTableViewController *weakSelf = self; + [[ContactsUpdater sharedUpdater] lookupIdentifier:phoneNumber + success:^(SignalRecipient *recipient) { + DDLogWarn(@"Lookup contact with recipient: %@ %@", recipient, phoneNumber); + + MessageComposeTableViewController *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + if (!strongSelf.phoneNumberAccountSet) { + strongSelf.phoneNumberAccountSet = [NSMutableSet set]; + } + if (![strongSelf.phoneNumberAccountSet containsObject:phoneNumber]) { + [strongSelf.phoneNumberAccountSet addObject:phoneNumber]; + [strongSelf.tableView reloadData]; + } + } + failure:^(NSError *error) { + DDLogWarn(@"Failed to lookup contact with error: %@ %@", error, phoneNumber); + }]; + + return NO; + +// // This dictionary is used to cache the set of known Signal +// // accounts that correspond to "non-contact phone numbers." +// @property (nonatomic) NSMutableSet *phoneNumberAccountSet; + +} + +- (void)setSearchPhoneNumber:(NSString *)searchPhoneNumber { + if ([_searchPhoneNumber isEqualToString:searchPhoneNumber]) { + return; + } + + _searchPhoneNumber = searchPhoneNumber; [self.tableView reloadData]; } @@ -371,7 +433,6 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie [alertController addAction:cancelAction]; [alertController addAction:okAction]; - self.sendTextButton.hidden = YES; self.searchController.searchBar.text = @""; //must dismiss search controller before presenting alert. @@ -430,15 +491,30 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (section == MessageComposeTableViewControllerSectionInvite) { - if (floor(NSFoundationVersionNumber) < NSFoundationVersionNumber_iOS_9_0) { - // Invite flow not supported on iOS8 - return 0; - } - return 1; - } else if (section == MessageComposeTableViewControllerSectionNewConversationForNonContact) { - return _showNewConversationForNonContactButton ? 1 : 0; + BOOL showNonContactConversation = NO; + BOOL showInviteViaSMS = NO; + BOOL showInviteFlow = NO; + + BOOL hasPhoneNumber = self.searchPhoneNumber.length > 0; + BOOL isKnownSignalUser = self.searchPhoneNumber && [self.phoneNumberAccountSet containsObject:self.searchPhoneNumber]; + BOOL isInviteFlowSupported = floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_9_0; + if (hasPhoneNumber && isKnownSignalUser) { + showNonContactConversation = YES; + } else if (hasPhoneNumber) { + showInviteViaSMS = YES; + } else if (isInviteFlowSupported) { + showInviteFlow = YES; + } + + if (section == MessageComposeTableViewControllerSectionInviteNonContactConversation) { + return showNonContactConversation ? 1 : 0; + } else if (section == MessageComposeTableViewControllerSectionInviteViaSMS) { + return showInviteViaSMS ? 1 : 0; + } else if (section == MessageComposeTableViewControllerSectionInviteFlow) { + return showInviteFlow ? 1 : 0; } else { + OWSAssert(section == MessageComposeTableViewControllerSectionContacts) + if (self.searchController.active) { return (NSInteger)[self.searchResults count]; } else { @@ -449,16 +525,23 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - if (indexPath.section == MessageComposeTableViewControllerSectionInvite) { - return self.inviteCell; - } else if (indexPath.section == MessageComposeTableViewControllerSectionNewConversationForNonContact) { - OWSAssert(self.nonContactPhoneNumber.length > 0); - + if (indexPath.section == MessageComposeTableViewControllerSectionInviteNonContactConversation) { self.conversationForNonContactCell.textLabel.text = [NSString stringWithFormat:NSLocalizedString(@"NEW_CONVERSATION_FOR_NON_CONTACT_FORMAT", @"Text for button to start a new conversation with a non-contact"), - self.nonContactPhoneNumber]; + self.searchPhoneNumber]; return self.conversationForNonContactCell; + } else if (indexPath.section == MessageComposeTableViewControllerSectionInviteViaSMS) { + // TODO: We should rework this string to be a format, to account for languages where the + // phone number should not appear at the end of the copy. + self.inviteViaSMSCell.textLabel.text = [NSLocalizedString(@"SEND_SMS_BUTTON", + @"Text for button to send a Signal invite via SMS") + stringByAppendingString:self.searchPhoneNumber]; + return self.inviteViaSMSCell; + } else if (indexPath.section == MessageComposeTableViewControllerSectionInviteFlow) { + return self.inviteCell; } else { + OWSAssert(indexPath.section == MessageComposeTableViewControllerSectionContacts) + ContactTableViewCell *cell = (ContactTableViewCell *)[tableView dequeueReusableCellWithIdentifier:MessageComposeTableViewControllerCellContact]; @@ -472,7 +555,18 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - if (indexPath.section == MessageComposeTableViewControllerSectionInvite) { + if (indexPath.section == MessageComposeTableViewControllerSectionInviteNonContactConversation) { + OWSAssert(self.searchPhoneNumber.length > 0); + + if (self.searchPhoneNumber.length > 0) { + [self dismissViewControllerAnimated:YES + completion:^() { + [Environment messageIdentifier:self.searchPhoneNumber withCompose:YES]; + }]; + } + } else if (indexPath.section == MessageComposeTableViewControllerSectionInviteViaSMS) { + [self sendText]; + } else if (indexPath.section == MessageComposeTableViewControllerSectionInviteFlow) { void (^showInvite)() = ^{ OWSInviteFlow *inviteFlow = [[OWSInviteFlow alloc] initWithPresentingViewController:self contactsManager:self.contactsManager]; @@ -489,15 +583,6 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } else { showInvite(); } - } else if (indexPath.section == MessageComposeTableViewControllerSectionNewConversationForNonContact) { - OWSAssert(self.nonContactPhoneNumber.length > 0); - - if (self.nonContactPhoneNumber.length > 0) { - [self dismissViewControllerAnimated:YES - completion:^() { - [Environment messageIdentifier:self.nonContactPhoneNumber withCompose:YES]; - }]; - } } else { NSString *identifier = [[[self contactForIndexPath:indexPath] textSecureIdentifiers] firstObject]; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 8fe4c9cd6..030ad11c0 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -244,9 +244,6 @@ /* Generic server error */ "ERROR_DESCRIPTION_SERVER_FAILURE" = "Server Error. Please try again later."; -/* Worst case generic error message */ -"ERROR_DESCRIPTION_UNKNOWN_ERROR" = "An unkown error occurred."; - /* Error message when attempting to send message */ "ERROR_DESCRIPTION_UNREGISTERED_RECIPIENT" = "Contact is not a Signal user."; @@ -504,6 +501,9 @@ /* No comment provided by engineer. */ "NEW_GROUP_REQUEST_ADDPEOPLE" = "Add people"; +/* Label for a button that lets users search for contacts by phone number */ +"NO_CONTACTS_SEARCH_BY_PHONE_NUMBER" = "Find Contacts by Phone Number"; + /* No comment provided by engineer. */ "NOTIFICATION_SEND_FAILED" = "Your message failed to send to %@."; From f9c20a36a4bb9bfbe03b92b167353cfac3544f5e Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 2 Feb 2017 11:57:59 -0500 Subject: [PATCH 3/4] Clean up ahead of PR. // FREEBIE --- .../MessageComposeTableViewController.m | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/Signal/src/view controllers/MessageComposeTableViewController.m b/Signal/src/view controllers/MessageComposeTableViewController.m index ca277354e..0684f7348 100644 --- a/Signal/src/view controllers/MessageComposeTableViewController.m +++ b/Signal/src/view controllers/MessageComposeTableViewController.m @@ -336,19 +336,15 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } } -- (BOOL)checkIsNonContactPhoneNumberSignalUser:(NSString *)phoneNumber +- (void)checkIsNonContactPhoneNumberSignalUser:(NSString *)phoneNumber { - DDLogWarn(@"isNonContactPhoneNumberSignalUser: %@", phoneNumber); - if ([self.phoneNumberAccountSet containsObject:phoneNumber]) { - return YES; + return; } __weak MessageComposeTableViewController *weakSelf = self; [[ContactsUpdater sharedUpdater] lookupIdentifier:phoneNumber success:^(SignalRecipient *recipient) { - DDLogWarn(@"Lookup contact with recipient: %@ %@", recipient, phoneNumber); - MessageComposeTableViewController *strongSelf = weakSelf; if (!strongSelf) { return; @@ -362,15 +358,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } } failure:^(NSError *error) { - DDLogWarn(@"Failed to lookup contact with error: %@ %@", error, phoneNumber); + // Ignore. }]; - - return NO; - -// // This dictionary is used to cache the set of known Signal -// // accounts that correspond to "non-contact phone numbers." -// @property (nonatomic) NSMutableSet *phoneNumberAccountSet; - } - (void)setSearchPhoneNumber:(NSString *)searchPhoneNumber { @@ -487,16 +476,18 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie #pragma mark - Table View Data Source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return 4; + return MessageComposeTableViewControllerSectionContacts + 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + // This logic will determine which one (if any) of the following special controls + // should be shown. No more than one should be shown at a time. BOOL showNonContactConversation = NO; BOOL showInviteViaSMS = NO; BOOL showInviteFlow = NO; BOOL hasPhoneNumber = self.searchPhoneNumber.length > 0; - BOOL isKnownSignalUser = self.searchPhoneNumber && [self.phoneNumberAccountSet containsObject:self.searchPhoneNumber]; + BOOL isKnownSignalUser = hasPhoneNumber && [self.phoneNumberAccountSet containsObject:self.searchPhoneNumber]; BOOL isInviteFlowSupported = floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_9_0; if (hasPhoneNumber && isKnownSignalUser) { showNonContactConversation = YES; @@ -584,6 +575,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie showInvite(); } } else { + OWSAssert(indexPath.section == MessageComposeTableViewControllerSectionContacts) + NSString *identifier = [[[self contactForIndexPath:indexPath] textSecureIdentifiers] firstObject]; [self dismissViewControllerAnimated:YES From 4f9ce0c0e204015043688ec4c94c1102f4ef185a Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 2 Feb 2017 22:46:10 -0500 Subject: [PATCH 4/4] Respond to CR. // FREEBIE --- .../MessageComposeTableViewController.m | 31 +++++++++---------- .../translations/en.lproj/Localizable.strings | 7 +++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Signal/src/view controllers/MessageComposeTableViewController.m b/Signal/src/view controllers/MessageComposeTableViewController.m index 0684f7348..819d3317c 100644 --- a/Signal/src/view controllers/MessageComposeTableViewController.m +++ b/Signal/src/view controllers/MessageComposeTableViewController.m @@ -40,7 +40,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) NSString *searchPhoneNumber; // This dictionary is used to cache the set of phone numbers // which are known to correspond to Signal accounts. -@property (nonatomic) NSMutableSet *phoneNumberAccountSet; +@property (nonatomic, nonnull, readonly) NSMutableSet *phoneNumberAccountSet; @property (nonatomic) BOOL isBackgroundViewHidden; @@ -54,10 +54,13 @@ NS_ASSUME_NONNULL_BEGIN // which is not known to correspond to a signal account, or: // * "Invite contacts" if the invite flow is available, or: // * Nothing, otherwise. -NSInteger const MessageComposeTableViewControllerSectionInviteNonContactConversation = 0; -NSInteger const MessageComposeTableViewControllerSectionInviteViaSMS = 1; -NSInteger const MessageComposeTableViewControllerSectionInviteFlow = 2; -NSInteger const MessageComposeTableViewControllerSectionContacts = 3; +typedef NS_ENUM(NSInteger, AdvancedSettingsTableViewControllerSection) { + MessageComposeTableViewControllerSectionInviteNonContactConversation = 0, + MessageComposeTableViewControllerSectionInviteViaSMS, + MessageComposeTableViewControllerSectionInviteFlow, + MessageComposeTableViewControllerSectionContacts, + MessageComposeTableViewControllerSection_Count // meta section +}; NSString *const MessageComposeTableViewControllerCellInvite = @"ContactTableInviteCell"; NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableViewCell"; @@ -72,7 +75,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } _contactsManager = [Environment getCurrent].contactsManager; - + _phoneNumberAccountSet = [NSMutableSet set]; + return self; } @@ -349,9 +353,6 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie if (!strongSelf) { return; } - if (!strongSelf.phoneNumberAccountSet) { - strongSelf.phoneNumberAccountSet = [NSMutableSet set]; - } if (![strongSelf.phoneNumberAccountSet containsObject:phoneNumber]) { [strongSelf.phoneNumberAccountSet addObject:phoneNumber]; [strongSelf.tableView reloadData]; @@ -476,7 +477,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie #pragma mark - Table View Data Source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return MessageComposeTableViewControllerSectionContacts + 1; + return MessageComposeTableViewControllerSection_Count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { @@ -488,7 +489,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie BOOL hasPhoneNumber = self.searchPhoneNumber.length > 0; BOOL isKnownSignalUser = hasPhoneNumber && [self.phoneNumberAccountSet containsObject:self.searchPhoneNumber]; - BOOL isInviteFlowSupported = floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_9_0; + BOOL isInviteFlowSupported = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(9, 0); if (hasPhoneNumber && isKnownSignalUser) { showNonContactConversation = YES; } else if (hasPhoneNumber) { @@ -522,11 +523,9 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.searchPhoneNumber]; return self.conversationForNonContactCell; } else if (indexPath.section == MessageComposeTableViewControllerSectionInviteViaSMS) { - // TODO: We should rework this string to be a format, to account for languages where the - // phone number should not appear at the end of the copy. - self.inviteViaSMSCell.textLabel.text = [NSLocalizedString(@"SEND_SMS_BUTTON", - @"Text for button to send a Signal invite via SMS") - stringByAppendingString:self.searchPhoneNumber]; + self.inviteViaSMSCell.textLabel.text = [NSString stringWithFormat:NSLocalizedString(@"SEND_INVITE_VIA_SMS_BUTTON_FORMAT", + @"Text for button to send a Signal invite via SMS. %@ is placeholder for the receipient's phone number."), + self.searchPhoneNumber]; return self.inviteViaSMSCell; } else if (indexPath.section == MessageComposeTableViewControllerSectionInviteFlow) { return self.inviteCell; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 030ad11c0..23a13277e 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -244,6 +244,9 @@ /* Generic server error */ "ERROR_DESCRIPTION_SERVER_FAILURE" = "Server Error. Please try again later."; +/* Worst case generic error message */ +"ERROR_DESCRIPTION_UNKNOWN_ERROR" = "ERROR_DESCRIPTION_UNKNOWN_ERROR"; + /* Error message when attempting to send message */ "ERROR_DESCRIPTION_UNREGISTERED_RECIPIENT" = "Contact is not a Signal user."; @@ -708,8 +711,8 @@ /* Alert body after invite succeeded */ "SEND_INVITE_SUCCESS" = "You've invited your friend to use Signal!"; -/* No comment provided by engineer. */ -"SEND_SMS_BUTTON" = "Send SMS to: "; +/* Text for button to send a Signal invite via SMS */ +"SEND_INVITE_VIA_SMS_BUTTON_FORMAT" = "Send Invite via SMS to: %@"; /* No comment provided by engineer. */ "SEND_SMS_CONFIRM_TITLE" = "Invite a friend via insecure SMS?";