Merge branch 'charlesmchen/blocking7'

pull/1/head
Matthew Chen 8 years ago
commit 68d2ea2fd8

@ -10,6 +10,8 @@
NS_ASSUME_NONNULL_BEGIN
typedef void (^BlockAlertCompletionBlock)();
@implementation BlockListUIUtils
+ (void)showBlockContactActionSheet:(Contact *)contact
@ -27,10 +29,12 @@ NS_ASSUME_NONNULL_BEGIN
if (phoneNumbers.count < 1) {
DDLogError(@"%@ Contact has no phone numbers", self.tag);
OWSAssert(0);
[self showBlockFailedAlert:fromViewController];
if (completionBlock) {
completionBlock(NO);
}
[self showBlockFailedAlert:fromViewController
completionBlock:^{
if (completionBlock) {
completionBlock(NO);
}
}];
return;
}
NSString *displayName = [contactsManager displayNameForContact:contact];
@ -81,10 +85,12 @@ NS_ASSUME_NONNULL_BEGIN
[self blockPhoneNumbers:phoneNumbers
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager];
if (completionBlock) {
completionBlock(YES);
}
blockingManager:blockingManager
completionBlock:^{
if (completionBlock) {
completionBlock(YES);
}
}];
}];
[actionSheetController addAction:unblockAction];
@ -104,6 +110,7 @@ NS_ASSUME_NONNULL_BEGIN
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssert(phoneNumbers.count > 0);
OWSAssert(displayName.length > 0);
@ -122,7 +129,8 @@ NS_ASSUME_NONNULL_BEGIN
@"The message format of the 'user blocked' "
@"alert. Embeds {{the blocked user's name or phone number}}."),
[self formatDisplayNameForAlertMessage:displayName]]
fromViewController:fromViewController];
fromViewController:fromViewController
completionBlock:completionBlock];
}
+ (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber
@ -153,10 +161,12 @@ NS_ASSUME_NONNULL_BEGIN
[BlockListUIUtils unblockPhoneNumber:phoneNumber
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager];
if (completionBlock) {
completionBlock(NO);
}
blockingManager:blockingManager
completionBlock:^{
if (completionBlock) {
completionBlock(NO);
}
}];
}];
[actionSheetController addAction:unblockAction];
@ -176,6 +186,7 @@ NS_ASSUME_NONNULL_BEGIN
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssert(phoneNumber.length > 0);
OWSAssert(displayName.length > 0);
@ -191,10 +202,12 @@ NS_ASSUME_NONNULL_BEGIN
@"The message format of the 'user unblocked' "
@"alert. Embeds {{the blocked user's name or phone number}}."),
[self formatDisplayNameForAlertMessage:displayName]]
fromViewController:fromViewController];
fromViewController:fromViewController
completionBlock:completionBlock];
}
+ (void)showBlockFailedAlert:(UIViewController *)fromViewController
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssert(fromViewController);
@ -202,10 +215,12 @@ NS_ASSUME_NONNULL_BEGIN
@"The title of the 'block user failed' alert.")
message:NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCK_FAILED_ALERT_MESSAGE",
@"The title of the 'block user failed' alert.")
fromViewController:fromViewController];
fromViewController:fromViewController
completionBlock:completionBlock];
}
+ (void)showUnblockFailedAlert:(UIViewController *)fromViewController
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssert(fromViewController);
@ -213,12 +228,14 @@ NS_ASSUME_NONNULL_BEGIN
@"The title of the 'unblock user failed' alert.")
message:NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCK_FAILED_ALERT_MESSAGE",
@"The title of the 'unblock user failed' alert.")
fromViewController:fromViewController];
fromViewController:fromViewController
completionBlock:completionBlock];
}
+ (void)showOkAlertWithTitle:(NSString *)title
message:(NSString *)message
fromViewController:(UIViewController *)fromViewController
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssert(title.length > 0);
OWSAssert(message.length > 0);
@ -229,7 +246,7 @@ NS_ASSUME_NONNULL_BEGIN
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
style:UIAlertActionStyleDefault
handler:nil]];
handler:completionBlock]];
[fromViewController presentViewController:controller animated:YES completion:nil];
}

@ -2,12 +2,15 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "MessagesViewController.h"
#import "AppDelegate.h"
#import "AttachmentSharing.h"
#import "BlockListUIUtils.h"
#import "DebugUITableViewController.h"
#import "BlockListViewController.h"
#import "Environment.h"
#import "FingerprintViewController.h"
#import "FullImageViewController.h"
#import "MessagesViewController.h"
#import "NSDate+millisecondTimeStamp.h"
#import "NewGroupViewController.h"
#import "OWSCall.h"
@ -34,6 +37,7 @@
#import "TSIncomingMessage.h"
#import "TSInfoMessage.h"
#import "TSInvalidIdentityKeyErrorMessage.h"
#import "ThreadUtil.h"
#import "UIFont+OWS.h"
#import "UIUtil.h"
#import "UIViewController+CameraPermissions.h"
@ -51,19 +55,18 @@
#import <SignalServiceKit/ContactsUpdater.h>
#import <SignalServiceKit/MimeTypeUtil.h>
#import <SignalServiceKit/OWSAttachmentsProcessor.h>
#import <SignalServiceKit/OWSBlockingManager.h>
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
#import <SignalServiceKit/OWSFingerprint.h>
#import <SignalServiceKit/OWSFingerprintBuilder.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/SignalRecipient.h>
#import <SignalServiceKit/Threading.h>
#import <SignalServiceKit/TSAccountManager.h>
#import <SignalServiceKit/TSInvalidIdentityKeySendingErrorMessage.h>
#import <SignalServiceKit/TSMessagesManager.h>
#import <SignalServiceKit/TSNetworkManager.h>
#import <SignalServiceKit/Threading.h>
#import <YapDatabase/YapDatabaseView.h>
#import "ThreadUtil.h"
#import "DebugUITableViewController.h"
@import Photos;
@ -198,6 +201,7 @@ typedef enum : NSUInteger {
@property (nonatomic) UILabel *navigationBarTitleLabel;
@property (nonatomic) UILabel *navigationBarSubtitleLabel;
@property (nonatomic) UIButton *attachButton;
@property (nonatomic) UIView *blockStateIndicator;
@property (nonatomic) CGFloat previousCollectionViewFrameWidth;
@ -213,8 +217,10 @@ typedef enum : NSUInteger {
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
@property (nonatomic, readonly) TSNetworkManager *networkManager;
@property (nonatomic, readonly) OutboundCallInitiator *outboundCallInitiator;
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
@property (nonatomic) NSCache *messageAdapterCache;
@property (nonatomic) BOOL userHasScrolled;
@end
@ -270,6 +276,24 @@ typedef enum : NSUInteger {
_disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithStorageManager:_storageManager];
_messagesManager = [TSMessagesManager sharedManager];
_networkManager = [TSNetworkManager sharedManager];
_blockingManager = [OWSBlockingManager sharedManager];
[self addNotificationListeners];
}
- (void)addNotificationListeners
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(blockedPhoneNumbersDidChange:)
name:kNSNotificationName_BlockedPhoneNumbersDidChange
object:nil];
}
- (void)blockedPhoneNumbersDidChange:(id)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
[self ensureBlockStateIndicator];
});
}
- (void)peekSetup {
@ -500,6 +524,142 @@ typedef enum : NSUInteger {
@"Short name for edit menu item to share contents of media message.")
action:shareSelector],
];
[self ensureBlockStateIndicator];
}
- (void)setUserHasScrolled:(BOOL)userHasScrolled {
_userHasScrolled = userHasScrolled;
[self ensureBlockStateIndicator];
}
- (void)ensureBlockStateIndicator
{
// This method should be called rarely, so it's simplest to discard and
// rebuild the indicator view every time.
[self.blockStateIndicator removeFromSuperview];
self.blockStateIndicator = nil;
if (self.userHasScrolled) {
return;
}
NSString *blockStateMessage = nil;
if ([self isBlockedContactConversation]) {
blockStateMessage = NSLocalizedString(@"MESSAGES_VIEW_CONTACT_BLOCKED",
@"Indicates that this 1:1 conversation has been blocked.");
} else if (isGroupConversation) {
int blockedGroupMemberCount = [self blockedGroupMemberCount];
if (blockedGroupMemberCount == 1) {
blockStateMessage = NSLocalizedString(@"MESSAGES_VIEW_GROUP_1_MEMBER_BLOCKED",
@"Indicates that a single member of this group has been blocked.");
} else if (blockedGroupMemberCount > 1) {
blockStateMessage = [NSString stringWithFormat:NSLocalizedString(@"MESSAGES_VIEW_GROUP_N_MEMBERS_BLOCKED_FORMAT",
@"Indicates that some members of this group has been blocked. Embeds "
@"{{the number of blocked users in this group}}."),
blockedGroupMemberCount];
}
}
if (blockStateMessage) {
UILabel *label = [UILabel new];
label.font = [UIFont ows_mediumFontWithSize:14.f];
label.text = blockStateMessage;
label.textColor = [UIColor whiteColor];
UIView * blockStateIndicator = [UIView new];
blockStateIndicator.backgroundColor = [UIColor ows_redColor];
blockStateIndicator.layer.cornerRadius = 2.5f;
// Use a shadow to "pop" the indicator above the other views.
blockStateIndicator.layer.shadowColor = [UIColor blackColor].CGColor;
blockStateIndicator.layer.shadowOffset = CGSizeMake(2, 3);
blockStateIndicator.layer.shadowRadius = 2.f;
blockStateIndicator.layer.shadowOpacity = 0.35f;
[blockStateIndicator addSubview:label];
[label autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:5];
[label autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:5];
[label autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:15];
[label autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:15];
[blockStateIndicator addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(blockStateIndicatorWasTapped:)]];
[self.view addSubview:blockStateIndicator];
[blockStateIndicator autoHCenterInSuperview];
[blockStateIndicator autoPinToTopLayoutGuideOfViewController:self withInset:10];
[self.view layoutSubviews];
self.blockStateIndicator = blockStateIndicator;
}
}
- (void)blockStateIndicatorWasTapped:(UIGestureRecognizer *)sender {
if (sender.state != UIGestureRecognizerStateRecognized) {
return;
}
if ([self isBlockedContactConversation]) {
// If this a blocked 1:1 conversation, offer to unblock the user.
[self showUnblockContactUI:nil];
} else if (isGroupConversation) {
// If this a group conversation with at least one blocked member,
// Show the block list view.
int blockedGroupMemberCount = [self blockedGroupMemberCount];
if (blockedGroupMemberCount > 0) {
BlockListViewController *vc = [[BlockListViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
}
}
- (void)showUnblockContactUI:(BlockActionCompletionBlock)completionBlock
{
OWSAssert([self.thread isKindOfClass:[TSContactThread class]]);
self.userHasScrolled = NO;
// To avoid "noisy" animations (hiding the keyboard before showing
// the action sheet, re-showing it after), hide the keyboard before
// showing the "unblock" action sheet.
//
// Unblocking is a rare interaction, so it's okay to leave the keyboard
// hidden.
[self dismissKeyBoard];
NSString *contactIdentifier = ((TSContactThread *)self.thread).contactIdentifier;
[BlockListUIUtils showUnblockPhoneNumberActionSheet:contactIdentifier
fromViewController:self
blockingManager:_blockingManager
contactsManager:_contactsManager
completionBlock:completionBlock];
}
- (BOOL)isBlockedContactConversation
{
if (![self.thread isKindOfClass:[TSContactThread class]]) {
return NO;
}
NSString *contactIdentifier = ((TSContactThread *)self.thread).contactIdentifier;
return [[_blockingManager blockedPhoneNumbers] containsObject:contactIdentifier];
}
- (int)blockedGroupMemberCount
{
OWSAssert(isGroupConversation);
OWSAssert([self.thread isKindOfClass:[TSGroupThread class]]);
TSGroupThread *groupThread = (TSGroupThread *)self.thread;
int blockedMemberCount = 0;
NSArray<NSString *> *blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers];
for (NSString *contactIdentifier in groupThread.groupModel.groupMemberIds) {
if ([blockedPhoneNumbers containsObject:contactIdentifier]) {
blockedMemberCount++;
}
}
return blockedMemberCount;
}
- (void)startReadTimer {
@ -585,6 +745,7 @@ typedef enum : NSUInteger {
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
self.inputToolbar.contentView.textView.editable = NO;
self.userHasScrolled = NO;
}
#pragma mark - Initiliazers
@ -693,7 +854,7 @@ typedef enum : NSUInteger {
backItem,
[[UIBarButtonItem alloc] initWithCustomView:self.navigationBarTitleView],
];
if (self.userLeftGroup) {
self.navigationItem.rightBarButtonItems = @[];
return;
@ -842,6 +1003,16 @@ typedef enum : NSUInteger {
return;
}
if ([self isBlockedContactConversation]) {
__weak MessagesViewController *weakSelf = self;
[self showUnblockContactUI:^(BOOL isBlocked) {
if (!isBlocked) {
[weakSelf callAction:nil];
}
}];
return;
}
[self.outboundCallInitiator initiateCallWithRecipientId:self.thread.contactIdentifier];
}
@ -857,6 +1028,36 @@ typedef enum : NSUInteger {
senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date
{
[self didPressSendButton:button
withMessageText:text
senderId:senderId
senderDisplayName:senderDisplayName
date:date
updateKeyboardState:YES];
}
- (void)didPressSendButton:(UIButton *)button
withMessageText:(NSString *)text
senderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date
updateKeyboardState:(BOOL)updateKeyboardState
{
if ([self isBlockedContactConversation]) {
__weak MessagesViewController *weakSelf = self;
[self showUnblockContactUI:^(BOOL isBlocked) {
if (!isBlocked) {
[weakSelf didPressSendButton:button
withMessageText:text
senderId:senderId
senderDisplayName:senderDisplayName
date:date
updateKeyboardState:NO];
}
}];
return;
}
text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
// Limit outgoing text messages to 64kb.
@ -888,7 +1089,10 @@ typedef enum : NSUInteger {
[ThreadUtil sendMessageWithText:text
inThread:self.thread
messageSender:self.messageSender];
[self toggleDefaultKeyboard];
if (updateKeyboardState)
{
[self toggleDefaultKeyboard];
}
[self finishSendingMessage];
}
}
@ -2319,6 +2523,17 @@ typedef enum : NSUInteger {
#pragma mark Accessory View
- (void)didPressAccessoryButton:(UIButton *)sender {
if ([self isBlockedContactConversation]) {
__weak MessagesViewController *weakSelf = self;
[self showUnblockContactUI:^(BOOL isBlocked) {
if (!isBlocked) {
[weakSelf didPressAccessoryButton:nil];
}
}];
return;
}
UIAlertController *actionSheetController = [UIAlertController alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
@ -2551,7 +2766,17 @@ typedef enum : NSUInteger {
DDLogError(@"%@ %s",
self.tag,
__PRETTY_FUNCTION__);
if ([self isBlockedContactConversation]) {
__weak MessagesViewController *weakSelf = self;
[self showUnblockContactUI:^(BOOL isBlocked) {
if (!isBlocked) {
[weakSelf didPasteAttachment:attachment];
}
}];
return;
}
if (attachment == nil ||
[attachment hasError]) {
DDLogWarn(@"%@ %s Invalid attachment: %@.",
@ -2596,6 +2821,13 @@ typedef enum : NSUInteger {
completion:nil];
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
self.userHasScrolled = YES;
}
#pragma mark - Class methods
+ (UINib *)nib

@ -529,6 +529,15 @@
/* message footer while attachment is uploading */
"MESSAGE_STATUS_UPLOADING" = "Uploading...";
/* Indicates that this 1:1 conversation has been blocked. */
"MESSAGES_VIEW_CONTACT_BLOCKED" = "You Blocked this User";
/* Indicates that a single member of this group has been blocked. */
"MESSAGES_VIEW_GROUP_1_MEMBER_BLOCKED" = "You Blocked 1 Member of this Group";
/* Indicates that some members of this group has been blocked. Embeds {{the number of blocked user in this group}}. */
"MESSAGES_VIEW_GROUP_N_MEMBERS_BLOCKED_FORMAT" = "You Blocked %d Members of this Group";
/* The subtitle for the messages view title indicates that the title can be tapped to access settings for this conversation. */
"MESSAGES_VIEW_TITLE_SUBTITLE" = "Tap here for settings";

Loading…
Cancel
Save