Skip to content

Commit 37ce388

Browse files
committed
Add “add to profile whitelist” offer.
// FREEBIE
1 parent 9f6ca3d commit 37ce388

File tree

11 files changed

+173
-21
lines changed

11 files changed

+173
-21
lines changed

Signal/src/Profiles/OWSProfileManager.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ extern NSString *const kNSNotificationName_OtherUsersProfileDidChange;
2424

2525
// These two methods should only be called from the main thread.
2626
- (NSData *)localProfileKey;
27+
- (BOOL)hasLocalProfile;
2728
- (nullable NSString *)localProfileName;
2829
- (nullable UIImage *)localProfileAvatarImage;
2930

@@ -39,16 +40,14 @@ extern NSString *const kNSNotificationName_OtherUsersProfileDidChange;
3940

4041
#pragma mark - Profile Whitelist
4142

42-
- (void)addUserToProfileWhitelist:(NSString *)recipientId;
43+
- (void)addThreadToProfileWhitelist:(TSThread *)thread;
4344

44-
- (BOOL)isUserInProfileWhitelist:(NSString *)recipientId;
45+
- (BOOL)isThreadInProfileWhitelist:(TSThread *)thread;
4546

46-
- (void)addGroupIdToProfileWhitelist:(NSData *)groupId;
47+
- (BOOL)isUserInProfileWhitelist:(NSString *)recipientId;
4748

4849
- (void)setContactRecipientIds:(NSArray<NSString *> *)contactRecipientIds;
4950

50-
- (BOOL)isThreadInProfileWhitelist:(TSThread *)thread;
51-
5251
#pragma mark - Other User's Profiles
5352

5453
- (void)setProfileKey:(NSData *)profileKey forRecipientId:(NSString *)recipientId;

Signal/src/Profiles/OWSProfileManager.m

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ - (NSData *)localProfileKey
254254
return self.localUserProfile.profileKey;
255255
}
256256

257+
- (BOOL)hasLocalProfile
258+
{
259+
OWSAssert([NSThread isMainThread]);
260+
261+
return (self.localProfileName.length > 0 || self.localProfileAvatarImage != nil);
262+
}
263+
257264
- (nullable NSString *)localProfileName
258265
{
259266
OWSAssert([NSThread isMainThread]);
@@ -489,6 +496,20 @@ - (void)addGroupIdToProfileWhitelist:(NSData *)groupId
489496
self.groupProfileWhitelistCache[groupIdKey] = @(YES);
490497
}
491498

499+
- (void)addThreadToProfileWhitelist:(TSThread *)thread
500+
{
501+
OWSAssert(thread);
502+
503+
if (thread.isGroupThread) {
504+
TSGroupThread *groupThread = (TSGroupThread *)thread;
505+
NSData *groupId = groupThread.groupModel.groupId;
506+
[self addGroupIdToProfileWhitelist:groupId];
507+
} else {
508+
NSString *recipientId = thread.contactIdentifier;
509+
[self addUserToProfileWhitelist:recipientId];
510+
}
511+
}
512+
492513
- (BOOL)isGroupIdInProfileWhitelist:(NSData *)groupId
493514
{
494515
OWSAssert(groupId.length > 0);

Signal/src/ViewControllers/ConversationView/MessagesViewController.m

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
#import <SignalServiceKit/NSDate+OWS.h>
7171
#import <SignalServiceKit/NSTimer+OWS.h>
7272
#import <SignalServiceKit/OWSAddToContactsOfferMessage.h>
73+
#import <SignalServiceKit/OWSAddToProfileWhitelistOfferMessage.h>
7374
#import <SignalServiceKit/OWSAttachmentsProcessor.h>
7475
#import <SignalServiceKit/OWSBlockingManager.h>
7576
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
@@ -2457,6 +2458,11 @@ - (void)handleInfoMessageTap:(TSInfoMessage *)message
24572458
OWSAssert([message isKindOfClass:[OWSAddToContactsOfferMessage class]]);
24582459
[self tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)message];
24592460
return;
2461+
case TSInfoMessageAddUserToProfileWhitelistOffer:
2462+
case TSInfoMessageAddGroupToProfileWhitelistOffer:
2463+
OWSAssert([message isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]);
2464+
[self tappedAddToProfileWhitelistOfferMessage:(OWSAddToProfileWhitelistOfferMessage *)message];
2465+
return;
24602466
case TSInfoMessageTypeGroupUpdate:
24612467
[self showConversationSettings];
24622468
return;
@@ -2584,7 +2590,7 @@ - (void)tappedUnknownContactBlockOfferMessage:(OWSUnknownContactBlockOfferMessag
25842590
[self presentViewController:actionSheetController animated:YES completion:nil];
25852591
}
25862592

2587-
- (void)tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)errorMessage
2593+
- (void)tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)message
25882594
{
25892595
if (!self.contactsManager.supportsContactEditing) {
25902596
DDLogError(@"%@ Contact editing not supported", self.tag);
@@ -2603,6 +2609,32 @@ - (void)tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)errorMes
26032609
editImmediately:YES];
26042610
}
26052611

2612+
- (void)tappedAddToProfileWhitelistOfferMessage:(OWSAddToProfileWhitelistOfferMessage *)message
2613+
{
2614+
UIAlertController *alertController =
2615+
[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
2616+
2617+
UIAlertAction *leaveAction = [UIAlertAction
2618+
actionWithTitle:NSLocalizedString(@"CONVERSATION_SETTINGS_VIEW_SHARE_PROFILE",
2619+
@"Button to confirm that user wants to share their profile with a user or group.")
2620+
style:UIAlertActionStyleDestructive
2621+
handler:^(UIAlertAction *_Nonnull action) {
2622+
[OWSProfileManager.sharedManager addThreadToProfileWhitelist:self.thread];
2623+
2624+
[self ensureDynamicInteractions];
2625+
}];
2626+
[alertController addAction:leaveAction];
2627+
2628+
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil)
2629+
style:UIAlertActionStyleCancel
2630+
handler:^(UIAlertAction *_Nonnull action){
2631+
// Do nothing.
2632+
}];
2633+
[alertController addAction:cancelAction];
2634+
2635+
[self presentViewController:alertController animated:YES completion:nil];
2636+
}
2637+
26062638
- (void)handleCallTap:(TSCall *)call
26072639
{
26082640
OWSAssert(call);

Signal/src/ViewControllers/OWSConversationSettingsViewController.m

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,7 @@ - (void)updateTableContents
305305
@"Indicates that user's profile has been shared with a user."))iconName
306306
:@"table_ic_share_profile"];
307307
}
308-
actionBlock:^{
309-
[weakSelf showShareProfileAlert];
310-
}]];
308+
actionBlock:nil]];
311309
} else {
312310
[mainSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
313311
return
@@ -801,14 +799,7 @@ - (void)showShareProfileAlert
801799

802800
- (void)shareProfile
803801
{
804-
if (self.isGroupThread) {
805-
TSGroupThread *groupThread = (TSGroupThread *)self.thread;
806-
NSData *groupId = groupThread.groupModel.groupId;
807-
[OWSProfileManager.sharedManager addGroupIdToProfileWhitelist:groupId];
808-
} else {
809-
NSString *recipientId = self.thread.contactIdentifier;
810-
[OWSProfileManager.sharedManager addUserToProfileWhitelist:recipientId];
811-
}
802+
[OWSProfileManager.sharedManager addThreadToProfileWhitelist:self.thread];
812803

813804
[self updateTableContents];
814805
}

Signal/src/util/ThreadUtil.m

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#import "TSUnreadIndicatorInteraction.h"
99
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
1010
#import <SignalServiceKit/OWSAddToContactsOfferMessage.h>
11+
#import <SignalServiceKit/OWSAddToProfileWhitelistOfferMessage.h>
1112
#import <SignalServiceKit/OWSBlockingManager.h>
1213
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
1314
#import <SignalServiceKit/OWSMessageSender.h>
@@ -151,6 +152,7 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
151152

152153
// Find any "dynamic" interactions and safety number changes.
153154
__block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil;
155+
__block OWSAddToProfileWhitelistOfferMessage *existingOWSAddToProfileWhitelistOffer = nil;
154156
__block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil;
155157
__block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil;
156158
NSMutableArray<TSInvalidIdentityKeyErrorMessage *> *blockingSafetyNumberChanges = [NSMutableArray new];
@@ -167,6 +169,9 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
167169
} else if ([object isKindOfClass:[OWSAddToContactsOfferMessage class]]) {
168170
OWSAssert(!existingAddToContactsOffer);
169171
existingAddToContactsOffer = (OWSAddToContactsOfferMessage *)object;
172+
} else if ([object isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]) {
173+
OWSAssert(!existingOWSAddToProfileWhitelistOffer);
174+
existingOWSAddToProfileWhitelistOffer = (OWSAddToProfileWhitelistOfferMessage *)object;
170175
} else if ([object isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
171176
OWSAssert(!existingUnreadIndicator);
172177
existingUnreadIndicator = (TSUnreadIndicatorInteraction *)object;
@@ -311,6 +316,7 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
311316

312317
BOOL shouldHaveBlockOffer = YES;
313318
BOOL shouldHaveAddToContactsOffer = YES;
319+
BOOL shouldHaveAddToProfileWhitelistOffer = YES;
314320

315321
BOOL isContactThread = [thread isKindOfClass:[TSContactThread class]];
316322
if (!isContactThread) {
@@ -326,6 +332,8 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
326332
shouldHaveAddToContactsOffer = NO;
327333
// Don't bother to block self.
328334
shouldHaveBlockOffer = NO;
335+
// Don't bother adding self to profile whitelist.
336+
shouldHaveAddToProfileWhitelistOffer = NO;
329337
} else {
330338
if ([[blockingManager blockedPhoneNumbers] containsObject:recipientId]) {
331339
// Only create "add to contacts" offers for users which are not already blocked.
@@ -361,7 +369,15 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
361369
shouldHaveBlockOffer = NO;
362370
}
363371

372+
if (![OWSProfileManager.sharedManager hasLocalProfile] ||
373+
[OWSProfileManager.sharedManager isThreadInProfileWhitelist:thread]) {
374+
// Don't show offer if thread is local user hasn't configured their profile.
375+
// Don't show offer if thread is already in profile whitelist.
376+
shouldHaveAddToProfileWhitelistOffer = NO;
377+
}
378+
364379
// We use these offset to control the ordering of the offers and indicators.
380+
const int kAddToProfileWhitelistOfferOffset = -4;
365381
const int kBlockOfferOffset = -3;
366382
const int kAddToContactsOfferOffset = -2;
367383
const int kUnreadIndicatorOfferOffset = -1;
@@ -371,7 +387,6 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
371387
self.tag,
372388
existingBlockOffer.uniqueId,
373389
existingBlockOffer.timestampForSorting);
374-
;
375390
[existingBlockOffer removeWithTransaction:transaction];
376391
} else if (!existingBlockOffer && shouldHaveBlockOffer) {
377392
DDLogInfo(@"Creating block offer for unknown contact");
@@ -402,7 +417,7 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
402417
[existingAddToContactsOffer removeWithTransaction:transaction];
403418
} else if (!existingAddToContactsOffer && shouldHaveAddToContactsOffer) {
404419

405-
DDLogInfo(@"Creating 'add to contacts' offer for unknown contact");
420+
DDLogInfo(@"%@ Creating 'add to contacts' offer for unknown contact", self.tag);
406421

407422
// We want the offer to be the first interaction in their
408423
// conversation's timeline, so we back-date it to slightly before
@@ -422,6 +437,32 @@ + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)th
422437
offerMessage.timestampForSorting);
423438
}
424439

440+
if (existingOWSAddToProfileWhitelistOffer && !shouldHaveAddToProfileWhitelistOffer) {
441+
DDLogInfo(@"%@ Removing 'add to profile whitelist' offer: %@ (%llu)",
442+
self.tag,
443+
existingOWSAddToProfileWhitelistOffer.uniqueId,
444+
existingOWSAddToProfileWhitelistOffer.timestampForSorting);
445+
[existingOWSAddToProfileWhitelistOffer removeWithTransaction:transaction];
446+
} else if (!existingOWSAddToProfileWhitelistOffer && shouldHaveAddToProfileWhitelistOffer) {
447+
448+
DDLogInfo(@"%@ Creating 'add to profile whitelist' offer", self.tag);
449+
450+
// We want the offer to be the first interaction in their
451+
// conversation's timeline, so we back-date it to slightly before
452+
// the first incoming message (which we know is the first message).
453+
uint64_t offerTimestamp
454+
= (uint64_t)((long long)firstMessage.timestampForSorting + kAddToProfileWhitelistOfferOffset);
455+
456+
TSMessage *offerMessage =
457+
[OWSAddToProfileWhitelistOfferMessage addToProfileWhitelistOfferMessage:offerTimestamp thread:thread];
458+
[offerMessage saveWithTransaction:transaction];
459+
460+
DDLogInfo(@"%@ Creating 'add to profile whitelist' offer: %@ (%llu)",
461+
self.tag,
462+
offerMessage.uniqueId,
463+
offerMessage.timestampForSorting);
464+
}
465+
425466
BOOL shouldHaveUnreadIndicator
426467
= (interactionAfterUnreadIndicator && !hideUnreadMessagesIndicator && threadMessageCount > 1);
427468
if (!shouldHaveUnreadIndicator) {

Signal/src/views/OWSSystemMessageCell.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ - (UIImage *)iconForInteraction:(TSInteraction *)interaction
144144
case TSInfoMessageTypeSessionDidEnd:
145145
case TSInfoMessageTypeUnsupportedMessage:
146146
case TSInfoMessageAddToContactsOffer:
147+
case TSInfoMessageAddUserToProfileWhitelistOffer:
148+
case TSInfoMessageAddGroupToProfileWhitelistOffer:
147149
result = [UIImage imageNamed:@"system_message_info"];
148150
break;
149151
case TSInfoMessageTypeGroupUpdate:

Signal/translations/en.lproj/Localizable.strings

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@
1616
/* Title for the 'add group member' view. */
1717
"ADD_GROUP_MEMBER_VIEW_TITLE" = "Add Member";
1818

19+
/* Message shown in conversation view that offers to share your profile with a group. */
20+
"ADD_GROUP_TO_PROFILE_WHITELIST_OFFER" = "Would you like to share your profile with this group?";
21+
1922
/* Message shown in conversation view that offers to add an unknown user to your phone's contacts. */
2023
"ADD_TO_CONTACTS_OFFER" = "Would you like to add this user to your contacts?";
2124

25+
/* Message shown in conversation view that offers to share your profile with a user. */
26+
"ADD_USER_TO_PROFILE_WHITELIST_OFFER" = "Would you like to share your profile with this user?";
27+
2228
/* The label for the 'discard' button in alerts and action sheets. */
2329
"ALERT_DISCARD_BUTTON" = "Discard";
2430

@@ -341,10 +347,10 @@
341347
"CONVERSATION_SETTINGS_UNMUTE_ACTION" = "Unmute";
342348

343349
/* Indicates that user's profile has been shared with a group. */
344-
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_GROUP" = "Your profile is shared this group.";
350+
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_GROUP" = "This group can see your profile.";
345351

346352
/* Indicates that user's profile has been shared with a user. */
347-
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_USER" = "Your profile is shared this user.";
353+
"CONVERSATION_SETTINGS_VIEW_PROFILE_IS_SHARED_WITH_USER" = "This user can see your profile.";
348354

349355
/* Button to confirm that user wants to share their profile with a user or group. */
350356
"CONVERSATION_SETTINGS_VIEW_SHARE_PROFILE" = "Share Profile";

SignalServiceKit/src/Messages/Interactions/TSInfoMessage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ typedef NS_ENUM(NSInteger, TSInfoMessageType) {
1919
TSInfoMessageTypeDisappearingMessagesUpdate,
2020
TSInfoMessageAddToContactsOffer,
2121
TSInfoMessageVerificationStateChange,
22+
TSInfoMessageAddUserToProfileWhitelistOffer,
23+
TSInfoMessageAddGroupToProfileWhitelistOffer,
2224
};
2325

2426
+ (instancetype)userNotRegisteredMessageInThread:(TSThread *)thread;

SignalServiceKit/src/Messages/Interactions/TSInfoMessage.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ - (NSString *)description {
9595
case TSInfoMessageVerificationStateChange:
9696
return NSLocalizedString(@"VERIFICATION_STATE_CHANGE_GENERIC",
9797
@"Generic message indicating that verification state changed for a given user.");
98+
case TSInfoMessageAddUserToProfileWhitelistOffer:
99+
return NSLocalizedString(@"ADD_USER_TO_PROFILE_WHITELIST_OFFER",
100+
@"Message shown in conversation view that offers to share your profile with a user.");
101+
case TSInfoMessageAddGroupToProfileWhitelistOffer:
102+
return NSLocalizedString(@"ADD_GROUP_TO_PROFILE_WHITELIST_OFFER",
103+
@"Message shown in conversation view that offers to share your profile with a group.");
98104
default:
99105
break;
100106
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
3+
//
4+
5+
#import "TSInfoMessage.h"
6+
7+
NS_ASSUME_NONNULL_BEGIN
8+
9+
@interface OWSAddToProfileWhitelistOfferMessage : TSInfoMessage
10+
11+
+ (instancetype)addToProfileWhitelistOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread;
12+
13+
@property (nonatomic, readonly) NSString *contactId;
14+
15+
@end
16+
17+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)