// // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // #import "ContactsViewHelper.h" #import "ContactTableViewCell.h" #import "Environment.h" #import "SignalAccount.h" #import #import #import #import NS_ASSUME_NONNULL_BEGIN @interface ContactsViewHelper () @property (nonatomic) NSDictionary *signalAccountMap; @property (nonatomic) NSArray *signalAccounts; @property (nonatomic) NSArray *blockedPhoneNumbers; @end #pragma mark - @implementation ContactsViewHelper - (instancetype)init { self = [super init]; if (!self) { return self; } _blockingManager = [OWSBlockingManager sharedManager]; _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; _contactsManager = [Environment getCurrent].contactsManager; self.signalAccountMap = self.contactsManager.signalAccountMap; self.signalAccounts = self.contactsManager.signalAccounts; [self observeNotifications]; return self; } - (void)observeNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(signalAccountsDidChange:) name:OWSContactsManagerSignalAccountsDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(blockedPhoneNumbersDidChange:) name:kNSNotificationName_BlockedPhoneNumbersDidChange object:nil]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)signalAccountsDidChange:(NSNotification *)notification { dispatch_async(dispatch_get_main_queue(), ^{ [self updateContacts]; }); } - (void)blockedPhoneNumbersDidChange:(id)notification { dispatch_async(dispatch_get_main_queue(), ^{ self.blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; [self updateContacts]; }); } #pragma mark - Contacts - (nullable SignalAccount *)signalAccountForRecipientId:(NSString *)recipientId { OWSAssert([NSThread isMainThread]); OWSAssert(recipientId.length > 0); return self.signalAccountMap[recipientId]; } - (BOOL)isSignalAccountHidden:(SignalAccount *)signalAccount { OWSAssert([NSThread isMainThread]); if ([self.delegate shouldHideLocalNumber] && [self isCurrentUser:signalAccount]) { return YES; } return NO; } - (BOOL)isCurrentUser:(SignalAccount *)signalAccount { OWSAssert([NSThread isMainThread]); NSString *localNumber = [TSAccountManager localNumber]; if ([signalAccount.recipientId isEqualToString:localNumber]) { return YES; } for (PhoneNumber *phoneNumber in signalAccount.contact.parsedPhoneNumbers) { if ([[phoneNumber toE164] isEqualToString:localNumber]) { return YES; } } return NO; } - (NSString *)localNumber { return [TSAccountManager localNumber]; } - (BOOL)isContactBlocked:(Contact *)contact { OWSAssert([NSThread isMainThread]); if (contact.parsedPhoneNumbers.count < 1) { // Do not consider contacts without any valid phone numbers to be blocked. return NO; } for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { if ([_blockedPhoneNumbers containsObject:phoneNumber.toE164]) { return YES; } } return NO; } - (BOOL)isRecipientIdBlocked:(NSString *)recipientId { AssertIsOnMainThread(); return [_blockedPhoneNumbers containsObject:recipientId]; } - (void)updateContacts { AssertIsOnMainThread(); NSMutableDictionary *signalAccountMap = [NSMutableDictionary new]; NSMutableArray *signalAccounts = [NSMutableArray new]; for (SignalAccount *signalAccount in self.contactsManager.signalAccounts) { if (![self isSignalAccountHidden:signalAccount]) { signalAccountMap[signalAccount.recipientId] = signalAccount; [signalAccounts addObject:signalAccount]; } } self.signalAccountMap = [signalAccountMap copy]; self.signalAccounts = [signalAccounts copy]; [self.delegate contactsViewHelperDidUpdateContacts]; } - (BOOL)doesSignalAccount:(SignalAccount *)signalAccount matchSearchTerm:(NSString *)searchTerm { OWSAssert(signalAccount); OWSAssert(searchTerm.length > 0); if ([signalAccount.contact.fullName.lowercaseString containsString:searchTerm.lowercaseString]) { return YES; } NSString *asPhoneNumber = [PhoneNumber removeFormattingCharacters:searchTerm]; if (asPhoneNumber.length > 0 && [signalAccount.recipientId containsString:asPhoneNumber]) { return YES; } return NO; } - (BOOL)doesSignalAccount:(SignalAccount *)signalAccount matchSearchTerms:(NSArray *)searchTerms { OWSAssert(signalAccount); OWSAssert(searchTerms.count > 0); for (NSString *searchTerm in searchTerms) { if (![self doesSignalAccount:signalAccount matchSearchTerm:searchTerm]) { return NO; } } return YES; } - (NSArray *)signalAccountsMatchingSearchString:(NSString *)searchText { NSArray *searchTerms = [[searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; if (searchTerms.count < 1) { return self.signalAccounts; } return [self.signalAccounts filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(SignalAccount *signalAccount, NSDictionary *_Nullable bindings) { return [self doesSignalAccount:signalAccount matchSearchTerms:searchTerms]; }]]; } @end NS_ASSUME_NONNULL_END