Merge branch 'feature/nonContactConversations'

pull/1/head
Matthew Chen 8 years ago
commit 8b45ac2233

@ -1,9 +1,5 @@
// //
// MessageComposeTableViewController.m // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
//
// Created by Dylan Bourgeois on 02/11/14.
//
// //
#import "MessageComposeTableViewController.h" #import "MessageComposeTableViewController.h"
@ -24,24 +20,47 @@ NS_ASSUME_NONNULL_BEGIN
UISearchResultsUpdating, UISearchResultsUpdating,
MFMessageComposeViewControllerDelegate> MFMessageComposeViewControllerDelegate>
@property (nonatomic, strong) IBOutlet UITableViewCell *inviteCell; @property (nonatomic) IBOutlet UITableViewCell *inviteCell;
@property (nonatomic, strong) IBOutlet OWSNoSignalContactsView *noSignalContactsView; @property (nonatomic) UITableViewCell *conversationForNonContactCell;
@property (nonatomic) UITableViewCell *inviteViaSMSCell;
@property (nonatomic) IBOutlet OWSNoSignalContactsView *noSignalContactsView;
@property (nonatomic) UIButton *sendTextButton; @property (nonatomic) UISearchController *searchController;
@property (nonatomic, strong) UISearchController *searchController; @property (nonatomic) UIActivityIndicatorView *activityIndicator;
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator; @property (nonatomic) UIBarButtonItem *addGroup;
@property (nonatomic, strong) UIBarButtonItem *addGroup; @property (nonatomic) UIView *loadingBackgroundView;
@property (nonatomic, strong) UIView *loadingBackgroundView;
@property (nonatomic) NSString *currentSearchTerm; @property (nonatomic) NSString *currentSearchTerm;
@property (copy) NSArray<Contact *> *contacts; @property (copy) NSArray<Contact *> *contacts;
@property (copy) NSArray<Contact *> *searchResults; @property (copy) NSArray<Contact *> *searchResults;
@property (nonatomic, readonly) OWSContactsManager *contactsManager; @property (nonatomic, readonly) OWSContactsManager *contactsManager;
// 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, nonnull, readonly) NSMutableSet *phoneNumberAccountSet;
@property (nonatomic) BOOL isBackgroundViewHidden;
@end @end
NSInteger const MessageComposeTableViewControllerSectionInvite = 0; // The "special" sections are used to display (at most) one of three cells:
NSInteger const MessageComposeTableViewControllerSectionContacts = 1; //
// * "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.
typedef NS_ENUM(NSInteger, AdvancedSettingsTableViewControllerSection) {
MessageComposeTableViewControllerSectionInviteNonContactConversation = 0,
MessageComposeTableViewControllerSectionInviteViaSMS,
MessageComposeTableViewControllerSectionInviteFlow,
MessageComposeTableViewControllerSectionContacts,
MessageComposeTableViewControllerSection_Count // meta section
};
NSString *const MessageComposeTableViewControllerCellInvite = @"ContactTableInviteCell"; NSString *const MessageComposeTableViewControllerCellInvite = @"ContactTableInviteCell";
NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableViewCell"; NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableViewCell";
@ -56,6 +75,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
} }
_contactsManager = [Environment getCurrent].contactsManager; _contactsManager = [Environment getCurrent].contactsManager;
_phoneNumberAccountSet = [NSMutableSet set];
return self; return self;
} }
@ -88,6 +108,9 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
self.inviteCell.textLabel.text = NSLocalizedString( self.inviteCell.textLabel.text = NSLocalizedString(
@"INVITE_FRIENDS_CONTACT_TABLE_BUTTON", @"Text for button at the top of the contact picker"); @"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.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
[self createLoadingAndBackgroundViews]; [self createLoadingAndBackgroundViews];
self.title = NSLocalizedString(@"MESSAGE_COMPOSEVIEW_TITLE", @""); self.title = NSLocalizedString(@"MESSAGE_COMPOSEVIEW_TITLE", @"");
@ -156,9 +179,36 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
[_loadingBackgroundView addSubview:loadingProgressView]; [_loadingBackgroundView addSubview:loadingProgressView];
[_loadingBackgroundView addSubview:loadingLabel]; [_loadingBackgroundView addSubview:loadingLabel];
[self.noSignalContactsView.inviteButton addTarget:self UIButton *inviteButton = self.noSignalContactsView.inviteButton;
[inviteButton addTarget:self
action:@selector(presentInviteFlow) action:@selector(presentInviteFlow)
forControlEvents:UIControlEventTouchUpInside]; 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 - (void)presentInviteFlow
@ -168,9 +218,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
[self presentViewController:inviteFlow.actionSheetController animated:YES completion:nil]; [self presentViewController:inviteFlow.actionSheetController animated:YES completion:nil];
} }
- (void)showLoadingBackgroundView:(BOOL)show { - (void)showLoadingBackgroundView:(BOOL)show {
if (show) { if (show && !self.isBackgroundViewHidden) {
_addGroup = self.navigationItem.rightBarButtonItem != nil ? _addGroup : self.navigationItem.rightBarButtonItem; _addGroup = self.navigationItem.rightBarButtonItem != nil ? _addGroup : self.navigationItem.rightBarButtonItem;
self.navigationItem.rightBarButtonItem = nil; self.navigationItem.rightBarButtonItem = nil;
self.searchController.searchBar.hidden = YES; self.searchController.searchBar.hidden = YES;
@ -201,6 +250,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
self.inviteCell.hidden = YES; self.inviteCell.hidden = YES;
self.conversationForNonContactCell.hidden = YES;
self.inviteViaSMSCell.hidden = YES;
self.searchController.searchBar.hidden = YES; self.searchController.searchBar.hidden = YES;
self.tableView.backgroundView = self.noSignalContactsView; self.tableView.backgroundView = self.noSignalContactsView;
self.tableView.backgroundView.opaque = YES; self.tableView.backgroundView.opaque = YES;
@ -212,6 +263,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
self.searchController.searchBar.hidden = NO; self.searchController.searchBar.hidden = NO;
self.tableView.backgroundView = nil; self.tableView.backgroundView = nil;
self.inviteCell.hidden = NO; self.inviteCell.hidden = NO;
self.conversationForNonContactCell.hidden = NO;
self.inviteViaSMSCell.hidden = NO;
} }
} }
@ -238,17 +291,6 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
self.searchController.searchBar.delegate = self; self.searchController.searchBar.delegate = self;
self.searchController.searchBar.placeholder = NSLocalizedString(@"SEARCH_BYNAMEORNUMBER_PLACEHOLDER_TEXT", @""); 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]; [self initializeRefreshControl];
} }
@ -277,10 +319,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
} }
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
self.sendTextButton.hidden = YES;
} }
#pragma mark - Filter #pragma mark - Filter
- (void)filterContentForSearchText:(NSString *)searchText - (void)filterContentForSearchText:(NSString *)searchText
@ -291,16 +331,47 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
NSString *formattedNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:searchText].toE164; NSString *formattedNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:searchText].toE164;
// text to a non-signal number if we have no results and a valid phone # // text to a non-signal number if we have no results and a valid phone #
if (self.searchResults.count == 0 && searchText.length > 8 && formattedNumber) { 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.currentSearchTerm = formattedNumber;
self.searchPhoneNumber = formattedNumber;
// Kick off account lookup if necessary.
[self checkIsNonContactPhoneNumberSignalUser:formattedNumber];
} else { } else {
self.sendTextButton.hidden = YES; _searchPhoneNumber = nil;
} }
} }
- (void)checkIsNonContactPhoneNumberSignalUser:(NSString *)phoneNumber
{
if ([self.phoneNumberAccountSet containsObject:phoneNumber]) {
return;
}
__weak MessageComposeTableViewController *weakSelf = self;
[[ContactsUpdater sharedUpdater] lookupIdentifier:phoneNumber
success:^(SignalRecipient *recipient) {
MessageComposeTableViewController *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
if (![strongSelf.phoneNumberAccountSet containsObject:phoneNumber]) {
[strongSelf.phoneNumberAccountSet addObject:phoneNumber];
[strongSelf.tableView reloadData];
}
}
failure:^(NSError *error) {
// Ignore.
}];
}
- (void)setSearchPhoneNumber:(NSString *)searchPhoneNumber {
if ([_searchPhoneNumber isEqualToString:searchPhoneNumber]) {
return;
}
_searchPhoneNumber = searchPhoneNumber;
[self.tableView reloadData];
}
#pragma mark - Send Normal Text to Unknown Contact #pragma mark - Send Normal Text to Unknown Contact
@ -352,7 +423,6 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
[alertController addAction:cancelAction]; [alertController addAction:cancelAction];
[alertController addAction:okAction]; [alertController addAction:okAction];
self.sendTextButton.hidden = YES;
self.searchController.searchBar.text = @""; self.searchController.searchBar.text = @"";
//must dismiss search controller before presenting alert. //must dismiss search controller before presenting alert.
@ -407,17 +477,36 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
#pragma mark - Table View Data Source #pragma mark - Table View Data Source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2; return MessageComposeTableViewControllerSection_Count;
} }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == MessageComposeTableViewControllerSectionInvite) { // This logic will determine which one (if any) of the following special controls
if (floor(NSFoundationVersionNumber) < NSFoundationVersionNumber_iOS_9_0) { // should be shown. No more than one should be shown at a time.
// Invite flow not supported on iOS8 BOOL showNonContactConversation = NO;
return 0; BOOL showInviteViaSMS = NO;
} BOOL showInviteFlow = NO;
return 1;
BOOL hasPhoneNumber = self.searchPhoneNumber.length > 0;
BOOL isKnownSignalUser = hasPhoneNumber && [self.phoneNumberAccountSet containsObject:self.searchPhoneNumber];
BOOL isInviteFlowSupported = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(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 { } else {
OWSAssert(section == MessageComposeTableViewControllerSectionContacts)
if (self.searchController.active) { if (self.searchController.active) {
return (NSInteger)[self.searchResults count]; return (NSInteger)[self.searchResults count];
} else { } else {
@ -428,9 +517,21 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ {
if (indexPath.section == MessageComposeTableViewControllerSectionInvite) { 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.searchPhoneNumber];
return self.conversationForNonContactCell;
} else if (indexPath.section == MessageComposeTableViewControllerSectionInviteViaSMS) {
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; return self.inviteCell;
} else { } else {
OWSAssert(indexPath.section == MessageComposeTableViewControllerSectionContacts)
ContactTableViewCell *cell = (ContactTableViewCell *)[tableView ContactTableViewCell *cell = (ContactTableViewCell *)[tableView
dequeueReusableCellWithIdentifier:MessageComposeTableViewControllerCellContact]; dequeueReusableCellWithIdentifier:MessageComposeTableViewControllerCellContact];
@ -444,7 +545,18 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (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)() = ^{ void (^showInvite)() = ^{
OWSInviteFlow *inviteFlow = OWSInviteFlow *inviteFlow =
[[OWSInviteFlow alloc] initWithPresentingViewController:self contactsManager:self.contactsManager]; [[OWSInviteFlow alloc] initWithPresentingViewController:self contactsManager:self.contactsManager];
@ -462,6 +574,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
showInvite(); showInvite();
} }
} else { } else {
OWSAssert(indexPath.section == MessageComposeTableViewControllerSectionContacts)
NSString *identifier = [[[self contactForIndexPath:indexPath] textSecureIdentifiers] firstObject]; NSString *identifier = [[[self contactForIndexPath:indexPath] textSecureIdentifiers] firstObject];
[self dismissViewControllerAnimated:YES [self dismissViewControllerAnimated:YES

@ -245,7 +245,7 @@
"ERROR_DESCRIPTION_SERVER_FAILURE" = "Server Error. Please try again later."; "ERROR_DESCRIPTION_SERVER_FAILURE" = "Server Error. Please try again later.";
/* Worst case generic error message */ /* Worst case generic error message */
"ERROR_DESCRIPTION_UNKNOWN_ERROR" = "An unkown error occurred."; "ERROR_DESCRIPTION_UNKNOWN_ERROR" = "ERROR_DESCRIPTION_UNKNOWN_ERROR";
/* Error message when attempting to send message */ /* Error message when attempting to send message */
"ERROR_DESCRIPTION_UNREGISTERED_RECIPIENT" = "Contact is not a Signal user."; "ERROR_DESCRIPTION_UNREGISTERED_RECIPIENT" = "Contact is not a Signal user.";
@ -489,6 +489,9 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NETWORK_STATUS_TEXT" = "You can check your network status by looking at the colored bar above your inbox."; "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 */ /* Action Sheet title prompting the user for a group avatar */
"NEW_GROUP_ADD_PHOTO_ACTION" = "Set Group Photo"; "NEW_GROUP_ADD_PHOTO_ACTION" = "Set Group Photo";
@ -501,6 +504,9 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NEW_GROUP_REQUEST_ADDPEOPLE" = "Add people"; "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. */ /* No comment provided by engineer. */
"NOTIFICATION_SEND_FAILED" = "Your message failed to send to %@."; "NOTIFICATION_SEND_FAILED" = "Your message failed to send to %@.";
@ -705,8 +711,8 @@
/* Alert body after invite succeeded */ /* Alert body after invite succeeded */
"SEND_INVITE_SUCCESS" = "You've invited your friend to use Signal!"; "SEND_INVITE_SUCCESS" = "You've invited your friend to use Signal!";
/* No comment provided by engineer. */ /* Text for button to send a Signal invite via SMS */
"SEND_SMS_BUTTON" = "Send SMS to: "; "SEND_INVITE_VIA_SMS_BUTTON_FORMAT" = "Send Invite via SMS to: %@";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SEND_SMS_CONFIRM_TITLE" = "Invite a friend via insecure SMS?"; "SEND_SMS_CONFIRM_TITLE" = "Invite a friend via insecure SMS?";

Loading…
Cancel
Save