diff --git a/Signal/src/ViewControllers/AddToBlockListViewController.m b/Signal/src/ViewControllers/AddToBlockListViewController.m index 27e25fd2e..d7a8695a0 100644 --- a/Signal/src/ViewControllers/AddToBlockListViewController.m +++ b/Signal/src/ViewControllers/AddToBlockListViewController.m @@ -16,6 +16,7 @@ #import "ViewControllerUtils.h" #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -31,6 +32,7 @@ NSString *const kContactsTable_CellReuseIdentifier = @"kContactsTable_CellReuseI UITableViewDelegate> @property (nonatomic, readonly) OWSBlockingManager *blockingManager; +@property (nonatomic, readonly) NSArray *blockedPhoneNumbers; @property (nonatomic) UIButton *countryNameButton; @property (nonatomic) UIButton *countryCodeButton; @@ -59,8 +61,9 @@ NSString *const kContactsTable_CellReuseIdentifier = @"kContactsTable_CellReuseI self.view.backgroundColor = [UIColor whiteColor]; _blockingManager = [OWSBlockingManager sharedManager]; + _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; _contactsManager = [Environment getCurrent].contactsManager; - self.contacts = self.contactsManager.signalContacts; + self.contacts = [self filteredContacts]; self.title = NSLocalizedString(@"SETTINGS_ADD_TO_BLOCK_LIST_TITLE", @""); @@ -316,20 +319,64 @@ NSString *const kContactsTable_CellReuseIdentifier = @"kContactsTable_CellReuseI - (void)blockedPhoneNumbersDidChange:(id)notification { - // TODO: Once we have a list of contacts, we should update it here. + dispatch_async(dispatch_get_main_queue(), ^{ + _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; + + [self updateContacts]; + }); } - (void)signalRecipientsDidChange:(NSNotification *)notification { - [self updateContacts]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateContacts]; + }); } - (void)updateContacts { - dispatch_async(dispatch_get_main_queue(), ^{ - self.contacts = self.contactsManager.signalContacts; - [self.contactsTableView reloadData]; - }); + OWSAssert([NSThread isMainThread]); + + self.contacts = [self filteredContacts]; + [self.contactsTableView reloadData]; +} + +- (BOOL)isContactBlockedOrHidden:(Contact *)contact +{ + if (contact.parsedPhoneNumbers.count < 1) { + // Hide contacts without any valid phone numbers. + return YES; + } + + for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { + if ([_blockedPhoneNumbers containsObject:phoneNumber.toE164]) { + return YES; + } + } + + return NO; +} + +- (BOOL)isCurrentUserContact:(Contact *)contact +{ + for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { + if ([[phoneNumber toE164] isEqualToString:[TSAccountManager localNumber]]) { + return YES; + } + } + + return NO; +} + +- (NSArray *_Nonnull)filteredContacts +{ + NSMutableArray *result = [NSMutableArray new]; + for (Contact *contact in self.contactsManager.signalContacts) { + if (![self isContactBlockedOrHidden:contact] && ![self isCurrentUserContact:contact]) { + [result addObject:contact]; + } + } + return [result copy]; } #pragma mark - CountryCodeViewControllerDelegate diff --git a/Signal/src/ViewControllers/BlockListViewController.m b/Signal/src/ViewControllers/BlockListViewController.m index c99be8eda..538da8d44 100644 --- a/Signal/src/ViewControllers/BlockListViewController.m +++ b/Signal/src/ViewControllers/BlockListViewController.m @@ -45,7 +45,7 @@ typedef NS_ENUM(NSInteger, BlockListViewControllerSection) { _blockingManager = [OWSBlockingManager sharedManager]; _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; _contactsManager = [Environment getCurrent].contactsManager; - self.contacts = self.contactsManager.signalContacts; + self.contacts = [self.contactsManager.signalContacts copy]; self.title = NSLocalizedString(@"SETTINGS_BLOCK_LIST_TITLE", @"Label for the block list section of the settings view"); @@ -172,22 +172,26 @@ typedef NS_ENUM(NSInteger, BlockListViewControllerSection) { - (void)blockedPhoneNumbersDidChange:(id)notification { - _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; + dispatch_async(dispatch_get_main_queue(), ^{ + _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; - [self.tableView reloadData]; + [self.tableView reloadData]; + }); } - (void)signalRecipientsDidChange:(NSNotification *)notification { - [self updateContacts]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateContacts]; + }); } - (void)updateContacts { - dispatch_async(dispatch_get_main_queue(), ^{ - self.contacts = self.contactsManager.signalContacts; - [self.tableView reloadData]; - }); + OWSAssert([NSThread isMainThread]); + + self.contacts = [self.contactsManager.signalContacts copy]; + [self.tableView reloadData]; } #pragma mark - Logging diff --git a/Signal/src/ViewControllers/MessageComposeTableViewController.m b/Signal/src/ViewControllers/MessageComposeTableViewController.m index 26f87ef0d..4d76e6c0c 100644 --- a/Signal/src/ViewControllers/MessageComposeTableViewController.m +++ b/Signal/src/ViewControllers/MessageComposeTableViewController.m @@ -13,6 +13,7 @@ #import "Signal-Swift.h" #import "UIColor+OWS.h" #import "UIUtil.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -20,6 +21,9 @@ NS_ASSUME_NONNULL_BEGIN UISearchResultsUpdating, MFMessageComposeViewControllerDelegate> +@property (nonatomic, readonly) OWSBlockingManager *blockingManager; +@property (nonatomic, readonly) NSArray *blockedPhoneNumbers; + @property (nonatomic) IBOutlet UITableViewCell *inviteCell; @property (nonatomic) IBOutlet OWSNoSignalContactsView *noSignalContactsView; @@ -75,7 +79,10 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie _contactsManager = [Environment getCurrent].contactsManager; _phoneNumberAccountSet = [NSMutableSet set]; - + + _blockingManager = [OWSBlockingManager sharedManager]; + _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; + [self observeNotifications]; return self; @@ -101,6 +108,10 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie selector:@selector(signalRecipientsDidChange:) name:OWSContactsManagerSignalRecipientsDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(blockedPhoneNumbersDidChange:) + name:kNSNotificationName_BlockedPhoneNumbersDidChange + object:nil]; } - (void)dealloc @@ -109,7 +120,18 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie } - (void)signalRecipientsDidChange:(NSNotification *)notification { - [self updateContacts]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateContacts]; + }); +} + +- (void)blockedPhoneNumbersDidChange:(id)notification +{ + dispatch_async(dispatch_get_main_queue(), ^{ + _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; + + [self updateContacts]; + }); } - (void)viewDidLoad { @@ -123,7 +145,7 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.tableView.estimatedRowHeight = (CGFloat)60.0; self.tableView.rowHeight = UITableViewAutomaticDimension; - self.contacts = self.contactsManager.signalContacts; + self.contacts = [self filteredContacts]; self.searchResults = self.contacts; [self initializeSearch]; @@ -241,10 +263,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie if (show) { self.searchController.searchBar.hidden = YES; self.tableView.backgroundView = _loadingBackgroundView; - self.refreshControl = nil; self.tableView.backgroundView.opaque = YES; } else { - [self initializeRefreshControl]; self.searchController.searchBar.hidden = NO; self.tableView.backgroundView = nil; } @@ -263,14 +283,11 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie _isNoContactsViewVisible = isNoContactsViewVisible; if (isNoContactsViewVisible) { - self.refreshControl = nil; self.searchController.searchBar.hidden = YES; self.tableView.backgroundView = self.noSignalContactsView; self.tableView.backgroundView.opaque = YES; self.navigationItem.rightBarButtonItem = nil; } else { - [self initializeRefreshControl]; - self.refreshControl.enabled = YES; self.searchController.searchBar.hidden = NO; self.tableView.backgroundView = nil; self.navigationItem.rightBarButtonItem = self.createGroupBarButtonItem; @@ -301,15 +318,6 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie self.searchController.searchBar.searchBarStyle = UISearchBarStyleMinimal; self.searchController.searchBar.delegate = self; self.searchController.searchBar.placeholder = NSLocalizedString(@"SEARCH_BYNAMEORNUMBER_PLACEHOLDER_TEXT", @""); - - [self initializeRefreshControl]; -} - -- (void)initializeRefreshControl { - UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; - [refreshControl addTarget:self action:@selector(refreshContacts) forControlEvents:UIControlEventValueChanged]; - self.refreshControl = refreshControl; - [self.tableView addSubview:self.refreshControl]; } #pragma mark - UISearchResultsUpdating @@ -667,46 +675,39 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie return contact; } -#pragma mark Refresh controls - -- (void)updateAfterRefreshTry { - [self.refreshControl endRefreshing]; - - [self showLoadingBackgroundView:NO]; - - [self showEmptyBackgroundViewIfNecessary]; -} - -- (void)refreshContacts { - [[ContactsUpdater sharedUpdater] updateSignalContactIntersectionWithABContacts:self.contactsManager.allContacts - success:^{ - [self updateContacts]; - } - failure:^(NSError *error) { - dispatch_async(dispatch_get_main_queue(), ^{ - UIAlertView *alert = - [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"ERROR_WAS_DETECTED_TITLE", @"") - message:NSLocalizedString(@"TIMEOUT_CONTACTS_DETAIL", @"") - delegate:nil - cancelButtonTitle:NSLocalizedString(@"OK", @"") - otherButtonTitles:nil]; - [alert show]; - [self updateAfterRefreshTry]; - }); - }]; - - if ([self.contacts count] == 0) { - [self showLoadingBackgroundView:YES]; - } -} - - (void)updateContacts { - self.contacts = self.contactsManager.signalContacts; - dispatch_async(dispatch_get_main_queue(), ^{ - [self updateSearchResultsForSearchController:self.searchController]; - [self.tableView reloadData]; - [self updateAfterRefreshTry]; - }); + OWSAssert([NSThread isMainThread]); + + self.contacts = [self filteredContacts]; + [self updateSearchResultsForSearchController:self.searchController]; + [self.tableView reloadData]; +} + +- (BOOL)isContactBlockedOrHidden:(Contact *)contact +{ + if (contact.parsedPhoneNumbers.count < 1) { + // Hide contacts without any valid phone numbers. + return YES; + } + + for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { + if ([_blockedPhoneNumbers containsObject:phoneNumber.toE164]) { + return YES; + } + } + + return NO; +} + +- (NSArray *_Nonnull)filteredContacts +{ + NSMutableArray *result = [NSMutableArray new]; + for (Contact *contact in self.contactsManager.signalContacts) { + if (![self isContactBlockedOrHidden:contact]) { + [result addObject:contact]; + } + } + return [result copy]; } #pragma mark - Navigation diff --git a/Signal/src/ViewControllers/NewGroupViewController.m b/Signal/src/ViewControllers/NewGroupViewController.m index a78f3ad2e..6c8b84415 100644 --- a/Signal/src/ViewControllers/NewGroupViewController.m +++ b/Signal/src/ViewControllers/NewGroupViewController.m @@ -15,6 +15,7 @@ #import #import #import +#import #import #import @@ -28,6 +29,10 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue" @property (nonatomic, readonly, strong) OWSMessageSender *messageSender; @property (nonatomic, readonly, strong) OWSContactsManager *contactsManager; +@property (nonatomic, readonly) OWSBlockingManager *blockingManager; +@property (nonatomic, readonly) NSArray *blockedPhoneNumbers; + + @end @implementation NewGroupViewController @@ -61,6 +66,9 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue" _messageSender = [Environment getCurrent].messageSender; _contactsManager = [Environment getCurrent].contactsManager; + _blockingManager = [OWSBlockingManager sharedManager]; + _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; + [self observeNotifications]; } @@ -70,6 +78,10 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue" selector:@selector(signalRecipientsDidChange:) name:OWSContactsManagerSignalRecipientsDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(blockedPhoneNumbersDidChange:) + name:kNSNotificationName_BlockedPhoneNumbersDidChange + object:nil]; } - (void)dealloc @@ -78,17 +90,83 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue" } - (void)signalRecipientsDidChange:(NSNotification *)notification { - [self updateContacts]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateContacts]; + }); +} + +- (void)blockedPhoneNumbersDidChange:(id)notification +{ + dispatch_async(dispatch_get_main_queue(), ^{ + _blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers]; + + [self updateContacts]; + }); } - (void)updateContacts { AssertIsOnMainThread(); - contacts = self.contactsManager.signalContacts; + contacts = [self filteredContacts]; [self.tableView reloadData]; } +- (BOOL)isContactBlockedOrHidden:(Contact *)contact +{ + if (contact.parsedPhoneNumbers.count < 1) { + // Hide contacts without any valid phone numbers. + return YES; + } + + for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { + if ([_blockedPhoneNumbers containsObject:phoneNumber.toE164]) { + return YES; + } + } + + return NO; +} + +- (BOOL)isCurrentUserContact:(Contact *)contact +{ + for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { + if ([[phoneNumber toE164] isEqualToString:[TSAccountManager localNumber]]) { + return YES; + } + } + + return NO; +} + +- (BOOL)isContactInGroup:(Contact *)contact +{ + for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { + if (_thread != nil && _thread.groupModel.groupMemberIds) { + // TODO: What if a contact has two phone numbers that + // correspond to signal account and one has been added + // to the group but not the other? + if ([_thread.groupModel.groupMemberIds containsObject:[phoneNumber toE164]]) { + return YES; + } + } + } + + return NO; +} + +- (NSArray *_Nonnull)filteredContacts +{ + NSMutableArray *result = [NSMutableArray new]; + for (Contact *contact in self.contactsManager.signalContacts) { + if (![self isContactBlockedOrHidden:contact] && ![self isCurrentUserContact:contact] + && ![self isContactInGroup:contact]) { + [result addObject:contact]; + } + } + return [result copy]; +} + - (void)configWithThread:(TSGroupThread *)gThread { _thread = gThread; } @@ -96,26 +174,12 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue" - (void)viewDidLoad { [super viewDidLoad]; [self.navigationController.navigationBar setTranslucent:NO]; - - contacts = self.contactsManager.signalContacts; + contacts = [self filteredContacts]; self.tableView.tableHeaderView.frame = CGRectMake(0, 0, 400, 44); self.tableView.tableHeaderView = self.tableView.tableHeaderView; - - contacts = [contacts filter:^int(Contact *contact) { - for (PhoneNumber *number in [contact parsedPhoneNumbers]) { - if ([[number toE164] isEqualToString:[TSAccountManager localNumber]]) { - // remove local number - return NO; - } else if (_thread != nil && _thread.groupModel.groupMemberIds) { - return ![_thread.groupModel.groupMemberIds containsObject:[number toE164]]; - } - } - return YES; - }]; - [self initializeDelegates]; [self initializeTableView]; [self initializeKeyboardHandlers];