Changes for unseen indicator.

* Create separate database views for “unseen” and “unread” messages.
* Add “unseen tracking” to info and error messages.
* Rationalize “timestamp” vs. “receipt timestamp”.
* Ensure microsecond precision for interaction sorting.
* Add OWSFail() macros.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 32d5e52142
commit 7c5a11b221

@ -189,6 +189,23 @@ NS_ASSUME_NONNULL_BEGIN
return hasUnread;
}
- (NSArray<id<OWSReadTracking>> *)unseenMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction
{
NSMutableArray<id<OWSReadTracking>> *messages = [NSMutableArray new];
[[transaction ext:TSUnseenDatabaseViewExtensionName]
enumerateRowsInGroup:self.uniqueId
usingBlock:^(
NSString *collection, NSString *key, id object, id metadata, NSUInteger index, BOOL *stop) {
if (![object conformsToProtocol:@protocol(OWSReadTracking)]) {
DDLogError(@"%@ Unexpected object in unseen messages: %@", self.tag, object);
}
[messages addObject:(id<OWSReadTracking>)object];
}];
return [messages copy];
}
- (NSArray<id<OWSReadTracking> > *)unreadMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction
{
NSMutableArray<id<OWSReadTracking> > *messages = [NSMutableArray new];
@ -218,9 +235,12 @@ NS_ASSUME_NONNULL_BEGIN
- (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
for (id<OWSReadTracking> message in [self unreadMessagesWithTransaction:transaction]) {
for (id<OWSReadTracking> message in [self unseenMessagesWithTransaction:transaction]) {
[message markAsReadLocallyWithTransaction:transaction];
}
// Just to be defensive, we'll also check for unread messages.
OWSAssert([self unreadMessagesWithTransaction:transaction].count < 1);
}
- (void)markAllAsRead
@ -255,7 +275,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)updateWithLastMessage:(TSInteraction *)lastMessage transaction:(YapDatabaseReadWriteTransaction *)transaction {
NSDate *lastMessageDate = [lastMessage receiptDateForSorting];
NSDate *lastMessageDate = [lastMessage dateForSorting];
if ([lastMessage isKindOfClass:[TSErrorMessage class]]) {
TSErrorMessage *errorMessage = (TSErrorMessage *)lastMessage;

@ -2,12 +2,13 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSReadTracking.h"
#import "OWSSignalServiceProtos.pb.h"
#import "TSMessage.h"
NS_ASSUME_NONNULL_BEGIN
@interface TSErrorMessage : TSMessage
@interface TSErrorMessage : TSMessage <OWSReadTracking>
typedef NS_ENUM(int32_t, TSErrorMessageType) {
TSErrorMessageNoSession,
@ -56,6 +57,8 @@ typedef NS_ENUM(int32_t, TSErrorMessageType) {
@property (nonatomic, readonly) TSErrorMessageType errorType;
@property (nullable, nonatomic, readonly) NSString *recipientId;
- (void)markAsReadLocallyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
@end
NS_ASSUME_NONNULL_END

@ -9,14 +9,38 @@
#import "TSErrorMessage_privateConstructor.h"
#import "TSMessagesManager.h"
#import "TextSecureKitEnv.h"
#import <YapDatabase/YapDatabaseConnection.h>
NS_ASSUME_NONNULL_BEGIN
NSUInteger TSErrorMessageSchemaVersion = 1;
@interface TSErrorMessage ()
@property (nonatomic, getter=wasRead) BOOL read;
@property (nonatomic, readonly) NSUInteger errorMessageSchemaVersion;
@end
#pragma mark -
@implementation TSErrorMessage
- (instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
self = [super initWithCoder:coder];
if (!self) {
return self;
}
if (self.errorMessageSchemaVersion < 1) {
_read = YES;
}
_errorMessageSchemaVersion = TSErrorMessageSchemaVersion;
return self;
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp
@ -44,6 +68,7 @@ NS_ASSUME_NONNULL_BEGIN
_errorType = errorMessageType;
_recipientId = recipientId;
_errorMessageSchemaVersion = TSErrorMessageSchemaVersion;
return self;
}
@ -135,6 +160,40 @@ NS_ASSUME_NONNULL_BEGIN
recipientId:recipientId];
}
#pragma mark - OWSReadTracking
- (BOOL)shouldAffectUnreadCounts
{
return NO;
}
- (void)markAsReadLocally
{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self markAsReadLocallyWithTransaction:transaction];
}];
}
- (void)markAsReadLocallyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(transaction);
DDLogInfo(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
_read = YES;
[self saveWithTransaction:transaction];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

@ -107,7 +107,6 @@ extern NSString *const TSIncomingMessageWasReadOnThisDeviceNotification;
// This will be 0 for messages created before we were tracking sourceDeviceId
@property (nonatomic, readonly) UInt32 sourceDeviceId;
@property (nonatomic, readonly, getter=wasRead) BOOL read;
/*
* Marks a message as having been read on this device (as opposed to responding to a remote read receipt).

@ -12,11 +12,24 @@ NS_ASSUME_NONNULL_BEGIN
NSString *const TSIncomingMessageWasReadOnThisDeviceNotification = @"TSIncomingMessageWasReadOnThisDeviceNotification";
@interface TSIncomingMessage ()
@property (nonatomic, getter=wasRead) BOOL read;
@end
#pragma mark -
@implementation TSIncomingMessage
- (instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
self = [super initWithCoder:coder];
if (!self) {
return self;
}
return self;
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp
@ -57,8 +70,6 @@ NSString *const TSIncomingMessageWasReadOnThisDeviceNotification = @"TSIncomingM
_sourceDeviceId = sourceDeviceId;
_read = NO;
OWSAssert(self.receivedAtDate);
return self;
}
@ -97,6 +108,13 @@ NSString *const TSIncomingMessageWasReadOnThisDeviceNotification = @"TSIncomingM
return foundMessage;
}
#pragma mark - OWSReadTracking
- (BOOL)shouldAffectUnreadCounts
{
return YES;
}
- (void)markAsReadFromReadReceipt
{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {

@ -2,11 +2,12 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSReadTracking.h"
#import "TSMessage.h"
NS_ASSUME_NONNULL_BEGIN
@interface TSInfoMessage : TSMessage
@interface TSInfoMessage : TSMessage <OWSReadTracking>
typedef NS_ENUM(NSInteger, TSInfoMessageType) {
TSInfoMessageTypeSessionDidEnd,
@ -41,6 +42,8 @@ typedef NS_ENUM(NSInteger, TSInfoMessageType) {
expiresInSeconds:(uint32_t)expiresInSeconds
expireStartedAt:(uint64_t)expireStartedAt NS_UNAVAILABLE;
- (void)markAsReadLocallyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
@end
NS_ASSUME_NONNULL_END

@ -2,16 +2,40 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "NSDate+millisecondTimeStamp.h"
#import "TSInfoMessage.h"
#import "NSDate+millisecondTimeStamp.h"
#import <YapDatabase/YapDatabaseConnection.h>
NS_ASSUME_NONNULL_BEGIN
NSUInteger TSInfoMessageSchemaVersion = 1;
@interface TSInfoMessage ()
@property (nonatomic, getter=wasRead) BOOL read;
@property (nonatomic, readonly) NSUInteger infoMessageSchemaVersion;
@end
#pragma mark -
@implementation TSInfoMessage
- (instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
self = [super initWithCoder:coder];
if (!self) {
return self;
}
if (self.infoMessageSchemaVersion < 1) {
_read = YES;
}
_infoMessageSchemaVersion = TSInfoMessageSchemaVersion;
return self;
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp
@ -30,6 +54,7 @@ NS_ASSUME_NONNULL_BEGIN
}
_messageType = infoMessage;
_infoMessageSchemaVersion = TSInfoMessageSchemaVersion;
return self;
}
@ -74,6 +99,40 @@ NS_ASSUME_NONNULL_BEGIN
return @"Unknown Info Message Type";
}
#pragma mark - OWSReadTracking
- (BOOL)shouldAffectUnreadCounts
{
return NO;
}
- (void)markAsReadLocally
{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self markAsReadLocallyWithTransaction:transaction];
}];
}
- (void)markAsReadLocallyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(transaction);
DDLogInfo(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);
_read = YES;
[self saveWithTransaction:transaction];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

@ -16,7 +16,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) TSThread *thread;
@property (nonatomic, readonly) uint64_t timestamp;
- (NSDate *)date;
- (NSString *)description;
/**
@ -33,7 +32,10 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)interactionForTimestamp:(uint64_t)timestamp
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
- (nullable NSDate *)receiptDateForSorting;
// NSDate has second precision, uint64_t timestamps have millisecond precision
// so prefer timestampForSorting over dateForSorting.
- (NSDate *)dateForSorting;
- (uint64_t)timestampForSorting;
// "Dynamic" interactions are not messages or static events (like
// info messages, error messages, etc.). They are interactions

@ -3,6 +3,7 @@
//
#import "TSInteraction.h"
#import "NSDate+millisecondTimeStamp.h"
#import "TSDatabaseSecondaryIndexes.h"
#import "TSStorageManager+messageIDs.h"
#import "TSThread.h"
@ -52,7 +53,6 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
#pragma mark Thread
- (TSThread *)thread
@ -72,11 +72,6 @@ NS_ASSUME_NONNULL_BEGIN
return self.timestamp;
}
- (NSDate *)date {
uint64_t seconds = self.timestamp / 1000;
return [NSDate dateWithTimeIntervalSince1970:seconds];
}
+ (NSString *)stringFromTimeStamp:(uint64_t)timestamp {
return [[NSNumber numberWithUnsignedLongLong:timestamp] stringValue];
}
@ -88,9 +83,14 @@ NS_ASSUME_NONNULL_BEGIN
return [myNumber unsignedLongLongValue];
}
- (nullable NSDate *)receiptDateForSorting
- (NSDate *)dateForSorting
{
return self.date;
return [NSDate ows_dateWithMillisecondsSince1970:self.timestampForSorting];
}
- (uint64_t)timestampForSorting
{
return self.timestamp;
}
- (NSString *)description {

@ -21,9 +21,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) uint64_t expiresAt;
@property (nonatomic, readonly) BOOL isExpiringMessage;
@property (nonatomic, readonly) BOOL shouldStartExpireTimer;
// _DO NOT_ access this property directly. You almost certainly
// want to use receiptDateForSorting instead.
@property (nonatomic, readonly) NSDate *receivedAtDate;
- (instancetype)initWithTimestamp:(uint64_t)timestamp;

@ -35,6 +35,13 @@ static const NSUInteger OWSMessageSchemaVersion = 3;
*/
@property (nonatomic, readonly) NSUInteger schemaVersion;
// The timestamp property is populated by the envelope,
// which is created by the sender.
//
// We typically want to order messages locally by when
// they were received & decrypted, not by when they were sent.
@property (nonatomic, readonly) uint64_t receivedAtTimestamp;
@end
#pragma mark -
@ -104,7 +111,12 @@ static const NSUInteger OWSMessageSchemaVersion = 3;
_expiresInSeconds = expiresInSeconds;
_expireStartedAt = expireStartedAt;
[self updateExpiresAt];
_receivedAtDate = [NSDate date];
if ([self shouldUseReceiptDateForSorting]) {
_receivedAtTimestamp = self.timestamp;
} else {
_receivedAtTimestamp = [NSDate ows_millisecondTimeStamp];
}
return self;
}
@ -133,10 +145,20 @@ static const NSUInteger OWSMessageSchemaVersion = 3;
_attachmentIds = [NSMutableArray new];
}
if (!_receivedAtDate) {
// TSIncomingMessage.receivedAt has been superceded by TSMessage.receivedAtDate.
NSDate *receivedAt = [coder decodeObjectForKey:@"receivedAt"];
_receivedAtDate = receivedAt;
if (_receivedAtTimestamp == 0) {
// Upgrade from the older "receivedAtDate" and "receivedAt" properties if
// necessary.
NSDate *receivedAtDate = [coder decodeObjectForKey:@"receivedAtDate"];
if (!receivedAtDate) {
receivedAtDate = [coder decodeObjectForKey:@"receivedAt"];
}
if (receivedAtDate) {
_receivedAtTimestamp = [NSDate ows_millisecondsSince1970ForDate:receivedAtDate];
}
}
if ([self shouldUseReceiptDateForSorting]) {
_receivedAtTimestamp = self.timestamp;
}
_schemaVersion = OWSMessageSchemaVersion;
@ -224,10 +246,19 @@ static const NSUInteger OWSMessageSchemaVersion = 3;
return self.expiresInSeconds > 0;
}
- (nullable NSDate *)receiptDateForSorting
- (uint64_t)timestampForSorting
{
if ([self shouldUseReceiptDateForSorting] && self.receivedAtTimestamp > 0) {
return self.receivedAtTimestamp;
} else {
OWSAssert(self.timestamp > 0);
return self.timestamp;
}
}
- (BOOL)shouldUseReceiptDateForSorting
{
// Prefer receivedAtDate if set, otherwise fallback to date.
return self.receivedAtDate ?: self.date;
return YES;
}
#pragma mark - Logging

@ -186,8 +186,6 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
_attachmentFilenameMap = [NSMutableDictionary new];
OWSAssert(self.receivedAtDate);
return self;
}

@ -1,9 +1,5 @@
//
// TSInvalidIdentityKeyErrorMessage.m
// Signal
//
// Created by Frederic Jacobs on 15/02/15.
// Copyright (c) 2015 Open Whisper Systems. All rights reserved.
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSInvalidIdentityKeyErrorMessage.h"
@ -29,6 +25,11 @@ NS_ASSUME_NONNULL_BEGIN
return nil;
}
- (BOOL)isDynamicInteraction
{
return YES;
}
@end
NS_ASSUME_NONNULL_END

@ -32,14 +32,11 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
- (nullable NSDate *)receiptDateForSorting
- (BOOL)shouldUseReceiptDateForSorting
{
// Always use date, since we're creating these interactions after the fact
// and back-dating them.
//
// By default [TSMessage receiptDateForSorting] will prefer to use receivedAtDate
// which is not back-dated.
return self.date;
// 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

@ -15,6 +15,10 @@
*/
@property (nonatomic, readonly, getter=wasRead) BOOL read;
@property (nonatomic, readonly) NSString *uniqueThreadId;
- (BOOL)shouldAffectUnreadCounts;
/**
* Call when the user viewed the message/call on this device. "locally" as opposed to being notified via a read receipt
* sync message of a remote read.
@ -22,6 +26,4 @@
- (void)markAsReadLocally;
- (void)markAsReadLocallyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
@property (nonatomic, readonly) NSString *uniqueThreadId;
@end

@ -34,14 +34,11 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
- (nullable NSDate *)receiptDateForSorting
- (BOOL)shouldUseReceiptDateForSorting
{
// Always use date, since we're creating these interactions after the fact
// and back-dating them.
//
// By default [TSMessage receiptDateForSorting] will prefer to use receivedAtDate
// which is not back-dated.
return self.date;
// 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

@ -13,13 +13,15 @@ NSUInteger TSCallCurrentSchemaVersion = 1;
@interface TSCall ()
@property (nonatomic, getter=wasRead) BOOL read;
@property (nonatomic, readonly) NSUInteger callSchemaVersion;
@end
@implementation TSCall
#pragma mark -
@synthesize read = _read;
@implementation TSCall
- (instancetype)initWithTimestamp:(uint64_t)timestamp
withCallNumber:(NSString *)contactNumber
@ -77,6 +79,11 @@ NSUInteger TSCallCurrentSchemaVersion = 1;
#pragma mark - OWSReadTracking
- (BOOL)shouldAffectUnreadCounts
{
return YES;
}
- (void)markAsReadLocallyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
DDLogInfo(@"%@ marking as read uniqueId: %@ which has timestamp: %llu", self.tag, self.uniqueId, self.timestamp);

@ -15,12 +15,20 @@ extern NSString *TSSecondaryDevicesGroup;
extern NSString *TSThreadDatabaseViewExtensionName;
extern NSString *TSMessageDatabaseViewExtensionName;
extern NSString *TSUnreadDatabaseViewExtensionName;
extern NSString *TSUnseenDatabaseViewExtensionName;
extern NSString *TSDynamicMessagesDatabaseViewExtensionName;
extern NSString *TSSecondaryDevicesDatabaseViewExtensionName;
+ (BOOL)registerThreadDatabaseView;
+ (BOOL)registerBuddyConversationDatabaseView;
+ (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;
+ (void)asyncRegisterSecondaryDevicesDatabaseView;

@ -3,15 +3,13 @@
//
#import "TSDatabaseView.h"
#import <YapDatabase/YapDatabaseView.h>
#import "OWSDevice.h"
#import "OWSReadTracking.h"
#import "TSIncomingMessage.h"
#import "TSOutgoingMessage.h"
#import "TSStorageManager.h"
#import "TSThread.h"
#import <YapDatabase/YapDatabaseView.h>
NSString *TSInboxGroup = @"TSInboxGroup";
NSString *TSArchiveGroup = @"TSArchiveGroup";
@ -22,12 +20,15 @@ NSString *TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
NSString *TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName";
NSString *TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName";
NSString *TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
NSString *TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName";
NSString *TSDynamicMessagesDatabaseViewExtensionName = @"TSDynamicMessagesDatabaseViewExtensionName";
NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName";
@implementation TSDatabaseView
+ (BOOL)registerMessageDatabaseViewWithName:(NSString *)viewName viewGrouping:(YapDatabaseViewGrouping *)viewGrouping
+ (BOOL)registerMessageDatabaseViewWithName:(NSString *)viewName
viewGrouping:(YapDatabaseViewGrouping *)viewGrouping
version:(NSString *)version
{
OWSAssert(viewName.length > 0);
OWSAssert((viewGrouping));
@ -45,7 +46,7 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]];
YapDatabaseView *view =
[[YapDatabaseView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"1" options:options];
[[YapDatabaseView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:version options:options];
return [[TSStorageManager sharedManager].database registerExtension:view withName:viewName];
}
@ -56,14 +57,34 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if ([object conformsToProtocol:@protocol(OWSReadTracking)]) {
id<OWSReadTracking> possiblyRead = (id<OWSReadTracking>)object;
if (possiblyRead.read == NO) {
if (!possiblyRead.wasRead && possiblyRead.shouldAffectUnreadCounts) {
return possiblyRead.uniqueThreadId;
}
}
return nil;
}];
return [self registerMessageDatabaseViewWithName:TSUnreadDatabaseViewExtensionName viewGrouping:viewGrouping];
return [self registerMessageDatabaseViewWithName:TSUnreadDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"1"];
}
+ (BOOL)registerUnseenDatabaseView
{
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if ([object conformsToProtocol:@protocol(OWSReadTracking)]) {
id<OWSReadTracking> possiblyRead = (id<OWSReadTracking>)object;
if (!possiblyRead.wasRead) {
return possiblyRead.uniqueThreadId;
}
}
return nil;
}];
return [self registerMessageDatabaseViewWithName:TSUnseenDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"1"];
}
+ (BOOL)registerDynamicMessagesDatabaseView
@ -81,11 +102,12 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData
return nil;
}];
return
[self registerMessageDatabaseViewWithName:TSDynamicMessagesDatabaseViewExtensionName viewGrouping:viewGrouping];
return [self registerMessageDatabaseViewWithName:TSDynamicMessagesDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"2"];
}
+ (BOOL)registerBuddyConversationDatabaseView
+ (BOOL)registerThreadInteractionsDatabaseView
{
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
@ -95,7 +117,9 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData
return nil;
}];
return [self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName viewGrouping:viewGrouping];
return [self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"1"];
}
+ (BOOL)registerThreadDatabaseView {
@ -194,19 +218,12 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData
TSInteraction *message1 = (TSInteraction *)object1;
TSInteraction *message2 = (TSInteraction *)object2;
NSDate *date1 = [self localTimeReceiveDateForInteraction:message1];
NSDate *date2 = [self localTimeReceiveDateForInteraction:message2];
uint64_t timestamp1 = message1.timestampForSorting;
uint64_t timestamp2 = message2.timestampForSorting;
NSComparisonResult result = [date1 compare:date2];
// NSDates are only accurate to the second, we might want finer precision
if (result != NSOrderedSame) {
return result;
}
if (message1.timestamp > message2.timestamp) {
if (timestamp1 > timestamp2) {
return NSOrderedDescending;
} else if (message1.timestamp < message2.timestamp) {
} else if (timestamp1 < timestamp2) {
return NSOrderedAscending;
} else {
return NSOrderedSame;
@ -274,10 +291,6 @@ NSString *TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesData
}];
}
+ (NSDate *)localTimeReceiveDateForInteraction:(TSInteraction *)interaction {
return [interaction receiptDateForSorting];
}
#pragma mark - Logging
+ (NSString *)tag

@ -197,8 +197,9 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
{
// Register extensions which are essential for rendering threads synchronously
[TSDatabaseView registerThreadDatabaseView];
[TSDatabaseView registerBuddyConversationDatabaseView];
[TSDatabaseView registerThreadInteractionsDatabaseView];
[TSDatabaseView registerUnreadDatabaseView];
[TSDatabaseView registerUnseenDatabaseView];
[TSDatabaseView registerDynamicMessagesDatabaseView];
[self.database registerExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"];

@ -13,24 +13,40 @@
#define CONVERT_TO_STRING(X) #X
#define CONVERT_EXPR_TO_STRING(X) CONVERT_TO_STRING(X)
#define OWSAssert(X) \
if (!(X)) { \
NSLog(@"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
NSAssert(0, @"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
}
// OWSAssert() should be used in Obj-C and Swift methods.
// OWSCAssert() should be used in free functions.
#define OWSCAssert(X) \
if (!(X)) { \
NSLog(@"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
NSCAssert(0, @"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
}
// OWSAssert() and OWSFail() should be used in Obj-C methods.
// OWSCAssert() and OWSCFail() should be used in free functions.
#define OWSAssert(X) \
if (!(X)) { \
NSLog(@"%s Assertion failed: %s", __PRETTY_FUNCTION__, CONVERT_EXPR_TO_STRING(X)); \
NSAssert(0, @"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
}
#define OWSCAssert(X) \
if (!(X)) { \
NSLog(@"%s Assertion failed: %s", __PRETTY_FUNCTION__, CONVERT_EXPR_TO_STRING(X)); \
NSCAssert(0, @"Assertion failed: %s", CONVERT_EXPR_TO_STRING(X)); \
}
#define OWSFail(X) \
{ \
NSLog(@"%s %@", __PRETTY_FUNCTION__, X); \
NSAssert(0, X); \
}
#define OWSCFail(X) \
{ \
if (!(X)) { \
NSLog(@"%s %@", __PRETTY_FUNCTION__, X); \
NSCAssert(0, X); \
}
#else
#define OWSAssert(X)
#define OWSCAssert(X)
#define OWSFail(X)
#define OWSCFail(X)
#endif

Loading…
Cancel
Save