Merge branch 'charlesmchen/searchVsNonSignalContacts'

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

@ -44,6 +44,8 @@ NS_ASSUME_NONNULL_BEGIN
- (NSArray<SignalAccount *> *)signalAccountsMatchingSearchString:(NSString *)searchText;
- (NSArray<Contact *> *)nonSignalContactsMatchingSearchString:(NSString *)searchText;
@end
NS_ASSUME_NONNULL_END

@ -15,6 +15,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface ContactsViewHelper ()
// This property is a cached value that is lazy-populated.
@property (nonatomic, nullable) NSArray<Contact *> *nonSignalContacts;
@property (nonatomic) NSDictionary<NSString *, SignalAccount *> *signalAccountMap;
@property (nonatomic) NSArray<SignalAccount *> *signalAccounts;
@ -143,6 +146,7 @@ NS_ASSUME_NONNULL_BEGIN
}
self.signalAccountMap = [signalAccountMap copy];
self.signalAccounts = [signalAccounts copy];
self.nonSignalContacts = nil;
[self.delegate contactsViewHelperDidUpdateContacts];
}
@ -178,15 +182,19 @@ NS_ASSUME_NONNULL_BEGIN
return YES;
}
- (NSArray<NSString *> *)searchTermsForSearchString:(NSString *)searchText
{
return [[[searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *_Nullable searchTerm,
NSDictionary<NSString *, id> *_Nullable bindings) {
return searchTerm.length > 0;
}]];
}
- (NSArray<SignalAccount *> *)signalAccountsMatchingSearchString:(NSString *)searchText
{
NSArray<NSString *> *searchTerms =
[[[searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *_Nullable searchTerm,
NSDictionary<NSString *, id> *_Nullable bindings) {
return searchTerm.length > 0;
}]];
NSArray<NSString *> *searchTerms = [self searchTermsForSearchString:searchText];
if (searchTerms.count < 1) {
return self.signalAccounts;
@ -199,6 +207,76 @@ NS_ASSUME_NONNULL_BEGIN
}]];
}
- (BOOL)doesContact:(Contact *)contact matchSearchTerm:(NSString *)searchTerm
{
OWSAssert(contact);
OWSAssert(searchTerm.length > 0);
if ([contact.fullName.lowercaseString containsString:searchTerm.lowercaseString]) {
return YES;
}
NSString *asPhoneNumber = [PhoneNumber removeFormattingCharacters:searchTerm];
if (asPhoneNumber.length > 0) {
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
if ([phoneNumber.toE164 containsString:asPhoneNumber]) {
return YES;
}
}
}
return NO;
}
- (BOOL)doesContact:(Contact *)contact matchSearchTerms:(NSArray<NSString *> *)searchTerms
{
OWSAssert(contact);
OWSAssert(searchTerms.count > 0);
for (NSString *searchTerm in searchTerms) {
if (![self doesContact:contact matchSearchTerm:searchTerm]) {
return NO;
}
}
return YES;
}
- (NSArray<Contact *> *)nonSignalContactsMatchingSearchString:(NSString *)searchText
{
NSArray<NSString *> *searchTerms = [self searchTermsForSearchString:searchText];
if (searchTerms.count < 1) {
return [NSArray new];
}
return [self.nonSignalContacts filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(Contact *contact,
NSDictionary<NSString *, id> *_Nullable bindings) {
return [self doesContact:contact matchSearchTerms:searchTerms];
}]];
}
- (nullable NSArray<Contact *> *)nonSignalContacts
{
if (!_nonSignalContacts) {
NSMutableSet<Contact *> *nonSignalContacts = [NSMutableSet new];
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (Contact *contact in self.contactsManager.allContactsMap.allValues) {
NSArray<SignalRecipient *> *signalRecipients = [contact signalRecipientsWithTransaction:transaction];
if (signalRecipients.count < 1) {
[nonSignalContacts addObject:contact];
}
}
}];
_nonSignalContacts = [nonSignalContacts.allObjects
sortedArrayUsingComparator:^NSComparisonResult(Contact *_Nonnull left, Contact *_Nonnull right) {
return [left.fullName compare:right.fullName];
}];
}
return _nonSignalContacts;
}
@end
NS_ASSUME_NONNULL_END

@ -218,6 +218,10 @@ NS_ASSUME_NONNULL_BEGIN
OWSTableSection *section = [OWSTableSection new];
const CGFloat kActionCellHeight
= ScaleFromIPhone5To7Plus(round((kOWSTable_DefaultCellHeight + [ContactTableViewCell rowHeight]) * 0.5f),
[ContactTableViewCell rowHeight]);
// Find Non-Contacts by Phone Number
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{
UITableViewCell *cell = [UITableViewCell new];
@ -228,7 +232,7 @@ NS_ASSUME_NONNULL_BEGIN
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
customRowHeight:[ContactTableViewCell rowHeight]
customRowHeight:kActionCellHeight
actionBlock:^{
NewNonContactConversationViewController *viewController =
[NewNonContactConversationViewController new];
@ -246,7 +250,7 @@ NS_ASSUME_NONNULL_BEGIN
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
customRowHeight:[ContactTableViewCell rowHeight]
customRowHeight:kActionCellHeight
actionBlock:^{
[weakSelf presentInviteFlow];
}]];
@ -287,7 +291,7 @@ NS_ASSUME_NONNULL_BEGIN
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
customRowHeight:[ContactTableViewCell rowHeight]
customRowHeight:kActionCellHeight
actionBlock:^{
[weakSelf sendTextToPhoneNumber:phoneNumber];
}]];
@ -316,6 +320,40 @@ NS_ASSUME_NONNULL_BEGIN
}
BOOL hasSearchText = [self.searchBar text].length > 0;
BOOL hasSearchResults = filteredSignalAccounts.count > 0;
// Invitation offers for non-signal contacts
if (hasSearchText) {
for (Contact *contact in [helper nonSignalContactsMatchingSearchString:[self.searchBar text]]) {
hasSearchResults = YES;
OWSAssert(contact.parsedPhoneNumbers.count > 0);
// TODO: Should we invite all of their phone numbers?
PhoneNumber *phoneNumber = contact.parsedPhoneNumbers[0];
NSString *displayName = contact.fullName;
if (displayName.length < 1) {
displayName = phoneNumber.toE164;
}
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{
UITableViewCell *cell = [UITableViewCell new];
cell.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."),
displayName];
cell.textLabel.font = [UIFont ows_regularFontWithSize:18.f];
cell.textLabel.textColor = [UIColor blackColor];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
customRowHeight:kActionCellHeight
actionBlock:^{
[weakSelf sendTextToPhoneNumber:phoneNumber.toE164];
}]];
}
}
if (!hasSearchText && helper.signalAccounts.count < 1) {
// No Contacts
@ -329,11 +367,11 @@ NS_ASSUME_NONNULL_BEGIN
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
customRowHeight:[ContactTableViewCell rowHeight]
customRowHeight:kActionCellHeight
actionBlock:nil]];
}
if (hasSearchText && filteredSignalAccounts.count < 1) {
if (hasSearchText && !hasSearchResults) {
// No Search Results
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{
@ -346,7 +384,7 @@ NS_ASSUME_NONNULL_BEGIN
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
customRowHeight:[ContactTableViewCell rowHeight]
customRowHeight:kActionCellHeight
actionBlock:nil]];
}

@ -19,6 +19,8 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
@property (nonnull, readonly) NSCache<NSString *, UIImage *> *avatarCache;
@property (atomic, readonly) NSDictionary<NSString *, Contact *> *allContactsMap;
// signalAccountMap and signalAccounts hold the same data.
// signalAccountMap is for lookup. signalAccounts contains the accounts
// ordered by display order.

Loading…
Cancel
Save