Rework the contact offers.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 5f2f8ec6d8
commit 98eb4693c5

@ -177,7 +177,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
// we need to bump this constant.
//
// We added a number of database views in v2.13.0.
NSString *kLastVersionWithDatabaseViewChange = @"2.16.0";
NSString *kLastVersionWithDatabaseViewChange = @"2.13.0";
BOOL mayNeedUpgrade = ([TSAccountManager isRegistered] && lastLaunchedAppVersion
&& (!lastCompletedLaunchAppVersion ||
[VersionMigrations isVersion:lastCompletedLaunchAppVersion

@ -8,17 +8,19 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSContactOffersInteraction : TSInteraction
//@property (atomic, readonly) BOOL hasMoreUnseenMessages;
//
//@property (atomic, readonly) NSUInteger missingUnseenSafetyNumberChangeCount;
@property (nonatomic, readonly) BOOL hasBlockOffer;
@property (nonatomic, readonly) BOOL hasAddToContactsOffer;
@property (nonatomic, readonly) BOOL hasAddToProfileWhitelistOffer;
@property (nonatomic, readonly) NSString *contactId;
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTimestamp:(uint64_t)timestamp
thread:(TSThread *)thread
// hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
// missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
NS_DESIGNATED_INITIALIZER;
hasBlockOffer:(BOOL)hasBlockOffer
hasAddToContactsOffer:(BOOL)hasAddToContactsOffer
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
contactId:(NSString *)contactId NS_DESIGNATED_INITIALIZER;
@end

@ -6,14 +6,6 @@
NS_ASSUME_NONNULL_BEGIN
@interface OWSContactOffersInteraction ()
//@property (atomic) BOOL hasMoreUnseenMessages;
@end
#pragma mark -
@implementation OWSContactOffersInteraction
- (instancetype)initWithCoder:(NSCoder *)coder
@ -21,9 +13,12 @@ NS_ASSUME_NONNULL_BEGIN
return [super initWithCoder:coder];
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread
// hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
// missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
- (instancetype)initWithTimestamp:(uint64_t)timestamp
thread:(TSThread *)thread
hasBlockOffer:(BOOL)hasBlockOffer
hasAddToContactsOffer:(BOOL)hasAddToContactsOffer
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
contactId:(NSString *)contactId
{
self = [super initWithTimestamp:timestamp inThread:thread];
@ -31,8 +26,11 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
// _hasMoreUnseenMessages = hasMoreUnseenMessages;
// _missingUnseenSafetyNumberChangeCount = missingUnseenSafetyNumberChangeCount;
_hasBlockOffer = hasBlockOffer;
_hasAddToContactsOffer = hasAddToContactsOffer;
_hasAddToProfileWhitelistOffer = hasAddToProfileWhitelistOffer;
OWSAssert(contactId.length > 0);
_contactId = contactId;
return self;
}

@ -158,8 +158,8 @@ NS_ASSUME_NONNULL_BEGIN
return [cachedSize CGSizeValue];
}
CGSize result = [self.referenceContactOffersCell bubbleSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
CGSize result = [self.referenceUnreadIndicatorCell bubbleSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
[self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey];
@ -178,8 +178,8 @@ NS_ASSUME_NONNULL_BEGIN
return [cachedSize CGSizeValue];
}
CGSize result = [self.referenceUnreadIndicatorCell bubbleSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
CGSize result = [self.referenceContactOffersCell bubbleSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
[self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey];

@ -153,10 +153,9 @@ NS_ASSUME_NONNULL_BEGIN
const int kMaxBlockOfferOutgoingMessageCount = 10;
// Find any "dynamic" interactions and safety number changes.
__block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil;
__block OWSAddToProfileWhitelistOfferMessage *existingOWSAddToProfileWhitelistOffer = nil;
__block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil;
NSMutableArray<TSInteraction *> *interactionsToDelete = [NSMutableArray new];
__block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil;
__block OWSContactOffersInteraction *existingContactOffers = nil;
NSMutableArray<TSInvalidIdentityKeyErrorMessage *> *blockingSafetyNumberChanges = [NSMutableArray new];
NSMutableArray<TSInteraction *> *nonBlockingSafetyNumberChanges = [NSMutableArray new];
// We use different views for performance reasons.
@ -166,17 +165,27 @@ NS_ASSUME_NONNULL_BEGIN
NSString *collection, NSString *key, id object, id metadata, NSUInteger index, BOOL *stop) {
if ([object isKindOfClass:[OWSUnknownContactBlockOfferMessage class]]) {
OWSAssert(!existingBlockOffer);
existingBlockOffer = (OWSUnknownContactBlockOfferMessage *)object;
[interactionsToDelete addObject:object];
} else if ([object isKindOfClass:[OWSAddToContactsOfferMessage class]]) {
OWSAssert(!existingAddToContactsOffer);
existingAddToContactsOffer = (OWSAddToContactsOfferMessage *)object;
[interactionsToDelete addObject:object];
} else if ([object isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]) {
OWSAssert(!existingOWSAddToProfileWhitelistOffer);
existingOWSAddToProfileWhitelistOffer = (OWSAddToProfileWhitelistOfferMessage *)object;
[interactionsToDelete addObject:object];
} else if ([object isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
OWSAssert(!existingUnreadIndicator);
if (existingUnreadIndicator) {
// There should never be more than one unread indicator in
// a given thread, but if there is, discard all but one.
[interactionsToDelete addObject:existingUnreadIndicator];
}
existingUnreadIndicator = (TSUnreadIndicatorInteraction *)object;
} else if ([object isKindOfClass:[OWSContactOffersInteraction class]]) {
OWSAssert(!existingContactOffers);
if (existingContactOffers) {
// There should never be more than one "contact offers" in
// a given thread, but if there is, discard all but one.
[interactionsToDelete addObject:existingContactOffers];
}
existingContactOffers = (OWSContactOffersInteraction *)object;
} else if ([object isKindOfClass:[TSInvalidIdentityKeyErrorMessage class]]) {
[blockingSafetyNumberChanges addObject:object];
} else if ([object isKindOfClass:[TSErrorMessage class]]) {
@ -189,6 +198,11 @@ NS_ASSUME_NONNULL_BEGIN
}
}];
for (TSInteraction *interaction in interactionsToDelete) {
DDLogDebug(@"Cleaning up interaction: %@", [interaction class]);
[interaction removeWithTransaction:transaction];
}
// Determine if there are "unread" messages in this conversation.
// If we've been passed a firstUnseenInteractionTimestampParameter,
// just use that value in order to preserve continuity of the
@ -326,6 +340,8 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveAddToContactsOffer = NO;
// Only create block offers in 1:1 conversations.
shouldHaveBlockOffer = NO;
// Only create profile whitelist offers in 1:1 conversations.
shouldHaveAddToProfileWhitelistOffer = NO;
} else {
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
@ -352,6 +368,8 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveAddToContactsOffer = NO;
// Only create block offers for non-contacts.
shouldHaveBlockOffer = NO;
// Don't create profile whitelist offers for non-contacts.
shouldHaveAddToProfileWhitelistOffer = NO;
}
}
}
@ -359,6 +377,7 @@ NS_ASSUME_NONNULL_BEGIN
if (!firstMessage) {
shouldHaveAddToContactsOffer = NO;
shouldHaveBlockOffer = NO;
shouldHaveAddToProfileWhitelistOffer = NO;
}
if (outgoingMessageCount > kMaxBlockOfferOutgoingMessageCount) {
@ -393,11 +412,12 @@ NS_ASSUME_NONNULL_BEGIN
}
}
BOOL shouldHaveContactOffers
= (shouldHaveBlockOffer || shouldHaveAddToContactsOffer || shouldHaveAddToProfileWhitelistOffer);
// 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;
const int kUnreadIndicatorOffset = -2;
const int kContactOffersOffset = -1;
// We want the offers to be the first interactions in their
// conversation's timeline, so we back-date them to slightly before
@ -406,74 +426,48 @@ NS_ASSUME_NONNULL_BEGIN
long long startOfConversationTimestamp
= (long long)(firstMessage ? firstMessage.timestampForSorting : 1000);
if (existingBlockOffer && !shouldHaveBlockOffer) {
DDLogInfo(@"%@ Removing block offer: %@ (%llu)",
self.tag,
existingBlockOffer.uniqueId,
existingBlockOffer.timestampForSorting);
[existingBlockOffer removeWithTransaction:transaction];
} else if (!existingBlockOffer && shouldHaveBlockOffer) {
DDLogInfo(@"Creating block offer for unknown contact");
uint64_t blockOfferTimestamp = (uint64_t)(startOfConversationTimestamp + kBlockOfferOffset);
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
TSMessage *offerMessage =
[OWSUnknownContactBlockOfferMessage unknownContactBlockOfferMessage:blockOfferTimestamp
thread:thread
contactId:recipientId];
[offerMessage saveWithTransaction:transaction];
uint64_t contactOffersTimestamp = (uint64_t)(startOfConversationTimestamp + kContactOffersOffset);
DDLogInfo(@"%@ Creating block offer: %@ (%llu)",
self.tag,
offerMessage.uniqueId,
offerMessage.timestampForSorting);
// If the contact offers' properties have changed, discard the current
// one and create a new one.
if (existingContactOffers) {
if (existingContactOffers.hasBlockOffer != shouldHaveBlockOffer
|| existingContactOffers.hasAddToContactsOffer != shouldHaveAddToContactsOffer
|| existingContactOffers.hasAddToProfileWhitelistOffer != shouldHaveAddToProfileWhitelistOffer) {
DDLogInfo(@"%@ Removing stale contact offers: %@ (%llu)",
self.tag,
existingContactOffers.uniqueId,
existingContactOffers.timestampForSorting);
// Preserve the timestamp of the existing "contact offers" so that
// we replace it in the same position in the timeline.
contactOffersTimestamp = existingContactOffers.timestamp;
[existingContactOffers removeWithTransaction:transaction];
existingContactOffers = nil;
}
}
if (existingAddToContactsOffer && !shouldHaveAddToContactsOffer) {
DDLogInfo(@"%@ Removing 'add to contacts' offer: %@ (%llu)",
if (existingContactOffers && !shouldHaveContactOffers) {
DDLogInfo(@"%@ Removing contact offers: %@ (%llu)",
self.tag,
existingAddToContactsOffer.uniqueId,
existingAddToContactsOffer.timestampForSorting);
[existingAddToContactsOffer removeWithTransaction:transaction];
} else if (!existingAddToContactsOffer && shouldHaveAddToContactsOffer) {
DDLogInfo(@"%@ Creating 'add to contacts' offer for unknown contact", self.tag);
uint64_t offerTimestamp = (uint64_t)(startOfConversationTimestamp + kAddToContactsOfferOffset);
existingContactOffers.uniqueId,
existingContactOffers.timestampForSorting);
[existingContactOffers removeWithTransaction:transaction];
} else if (!existingContactOffers && shouldHaveContactOffers) {
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
TSMessage *offerMessage = [OWSAddToContactsOfferMessage addToContactsOfferMessage:offerTimestamp
thread:thread
contactId:recipientId];
[offerMessage saveWithTransaction:transaction];
DDLogInfo(@"%@ Creating 'add to contacts' offer: %@ (%llu)",
self.tag,
offerMessage.uniqueId,
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);
uint64_t offerTimestamp = (uint64_t)(startOfConversationTimestamp + kAddToProfileWhitelistOfferOffset);
TSMessage *offerMessage =
[OWSAddToProfileWhitelistOfferMessage addToProfileWhitelistOfferMessage:offerTimestamp thread:thread];
[offerMessage saveWithTransaction:transaction];
TSInteraction *offersMessage =
[[OWSContactOffersInteraction alloc] initWithTimestamp:contactOffersTimestamp
thread:thread
hasBlockOffer:shouldHaveBlockOffer
hasAddToContactsOffer:shouldHaveAddToContactsOffer
hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer
contactId:recipientId];
[offersMessage saveWithTransaction:transaction];
DDLogInfo(@"%@ Creating 'add to profile whitelist' offer: %@ (%llu)",
DDLogInfo(@"%@ Creating contact offers: %@ (%llu)",
self.tag,
offerMessage.uniqueId,
offerMessage.timestampForSorting);
offersMessage.uniqueId,
offersMessage.timestampForSorting);
}
BOOL shouldHaveUnreadIndicator
@ -490,8 +484,8 @@ NS_ASSUME_NONNULL_BEGIN
// message in the conversation timeline...
//
// ...unless we have a fixed timestamp for the unread indicator.
uint64_t indicatorTimestamp = (uint64_t)(
(long long)interactionAfterUnreadIndicator.timestampForSorting + kUnreadIndicatorOfferOffset);
uint64_t indicatorTimestamp
= (uint64_t)((long long)interactionAfterUnreadIndicator.timestampForSorting + kUnreadIndicatorOffset);
if (indicatorTimestamp && existingUnreadIndicator.timestampForSorting == indicatorTimestamp) {
// Keep the existing indicator; it is in the correct position.

@ -115,20 +115,24 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)subtitleForInteraction:(OWSContactOffersInteraction *)interaction
{
if (!interaction.hasMoreUnseenMessages) {
return nil;
}
NSString *subtitleFormat = (interaction.missingUnseenSafetyNumberChangeCount > 0
? NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_FORMAT",
@"Messages that indicates that there are more unseen messages that be revealed by tapping the 'load "
@"earlier messages' button. Embeds {{the name of the 'load earlier messages' button}}")
: NSLocalizedString(
@"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_AND_SAFETY_NUMBER_CHANGES_FORMAT",
@"Messages that indicates that there are more unseen messages including safety number changes that "
@"be revealed by tapping the 'load earlier messages' button. Embeds {{the name of the 'load earlier "
@"messages' button}}."));
NSString *loadMoreButtonName = [NSBundle jsq_localizedStringForKey:@"load_earlier_messages"];
return [NSString stringWithFormat:subtitleFormat, loadMoreButtonName];
return nil;
// if (!interaction.hasMoreUnseenMessages) {
// return nil;
// }
// NSString *subtitleFormat = (interaction.missingUnseenSafetyNumberChangeCount > 0
// ? NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_FORMAT",
// @"Messages that indicates that there are more unseen messages that be revealed by tapping the
// 'load "
// @"earlier messages' button. Embeds {{the name of the 'load earlier messages' button}}")
// : NSLocalizedString(
// @"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_AND_SAFETY_NUMBER_CHANGES_FORMAT",
// @"Messages that indicates that there are more unseen messages including safety number changes
// that "
// @"be revealed by tapping the 'load earlier messages' button. Embeds {{the name of the 'load
// earlier "
// @"messages' button}}."));
// NSString *loadMoreButtonName = [NSBundle jsq_localizedStringForKey:@"load_earlier_messages"];
// return [NSString stringWithFormat:subtitleFormat, loadMoreButtonName];
}
- (CGFloat)subtitleHMargin

@ -144,7 +144,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
[self registerMessageDatabaseViewWithName:TSUnseenDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"2"
version:@"1"
async:YES];
}

Loading…
Cancel
Save