Merge branch 'charlesmchen/blocking10'

This commit is contained in:
Michael Kirk 2017-04-06 20:59:14 -04:00
commit dc174ad6f0
8 changed files with 265 additions and 62 deletions

View File

@ -501,7 +501,13 @@ NSString *const kContactsTable_CellReuseIdentifier = @"kContactsTable_CellReuseI
if (!cell) {
cell = [ContactTableViewCell new];
}
cell.isBlocked = [self isContactBlocked:contact];
BOOL isBlocked = [self isContactBlocked:contact];
if (isBlocked) {
cell.accessoryMessage
= NSLocalizedString(@"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked.");
} else {
OWSAssert(cell.accessoryMessage == nil);
}
[cell configureWithContact:contact contactsManager:self.contactsManager];
return cell;
}

View File

@ -16,6 +16,8 @@ typedef void (^BlockActionCompletionBlock)(BOOL isBlocked);
- (instancetype)init NS_UNAVAILABLE;
#pragma mark - Block
+ (void)showBlockContactActionSheet:(Contact *)contact
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
@ -28,6 +30,14 @@ typedef void (^BlockActionCompletionBlock)(BOOL isBlocked);
contactsManager:(OWSContactsManager *)contactsManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
#pragma mark - Unblock
+ (void)showUnblockContactActionSheet:(Contact *)contact
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
contactsManager:(OWSContactsManager *)contactsManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
+ (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager

View File

@ -14,6 +14,8 @@ typedef void (^BlockAlertCompletionBlock)();
@implementation BlockListUIUtils
#pragma mark - Block
+ (void)showBlockContactActionSheet:(Contact *)contact
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
@ -133,18 +135,63 @@ typedef void (^BlockAlertCompletionBlock)();
completionBlock:completionBlock];
}
#pragma mark - Unblock
+ (void)showUnblockContactActionSheet:(Contact *)contact
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
contactsManager:(OWSContactsManager *)contactsManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
NSMutableArray<NSString *> *phoneNumbers = [NSMutableArray new];
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
if (phoneNumber.toE164.length > 0) {
[phoneNumbers addObject:phoneNumber.toE164];
}
}
if (phoneNumbers.count < 1) {
DDLogError(@"%@ Contact has no phone numbers", self.tag);
OWSAssert(0);
[self showUnblockFailedAlert:fromViewController
completionBlock:^{
if (completionBlock) {
completionBlock(NO);
}
}];
return;
}
NSString *displayName = [contactsManager displayNameForContact:contact];
[self showUnblockPhoneNumbersActionSheet:phoneNumbers
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
}
+ (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
contactsManager:(OWSContactsManager *)contactsManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
OWSAssert(phoneNumber.length > 0);
NSString *displayName = [contactsManager displayNameForPhoneIdentifier:phoneNumber];
[self showUnblockPhoneNumbersActionSheet:@[ phoneNumber ]
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
}
+ (void)showUnblockPhoneNumbersActionSheet:(NSArray<NSString *> *)phoneNumbers
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
OWSAssert(phoneNumbers.count > 0);
OWSAssert(displayName.length > 0);
OWSAssert(fromViewController);
OWSAssert(blockingManager);
OWSAssert(contactsManager);
NSString *displayName = [contactsManager displayNameForPhoneIdentifier:phoneNumber];
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_TITLE_FORMAT",
@"A format for the 'unblock user' action sheet title. Embeds "
@ -158,15 +205,15 @@ typedef void (^BlockAlertCompletionBlock)();
actionWithTitle:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_BUTTON", @"Button label for the 'unblock' button")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
[BlockListUIUtils unblockPhoneNumber:phoneNumber
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:^{
if (completionBlock) {
completionBlock(NO);
}
}];
[BlockListUIUtils unblockPhoneNumbers:phoneNumbers
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:^{
if (completionBlock) {
completionBlock(NO);
}
}];
}];
[actionSheetController addAction:unblockAction];
@ -182,18 +229,21 @@ typedef void (^BlockAlertCompletionBlock)();
[fromViewController presentViewController:actionSheetController animated:YES completion:nil];
}
+ (void)unblockPhoneNumber:(NSString *)phoneNumber
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
+ (void)unblockPhoneNumbers:(NSArray<NSString *> *)phoneNumbers
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssert(phoneNumber.length > 0);
OWSAssert(phoneNumbers.count > 0);
OWSAssert(displayName.length > 0);
OWSAssert(fromViewController);
OWSAssert(blockingManager);
[blockingManager removeBlockedPhoneNumber:phoneNumber];
for (NSString *phoneNumber in phoneNumbers) {
OWSAssert(phoneNumber.length > 0);
[blockingManager removeBlockedPhoneNumber:phoneNumber];
}
[self showOkAlertWithTitle:NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE",
@"The title of the 'user unblocked' alert.")
@ -232,6 +282,8 @@ typedef void (^BlockAlertCompletionBlock)();
completionBlock:completionBlock];
}
#pragma mark - UI
+ (void)showOkAlertWithTitle:(NSString *)title
message:(NSString *)message
fromViewController:(UIViewController *)fromViewController

View File

@ -622,7 +622,13 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
dequeueReusableCellWithIdentifier:MessageComposeTableViewControllerCellContact];
Contact *contact = [self contactForIndexPath:indexPath];
cell.isBlocked = [self isContactBlocked:contact];
BOOL isBlocked = [self isContactBlocked:contact];
if (isBlocked) {
cell.accessoryMessage
= NSLocalizedString(@"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked.");
} else {
OWSAssert(cell.accessoryMessage == nil);
}
[cell configureWithContact:contact contactsManager:self.contactsManager];
return cell;

View File

@ -3,6 +3,8 @@
//
#import "NewGroupViewController.h"
#import "BlockListUIUtils.h"
#import "ContactTableViewCell.h"
#import "Environment.h"
#import "FunctionalUtil.h"
#import "OWSContactsManager.h"
@ -107,18 +109,50 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue"
- (void)updateContacts {
AssertIsOnMainThread();
// Snapshot selection state.
NSMutableSet *selectedContacts = [NSMutableSet set];
for (NSIndexPath *indexPath in [self.tableView indexPathsForSelectedRows]) {
Contact *contact = contacts[(NSUInteger)indexPath.row];
[selectedContacts addObject:contact];
}
contacts = [self filteredContacts];
[self.tableView reloadData];
// Restore selection state.
for (Contact *contact in selectedContacts) {
if ([contacts containsObject:contact]) {
NSInteger row = (NSInteger)[contacts indexOfObject:contact];
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]
animated:NO
scrollPosition:UITableViewScrollPositionNone];
}
}
}
- (BOOL)isContactBlockedOrHidden:(Contact *)contact
- (BOOL)isContactHidden:(Contact *)contact
{
if (contact.parsedPhoneNumbers.count < 1) {
// Hide contacts without any valid phone numbers.
return YES;
}
if ([self isCurrentUserContact:contact]) {
// We never want to add ourselves to a group.
return YES;
}
return NO;
}
- (BOOL)isContactBlocked:(Contact *)contact
{
if (contact.parsedPhoneNumbers.count < 1) {
// Hide contacts without any valid phone numbers.
return NO;
}
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
if ([_blockedPhoneNumbers containsObject:phoneNumber.toE164]) {
return YES;
@ -139,6 +173,17 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue"
return NO;
}
- (NSArray<Contact *> *_Nonnull)filteredContacts
{
NSMutableArray<Contact *> *result = [NSMutableArray new];
for (Contact *contact in self.contactsManager.signalContacts) {
if (![self isContactHidden:contact]) {
[result addObject:contact];
}
}
return [result copy];
}
- (BOOL)isContactInGroup:(Contact *)contact
{
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
@ -155,18 +200,6 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue"
return NO;
}
- (NSArray<Contact *> *_Nonnull)filteredContacts
{
NSMutableArray<Contact *> *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;
}
@ -421,39 +454,113 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue"
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"GroupSearchCell"];
ContactTableViewCell *cell
= (ContactTableViewCell *)[tableView dequeueReusableCellWithIdentifier:[ContactTableViewCell reuseIdentifier]];
if (!cell) {
cell = [ContactTableViewCell new];
}
NSUInteger row = (NSUInteger)indexPath.row;
Contact *contact = contacts[row];
cell.textLabel.attributedText = [self.contactsManager formattedFullNameForContact:contact font:cell.textLabel.font];
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
if ([[tableView indexPathsForSelectedRows] containsObject:indexPath]) {
[self adjustSelected:cell];
}
[self updateContentsOfCell:cell indexPath:indexPath];
return cell;
}
#pragma mark - Table View delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self adjustSelected:cell];
- (void)updateContentsOfCell:(ContactTableViewCell *)cell indexPath:(NSIndexPath *)indexPath
{
OWSAssert(cell);
OWSAssert(indexPath);
Contact *contact = contacts[(NSUInteger)indexPath.row];
OWSAssert(contact != nil);
BOOL isBlocked = [self isContactBlocked:contact];
BOOL isInGroup = [self isContactInGroup:contact];
BOOL isSelected = [[self.tableView indexPathsForSelectedRows] containsObject:indexPath];
// More than one of these conditions might be true.
// In order of priority...
cell.accessoryMessage = nil;
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryNone;
if (isInGroup) {
OWSAssert(!isSelected);
// ...if the user is already in the group, indicate that.
cell.accessoryMessage = NSLocalizedString(
@"CONTACT_CELL_IS_IN_GROUP", @"An indicator that a contact is a member of the current group.");
} else if (isSelected) {
// ...if the user is being added to the group, indicate that.
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else if (isBlocked) {
// ...if the user is blocked, indicate that.
cell.accessoryMessage
= NSLocalizedString(@"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked.");
}
[cell configureWithContact:contact contactsManager:self.contactsManager];
}
- (void)adjustSelected:(UITableViewCell *)cell {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [ContactTableViewCell rowHeight];
}
#pragma mark - Table View delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Contact *contact = contacts[(NSUInteger)indexPath.row];
BOOL isBlocked = [self isContactBlocked:contact];
BOOL isInGroup = [self isContactInGroup:contact];
if (isInGroup) {
// Deselect.
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSString *displayName = [_contactsManager displayNameForContact:contact];
UIAlertController *controller = [UIAlertController
alertControllerWithTitle:
NSLocalizedString(@"EDIT_GROUP_VIEW_ALREADY_IN_GROUP_ALERT_TITLE",
@"A title of the alert if user tries to add a user to a group who is already in the group.")
message:[NSString
stringWithFormat:
NSLocalizedString(@"EDIT_GROUP_VIEW_ALREADY_IN_GROUP_ALERT_MESSAGE_FORMAT",
@"A format for the message of the alert if user tries to "
@"add a user to a group who is already in the group. Embeds {{the "
@"blocked user's name or phone number}}."),
displayName]
preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:controller animated:YES completion:nil];
return;
} else if (isBlocked) {
// Deselect.
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
__weak NewGroupViewController *weakSelf = self;
[BlockListUIUtils showUnblockContactActionSheet:contact
fromViewController:self
blockingManager:_blockingManager
contactsManager:_contactsManager
completionBlock:^(BOOL isStillBlocked) {
if (!isStillBlocked) {
// Re-select.
[weakSelf.tableView selectRowAtIndexPath:indexPath
animated:YES
scrollPosition:UITableViewScrollPositionNone];
ContactTableViewCell *cell = (ContactTableViewCell *)[weakSelf.tableView
cellForRowAtIndexPath:indexPath];
[weakSelf updateContentsOfCell:cell indexPath:indexPath];
}
}];
return;
}
ContactTableViewCell *cell = (ContactTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[self updateContentsOfCell:cell indexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
ContactTableViewCell *cell = (ContactTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[self updateContentsOfCell:cell indexPath:indexPath];
}
#pragma mark - Text Field Delegate

View File

@ -17,7 +17,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface ContactTableViewCell : UITableViewCell
@property (nonatomic) BOOL isBlocked;
@property (nonatomic, nullable) NSString *accessoryMessage;
+ (nullable NSString *)reuseIdentifier;
+ (CGFloat)rowHeight;

View File

@ -29,6 +29,11 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+ (nullable NSString *)reuseIdentifier
{
return NSStringFromClass(self.class);
}
- (nullable NSString *)reuseIdentifier
{
return NSStringFromClass(self.class);
@ -70,11 +75,10 @@ NS_ASSUME_NONNULL_BEGIN
{
NSMutableAttributedString *attributedText =
[[contactsManager formattedFullNameForContact:contact font:self.nameLabel.font] mutableCopy];
if (self.isBlocked) {
if (self.accessoryMessage) {
UILabel *blockedLabel = [[UILabel alloc] init];
blockedLabel.textAlignment = NSTextAlignmentRight;
blockedLabel.text
= NSLocalizedString(@"CONTACT_BLOCKED_INDICATOR", @"An indicator that a contact has been blocked.");
blockedLabel.text = self.accessoryMessage;
blockedLabel.font = [UIFont ows_mediumFontWithSize:13.f];
blockedLabel.textColor = [UIColor colorWithWhite:0.5f alpha:1.f];
[blockedLabel sizeToFit];
@ -97,6 +101,13 @@ NS_ASSUME_NONNULL_BEGIN
[UIUtil applyRoundedBorderToImageView:self.avatarView];
}
- (void)prepareForReuse
{
self.accessoryMessage = nil;
self.accessoryView = nil;
self.accessoryType = UITableViewCellAccessoryNone;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -194,7 +194,10 @@
"CONFIRMATION_TITLE" = "Confirm";
/* An indicator that a contact has been blocked. */
"CONTACT_BLOCKED_INDICATOR" = "(Blocked)";
"CONTACT_CELL_IS_BLOCKED" = "Blocked";
/* An indicator that a contact is a member of the current group. */
"CONTACT_CELL_IS_IN_GROUP" = "Group Member";
/* No comment provided by engineer. */
"CONTACT_DETAIL_COMM_TYPE_INSECURE" = "Unregistered Number";
@ -256,6 +259,12 @@
/* table cell label in conversation settings */
"EDIT_GROUP_ACTION" = "Edit Group";
/* A format for the message of the alert if user tries to add a user to a group who is already in the group. Embeds {{the blocked user's name or phone number}}. */
"EDIT_GROUP_VIEW_ALREADY_IN_GROUP_ALERT_MESSAGE_FORMAT" = "%@ is already a member of this group.";
/* A title of the alert if user tries to add a user to a group who is already in the group. */
"EDIT_GROUP_VIEW_ALREADY_IN_GROUP_ALERT_TITLE" = "Already a Group Member";
/* Short name for edit menu item to copy contents of media message. */
"EDIT_ITEM_COPY_ACTION" = "Copy";