diff --git a/src/Contacts/TSThread.m b/src/Contacts/TSThread.m index 6ac555148..d8032a807 100644 --- a/src/Contacts/TSThread.m +++ b/src/Contacts/TSThread.m @@ -199,6 +199,8 @@ NS_ASSUME_NONNULL_BEGIN if (![object conformsToProtocol:@protocol(OWSReadTracking)]) { DDLogError(@"%@ Unexpected object in unseen messages: %@", self.tag, object); + OWSFail(@"Unexpected object in unseen messages."); + return; } [messages addObject:(id)object]; }]; diff --git a/src/Messages/Interactions/TSInteraction.h b/src/Messages/Interactions/TSInteraction.h index cc1bdc00e..2599e6330 100644 --- a/src/Messages/Interactions/TSInteraction.h +++ b/src/Messages/Interactions/TSInteraction.h @@ -32,10 +32,9 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)interactionForTimestamp:(uint64_t)timestamp withTransaction:(YapDatabaseReadWriteTransaction *)transaction; -// NSDate has second precision, uint64_t timestamps have millisecond precision -// so prefer timestampForSorting over dateForSorting. - (NSDate *)dateForSorting; - (uint64_t)timestampForSorting; +- (NSComparisonResult)compareForSorting:(TSInteraction *)other; // "Dynamic" interactions are not messages or static events (like // info messages, error messages, etc.). They are interactions diff --git a/src/Messages/Interactions/TSInteraction.m b/src/Messages/Interactions/TSInteraction.m index 6aee59449..1d72ffdd6 100644 --- a/src/Messages/Interactions/TSInteraction.m +++ b/src/Messages/Interactions/TSInteraction.m @@ -93,6 +93,22 @@ NS_ASSUME_NONNULL_BEGIN return self.timestamp; } +- (NSComparisonResult)compareForSorting:(TSInteraction *)other +{ + OWSAssert(other); + + uint64_t timestamp1 = self.timestampForSorting; + uint64_t timestamp2 = other.timestampForSorting; + + if (timestamp1 > timestamp2) { + return NSOrderedDescending; + } else if (timestamp1 < timestamp2) { + return NSOrderedAscending; + } else { + return NSOrderedSame; + } +} + - (NSString *)description { return @"Interaction description"; } diff --git a/src/Messages/Interactions/TSMessage.m b/src/Messages/Interactions/TSMessage.m index b5c8b9552..10433e6b1 100644 --- a/src/Messages/Interactions/TSMessage.m +++ b/src/Messages/Interactions/TSMessage.m @@ -111,12 +111,7 @@ static const NSUInteger OWSMessageSchemaVersion = 3; _expiresInSeconds = expiresInSeconds; _expireStartedAt = expireStartedAt; [self updateExpiresAt]; - - if ([self shouldUseReceiptDateForSorting]) { - _receivedAtTimestamp = self.timestamp; - } else { - _receivedAtTimestamp = [NSDate ows_millisecondTimeStamp]; - } + _receivedAtTimestamp = [NSDate ows_millisecondTimeStamp]; return self; } @@ -157,10 +152,6 @@ static const NSUInteger OWSMessageSchemaVersion = 3; } } - if ([self shouldUseReceiptDateForSorting]) { - _receivedAtTimestamp = self.timestamp; - } - _schemaVersion = OWSMessageSchemaVersion; return self; diff --git a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m index ec5f65df5..0274fb662 100644 --- a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m +++ b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m @@ -25,11 +25,6 @@ NS_ASSUME_NONNULL_BEGIN return nil; } -- (BOOL)isDynamicInteraction -{ - return YES; -} - @end NS_ASSUME_NONNULL_END diff --git a/src/Storage/TSDatabaseView.h b/src/Storage/TSDatabaseView.h index 3f614fd54..f8f5268bc 100644 --- a/src/Storage/TSDatabaseView.h +++ b/src/Storage/TSDatabaseView.h @@ -17,19 +17,24 @@ extern NSString *TSMessageDatabaseViewExtensionName; extern NSString *TSUnreadDatabaseViewExtensionName; extern NSString *TSUnseenDatabaseViewExtensionName; extern NSString *TSDynamicMessagesDatabaseViewExtensionName; +extern NSString *TSSafetyNumberChangeDatabaseViewExtensionName; extern NSString *TSSecondaryDevicesDatabaseViewExtensionName; + (BOOL)registerThreadDatabaseView; + (BOOL)registerThreadInteractionsDatabaseView; + // Instances of OWSReadTracking for wasRead is NO and shouldAffectUnreadCounts is YES. // // Should be used for "unread message counts". + (BOOL)registerUnreadDatabaseView; + // Should be used for "unread indicator". // // Instances of OWSReadTracking for wasRead is NO. + (BOOL)registerUnseenDatabaseView; + + (BOOL)registerDynamicMessagesDatabaseView; ++ (BOOL)registerSafetyNumberChangeDatabaseView; + (void)asyncRegisterSecondaryDevicesDatabaseView; @end diff --git a/src/Storage/TSDatabaseView.m b/src/Storage/TSDatabaseView.m index f6f31acd2..68f7f321f 100644 --- a/src/Storage/TSDatabaseView.m +++ b/src/Storage/TSDatabaseView.m @@ -6,6 +6,7 @@ #import "OWSDevice.h" #import "OWSReadTracking.h" #import "TSIncomingMessage.h" +#import "TSInvalidIdentityKeyErrorMessage.h" #import "TSOutgoingMessage.h" #import "TSStorageManager.h" #import "TSThread.h" @@ -22,6 +23,7 @@ NSString *TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionN NSString *TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName"; NSString *TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName"; NSString *TSDynamicMessagesDatabaseViewExtensionName = @"TSDynamicMessagesDatabaseViewExtensionName"; +NSString *TSSafetyNumberChangeDatabaseViewExtensionName = @"TSSafetyNumberChangeDatabaseViewExtensionName"; NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName"; @implementation TSDatabaseView @@ -104,7 +106,27 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData return [self registerMessageDatabaseViewWithName:TSDynamicMessagesDatabaseViewExtensionName viewGrouping:viewGrouping - version:@"2"]; + version:@"3"]; +} + ++ (BOOL)registerSafetyNumberChangeDatabaseView +{ + YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( + YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { + if ([object isKindOfClass:[TSInvalidIdentityKeyErrorMessage class]]) { + TSInteraction *interaction = (TSInteraction *)object; + if ([interaction isDynamicInteraction]) { + return interaction.uniqueThreadId; + } + } else { + OWSAssert(0); + } + return nil; + }]; + + return [self registerMessageDatabaseViewWithName:TSSafetyNumberChangeDatabaseViewExtensionName + viewGrouping:viewGrouping + version:@"1"]; } + (BOOL)registerThreadInteractionsDatabaseView @@ -218,16 +240,7 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData TSInteraction *message1 = (TSInteraction *)object1; TSInteraction *message2 = (TSInteraction *)object2; - uint64_t timestamp1 = message1.timestampForSorting; - uint64_t timestamp2 = message2.timestampForSorting; - - if (timestamp1 > timestamp2) { - return NSOrderedDescending; - } else if (timestamp1 < timestamp2) { - return NSOrderedAscending; - } else { - return NSOrderedSame; - } + return [message1 compareForSorting:message2]; } return NSOrderedSame; diff --git a/src/Storage/TSStorageManager.m b/src/Storage/TSStorageManager.m index 7879c7bba..0a2e4a21b 100644 --- a/src/Storage/TSStorageManager.m +++ b/src/Storage/TSStorageManager.m @@ -201,6 +201,7 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass"; [TSDatabaseView registerUnreadDatabaseView]; [TSDatabaseView registerUnseenDatabaseView]; [TSDatabaseView registerDynamicMessagesDatabaseView]; + [TSDatabaseView registerSafetyNumberChangeDatabaseView]; [self.database registerExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"]; // Register extensions which aren't essential for rendering threads async