diff --git a/Podfile.lock b/Podfile.lock index 27ebaee80..7f3048c85 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -43,7 +43,7 @@ PODS: - ProtocolBuffers (1.9.10) - Reachability (3.2) - SCWaveformView (1.0.0) - - SignalServiceKit (0.0.4): + - SignalServiceKit (0.0.5): - '25519' - AFNetworking - AxolotlKit @@ -137,7 +137,7 @@ CHECKOUT OPTIONS: :commit: 225b1baa11125ea84d4b960d700834b5b0a40ee1 :git: https://github.com/WhisperSystems/JSQMessagesViewController SignalServiceKit: - :commit: f5aac9610c274dad33c071fcdd9d2ab6b3d85f0d + :commit: 80671b247f616c3bd6264eccce5f806a4a538e68 :git: https://github.com/WhisperSystems/SignalServiceKit.git SocketRocket: :commit: 587ad297eb63eb0d64d4caeb32a7da646ad1132b @@ -160,7 +160,7 @@ SPEC CHECKSUMS: ProtocolBuffers: d088180c10072b3d24a9939a6314b7b9bcc2340b Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 SCWaveformView: 52a96750255d817e300565a80c81fb643e233e07 - SignalServiceKit: e27a3025c2d5c61696386e44a50ac8d2fe83151e + SignalServiceKit: f52bc6e17f717540d93b4247a93246648bf4085e SocketRocket: 3f77ec2104cc113add553f817ad90a77114f5d43 SQLCipher: 4c768761421736a247ed6cf412d9045615d53dff SSKeychain: c71293fa57216a40ab06c23f4085387583293de4 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 2d1bf9616..49efdecbb 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -9,6 +9,9 @@ /* Begin PBXBuildFile section */ 0DD55B166906AF3368995978 /* libPods-Signal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80CD5E19DD23200E7926EEA7 /* libPods-Signal.a */; }; 30209C98DABCE82064B4EAF5 /* libPods-SignalTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A33D3C7EB4B17BDBD47F0FCC /* libPods-SignalTests.a */; }; + 45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; }; + 45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; }; + 45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */; }; 45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; }; 4CE0E3771B954546007210CF /* TSAnimatedAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */; }; 701231B518ECAA4500D456C4 /* EvpMessageDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 701231B418ECAA4500D456C4 /* EvpMessageDigest.m */; }; @@ -489,6 +492,9 @@ /* Begin PBXFileReference section */ 453CC0361D08E1A60040EBA3 /* sn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sn; path = translations/sn.lproj/Localizable.strings; sourceTree = ""; }; 454B35071D08EED80026D658 /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = translations/mk.lproj/Localizable.strings; sourceTree = ""; }; + 45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSearcher.h; sourceTree = ""; }; + 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcher.m; sourceTree = ""; }; + 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcherTest.m; sourceTree = ""; }; 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Signal/src/util/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; }; 45E282DE1D08E67800ADD4C8 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = translations/gl.lproj/Localizable.strings; sourceTree = ""; }; 45E282DF1D08E6CC00ADD4C8 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = translations/id.lproj/Localizable.strings; sourceTree = ""; }; @@ -1182,6 +1188,8 @@ 76EB04A818170B33006006FC /* number directory */, 76EB040818170B33006006FC /* OWSContactsManager.h */, 76EB040918170B33006006FC /* OWSContactsManager.m */, + 45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */, + 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */, ); path = contact; sourceTree = ""; @@ -1782,6 +1790,7 @@ isa = PBXGroup; children = ( B660F6761C29867F00687D6E /* OWSContactsManagerTest.m */, + 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */, ); path = contact; sourceTree = ""; @@ -2594,6 +2603,7 @@ A547DD741A70A87800103EC7 /* DJWActionSheet+OWS.m in Sources */, 76EB062618170B33006006FC /* Queue.m in Sources */, D221A09A169C9E5E00537ABF /* main.m in Sources */, + 45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */, 76EB061618170B33006006FC /* AnonymousOccurrenceLogger.m in Sources */, B6258B331C29E2E60014138E /* NotificationsManager.m in Sources */, 76EB063018170B33006006FC /* Conversions.m in Sources */, @@ -2793,6 +2803,7 @@ B660F7461C29988E00687D6E /* HelloAckPacket.m in Sources */, B660F7471C29988E00687D6E /* HelloPacket.m in Sources */, B660F7481C29988E00687D6E /* RecipientUnavailable.m in Sources */, + 45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */, B660F7491C29988E00687D6E /* ShortAuthenticationStringGenerator.m in Sources */, B660F74A1C29988E00687D6E /* ZrtpHandshakeResult.m in Sources */, B660F74B1C29988E00687D6E /* ZrtpHandshakeSocket.m in Sources */, @@ -2806,6 +2817,7 @@ B660F7531C29988E00687D6E /* NetworkStream.m in Sources */, B660F7541C29988E00687D6E /* SecureEndPoint.m in Sources */, B660F7551C29988E00687D6E /* UdpSocket.m in Sources */, + 45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */, B660F7561C29988E00687D6E /* PushManager.m in Sources */, B660F7571C29988E00687D6E /* NotificationTracker.m in Sources */, B660F7581C29988E00687D6E /* RPAccountManager.m in Sources */, diff --git a/Signal/src/contact/OWSContactsManager.h b/Signal/src/contact/OWSContactsManager.h index 45ffa3e4f..4a3f89191 100644 --- a/Signal/src/contact/OWSContactsManager.h +++ b/Signal/src/contact/OWSContactsManager.h @@ -23,7 +23,6 @@ typedef void (^ABReloadRequestCompletionBlock)(NSArray *contacts); - (NSArray *)getContactsFromAddressBook:(ABAddressBookRef)addressBook; - (Contact *)latestContactForPhoneNumber:(PhoneNumber *)phoneNumber; -- (NSArray *)latestContactsWithSearchString:(NSString *)searchString; - (void)verifyABPermission; diff --git a/Signal/src/contact/OWSContactsManager.m b/Signal/src/contact/OWSContactsManager.m index 6dc185930..91f19c403 100644 --- a/Signal/src/contact/OWSContactsManager.m +++ b/Signal/src/contact/OWSContactsManager.m @@ -248,12 +248,6 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in }]; } -- (NSArray *)latestContactsWithSearchString:(NSString *)searchString { - return [self.latestContactsById.allValues filter:^int(Contact *contact) { - return searchString.length == 0 || [OWSContactsManager name:contact.fullName matchesQuery:searchString]; - }]; -} - #pragma mark - Contact/Phone Number util - (Contact *)contactForRecord:(ABRecordRef)record { diff --git a/Signal/src/contact/OWSContactsSearcher.h b/Signal/src/contact/OWSContactsSearcher.h new file mode 100644 index 000000000..09f96e0d2 --- /dev/null +++ b/Signal/src/contact/OWSContactsSearcher.h @@ -0,0 +1,16 @@ +// +// OWSContactsSearcher.h +// Signal +// +// Created by Michael Kirk on 6/27/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. +// + +#import "Contact.h" + +@interface OWSContactsSearcher : NSObject + +- (instancetype)initWithContacts:(NSArray *)contacts; +- (NSArray *)filterWithString:(NSString *)string; + +@end diff --git a/Signal/src/contact/OWSContactsSearcher.m b/Signal/src/contact/OWSContactsSearcher.m new file mode 100644 index 000000000..9c44693fe --- /dev/null +++ b/Signal/src/contact/OWSContactsSearcher.m @@ -0,0 +1,42 @@ +// +// OWSContactsSearcher.m +// Signal +// +// Created by Michael Kirk on 6/27/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. +// + +#import "OWSContactsSearcher.h" +#import + +@interface OWSContactsSearcher () + +@property (copy) NSArray *contacts; + +@end + +@implementation OWSContactsSearcher + +- (instancetype)initWithContacts:(NSArray *)contacts { + self = [super init]; + if (!self) return self; + + _contacts = contacts; + return self; +} + +- (NSArray *)filterWithString:(NSString *)string { + NSString *searchTerm = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + if ([searchTerm isEqualToString:@""]) { + return self.contacts; + } + + NSString *formattedNumber = [PhoneNumber removeFormattingCharacters:searchTerm]; + + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(fullName contains[c] %@) OR (ANY parsedPhoneNumbers.toE164 contains[c] %@)", searchTerm, formattedNumber]; + + return [self.contacts filteredArrayUsingPredicate:predicate]; +} + +@end diff --git a/Signal/src/view controllers/MessageComposeTableViewController.m b/Signal/src/view controllers/MessageComposeTableViewController.m index 8cb278d0a..21a1014fe 100644 --- a/Signal/src/view controllers/MessageComposeTableViewController.m +++ b/Signal/src/view controllers/MessageComposeTableViewController.m @@ -12,6 +12,7 @@ #import "ContactTableViewCell.h" #import "ContactsUpdater.h" +#import "OWSContactsSearcher.h" #import "Environment.h" #import "UIColor+OWS.h" #import "UIUtil.h" @@ -26,8 +27,8 @@ @property (nonatomic, strong) UIBarButtonItem *addGroup; @property (nonatomic, strong) UIView *loadingBackgroundView; @property (nonatomic, strong) UIView *emptyBackgroundView; -@property (copy) NSArray *contacts; @property (nonatomic) NSString *currentSearchTerm; +@property (copy) NSArray *contacts; @property (copy) NSArray *searchResults; @end @@ -263,16 +264,10 @@ #pragma mark - Filter - (void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope { - // search by contact name or number + OWSContactsSearcher *contactsSearcher = [[OWSContactsSearcher alloc] initWithContacts: self.contacts]; + self.searchResults = [contactsSearcher filterWithString:searchText]; + NSString *formattedNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:searchText].toE164; - NSPredicate *resultPredicate = [NSPredicate - predicateWithFormat:@"(fullName contains[c] %@) OR (ANY parsedPhoneNumbers.toE164 contains[c] %@)", searchText, formattedNumber]; - - self.searchResults = [self.contacts filteredArrayUsingPredicate:resultPredicate]; - if (!self.searchResults.count && self.searchController.searchBar.text.length == 0) { - self.searchResults = self.contacts; - } - // 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", @""); @@ -426,12 +421,6 @@ } #pragma mark - Table View delegate -- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { - Contact *contact = [self contactForIndexPath:indexPath]; - // TODO what does it mean to have non Signal contacts here? - return contact.isSignalContact ? indexPath : nil; -} - - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *identifier = [[[self contactForIndexPath:indexPath] textSecureIdentifiers] firstObject]; @@ -442,7 +431,6 @@ }]; } - - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { ContactTableViewCell *cell = (ContactTableViewCell *)[tableView cellForRowAtIndexPath:indexPath]; cell.accessoryType = UITableViewCellAccessoryNone; diff --git a/Signal/test/contact/OWSContactsSearcherTest.m b/Signal/test/contact/OWSContactsSearcherTest.m new file mode 100644 index 000000000..1223992ef --- /dev/null +++ b/Signal/test/contact/OWSContactsSearcherTest.m @@ -0,0 +1,69 @@ +// +// OWSContactSearcherTest.m +// Signal +// +// Created by Michael Kirk on 6/27/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. +// + +#import + +#import "OWSContactsSearcher.h" + +@interface OWSContactsSearcherTest : XCTestCase + +@property Contact *meow; +@property Contact *clement; +@property OWSContactsSearcher *contactsSearcher; + +@end + +@implementation OWSContactsSearcherTest + +- (void)setUp { + [super setUp]; + + self.meow = [[Contact alloc] initWithContactWithFirstName:@"Chairman" + andLastName:@"Meow" + andUserTextPhoneNumbers:@[ @"1-323-555-1234", @"+86 10 1111 2222" ] + andImage:nil + andContactID:1]; + + self.clement = [[Contact alloc] initWithContactWithFirstName:@"Clément" + andLastName:@"Duval" + andUserTextPhoneNumbers:@[ @"33 123456789" ] + andImage:nil + andContactID:2]; + + self.contactsSearcher = [[OWSContactsSearcher alloc] initWithContacts:@[self.meow, self.clement]]; +} + +- (void)testFilterWithStringMatchAllOnEmtpy { + XCTAssertEqualObjects((@[self.meow, self.clement]), [self.contactsSearcher filterWithString:@""]); + XCTAssertEqualObjects((@[self.meow, self.clement]), [self.contactsSearcher filterWithString:@" "]); +} + +- (void)testFilterWithStringMatchByName { + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"Chairman"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"Chair"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"Meow"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"Chairman Meow"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@" Chairman Meow "]); + XCTAssertEqualObjects((@[self.meow, self.clement]), ([self.contactsSearcher filterWithString:@"C"])); + XCTAssertEqualObjects(@[], [self.contactsSearcher filterWithString:@"Chairman Meowww"]); +} + +- (void)testFilterWithStringByNumber { + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"1-323-555-1234"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"+86 10 1111 2222"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"323-555-1234"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"323.555.1234"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"3235551234"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"323"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"323 555 1234"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"+1 323 555 1234"]); + XCTAssertEqualObjects(@[self.meow], [self.contactsSearcher filterWithString:@"+13235551234"]); + XCTAssertEqualObjects((@[self.meow, self.clement]), [self.contactsSearcher filterWithString:@"1234"]); +} + +@end