Add “add to profile whitelist” offer.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 9f6ca3d848
commit 37ce388eb6

@ -24,6 +24,7 @@ extern NSString *const kNSNotificationName_OtherUsersProfileDidChange;
// These two methods should only be called from the main thread.
- (NSData *)localProfileKey;
- (BOOL)hasLocalProfile;
- (nullable NSString *)localProfileName;
- (nullable UIImage *)localProfileAvatarImage;
@ -39,16 +40,14 @@ extern NSString *const kNSNotificationName_OtherUsersProfileDidChange;
#pragma mark - Profile Whitelist
- (void)addUserToProfileWhitelist:(NSString *)recipientId;
- (void)addThreadToProfileWhitelist:(TSThread *)thread;
- (BOOL)isUserInProfileWhitelist:(NSString *)recipientId;
- (BOOL)isThreadInProfileWhitelist:(TSThread *)thread;
- (void)addGroupIdToProfileWhitelist:(NSData *)groupId;
- (BOOL)isUserInProfileWhitelist:(NSString *)recipientId;
- (void)setContactRecipientIds:(NSArray<NSString *> *)contactRecipientIds;
- (BOOL)isThreadInProfileWhitelist:(TSThread *)thread;
#pragma mark - Other User's Profiles
- (void)setProfileKey:(NSData *)profileKey forRecipientId:(NSString *)recipientId;

@ -254,6 +254,13 @@ static const NSInteger kProfileKeyLength = 16;
return self.localUserProfile.profileKey;
}
- (BOOL)hasLocalProfile
{
OWSAssert([NSThread isMainThread]);
return (self.localProfileName.length > 0 || self.localProfileAvatarImage != nil);
}
- (nullable NSString *)localProfileName
{
OWSAssert([NSThread isMainThread]);
@ -489,6 +496,20 @@ static const NSInteger kProfileKeyLength = 16;
self.groupProfileWhitelistCache[groupIdKey] = @(YES);
}
- (void)addThreadToProfileWhitelist:(TSThread *)thread
{
OWSAssert(thread);
if (thread.isGroupThread) {
TSGroupThread *groupThread = (TSGroupThread *)thread;
NSData *groupId = groupThread.groupModel.groupId;
[self addGroupIdToProfileWhitelist:groupId];
} else {
NSString *recipientId = thread.contactIdentifier;
[self addUserToProfileWhitelist:recipientId];
}
}
- (BOOL)isGroupIdInProfileWhitelist:(NSData *)groupId
{
OWSAssert(groupId.length > 0);

@ -70,6 +70,7 @@
#import <SignalServiceKit/NSDate+OWS.h>
#import <SignalServiceKit/NSTimer+OWS.h>
#import <SignalServiceKit/OWSAddToContactsOfferMessage.h>
#import <SignalServiceKit/OWSAddToProfileWhitelistOfferMessage.h>
#import <SignalServiceKit/OWSAttachmentsProcessor.h>
#import <SignalServiceKit/OWSBlockingManager.h>
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
@ -2457,6 +2458,11 @@ typedef enum : NSUInteger {
OWSAssert([message isKindOfClass:[OWSAddToContactsOfferMessage class]]);
[self tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)message];
return;
case TSInfoMessageAddUserToProfileWhitelistOffer:
case TSInfoMessageAddGroupToProfileWhitelistOffer:
OWSAssert([message isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]);
[self tappedAddToProfileWhitelistOfferMessage:(OWSAddToProfileWhitelistOfferMessage *)message];
return;
case TSInfoMessageTypeGroupUpdate:
[self showConversationSettings];
return;
@ -2584,7 +2590,7 @@ typedef enum : NSUInteger {
[self presentViewController:actionSheetController animated:YES completion:nil];
}
- (void)tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)errorMessage
- (void)tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)message
{
if (!self.contactsManager.supportsContactEditing) {
DDLogError(@"%@ Contact editing not supported", self.tag);
@ -2603,6 +2609,32 @@ typedef enum : NSUInteger {
editImmediately:YES];
}
- (void)tappedAddToProfileWhitelistOfferMessage:(OWSAddToProfileWhitelistOfferMessage *)message
{
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *leaveAction = [UIAlertAction
actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_VIEW_SHARE_PROFILE",
@"Button to confirm that user wants to share their profile with a user or group.")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
[OWSProfileManager.sharedManager addThreadToProfileWhitelist:self.thread];
[self ensureDynamicInteractions];
}];
[alertController addAction:leaveAction];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil)
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action){
// Do nothing.
}];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)handleCallTap:(TSCall *)call
{
OWSAssert(call);

@ -305,9 +305,7 @@ NS_ASSUME_NONNULL_BEGIN
@"Indicates that user's profile has been shared with a user."))iconName
:@"table_ic_share_profile"];
}
actionBlock:^{
[weakSelf showShareProfileAlert];
}]];
actionBlock:nil]];
} else {
[mainSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
return
@ -801,14 +799,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)shareProfile
{
if (self.isGroupThread) {
TSGroupThread *groupThread = (TSGroupThread *)self.thread;
NSData *groupId = groupThread.groupModel.groupId;
[OWSProfileManager.sharedManager addGroupIdToProfileWhitelist:groupId];
} else {
NSString *recipientId = self.thread.contactIdentifier;
[OWSProfileManager.sharedManager addUserToProfileWhitelist:recipientId];
}
[OWSProfileManager.sharedManager addThreadToProfileWhitelist:self.thread];
[self updateTableContents];
}

@ -8,6 +8,7 @@
#import "TSUnreadIndicatorInteraction.h"
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
#import <SignalServiceKit/OWSAddToContactsOfferMessage.h>
#import <SignalServiceKit/OWSAddToProfileWhitelistOfferMessage.h>
#import <SignalServiceKit/OWSBlockingManager.h>
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
#import <SignalServiceKit/OWSMessageSender.h>
@ -151,6 +152,7 @@ NS_ASSUME_NONNULL_BEGIN
// Find any "dynamic" interactions and safety number changes.
__block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil;
__block OWSAddToProfileWhitelistOfferMessage *existingOWSAddToProfileWhitelistOffer = nil;
__block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil;
__block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil;
NSMutableArray<TSInvalidIdentityKeyErrorMessage *> *blockingSafetyNumberChanges = [NSMutableArray new];
@ -167,6 +169,9 @@ NS_ASSUME_NONNULL_BEGIN
} else if ([object isKindOfClass:[OWSAddToContactsOfferMessage class]]) {
OWSAssert(!existingAddToContactsOffer);
existingAddToContactsOffer = (OWSAddToContactsOfferMessage *)object;
} else if ([object isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]) {
OWSAssert(!existingOWSAddToProfileWhitelistOffer);
existingOWSAddToProfileWhitelistOffer = (OWSAddToProfileWhitelistOfferMessage *)object;
} else if ([object isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
OWSAssert(!existingUnreadIndicator);
existingUnreadIndicator = (TSUnreadIndicatorInteraction *)object;
@ -311,6 +316,7 @@ NS_ASSUME_NONNULL_BEGIN
BOOL shouldHaveBlockOffer = YES;
BOOL shouldHaveAddToContactsOffer = YES;
BOOL shouldHaveAddToProfileWhitelistOffer = YES;
BOOL isContactThread = [thread isKindOfClass:[TSContactThread class]];
if (!isContactThread) {
@ -326,6 +332,8 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveAddToContactsOffer = NO;
// Don't bother to block self.
shouldHaveBlockOffer = NO;
// Don't bother adding self to profile whitelist.
shouldHaveAddToProfileWhitelistOffer = NO;
} else {
if ([[blockingManager blockedPhoneNumbers] containsObject:recipientId]) {
// Only create "add to contacts" offers for users which are not already blocked.
@ -361,7 +369,15 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveBlockOffer = NO;
}
if (![OWSProfileManager.sharedManager hasLocalProfile] ||
[OWSProfileManager.sharedManager isThreadInProfileWhitelist:thread]) {
// Don't show offer if thread is local user hasn't configured their profile.
// Don't show offer if thread is already in profile whitelist.
shouldHaveAddToProfileWhitelistOffer = NO;
}
// We use these offset to control the ordering of the offers and indicators.
const int kAddToProfileWhitelistOfferOffset = -4;
const int kBlockOfferOffset = -3;
const int kAddToContactsOfferOffset = -2;
const int kUnreadIndicatorOfferOffset = -1;
@ -371,7 +387,6 @@ NS_ASSUME_NONNULL_BEGIN
self.tag,
existingBlockOffer.uniqueId,
existingBlockOffer.timestampForSorting);
;
[existingBlockOffer removeWithTransaction:transaction];
} else if (!existingBlockOffer && shouldHaveBlockOffer) {
DDLogInfo(@"Creating block offer for unknown contact");
@ -402,7 +417,7 @@ NS_ASSUME_NONNULL_BEGIN
[existingAddToContactsOffer removeWithTransaction:transaction];
} else if (!existingAddToContactsOffer && shouldHaveAddToContactsOffer) {
DDLogInfo(@"Creating 'add to contacts' offer for unknown contact");
DDLogInfo(@"%@ Creating 'add to contacts' offer for unknown contact", self.tag);
// We want the offer to be the first interaction in their
// conversation's timeline, so we back-date it to slightly before
@ -422,6 +437,32 @@ NS_ASSUME_NONNULL_BEGIN
offerMessage.timestampForSorting);
}
if (existingOWSAddToProfileWhitelistOffer && !shouldHaveAddToProfileWhitelistOffer) {
DDLogInfo(@"%@ Removing 'add to profile whitelist' offer: %@ (%llu)",
self.tag,
existingOWSAddToProfileWhitelistOffer.uniqueId,
existingOWSAddToProfileWhitelistOffer.timestampForSorting);
[existingOWSAddToProfileWhitelistOffer removeWithTransaction:transaction];
} else if (!existingOWSAddToProfileWhitelistOffer && shouldHaveAddToProfileWhitelistOffer) {
DDLogInfo(@"%@ Creating 'add to profile whitelist' offer", self.tag);
// We want the offer to be the first interaction in their
// conversation's timeline, so we back-date it to slightly before
// the first incoming message (which we know is the first message).
uint64_t offerTimestamp
= (uint64_t)((long long)firstMessage.timestampForSorting + kAddToProfileWhitelistOfferOffset);
TSMessage *offerMessage =
[OWSAddToProfileWhitelistOfferMessage addToProfileWhitelistOfferMessage:offerTimestamp thread:thread];
[offerMessage saveWithTransaction:transaction];
DDLogInfo(@"%@ Creating 'add to profile whitelist' offer: %@ (%llu)",
self.tag,
offerMessage.uniqueId,
offerMessage.timestampForSorting);
}
BOOL shouldHaveUnreadIndicator
= (interactionAfterUnreadIndicator && !hideUnreadMessagesIndicator && threadMessageCount > 1);
if (!shouldHaveUnreadIndicator) {

@ -144,6 +144,8 @@ NS_ASSUME_NONNULL_BEGIN
case TSInfoMessageTypeSessionDidEnd:
case TSInfoMessageTypeUnsupportedMessage:
case TSInfoMessageAddToContactsOffer:
case TSInfoMessageAddUserToProfileWhitelistOffer:
case TSInfoMessageAddGroupToProfileWhitelistOffer:
result = [UIImage imageNamed:@"system_message_info"];
break;
case TSInfoMessageTypeGroupUpdate:

@ -16,9 +16,15 @@
/* Title for the 'add group member' view. */
"ADD_GROUP_MEMBER_VIEW_TITLE" = "Add Member";
/* Message shown in conversation view that offers to share your profile with a group. */
"ADD_GROUP_TO_PROFILE_WHITELIST_OFFER" = "Would you like to share your profile with this group?";
/* Message shown in conversation view that offers to add an unknown user to your phone's contacts. */
"ADD_TO_CONTACTS_OFFER" = "Would you like to add this user to your contacts?";
/* Message shown in conversation view that offers to share your profile with a user. */
"ADD_USER_TO_PROFILE_WHITELIST_OFFER" = "Would you like to share your profile with this user?";
/* The label for the 'discard' button in alerts and action sheets. */
"ALERT_DISCARD_BUTTON" = "Discard";
@ -341,10 +347,10 @@
"CONVERSATION_SETTINGS_UNMUTE_ACTION" = "Unmute";
/* Indicates that user's profile has been shared with a group. */
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_GROUP" = "Your profile is shared this group.";
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_GROUP" = "This group can see your profile.";
/* Indicates that user's profile has been shared with a user. */
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_USER" = "Your profile is shared this user.";
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_USER" = "This user can see your profile.";
/* Button to confirm that user wants to share their profile with a user or group. */
"CONVERSATION_SETTINGS_VIEW_SHARE_PROFILE" = "Share Profile";

@ -19,6 +19,8 @@ typedef NS_ENUM(NSInteger, TSInfoMessageType) {
TSInfoMessageTypeDisappearingMessagesUpdate,
TSInfoMessageAddToContactsOffer,
TSInfoMessageVerificationStateChange,
TSInfoMessageAddUserToProfileWhitelistOffer,
TSInfoMessageAddGroupToProfileWhitelistOffer,
};
+ (instancetype)userNotRegisteredMessageInThread:(TSThread *)thread;

@ -95,6 +95,12 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
case TSInfoMessageVerificationStateChange:
return NSLocalizedString(@"VERIFICATION_STATE_CHANGE_GENERIC",
@"Generic message indicating that verification state changed for a given user.");
case TSInfoMessageAddUserToProfileWhitelistOffer:
return NSLocalizedString(@"ADD_USER_TO_PROFILE_WHITELIST_OFFER",
@"Message shown in conversation view that offers to share your profile with a user.");
case TSInfoMessageAddGroupToProfileWhitelistOffer:
return NSLocalizedString(@"ADD_GROUP_TO_PROFILE_WHITELIST_OFFER",
@"Message shown in conversation view that offers to share your profile with a group.");
default:
break;
}

@ -0,0 +1,17 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSInfoMessage.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSAddToProfileWhitelistOfferMessage : TSInfoMessage
+ (instancetype)addToProfileWhitelistOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread;
@property (nonatomic, readonly) NSString *contactId;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,35 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSAddToProfileWhitelistOfferMessage.h"
#import "TSThread.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSAddToProfileWhitelistOfferMessage
+ (instancetype)addToProfileWhitelistOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread
{
return [[OWSAddToProfileWhitelistOfferMessage alloc]
initWithTimestamp:timestamp
inThread:thread
messageType:(thread.isGroupThread ? TSInfoMessageAddGroupToProfileWhitelistOffer
: TSInfoMessageAddUserToProfileWhitelistOffer)];
}
- (BOOL)shouldUseReceiptDateForSorting
{
// Use the timestamp, not the "received at" timestamp to sort,
// since we're creating these interactions after the fact and back-dating them.
return NO;
}
- (BOOL)isDynamicInteraction
{
return YES;
}
@end
NS_ASSUME_NONNULL_END
Loading…
Cancel
Save