mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
parent
11b8819274
commit
5671fd2520
75 changed files with 692 additions and 399 deletions
|
@ -469,6 +469,7 @@
|
|||
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */; };
|
||||
4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB5F26820F7D060004D1B42 /* MessageActions.swift */; };
|
||||
4CB93DC22180FF07004B9764 /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB93DC12180FF07004B9764 /* ProximityMonitoringManager.swift */; };
|
||||
4CBBCA6321714B4500EEB37D /* OWS110SortIdMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CBBCA6221714B4500EEB37D /* OWS110SortIdMigration.swift */; };
|
||||
4CC0B59C20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */; };
|
||||
4CC1ECF9211A47CE00CC13BE /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; };
|
||||
|
@ -1190,6 +1191,7 @@
|
|||
4CA5F792211E1F06008C2708 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = "<group>"; };
|
||||
4CB5F26820F7D060004D1B42 /* MessageActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActions.swift; sourceTree = "<group>"; };
|
||||
4CB93DC12180FF07004B9764 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProximityMonitoringManager.swift; sourceTree = "<group>"; };
|
||||
4CBBCA6221714B4500EEB37D /* OWS110SortIdMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS110SortIdMigration.swift; sourceTree = "<group>"; };
|
||||
4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationConfigurationSyncOperation.swift; sourceTree = "<group>"; };
|
||||
4CC1ECF8211A47CD00CC13BE /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
|
||||
4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateNag.swift; sourceTree = "<group>"; };
|
||||
|
@ -1676,6 +1678,7 @@
|
|||
4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */,
|
||||
34D5872E208E2C4100D2255A /* OWS109OutgoingMessageState.h */,
|
||||
34D5872D208E2C4100D2255A /* OWS109OutgoingMessageState.m */,
|
||||
4CBBCA6221714B4500EEB37D /* OWS110SortIdMigration.swift */,
|
||||
349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */,
|
||||
34B6A908218B8824007C4606 /* OWS112TypingIndicatorsMigration.swift */,
|
||||
4C7537882193779700DF5E37 /* OWS113MultiAttachmentMediaMessages.swift */,
|
||||
|
@ -3311,6 +3314,7 @@
|
|||
34BEDB1721C80BCA007B0EAE /* OWSAnyTouchGestureRecognizer.m in Sources */,
|
||||
34B6A909218B8824007C4606 /* OWS112TypingIndicatorsMigration.swift in Sources */,
|
||||
346129B51FD1F7E800532771 /* OWSProfileManager.m in Sources */,
|
||||
4CBBCA6321714B4500EEB37D /* OWS110SortIdMigration.swift in Sources */,
|
||||
342950832124C9750000B063 /* OWSTextView.m in Sources */,
|
||||
452EC6E1205FF5DC000E787C /* Bench.swift in Sources */,
|
||||
342950882124CB0A0000B063 /* OWSSearchBar.m in Sources */,
|
||||
|
|
|
@ -126,7 +126,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
NSDate *date = viewItem.interaction.dateForSorting;
|
||||
NSDate *date = viewItem.interaction.receivedAtDate;
|
||||
NSString *dateString = [DateUtil formatDateForConversationDateBreaks:date].localizedUppercaseString;
|
||||
|
||||
// Update cell to reflect changes in dynamic text.
|
||||
|
|
|
@ -170,7 +170,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
@property (nonatomic) BOOL showLoadMoreHeader;
|
||||
@property (nonatomic) UILabel *loadMoreHeader;
|
||||
@property (nonatomic) uint64_t lastVisibleTimestamp;
|
||||
@property (nonatomic) uint64_t lastVisibleSortId;
|
||||
|
||||
@property (nonatomic) BOOL isUserScrolling;
|
||||
|
||||
|
@ -692,7 +692,7 @@ typedef enum : NSUInteger {
|
|||
[self scrollToDefaultPosition];
|
||||
}
|
||||
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self updateLastVisibleSortId];
|
||||
|
||||
if (!self.viewHasEverAppeared) {
|
||||
NSTimeInterval appearenceDuration = CACurrentMediaTime() - self.viewControllerCreatedAt;
|
||||
|
@ -1806,10 +1806,14 @@ typedef enum : NSUInteger {
|
|||
// DEPRECATED: we're no longer creating these incoming SN error's per message,
|
||||
// but there will be some legacy ones in the wild, behind which await
|
||||
// as-of-yet-undecrypted messages
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if ([errorMessage isKindOfClass:[TSInvalidIdentityKeyReceivingErrorMessage class]]) {
|
||||
// Deliberately crash if the user fails to explicitly accept the new identity
|
||||
// key. In practice we haven't been creating these messages in over a year.
|
||||
[errorMessage throws_acceptNewIdentityKey];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
}
|
||||
}];
|
||||
[actionSheetController addAction:acceptSafetyNumberAction];
|
||||
|
@ -2430,7 +2434,7 @@ typedef enum : NSUInteger {
|
|||
id<ConversationViewItem> lastViewItem = [self.viewItems lastObject];
|
||||
OWSAssertDebug(lastViewItem);
|
||||
|
||||
if (lastViewItem.interaction.timestampForSorting > self.lastVisibleTimestamp) {
|
||||
if (lastViewItem.interaction.sortId > self.lastVisibleSortId) {
|
||||
shouldShowScrollDownButton = YES;
|
||||
} else if (isScrolledUp) {
|
||||
shouldShowScrollDownButton = YES;
|
||||
|
@ -2529,7 +2533,6 @@ typedef enum : NSUInteger {
|
|||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(message);
|
||||
|
||||
[self updateLastVisibleTimestamp:message.timestampForSorting];
|
||||
self.lastMessageSentDate = [NSDate new];
|
||||
[self.conversationViewModel clearUnreadMessagesIndicator];
|
||||
self.inputToolbar.quotedReply = nil;
|
||||
|
@ -3268,8 +3271,8 @@ typedef enum : NSUInteger {
|
|||
|
||||
id<ConversationViewItem> _Nullable lastVisibleViewItem = [self.viewItems lastObject];
|
||||
if (lastVisibleViewItem) {
|
||||
uint64_t lastVisibleTimestamp = lastVisibleViewItem.interaction.timestampForSorting;
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, lastVisibleTimestamp);
|
||||
uint64_t lastVisibleSortId = lastVisibleViewItem.interaction.sortId;
|
||||
self.lastVisibleSortId = MAX(self.lastVisibleSortId, lastVisibleSortId);
|
||||
}
|
||||
|
||||
self.scrollDownButton.hidden = YES;
|
||||
|
@ -3277,12 +3280,12 @@ typedef enum : NSUInteger {
|
|||
self.hasUnreadMessages = NO;
|
||||
}
|
||||
|
||||
- (void)updateLastVisibleTimestamp
|
||||
- (void)updateLastVisibleSortId
|
||||
{
|
||||
id<ConversationViewItem> _Nullable lastVisibleViewItem = [self lastVisibleViewItem];
|
||||
if (lastVisibleViewItem) {
|
||||
uint64_t lastVisibleTimestamp = lastVisibleViewItem.interaction.timestampForSorting;
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, lastVisibleTimestamp);
|
||||
uint64_t lastVisibleSortId = lastVisibleViewItem.interaction.sortId;
|
||||
self.lastVisibleSortId = MAX(self.lastVisibleSortId, lastVisibleSortId);
|
||||
}
|
||||
|
||||
[self ensureScrollDownButton];
|
||||
|
@ -3295,15 +3298,6 @@ typedef enum : NSUInteger {
|
|||
self.hasUnreadMessages = numberOfUnreadMessages > 0;
|
||||
}
|
||||
|
||||
- (void)updateLastVisibleTimestamp:(uint64_t)timestamp
|
||||
{
|
||||
OWSAssertDebug(timestamp > 0);
|
||||
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, timestamp);
|
||||
|
||||
[self ensureScrollDownButton];
|
||||
}
|
||||
|
||||
- (void)markVisibleMessagesAsRead
|
||||
{
|
||||
if (self.presentedViewController) {
|
||||
|
@ -3319,15 +3313,16 @@ typedef enum : NSUInteger {
|
|||
return;
|
||||
}
|
||||
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self updateLastVisibleSortId];
|
||||
|
||||
uint64_t lastVisibleTimestamp = self.lastVisibleTimestamp;
|
||||
uint64_t lastVisibleSortId = self.lastVisibleSortId;
|
||||
|
||||
if (lastVisibleTimestamp == 0) {
|
||||
if (lastVisibleSortId == 0) {
|
||||
// No visible messages yet. New Thread.
|
||||
return;
|
||||
}
|
||||
[OWSReadReceiptManager.sharedManager markAsReadLocallyBeforeTimestamp:lastVisibleTimestamp thread:self.thread];
|
||||
|
||||
[OWSReadReceiptManager.sharedManager markAsReadLocallyBeforeSortId:self.lastVisibleSortId thread:self.thread];
|
||||
}
|
||||
|
||||
- (void)updateGroupModelTo:(TSGroupModel *)newGroupModel successCompletion:(void (^_Nullable)(void))successCompletion
|
||||
|
@ -3763,7 +3758,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||||
{
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self updateLastVisibleSortId];
|
||||
|
||||
__weak ConversationViewController *weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
@ -4192,7 +4187,7 @@ typedef enum : NSUInteger {
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self updateLastVisibleSortId];
|
||||
self.conversationStyle.viewWidth = self.collectionView.width;
|
||||
[self.collectionView.collectionViewLayout invalidateLayout];
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NSUInteger index,
|
||||
BOOL *stop) {
|
||||
NSTimeInterval ageSeconds
|
||||
= fabs(interaction.dateForSorting.timeIntervalSinceNow);
|
||||
= fabs(interaction.receivedAtDate.timeIntervalSinceNow);
|
||||
if (ageSeconds < maxAgeSeconds) {
|
||||
*stop = YES;
|
||||
return;
|
||||
|
|
|
@ -3452,6 +3452,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:YES
|
||||
durationSeconds:(uint32_t)[durationSeconds intValue]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3466,6 +3467,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:YES
|
||||
durationSeconds:(uint32_t)[durationSeconds intValue]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3480,6 +3482,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:YES
|
||||
durationSeconds:(uint32_t)[durationSeconds intValue]];
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3492,6 +3495,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:NO
|
||||
durationSeconds:0];
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3502,44 +3506,55 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
|
||||
[result addObject:[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:@"+19174054215"]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeSessionDidEnd]];
|
||||
// TODO: customMessage?
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupUpdate]];
|
||||
// TODO: customMessage?
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupQuit]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateDefault
|
||||
isLocalChange:YES]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateVerified
|
||||
isLocalChange:YES]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result
|
||||
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateNoLongerVerified
|
||||
isLocalChange:YES]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateDefault
|
||||
isLocalChange:NO]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateVerified
|
||||
isLocalChange:NO]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result
|
||||
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3556,12 +3571,16 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[result addObject:[TSErrorMessage corruptedMessageWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction]];
|
||||
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
TSInvalidIdentityKeyReceivingErrorMessage *_Nullable blockingSNChangeMessage =
|
||||
[TSInvalidIdentityKeyReceivingErrorMessage untrustedKeyWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
OWSAssertDebug(blockingSNChangeMessage);
|
||||
[result addObject:blockingSNChangeMessage];
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageNonBlockingIdentityChange
|
||||
|
@ -3724,9 +3743,10 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
OWSLogInfo(@"sendFakeMessages: %lu", (unsigned long)counter);
|
||||
|
||||
for (NSUInteger i = 0; i < counter; i++) {
|
||||
NSString *randomText = [self randomText];
|
||||
NSString *randomText = [[self randomText] stringByAppendingFormat:@" (sequence: %lu)", (unsigned long)i + 1];
|
||||
switch (arc4random_uniform(isTextOnly ? 2 : 4)) {
|
||||
case 0: {
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -3768,6 +3788,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
attachmentType:TSAttachmentTypeDefault];
|
||||
pointer.state = TSAttachmentPointerStateFailed;
|
||||
[pointer saveWithTransaction:transaction];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -4165,6 +4186,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
OWSDisappearingMessagesConfiguration *configuration =
|
||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId
|
||||
transaction:initialTransaction];
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message = [[TSOutgoingMessage alloc]
|
||||
initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -4232,6 +4254,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
for (NSNumber *timestamp in timestamps) {
|
||||
NSString *randomText = [self randomText];
|
||||
{
|
||||
// Legit usage of SenderTimestamp to backdate incoming sent messages for Debug
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp.unsignedLongLongValue
|
||||
inThread:thread
|
||||
|
@ -4247,6 +4270,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[message markAsReadNowWithSendReadReceipt:NO transaction:transaction];
|
||||
}
|
||||
{
|
||||
// MJK TODO - this might be the one place we actually use senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:timestamp.unsignedLongLongValue
|
||||
inThread:thread
|
||||
|
@ -4273,6 +4297,8 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
+ (void)createDisappearingMessagesWhichFailedToStartInThread:(TSThread *)thread
|
||||
{
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message = [[TSIncomingMessage alloc]
|
||||
initIncomingMessageWithTimestamp:now
|
||||
inThread:thread
|
||||
|
@ -4503,6 +4529,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[attachmentIds addObject:attachmentId];
|
||||
}
|
||||
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -4592,6 +4619,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
// uint64_t millisAgo = (uint64_t)(((double)arc4random() / ((double)0xffffffff)) * yearsMillis);
|
||||
// uint64_t timestamp = [NSDate ows_millisecondTimeStamp] - millisAgo;
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
|
|
@ -46,6 +46,7 @@ class DebugUIProfile: DebugUIPage {
|
|||
OWSTableItem(title: "Send Profile Key Message") { [weak self] in
|
||||
guard let strongSelf = self else { return }
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
let message = OWSProfileKeyMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: aThread)
|
||||
strongSelf.messageSender.sendPromise(message: message).done {
|
||||
Logger.info("Successfully sent profile key message to thread: \(String(describing: aThread))")
|
||||
|
|
|
@ -55,7 +55,7 @@ public class MediaGalleryItem: Equatable, Hashable {
|
|||
self.captionForDisplay = attachmentStream.caption?.filterForDisplay
|
||||
self.galleryDate = GalleryDate(message: message)
|
||||
self.albumIndex = message.attachmentIds.index(of: attachmentStream.uniqueId!)
|
||||
self.orderingKey = MediaGalleryItemOrderingKey(messageSortKey: message.timestampForSorting(), attachmentSortKey: albumIndex)
|
||||
self.orderingKey = MediaGalleryItemOrderingKey(messageSortKey: message.sortId, attachmentSortKey: albumIndex)
|
||||
}
|
||||
|
||||
var isVideo: Bool {
|
||||
|
@ -120,7 +120,7 @@ public struct GalleryDate: Hashable, Comparable, Equatable {
|
|||
let month: Int
|
||||
|
||||
init(message: TSMessage) {
|
||||
let date = message.dateForSorting()
|
||||
let date = message.receivedAtDate()
|
||||
|
||||
self.year = Calendar.current.component(.year, from: date)
|
||||
self.month = Calendar.current.component(.month, from: date)
|
||||
|
|
|
@ -324,7 +324,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
|||
if message is TSIncomingMessage {
|
||||
rows.append(valueRow(name: NSLocalizedString("MESSAGE_METADATA_VIEW_RECEIVED_DATE_TIME",
|
||||
comment: "Label for the 'received date & time' field of the 'message metadata' view."),
|
||||
value: DateUtil.formatPastTimestampRelativeToNow(message.timestampForSorting())))
|
||||
value: DateUtil.formatPastTimestampRelativeToNow(message.receivedAtTimestamp)))
|
||||
}
|
||||
|
||||
rows += addAttachmentMetadataRows()
|
||||
|
|
|
@ -462,6 +462,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
// Add an error message to the new group indicating
|
||||
// that group creation didn't succeed.
|
||||
// MJK TODO should be safe to remove senderTimestamp and just save immediately
|
||||
TSErrorMessage *errorMessage = [[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageGroupCreationFailed];
|
||||
|
|
|
@ -938,6 +938,7 @@ const CGFloat kIconViewLength = 24;
|
|||
if (self.disappearingMessagesConfiguration.dictionaryValueDidChange) {
|
||||
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self.disappearingMessagesConfiguration saveWithTransaction:transaction];
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
|
|
|
@ -306,23 +306,19 @@ private class SignalCallData: NSObject {
|
|||
|
||||
// MARK: - Dependencies
|
||||
|
||||
private var contactsManager : OWSContactsManager
|
||||
{
|
||||
private var contactsManager: OWSContactsManager {
|
||||
return Environment.shared.contactsManager
|
||||
}
|
||||
|
||||
private var messageSender : MessageSender
|
||||
{
|
||||
private var messageSender: MessageSender {
|
||||
return SSKEnvironment.shared.messageSender
|
||||
}
|
||||
|
||||
private var accountManager : AccountManager
|
||||
{
|
||||
private var accountManager: AccountManager {
|
||||
return AppEnvironment.shared.accountManager
|
||||
}
|
||||
|
||||
private var notificationsAdapter : CallNotificationsAdapter
|
||||
{
|
||||
private var notificationsAdapter: CallNotificationsAdapter {
|
||||
return AppEnvironment.shared.callNotificationsAdapter
|
||||
}
|
||||
|
||||
|
@ -370,6 +366,7 @@ private class SignalCallData: NSObject {
|
|||
let callData = SignalCallData(call: call)
|
||||
self.callData = callData
|
||||
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeOutgoingIncomplete, in: call.thread)
|
||||
callRecord.save()
|
||||
call.callRecord = callRecord
|
||||
|
@ -531,6 +528,7 @@ private class SignalCallData: NSObject {
|
|||
callRecord.updateCallType(RPRecentCallTypeIncomingMissed)
|
||||
}
|
||||
} else {
|
||||
// MJK TODO remove this timestamp param
|
||||
call.callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
withCallNumber: call.thread.contactIdentifier(),
|
||||
callType: RPRecentCallTypeIncomingMissed,
|
||||
|
@ -617,6 +615,7 @@ private class SignalCallData: NSObject {
|
|||
self.notificationsAdapter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: newCall, callerName: callerName)
|
||||
}
|
||||
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
withCallNumber: thread.contactIdentifier(),
|
||||
callType: RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity,
|
||||
|
@ -1038,6 +1037,7 @@ private class SignalCallData: NSObject {
|
|||
|
||||
Logger.info("\(call.identifiersForLogs).")
|
||||
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeIncomingIncomplete, in: call.thread)
|
||||
callRecord.save()
|
||||
call.callRecord = callRecord
|
||||
|
@ -1127,6 +1127,7 @@ private class SignalCallData: NSObject {
|
|||
owsFailDebug("Not expecting callrecord to already be set")
|
||||
callRecord.updateCallType(RPRecentCallTypeIncomingDeclined)
|
||||
} else {
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeIncomingDeclined, in: call.thread)
|
||||
callRecord.save()
|
||||
call.callRecord = callRecord
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#import <SignalServiceKit/TSInteraction.h>
|
||||
|
||||
@class YapDatabaseReadWriteTransaction;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSContactOffersInteraction : TSInteraction
|
||||
|
@ -11,6 +13,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic, readonly) BOOL hasBlockOffer;
|
||||
@property (nonatomic, readonly) BOOL hasAddToContactsOffer;
|
||||
@property (nonatomic, readonly) BOOL hasAddToProfileWhitelistOffer;
|
||||
|
||||
// TODO - remove this recipientId param
|
||||
// it's redundant with the interaction's TSContactThread
|
||||
@property (nonatomic, readonly) NSString *recipientId;
|
||||
@property (nonatomic, readonly) NSString *beforeInteractionId;
|
||||
|
||||
|
@ -18,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
// MJK TODO should be safe to remove this timestamp param
|
||||
- (instancetype)initInteractionWithUniqueId:(NSString *)uniqueId
|
||||
timestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
|
@ -27,6 +33,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
recipientId:(NSString *)recipientId
|
||||
beforeInteractionId:(NSString *)beforeInteractionId NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)updateHasBlockOffer:(BOOL)hasBlockOffer
|
||||
hasAddToContactsOffer:(BOOL)hasAddToContactsOffer
|
||||
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -6,6 +6,14 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSContactOffersInteraction ()
|
||||
|
||||
@property (nonatomic) BOOL hasBlockOffer;
|
||||
@property (nonatomic) BOOL hasAddToContactsOffer;
|
||||
@property (nonatomic) BOOL hasAddToProfileWhitelistOffer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSContactOffersInteraction
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// This class is vestigial.
|
||||
@interface TSUnreadIndicatorInteraction : TSInteraction
|
||||
__attribute__((deprecated)) @interface TSUnreadIndicatorInteraction : TSInteraction
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation TSUnreadIndicatorInteraction
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
|
|
|
@ -51,7 +51,6 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[];
|
|||
#import <SignalMessaging/SelectRecipientViewController.h>
|
||||
#import <SignalMessaging/SharingThreadPickerViewController.h>
|
||||
#import <SignalMessaging/SignalKeyingStorage.h>
|
||||
#import <SignalMessaging/TSUnreadIndicatorInteraction.h>
|
||||
#import <SignalMessaging/Theme.h>
|
||||
#import <SignalMessaging/ThreadUtil.h>
|
||||
#import <SignalMessaging/ThreadViewHelper.h>
|
||||
|
|
|
@ -241,6 +241,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
NSArray *attachments = self.attachmentStream ? @[ self.attachmentStream ] : @[];
|
||||
|
||||
// Legit usage of senderTimestamp to reference existing message
|
||||
return [[TSQuotedMessage alloc] initWithTimestamp:self.timestamp
|
||||
authorId:self.authorId
|
||||
body:self.body
|
||||
|
|
|
@ -25,12 +25,14 @@ public class ThreadViewModel: NSObject {
|
|||
@objc
|
||||
public init(thread: TSThread, transaction: YapDatabaseReadTransaction) {
|
||||
self.threadRecord = thread
|
||||
self.lastMessageDate = thread.lastMessageDate()
|
||||
|
||||
self.isGroupThread = thread.isGroupThread()
|
||||
self.name = thread.name()
|
||||
self.isMuted = thread.isMuted
|
||||
self.lastMessageText = thread.lastMessageText(transaction: transaction)
|
||||
self.lastMessageForInbox = thread.lastInteractionForInbox(transaction: transaction)
|
||||
let lastInteraction = thread.lastInteractionForInbox(transaction: transaction)
|
||||
self.lastMessageForInbox = lastInteraction
|
||||
self.lastMessageDate = lastInteraction?.receivedAtDate() ?? thread.creationDate
|
||||
|
||||
if let contactThread = thread as? TSContactThread {
|
||||
self.contactIdentifier = contactThread.contactIdentifier()
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class OWS110SortIdMigration: OWSDatabaseMigration {
|
||||
// increment a similar constant for each migration.
|
||||
@objc
|
||||
class func migrationId() -> String {
|
||||
return "110"
|
||||
}
|
||||
|
||||
override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) {
|
||||
Logger.debug("")
|
||||
BenchAsync(title: "Sort Migration") { completeBenchmark in
|
||||
self.doMigration {
|
||||
completeBenchmark()
|
||||
completion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func doMigration(completion: @escaping OWSDatabaseMigrationCompletion) {
|
||||
// TODO batch this?
|
||||
self.dbReadWriteConnection().readWrite { transaction in
|
||||
|
||||
var archivedThreads: [TSThread] = []
|
||||
|
||||
// get archived threads before migration
|
||||
TSThread.enumerateCollectionObjects(with: transaction) { (object, _) in
|
||||
guard let thread = object as? TSThread else {
|
||||
owsFailDebug("unexpected object: \(type(of: object))")
|
||||
return
|
||||
}
|
||||
|
||||
if thread.isArchivedByLegacyTimestampForSorting {
|
||||
archivedThreads.append(thread)
|
||||
}
|
||||
}
|
||||
|
||||
guard let legacySorting: YapDatabaseAutoViewTransaction = transaction.extension(TSMessageDatabaseViewExtensionName_Legacy) as? YapDatabaseAutoViewTransaction else {
|
||||
owsFailDebug("legacySorting was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
let totalCount: UInt = legacySorting.numberOfItemsInAllGroups()
|
||||
var completedCount: UInt = 0
|
||||
legacySorting.enumerateGroups { group, _ in
|
||||
autoreleasepool {
|
||||
legacySorting.enumerateKeysAndObjects(inGroup: group) { (_, _, object, _, _) in
|
||||
autoreleasepool {
|
||||
guard let interaction = object as? TSInteraction else {
|
||||
owsFailDebug("unexpected object: \(type(of: object))")
|
||||
return
|
||||
}
|
||||
|
||||
interaction.saveNextSortId(transaction: transaction)
|
||||
|
||||
completedCount += 1
|
||||
|
||||
if completedCount % 100 == 0 {
|
||||
// Legit usage of legacy sorting for migration to new sorting
|
||||
Logger.info("thread: \(interaction.uniqueThreadId), timestampForLegacySorting:\(interaction.timestampForLegacySorting()), sortId: \(interaction.sortId) totalCount: \(totalCount), completedcount: \(completedCount)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("re-archiving \(archivedThreads.count) threads which were previously archived")
|
||||
for archivedThread in archivedThreads {
|
||||
archivedThread.archiveThread(with: transaction)
|
||||
}
|
||||
|
||||
self.save(with: transaction)
|
||||
}
|
||||
|
||||
completion()
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[[OWS107LegacySounds alloc] init],
|
||||
[[OWS108CallLoggingPreference alloc] init],
|
||||
[[OWS109OutgoingMessageState alloc] init],
|
||||
[OWS110SortIdMigration new],
|
||||
[[OWS111UDAttributesMigration alloc] init],
|
||||
[[OWS112TypingIndicatorsMigration alloc] init],
|
||||
[[OWS113MultiAttachmentMediaMessages alloc] init],
|
||||
|
|
|
@ -1494,6 +1494,7 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
|
|||
return;
|
||||
}
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
OWSProfileKeyMessage *message =
|
||||
[[OWSProfileKeyMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread];
|
||||
[OWSProfileManager.sharedManager addThreadToProfileWhitelist:thread];
|
||||
|
|
|
@ -5,7 +5,21 @@
|
|||
import Foundation
|
||||
import SignalServiceKit
|
||||
|
||||
public class ConversationSearchResult: Comparable {
|
||||
public typealias MessageSortKey = UInt64
|
||||
public struct ConversationSortKey: Comparable {
|
||||
let creationDate: Date
|
||||
let lastMessageReceivedAtDate: Date?
|
||||
|
||||
// MARK: Comparable
|
||||
|
||||
public static func < (lhs: ConversationSortKey, rhs: ConversationSortKey) -> Bool {
|
||||
let lhsDate = lhs.lastMessageReceivedAtDate ?? lhs.creationDate
|
||||
let rhsDate = rhs.lastMessageReceivedAtDate ?? rhs.creationDate
|
||||
return lhsDate < rhsDate
|
||||
}
|
||||
}
|
||||
|
||||
public class ConversationSearchResult<SortKey>: Comparable where SortKey: Comparable {
|
||||
public let thread: ThreadViewModel
|
||||
|
||||
public let messageId: String?
|
||||
|
@ -13,9 +27,9 @@ public class ConversationSearchResult: Comparable {
|
|||
|
||||
public let snippet: String?
|
||||
|
||||
private let sortKey: UInt64
|
||||
private let sortKey: SortKey
|
||||
|
||||
init(thread: ThreadViewModel, sortKey: UInt64, messageId: String? = nil, messageDate: Date? = nil, snippet: String? = nil) {
|
||||
init(thread: ThreadViewModel, sortKey: SortKey, messageId: String? = nil, messageDate: Date? = nil, snippet: String? = nil) {
|
||||
self.thread = thread
|
||||
self.sortKey = sortKey
|
||||
self.messageId = messageId
|
||||
|
@ -65,11 +79,11 @@ public class ContactSearchResult: Comparable {
|
|||
|
||||
public class SearchResultSet {
|
||||
public let searchText: String
|
||||
public let conversations: [ConversationSearchResult]
|
||||
public let conversations: [ConversationSearchResult<ConversationSortKey>]
|
||||
public let contacts: [ContactSearchResult]
|
||||
public let messages: [ConversationSearchResult]
|
||||
public let messages: [ConversationSearchResult<MessageSortKey>]
|
||||
|
||||
public init(searchText: String, conversations: [ConversationSearchResult], contacts: [ContactSearchResult], messages: [ConversationSearchResult]) {
|
||||
public init(searchText: String, conversations: [ConversationSearchResult<ConversationSortKey>], contacts: [ContactSearchResult], messages: [ConversationSearchResult<MessageSortKey>]) {
|
||||
self.searchText = searchText
|
||||
self.conversations = conversations
|
||||
self.contacts = contacts
|
||||
|
@ -101,9 +115,9 @@ public class ConversationSearcher: NSObject {
|
|||
transaction: YapDatabaseReadTransaction,
|
||||
contactsManager: ContactsManagerProtocol) -> SearchResultSet {
|
||||
|
||||
var conversations: [ConversationSearchResult] = []
|
||||
var conversations: [ConversationSearchResult<ConversationSortKey>] = []
|
||||
var contacts: [ContactSearchResult] = []
|
||||
var messages: [ConversationSearchResult] = []
|
||||
var messages: [ConversationSearchResult<MessageSortKey>] = []
|
||||
|
||||
var existingConversationRecipientIds: Set<String> = Set()
|
||||
|
||||
|
@ -111,7 +125,8 @@ public class ConversationSearcher: NSObject {
|
|||
|
||||
if let thread = match as? TSThread {
|
||||
let threadViewModel = ThreadViewModel(thread: thread, transaction: transaction)
|
||||
let sortKey = NSDate.ows_millisecondsSince1970(for: threadViewModel.lastMessageDate)
|
||||
let sortKey = ConversationSortKey(creationDate: thread.creationDate,
|
||||
lastMessageReceivedAtDate: thread.lastInteractionForInbox(transaction: transaction)?.receivedAtDate())
|
||||
let searchResult = ConversationSearchResult(thread: threadViewModel, sortKey: sortKey)
|
||||
|
||||
if let contactThread = thread as? TSContactThread {
|
||||
|
@ -124,7 +139,7 @@ public class ConversationSearcher: NSObject {
|
|||
let thread = message.thread(with: transaction)
|
||||
|
||||
let threadViewModel = ThreadViewModel(thread: thread, transaction: transaction)
|
||||
let sortKey = message.timestamp
|
||||
let sortKey = message.sortId
|
||||
let searchResult = ConversationSearchResult(thread: threadViewModel,
|
||||
sortKey: sortKey,
|
||||
messageId: message.uniqueId,
|
||||
|
|
|
@ -6,13 +6,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@interface OWSUnreadIndicator : NSObject
|
||||
|
||||
@property (nonatomic, readonly) uint64_t timestamp;
|
||||
|
||||
@property (nonatomic, readonly) BOOL hasMoreUnseenMessages;
|
||||
|
||||
@property (nonatomic, readonly) NSUInteger missingUnseenSafetyNumberChangeCount;
|
||||
|
||||
// The timestamp of the oldest unseen message.
|
||||
// The sortId of the oldest unseen message.
|
||||
//
|
||||
// Once we enter messages view, we mark all messages read, so we need
|
||||
// a snapshot of what the first unread message was when we entered the
|
||||
|
@ -20,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// repeatedly. The unread indicator should continue to show up until
|
||||
// it has been cleared, at which point hideUnreadMessagesIndicator is
|
||||
// YES in ensureDynamicInteractionsForThread:...
|
||||
@property (nonatomic, readonly) uint64_t firstUnseenInteractionTimestamp;
|
||||
@property (nonatomic, readonly) uint64_t firstUnseenSortId;
|
||||
|
||||
// The index of the unseen indicator, counting from the _end_ of the conversation
|
||||
// history.
|
||||
|
@ -32,11 +30,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initUnreadIndicatorWithTimestamp:(uint64_t)timestamp
|
||||
- (instancetype)initWithFirstUnseenSortId:(uint64_t)firstUnseenSortId
|
||||
hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:(NSInteger)unreadIndicatorPosition
|
||||
firstUnseenInteractionTimestamp:(uint64_t)firstUnseenInteractionTimestamp NS_DESIGNATED_INITIALIZER;
|
||||
unreadIndicatorPosition:(NSInteger)unreadIndicatorPosition NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -8,11 +8,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@implementation OWSUnreadIndicator
|
||||
|
||||
- (instancetype)initUnreadIndicatorWithTimestamp:(uint64_t)timestamp
|
||||
- (instancetype)initWithFirstUnseenSortId:(uint64_t)firstUnseenSortId
|
||||
hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:(NSInteger)unreadIndicatorPosition
|
||||
firstUnseenInteractionTimestamp:(uint64_t)firstUnseenInteractionTimestamp
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
@ -20,11 +19,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return self;
|
||||
}
|
||||
|
||||
_timestamp = timestamp;
|
||||
_firstUnseenSortId = firstUnseenSortId;
|
||||
_hasMoreUnseenMessages = hasMoreUnseenMessages;
|
||||
_missingUnseenSafetyNumberChangeCount = missingUnseenSafetyNumberChangeCount;
|
||||
_unreadIndicatorPosition = unreadIndicatorPosition;
|
||||
_firstUnseenInteractionTimestamp = firstUnseenInteractionTimestamp;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -40,7 +38,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
OWSUnreadIndicator *other = object;
|
||||
return (self.timestamp == other.timestamp && self.hasMoreUnseenMessages == other.hasMoreUnseenMessages
|
||||
return (self.firstUnseenSortId == other.firstUnseenSortId
|
||||
&& self.hasMoreUnseenMessages == other.hasMoreUnseenMessages
|
||||
&& self.missingUnseenSafetyNumberChangeCount == other.missingUnseenSafetyNumberChangeCount
|
||||
&& self.unreadIndicatorPosition == other.unreadIndicatorPosition);
|
||||
}
|
||||
|
|
|
@ -235,6 +235,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
|
||||
BOOL isVoiceMessage = (attachments.count == 1 && attachments.firstObject.isVoiceMessage);
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -291,6 +292,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
|
||||
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -372,14 +374,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// have been marked as read.
|
||||
//
|
||||
// IFF this variable is non-null, there are unseen messages in the thread.
|
||||
NSNumber *_Nullable firstUnseenInteractionTimestamp = nil;
|
||||
NSNumber *_Nullable firstUnseenSortId = nil;
|
||||
if (lastUnreadIndicator) {
|
||||
firstUnseenInteractionTimestamp = @(lastUnreadIndicator.firstUnseenInteractionTimestamp);
|
||||
firstUnseenSortId = @(lastUnreadIndicator.firstUnseenSortId);
|
||||
} else {
|
||||
TSInteraction *_Nullable firstUnseenInteraction =
|
||||
[[TSDatabaseView unseenDatabaseViewExtension:transaction] firstObjectInGroup:thread.uniqueId];
|
||||
if (firstUnseenInteraction) {
|
||||
firstUnseenInteractionTimestamp = @(firstUnseenInteraction.timestampForSorting);
|
||||
firstUnseenSortId = @(firstUnseenInteraction.sortId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,7 +423,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (hideUnreadMessagesIndicator) {
|
||||
return;
|
||||
}
|
||||
if (!firstUnseenInteractionTimestamp) {
|
||||
if (!firstUnseenSortId) {
|
||||
// If there are no unseen interactions, don't show an unread indicator.
|
||||
return;
|
||||
}
|
||||
|
@ -489,13 +491,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (hasMoreUnseenMessages) {
|
||||
NSMutableSet<NSData *> *missingUnseenSafetyNumberChanges = [NSMutableSet set];
|
||||
for (TSInvalidIdentityKeyErrorMessage *safetyNumberChange in blockingSafetyNumberChanges) {
|
||||
BOOL isUnseen
|
||||
= safetyNumberChange.timestampForSorting >= firstUnseenInteractionTimestamp.unsignedLongLongValue;
|
||||
BOOL isUnseen = safetyNumberChange.sortId >= firstUnseenSortId.unsignedLongLongValue;
|
||||
if (!isUnseen) {
|
||||
continue;
|
||||
}
|
||||
BOOL isMissing
|
||||
= safetyNumberChange.timestampForSorting < interactionAfterUnreadIndicator.timestampForSorting;
|
||||
|
||||
BOOL isMissing = safetyNumberChange.sortId < interactionAfterUnreadIndicator.sortId;
|
||||
if (!isMissing) {
|
||||
continue;
|
||||
}
|
||||
|
@ -521,13 +522,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
NSInteger unreadIndicatorPosition = visibleUnseenMessageCount;
|
||||
|
||||
dynamicInteractions.unreadIndicator = [[OWSUnreadIndicator alloc]
|
||||
initUnreadIndicatorWithTimestamp:interactionAfterUnreadIndicator.timestampForSorting
|
||||
dynamicInteractions.unreadIndicator =
|
||||
[[OWSUnreadIndicator alloc] initWithFirstUnseenSortId:firstUnseenSortId.unsignedLongLongValue
|
||||
hasMoreUnseenMessages:hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:unreadIndicatorPosition
|
||||
firstUnseenInteractionTimestamp:firstUnseenInteractionTimestamp.unsignedLongLongValue];
|
||||
OWSLogInfo(@"Creating Unread Indicator: %llu", dynamicInteractions.unreadIndicator.timestamp);
|
||||
unreadIndicatorPosition:unreadIndicatorPosition];
|
||||
OWSLogInfo(@"Creating Unread Indicator: %llu", dynamicInteractions.unreadIndicator.firstUnseenSortId);
|
||||
}
|
||||
|
||||
+ (nullable NSNumber *)focusMessagePositionForThread:(TSThread *)thread
|
||||
|
|
|
@ -32,8 +32,9 @@ extern ConversationColorName const kConversationColorName_Default;
|
|||
*/
|
||||
@interface TSThread : TSYapDatabaseObject
|
||||
|
||||
// YES IFF this thread has ever had a message.
|
||||
@property (nonatomic) BOOL shouldThreadBeVisible;
|
||||
@property (nonatomic, readonly) NSDate *creationDate;
|
||||
@property (nonatomic, readonly) BOOL isArchivedByLegacyTimestampForSorting;
|
||||
|
||||
/**
|
||||
* Whether the object is a group thread or not.
|
||||
|
@ -77,7 +78,10 @@ extern ConversationColorName const kConversationColorName_Default;
|
|||
/**
|
||||
* Get all messages in the thread we weren't able to decrypt
|
||||
*/
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
- (NSArray<TSInvalidIdentityKeyReceivingErrorMessage *> *)receivedMessagesForInvalidKey:(NSData *)key;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (NSUInteger)unreadMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
NS_SWIFT_NAME(unreadMessageCount(transaction:));
|
||||
|
@ -86,14 +90,6 @@ extern ConversationColorName const kConversationColorName_Default;
|
|||
|
||||
- (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Returns the latest date of a message in the thread or the thread creation date if there are no messages in that
|
||||
*thread.
|
||||
*
|
||||
* @return The date of the last message or thread creation date.
|
||||
*/
|
||||
- (NSDate *)lastMessageDate;
|
||||
|
||||
/**
|
||||
* Returns the string that will be displayed typically in a conversations view as a preview of the last message
|
||||
*received in this thread.
|
||||
|
@ -117,31 +113,19 @@ extern ConversationColorName const kConversationColorName_Default;
|
|||
#pragma mark Archival
|
||||
|
||||
/**
|
||||
* Returns the last date at which a string was archived or nil if the thread was never archived or brought back to the
|
||||
*inbox.
|
||||
*
|
||||
* @return Last archival date.
|
||||
* @return YES if no new messages have been sent or received since the thread was last archived.
|
||||
*/
|
||||
- (nullable NSDate *)archivalDate;
|
||||
- (BOOL)isArchivedWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Archives a thread with the current date.
|
||||
* Archives a thread
|
||||
*
|
||||
* @param transaction Database transaction.
|
||||
*/
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Archives a thread with the reference date. This is currently only used for migrating older data that has already
|
||||
* been archived.
|
||||
*
|
||||
* @param transaction Database transaction.
|
||||
* @param date Date at which the thread was archived.
|
||||
*/
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction referenceDate:(NSDate *)date;
|
||||
|
||||
/**
|
||||
* Unarchives a thread that was archived previously.
|
||||
* Unarchives a thread
|
||||
*
|
||||
* @param transaction Database transaction.
|
||||
*/
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#import <SignalCoreKit/Cryptography.h>
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalCoreKit/NSString+SSK.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
@ -37,10 +38,8 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
@interface TSThread ()
|
||||
|
||||
@property (nonatomic) NSDate *creationDate;
|
||||
@property (nonatomic, copy, nullable) NSDate *archivalDate;
|
||||
@property (nonatomic) NSString *conversationColorName;
|
||||
@property (nonatomic, nullable) NSDate *lastMessageDate;
|
||||
|
||||
@property (nonatomic) NSNumber *archivedAsOfMessageSortId;
|
||||
@property (nonatomic, copy, nullable) NSString *messageDraft;
|
||||
@property (atomic, nullable) NSDate *mutedUntilDate;
|
||||
|
||||
|
@ -59,8 +58,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
self = [super initWithUniqueId:uniqueId];
|
||||
|
||||
if (self) {
|
||||
_archivalDate = nil;
|
||||
_lastMessageDate = nil;
|
||||
_creationDate = [NSDate date];
|
||||
_messageDraft = nil;
|
||||
|
||||
|
@ -122,6 +119,12 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
_conversationColorName = mappedColorName;
|
||||
}
|
||||
|
||||
// MJK TODO - keep these legacy properties around for a while, just in case...
|
||||
NSDate *_Nullable lastMessageDate = [coder decodeObjectOfClass:NSDate.class forKey:@"lastMessageDate"];
|
||||
NSDate *_Nullable archivalDate = [coder decodeObjectOfClass:NSDate.class forKey:@"archivalDate"];
|
||||
_isArchivedByLegacyTimestampForSorting =
|
||||
[self.class legacyIsArchivedWithLastMessageDate:lastMessageDate archivalDate:archivalDate];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -250,6 +253,8 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
return [interactions copy];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
- (NSArray<TSInvalidIdentityKeyReceivingErrorMessage *> *)receivedMessagesForInvalidKey:(NSData *)key
|
||||
{
|
||||
NSMutableArray *errorMessages = [NSMutableArray new];
|
||||
|
@ -268,6 +273,7 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
|
||||
return [errorMessages copy];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (NSUInteger)numberOfInteractions
|
||||
{
|
||||
|
@ -343,14 +349,6 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
return last;
|
||||
}
|
||||
|
||||
- (NSDate *)lastMessageDate {
|
||||
if (_lastMessageDate) {
|
||||
return _lastMessageDate;
|
||||
} else {
|
||||
return _creationDate;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)lastMessageTextWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
TSInteraction *interaction = [self lastInteractionForInboxWithTransaction:transaction];
|
||||
|
@ -398,10 +396,10 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
|
||||
self.shouldThreadBeVisible = YES;
|
||||
|
||||
// MJK FIXME - reconcile this
|
||||
NSDate *lastMessageDate = [lastMessage dateForSorting];
|
||||
if (!_lastMessageDate || [lastMessageDate timeIntervalSinceDate:self.lastMessageDate] > 0) {
|
||||
_lastMessageDate = lastMessageDate;
|
||||
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
@ -426,30 +424,54 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark Archival
|
||||
#pragma mark - Archival
|
||||
|
||||
- (nullable NSDate *)archivalDate
|
||||
- (BOOL)isArchivedWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
{
|
||||
return _archivalDate;
|
||||
if (!self.archivedAsOfMessageSortId) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
[self archiveThreadWithTransaction:transaction referenceDate:[NSDate date]];
|
||||
TSInteraction *_Nullable latestInteraction = [self lastInteractionForInboxWithTransaction:transaction];
|
||||
uint64_t latestSortIdForInbox = latestInteraction ? latestInteraction.sortId : 0;
|
||||
return self.archivedAsOfMessageSortId.unsignedLongLongValue >= latestSortIdForInbox;
|
||||
}
|
||||
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction referenceDate:(NSDate *)date {
|
||||
+ (BOOL)legacyIsArchivedWithLastMessageDate:(nullable NSDate *)lastMessageDate
|
||||
archivalDate:(nullable NSDate *)archivalDate
|
||||
{
|
||||
if (!archivalDate) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!lastMessageDate) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return [archivalDate compare:lastMessageDate] != NSOrderedAscending;
|
||||
}
|
||||
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[self applyChangeToSelfAndLatestCopy:transaction
|
||||
changeBlock:^(TSThread *thread) {
|
||||
uint64_t latestId = [SSKIncrementingIdFinder previousIdWithKey:TSInteraction.collection
|
||||
transaction:transaction];
|
||||
thread.archivedAsOfMessageSortId = @(latestId);
|
||||
}];
|
||||
|
||||
[self markAllAsReadWithTransaction:transaction];
|
||||
_archivalDate = date;
|
||||
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
- (void)unarchiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
_archivalDate = nil;
|
||||
[self saveWithTransaction:transaction];
|
||||
- (void)unarchiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[self applyChangeToSelfAndLatestCopy:transaction
|
||||
changeBlock:^(TSThread *thread) {
|
||||
thread.archivedAsOfMessageSortId = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark Drafts
|
||||
#pragma mark - Drafts
|
||||
|
||||
- (NSString *)currentDraftWithTransaction:(YapDatabaseReadTransaction *)transaction {
|
||||
TSThread *thread = [TSThread fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
|
||||
|
|
|
@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
messageTimestamps:(NSArray<NSNumber *> *)messageTimestamps
|
||||
receiptType:(SSKProtoReceiptMessageType)receiptType
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -88,6 +88,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (transcript.isEndSessionMessage) {
|
||||
OWSLogInfo(@"EndSession was sent to recipient: %@.", transcript.recipientId);
|
||||
[self.primaryStorage deleteAllSessionsForContact:transcript.recipientId protocolContext:transaction];
|
||||
|
||||
// MJK TODO - we don't use this timestamp, safe to remove
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp
|
||||
inThread:transcript.thread
|
||||
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];
|
||||
|
@ -145,12 +147,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
if (transcript.isExpirationTimerUpdate) {
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage
|
||||
contactsManager:self.contactsManager
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:outgoingMessage.expiresInSeconds
|
||||
thread:transcript.thread
|
||||
createdByRemoteRecipientId:nil
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
|
||||
|
||||
if (transcript.isExpirationTimerUpdate) {
|
||||
// early return to avoid saving an empty incoming message.
|
||||
OWSAssertDebug(transcript.body.length == 0);
|
||||
OWSAssertDebug(outgoingMessage.attachmentIds.count == 0);
|
||||
|
@ -167,9 +170,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[outgoingMessage updateWithWasSentFromLinkedDeviceWithUDRecipientIds:transcript.udRecipientIds
|
||||
nonUdRecipientIds:transcript.nonUdRecipientIds
|
||||
transaction:transaction];
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage
|
||||
contactsManager:self.contactsManager
|
||||
transaction:transaction];
|
||||
[[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:outgoingMessage
|
||||
expirationStartedAt:transcript.expirationStartedAt
|
||||
transaction:transaction];
|
||||
|
|
|
@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)init
|
||||
{
|
||||
// MJK TODO - remove SenderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:nil
|
||||
messageBody:nil
|
||||
|
|
|
@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithThread:(nullable TSThread *)thread groupId:(NSData *)groupId
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
* @param remoteName is nil when created by the local user
|
||||
*/
|
||||
// MJK TODO - can we remove sendertimestamp here
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
configuration:(OWSDisappearingMessagesConfiguration *)configuration
|
||||
|
|
|
@ -74,7 +74,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [NSString stringWithFormat:infoFormat, self.createdByRemoteName];
|
||||
}
|
||||
} else {
|
||||
// Changed by local request
|
||||
// Changed by localNumber on this device or via synced transcript
|
||||
if (self.configurationIsEnabled && self.configurationDurationSeconds > 0) {
|
||||
NSString *infoFormat = NSLocalizedString(@"YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION",
|
||||
@"Info message embedding a {{time amount}}, see the *_TIME_AMOUNT strings for context.");
|
||||
|
|
|
@ -10,6 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@interface OWSDisappearingMessagesConfigurationMessage : TSOutgoingMessage
|
||||
|
||||
// MJK TODO - remove senderTimestamp
|
||||
- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(nullable TSThread *)thread
|
||||
messageBody:(nullable NSString *)body
|
||||
|
|
|
@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithConfiguration:(OWSDisappearingMessagesConfiguration *)configuration thread:(TSThread *)thread
|
||||
{
|
||||
// MJK TODO - remove sender timestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -11,6 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
typedef NSData *_Nonnull (^DynamicOutgoingMessageBlock)(SignalRecipient *);
|
||||
|
||||
/// This class is only used in debug tools
|
||||
@interface OWSDynamicOutgoingMessage : TSOutgoingMessage
|
||||
|
||||
- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp
|
||||
|
|
|
@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [self initWithPlainTextDataBlock:block timestamp:[NSDate ows_millisecondTimeStamp] thread:thread];
|
||||
}
|
||||
|
||||
// MJK TODO can we remove sender timestamp?
|
||||
- (instancetype)initWithPlainTextDataBlock:(DynamicOutgoingMessageBlock)block
|
||||
timestamp:(uint64_t)timestamp
|
||||
thread:(nullable TSThread *)thread
|
||||
|
|
|
@ -20,6 +20,7 @@ NS_SWIFT_NAME(EndSessionMessage)
|
|||
quotedMessage:(nullable TSQuotedMessage *)quotedMessage
|
||||
contactShare:(nullable OWSContact *)contactShare NS_UNAVAILABLE;
|
||||
|
||||
// MJK TODO can we remove the sender timestamp?
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(nullable TSThread *)thread NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSRecipientIdentity.h"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSVerificationStateChangeMessage.h"
|
||||
|
|
|
@ -51,10 +51,6 @@ typedef NS_ENUM(int32_t, TSErrorMessageType) {
|
|||
failedMessageType:(TSErrorMessageType)errorMessageType
|
||||
recipientId:(nullable NSString *)recipientId NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(nullable TSThread *)thread
|
||||
failedMessageType:(TSErrorMessageType)errorMessageType;
|
||||
|
||||
+ (instancetype)corruptedMessageWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
|
|
|
@ -91,14 +91,11 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
|
|||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp. We don't actually currently surface it in the UI, but it serves as
|
||||
// a reference to the envelope which we failed to process.
|
||||
return [self initWithTimestamp:envelope.timestamp inThread:contactThread failedMessageType:errorMessageType];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFailedMessageType:(TSErrorMessageType)errorMessageType
|
||||
{
|
||||
return [self initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:nil failedMessageType:errorMessageType];
|
||||
}
|
||||
|
||||
- (OWSInteractionType)interactionType
|
||||
{
|
||||
return OWSInteractionType_Error;
|
||||
|
@ -157,7 +154,10 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
|
|||
|
||||
+ (instancetype)corruptedMessageInUnknownThread
|
||||
{
|
||||
return [[self alloc] initWithFailedMessageType:TSErrorMessageInvalidMessage];
|
||||
// MJK TODO - Seems like we could safely remove this timestamp
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:nil
|
||||
failedMessageType:TSErrorMessageInvalidMessage];
|
||||
}
|
||||
|
||||
+ (instancetype)invalidVersionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
|
@ -185,6 +185,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
|
|||
|
||||
+ (instancetype)nonblockingIdentityChangeInThread:(TSThread *)thread recipientId:(NSString *)recipientId
|
||||
{
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageNonBlockingIdentityChange
|
||||
|
|
|
@ -4,17 +4,16 @@
|
|||
|
||||
#import "TSErrorMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TSErrorMessage ()
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(TSThread *)thread
|
||||
inThread:(nullable TSThread *)thread
|
||||
failedMessageType:(TSErrorMessageType)errorMessageType NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (atomic, nullable) NSData *envelopeData;
|
||||
|
||||
@property NSDictionary *pendingOutgoingMessage;
|
||||
|
||||
#define TSPendingOutgoingMessageKey @"TSPendingOutgoingMessageKey"
|
||||
#define TSPendingOutgoingMessageRecipientKey @"TSPendingOutgoingMessageRecipientKey"
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -48,6 +48,7 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
|
|||
inThread:(TSThread *)thread
|
||||
messageType:(TSInfoMessageType)infoMessage
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initMessageWithTimestamp:timestamp
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
@ -100,6 +101,7 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
|
|||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(recipientId);
|
||||
|
||||
// MJK TODO - remove senderTimestamp
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageUserNotRegistered
|
||||
|
|
|
@ -37,6 +37,9 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
|||
@property (nonatomic, readonly) NSString *uniqueThreadId;
|
||||
@property (nonatomic, readonly) TSThread *thread;
|
||||
@property (nonatomic, readonly) uint64_t timestamp;
|
||||
@property (nonatomic, readonly) uint64_t sortId;
|
||||
@property (nonatomic, readonly) uint64_t receivedAtTimestamp;
|
||||
- (NSDate *)receivedAtDate;
|
||||
|
||||
- (OWSInteractionType)interactionType;
|
||||
|
||||
|
@ -58,8 +61,8 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
|||
filter:(BOOL (^_Nonnull)(TSInteraction *))filter
|
||||
withTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
- (NSDate *)dateForSorting;
|
||||
- (uint64_t)timestampForSorting;
|
||||
- (NSDate *)dateForLegacySorting;
|
||||
- (uint64_t)timestampForLegacySorting;
|
||||
- (NSComparisonResult)compareForSorting:(TSInteraction *)other;
|
||||
|
||||
// "Dynamic" interactions are not messages or static events (like
|
||||
|
@ -70,6 +73,9 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
|||
// unseen message indicators, etc.
|
||||
- (BOOL)isDynamicInteraction;
|
||||
|
||||
- (void)saveNextSortIdWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
NS_SWIFT_NAME(saveNextSortId(transaction:));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#import "TSDatabaseSecondaryIndexes.h"
|
||||
#import "TSThread.h"
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -31,6 +32,12 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
}
|
||||
}
|
||||
|
||||
@interface TSInteraction ()
|
||||
|
||||
@property (nonatomic) uint64_t sortId;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TSInteraction
|
||||
|
||||
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
|
||||
|
@ -58,7 +65,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
[TSDatabaseSecondaryIndexes
|
||||
enumerateMessagesWithTimestamp:timestamp
|
||||
withBlock:^(NSString *collection, NSString *key, BOOL *stop) {
|
||||
|
||||
TSInteraction *interaction =
|
||||
[TSInteraction fetchObjectWithUniqueID:key transaction:transaction];
|
||||
if (!filter(interaction)) {
|
||||
|
@ -105,6 +111,37 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
|
||||
_timestamp = timestamp;
|
||||
_uniqueThreadId = thread.uniqueId;
|
||||
_receivedAtTimestamp = [NSDate ows_millisecondTimeStamp];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Previously the receivedAtTimestamp field lived on TSMessage, but we've moved it up
|
||||
// to the TSInteraction superclass.
|
||||
if (_receivedAtTimestamp == 0) {
|
||||
// Upgrade from the older "TSMessage.receivedAtDate" and "TSMessage.receivedAt" properties if
|
||||
// necessary.
|
||||
NSDate *receivedAtDate = [coder decodeObjectForKey:@"receivedAtDate"];
|
||||
if (!receivedAtDate) {
|
||||
receivedAtDate = [coder decodeObjectForKey:@"receivedAt"];
|
||||
}
|
||||
|
||||
if (receivedAtDate) {
|
||||
_receivedAtTimestamp = [NSDate ows_millisecondsSince1970ForDate:receivedAtDate];
|
||||
}
|
||||
|
||||
// For TSInteractions which are not TSMessage's, the timestamp *is* the receivedAtTimestamp
|
||||
if (_receivedAtTimestamp == 0) {
|
||||
_receivedAtTimestamp = _timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -129,26 +166,31 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
|
||||
#pragma mark Date operations
|
||||
|
||||
- (NSDate *)dateForSorting
|
||||
- (NSDate *)dateForLegacySorting
|
||||
{
|
||||
return [NSDate ows_dateWithMillisecondsSince1970:self.timestampForSorting];
|
||||
return [NSDate ows_dateWithMillisecondsSince1970:self.timestampForLegacySorting];
|
||||
}
|
||||
|
||||
- (uint64_t)timestampForSorting
|
||||
- (uint64_t)timestampForLegacySorting
|
||||
{
|
||||
return self.timestamp;
|
||||
}
|
||||
|
||||
- (NSDate *)receivedAtDate
|
||||
{
|
||||
return [NSDate ows_dateWithMillisecondsSince1970:self.receivedAtTimestamp];
|
||||
}
|
||||
|
||||
- (NSComparisonResult)compareForSorting:(TSInteraction *)other
|
||||
{
|
||||
OWSAssertDebug(other);
|
||||
|
||||
uint64_t timestamp1 = self.timestampForSorting;
|
||||
uint64_t timestamp2 = other.timestampForSorting;
|
||||
uint64_t sortId1 = self.sortId;
|
||||
uint64_t sortId2 = self.sortId;
|
||||
|
||||
if (timestamp1 > timestamp2) {
|
||||
if (sortId1 > sortId2) {
|
||||
return NSOrderedDescending;
|
||||
} else if (timestamp1 < timestamp2) {
|
||||
} else if (sortId1 < sortId2) {
|
||||
return NSOrderedAscending;
|
||||
} else {
|
||||
return NSOrderedSame;
|
||||
|
@ -170,15 +212,21 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
(unsigned long)self.timestamp];
|
||||
}
|
||||
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// MJK can we remove this? We can't trust the legacy order of this id field. Any reason not to use UUID like for
|
||||
// other objects?
|
||||
if (!self.uniqueId) {
|
||||
OWSFailDebug(@"Missing uniqueId.");
|
||||
self.uniqueId = [NSUUID new].UUIDString;
|
||||
}
|
||||
if (self.sortId == 0) {
|
||||
self.sortId = [SSKIncrementingIdFinder nextIdWithKey:[TSInteraction collection] transaction:transaction];
|
||||
}
|
||||
|
||||
[super saveWithTransaction:transaction];
|
||||
|
||||
TSThread *fetchedThread = [TSThread fetchObjectWithUniqueID:self.uniqueThreadId transaction:transaction];
|
||||
TSThread *fetchedThread = [self threadWithTransaction:transaction];
|
||||
|
||||
[fetchedThread updateWithLastMessage:self transaction:transaction];
|
||||
}
|
||||
|
@ -195,6 +243,20 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - sorting migration
|
||||
|
||||
- (void)saveNextSortIdWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
if (self.sortId != 0) {
|
||||
// This could happen if something else in our startup process saved the interaction
|
||||
// e.g. another migration ran.
|
||||
// During the migration, since we're enumerating the interactions in the proper order,
|
||||
// we want to ignore any previously assigned sortId
|
||||
self.sortId = 0;
|
||||
}
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -47,13 +47,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
*/
|
||||
@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) uint64_t receivedAtTimestamp;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
@ -82,7 +75,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
_expiresInSeconds = expiresInSeconds;
|
||||
_expireStartedAt = expireStartedAt;
|
||||
[self updateExpiresAt];
|
||||
_receivedAtTimestamp = [NSDate ows_millisecondTimeStamp];
|
||||
_quotedMessage = quotedMessage;
|
||||
_contactShare = contactShare;
|
||||
|
||||
|
@ -135,18 +127,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
_attachmentIds = [NSMutableArray new];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
_schemaVersion = OWSMessageSchemaVersion;
|
||||
|
||||
return self;
|
||||
|
@ -382,7 +362,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
return self.expiresInSeconds > 0;
|
||||
}
|
||||
|
||||
- (uint64_t)timestampForSorting
|
||||
- (uint64_t)timestampForLegacySorting
|
||||
{
|
||||
if ([self shouldUseReceiptDateForSorting] && self.receivedAtTimestamp > 0) {
|
||||
return self.receivedAtTimestamp;
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) {
|
|||
quotedMessage:(nullable TSQuotedMessage *)quotedMessage
|
||||
contactShare:(nullable OWSContact *)contactShare NS_UNAVAILABLE;
|
||||
|
||||
// MJK TODO - Can we remove the sender timestamp param?
|
||||
- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(nullable TSThread *)thread
|
||||
messageBody:(nullable NSString *)body
|
||||
|
|
|
@ -257,6 +257,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt
|
|||
[attachmentIds addObject:attachmentId];
|
||||
}
|
||||
|
||||
// MJK TODO remove SenderTimestamp?
|
||||
return [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:body
|
||||
|
@ -273,6 +274,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt
|
|||
groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage
|
||||
expiresInSeconds:(uint32_t)expiresInSeconds;
|
||||
{
|
||||
// MJK TODO remove SenderTimestamp?
|
||||
return [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -208,6 +208,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return nil;
|
||||
}
|
||||
|
||||
// Legit usage of senderTimestamp - this class references the message it is quoting by it's sender timestamp
|
||||
return [[TSQuotedMessage alloc] initWithTimestamp:timestamp
|
||||
authorId:authorId
|
||||
body:body
|
||||
|
@ -229,7 +230,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NSArray<TSMessage *> *quotedMessages = (NSArray<TSMessage *> *)[TSInteraction
|
||||
interactionsWithTimestamp:timestamp
|
||||
filter:^BOOL(TSInteraction *interaction) {
|
||||
|
||||
if (![threadId isEqual:interaction.uniqueThreadId]) {
|
||||
return NO;
|
||||
}
|
||||
|
@ -243,7 +243,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// ignore other interaction types
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
withTransaction:transaction];
|
||||
|
||||
|
|
|
@ -10,10 +10,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
// DEPRECATED - we no longer create new instances of this class (as of mid-2017); However, existing instances may
|
||||
// exist, so we should keep this class around to honor their old behavior.
|
||||
@interface TSInvalidIdentityKeyReceivingErrorMessage : TSInvalidIdentityKeyErrorMessage
|
||||
__attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage : TSInvalidIdentityKeyErrorMessage
|
||||
|
||||
#ifdef DEBUG
|
||||
+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// TODO we can eventually deprecate this, since incoming messages are now always decrypted.
|
||||
@interface TSInvalidIdentityKeyReceivingErrorMessage ()
|
||||
__attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage()
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *authorId;
|
||||
|
||||
|
@ -34,11 +33,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@synthesize envelopeData = _envelopeData;
|
||||
|
||||
#ifdef DEBUG
|
||||
// We no longer create these messages, but they might exist on legacy clients so it's useful to be able to
|
||||
// create them with the debug UI
|
||||
+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp, references message which failed to decrypt
|
||||
TSInvalidIdentityKeyReceivingErrorMessage *errorMessage =
|
||||
[[self alloc] initForUnknownIdentityKeyWithTimestamp:envelope.timestamp
|
||||
inThread:contactThread
|
||||
|
@ -66,6 +70,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (nullable SSKProtoEnvelope *)envelope
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSInvalidIdentityKeyErrorMessage.h"
|
||||
|
@ -13,7 +13,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
extern NSString *TSInvalidPreKeyBundleKey;
|
||||
extern NSString *TSInvalidRecipientKey;
|
||||
|
||||
@interface TSInvalidIdentityKeySendingErrorMessage : TSInvalidIdentityKeyErrorMessage
|
||||
// DEPRECATED - we no longer create new instances of this class (as of mid-2017); However, existing instances may
|
||||
// exist, so we should keep this class around to honor their old behavior.
|
||||
__attribute__((deprecated)) @interface TSInvalidIdentityKeySendingErrorMessage : TSInvalidIdentityKeyErrorMessage
|
||||
|
||||
@property (nonatomic, readonly) NSString *messageId;
|
||||
|
||||
|
|
|
@ -24,26 +24,12 @@ NSString *TSInvalidRecipientKey = @"TSInvalidRecipientKey";
|
|||
|
||||
@end
|
||||
|
||||
// DEPRECATED - we no longer create new instances of this class (as of mid-2017); However, existing instances may
|
||||
// exist, so we should keep this class around to honor their old behavior.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation TSInvalidIdentityKeySendingErrorMessage
|
||||
|
||||
- (instancetype)initWithOutgoingMessage:(TSOutgoingMessage *)message
|
||||
inThread:(TSThread *)thread
|
||||
forRecipient:(NSString *)recipientId
|
||||
preKeyBundle:(PreKeyBundle *)preKeyBundle
|
||||
{
|
||||
// We want the error message to appear after the message.
|
||||
self = [super initWithTimestamp:message.timestamp + 1
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageWrongTrustedIdentityKey
|
||||
recipientId:recipientId];
|
||||
|
||||
if (self) {
|
||||
_messageId = message.uniqueId;
|
||||
_preKeyBundle = preKeyBundle;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (void)throws_acceptNewIdentityKey
|
||||
{
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSInfoMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSAddToContactsOfferMessage : TSInfoMessage
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
__attribute__((deprecated)) @interface OWSAddToContactsOfferMessage : TSInfoMessage
|
||||
|
||||
+ (instancetype)addToContactsOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread contactId:(NSString *)contactId;
|
||||
+ (instancetype)addToContactsOfferMessageWithTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId;
|
||||
|
||||
@property (nonatomic, readonly) NSString *contactId;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSAddToContactsOfferMessage.h"
|
||||
|
@ -14,9 +14,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark -
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation OWSAddToContactsOfferMessage
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+ (instancetype)addToContactsOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread contactId:(NSString *)contactId
|
||||
+ (instancetype)addToContactsOfferMessageWithTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId
|
||||
{
|
||||
return [[OWSAddToContactsOfferMessage alloc] initWithTimestamp:timestamp thread:thread contactId:contactId];
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSInfoMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSAddToProfileWhitelistOfferMessage : TSInfoMessage
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
__attribute__((deprecated)) @interface OWSAddToProfileWhitelistOfferMessage : TSInfoMessage
|
||||
|
||||
+ (instancetype)addToProfileWhitelistOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread;
|
||||
+ (instancetype)addToProfileWhitelistOfferMessageWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread;
|
||||
|
||||
@property (nonatomic, readonly) NSString *contactId;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSAddToProfileWhitelistOfferMessage.h"
|
||||
|
@ -7,9 +7,14 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation OWSAddToProfileWhitelistOfferMessage
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+ (instancetype)addToProfileWhitelistOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread
|
||||
+ (instancetype)addToProfileWhitelistOfferMessageWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread
|
||||
{
|
||||
return [[OWSAddToProfileWhitelistOfferMessage alloc]
|
||||
initWithTimestamp:timestamp
|
||||
|
|
|
@ -23,21 +23,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
expirationStartedAt:(uint64_t)expirationStartedAt
|
||||
transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction;
|
||||
|
||||
/**
|
||||
* Synchronize our disappearing messages settings with that of the given message. Useful so we can
|
||||
* become eventually consistent with remote senders.
|
||||
*
|
||||
* @param message
|
||||
* Can be an expiring or non expiring message. We match the expiration timer of the message, including disabling
|
||||
* expiring messages if the message is not an expiring message.
|
||||
*
|
||||
* @param contactsManager
|
||||
* Provides the contact name responsible for any configuration changes in an info message.
|
||||
*/
|
||||
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Synchronize our disappearing messages settings with that of the given message. Useful so we can
|
||||
* become eventually consistent with remote senders.
|
||||
|
@ -46,18 +31,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
* Can be 0, indicating a non-expiring message, or greater, indicating an expiring message. We match the expiration
|
||||
* timer of the message, including disabling expiring messages if the message is not an expiring message.
|
||||
*
|
||||
* @param timestampForSorting
|
||||
* timestampForSorting of the message before which we want to appear.
|
||||
* @param remoteRecipientId
|
||||
* nil for outgoing messages, otherwise the recipientId of the sender
|
||||
*
|
||||
* @param remoteContactName
|
||||
* nil for outgoing messages, otherwise the name of the sender
|
||||
* @param createdInExistingGroup
|
||||
* YES when being added to a group which already has DM enabled, otherwise NO
|
||||
*/
|
||||
- (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration
|
||||
thread:(TSThread *)thread
|
||||
appearBeforeTimestamp:(uint64_t)timestampForSorting
|
||||
createdByRemoteContactName:(nullable NSString *)remoteContactName
|
||||
createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId
|
||||
createdInExistingGroup:(BOOL)createdInExistingGroup
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
|
|
|
@ -108,6 +108,15 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
return queue;
|
||||
}
|
||||
|
||||
#pragma mark - Dependencies
|
||||
|
||||
- (id<ContactsManagerProtocol>)contactsManager
|
||||
{
|
||||
return SSKEnvironment.shared.contactsManager;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSUInteger)deleteExpiredMessages
|
||||
{
|
||||
AssertIsOnDisappearingMessagesQueue();
|
||||
|
@ -191,39 +200,24 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
TSThread *thread = [message threadWithTransaction:transaction];
|
||||
NSString *remoteContactName = nil;
|
||||
if ([message isKindOfClass:[TSIncomingMessage class]]) {
|
||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message;
|
||||
remoteContactName =
|
||||
[contactsManager displayNameForPhoneIdentifier:incomingMessage.authorId transaction:transaction];
|
||||
}
|
||||
|
||||
[self becomeConsistentWithDisappearingDuration:message.expiresInSeconds
|
||||
thread:thread
|
||||
appearBeforeTimestamp:message.timestampForSorting
|
||||
createdByRemoteContactName:remoteContactName
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
}
|
||||
#pragma mark - Apply Remote Configuration
|
||||
|
||||
- (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration
|
||||
thread:(TSThread *)thread
|
||||
appearBeforeTimestamp:(uint64_t)timestampForSorting
|
||||
createdByRemoteContactName:(nullable NSString *)remoteContactName
|
||||
createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId
|
||||
createdInExistingGroup:(BOOL)createdInExistingGroup
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(timestampForSorting > 0);
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
||||
|
||||
NSString *_Nullable remoteContactName = nil;
|
||||
if (remoteRecipientId) {
|
||||
remoteContactName = [self.contactsManager displayNameForPhoneIdentifier:remoteRecipientId];
|
||||
}
|
||||
|
||||
// Become eventually consistent in the case that the remote changed their settings at the same time.
|
||||
// Also in case remote doesn't support expiring messages
|
||||
OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration =
|
||||
|
@ -245,9 +239,9 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
|
||||
[disappearingMessagesConfiguration saveWithTransaction:transaction];
|
||||
|
||||
// We want the info message to appear _before_ the message.
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:timestampForSorting - 1
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
configuration:disappearingMessagesConfiguration
|
||||
createdByRemoteName:remoteContactName
|
||||
|
@ -258,6 +252,8 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
backgroundTask = nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)startIfNecessary
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
@ -393,7 +389,7 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
OWSFailDebug(@"starting old timer for message timestamp: %lu", (unsigned long)message.timestamp);
|
||||
|
||||
// We don't know when it was actually read, so assume it was read as soon as it was received.
|
||||
uint64_t readTimeBestGuess = message.timestampForSorting;
|
||||
uint64_t readTimeBestGuess = message.receivedAtTimestamp;
|
||||
[self startAnyExpirationForMessage:message expirationStartedAt:readTimeBestGuess transaction:transaction];
|
||||
}
|
||||
transaction:transaction];
|
||||
|
|
|
@ -541,6 +541,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
[messages addObject:[TSErrorMessage nonblockingIdentityChangeInThread:groupThread recipientId:recipientId]];
|
||||
}
|
||||
|
||||
// MJK TODO - why not save immediately, why build up this array?
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
|
@ -862,6 +863,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
|
||||
OWSAssertDebug(contactThread);
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
[messages addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:contactThread
|
||||
recipientId:recipientId
|
||||
|
@ -870,6 +872,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
|
||||
for (TSGroupThread *groupThread in
|
||||
[TSGroupThread groupThreadsWithRecipientId:recipientId transaction:transaction]) {
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
[messages
|
||||
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:groupThread
|
||||
|
@ -878,6 +881,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
isLocalChange:isLocalChange]];
|
||||
}
|
||||
|
||||
// MJK TODO - why not save in-line, vs storing in an array and saving the array?
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
|
|
|
@ -978,6 +978,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
// MJK TODO - safe to remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];
|
||||
|
@ -1026,6 +1027,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssertDebug(disappearingMessagesConfiguration);
|
||||
[disappearingMessagesConfiguration saveWithTransaction:transaction];
|
||||
NSString *name = [self.contactsManager displayNameForPhoneIdentifier:envelope.source transaction:transaction];
|
||||
|
||||
// MJK TODO - safe to remove senderTimestamp
|
||||
OWSDisappearingConfigurationUpdateInfoMessage *message =
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -1223,8 +1226,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
TSGroupThread *newGroupThread =
|
||||
[TSGroupThread getOrCreateThreadWithGroupId:groupId transaction:transaction];
|
||||
|
||||
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name
|
||||
memberIds:newMemberIds.allObjects
|
||||
image:oldGroupThread.groupModel.groupImage
|
||||
|
@ -1234,22 +1235,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
newGroupThread.groupModel = newGroupModel;
|
||||
[newGroupThread saveWithTransaction:transaction];
|
||||
|
||||
TSInfoMessage *infoMessage = [[TSInfoMessage alloc] initWithTimestamp:now
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:newGroupThread
|
||||
createdByRemoteRecipientId:nil
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
TSInfoMessage *infoMessage = [[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:newGroupThread
|
||||
messageType:TSInfoMessageTypeGroupUpdate
|
||||
customMessage:updateGroupInfo];
|
||||
[infoMessage saveWithTransaction:transaction];
|
||||
|
||||
if (dataMessage.hasExpireTimer && dataMessage.expireTimer > 0) {
|
||||
[[OWSDisappearingMessagesJob sharedJob]
|
||||
becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:newGroupThread
|
||||
appearBeforeTimestamp:now
|
||||
createdByRemoteContactName:nil
|
||||
createdInExistingGroup:YES
|
||||
transaction:transaction];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
case SSKProtoGroupContextTypeQuit: {
|
||||
|
@ -1265,6 +1263,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.contactsManager displayNameForPhoneIdentifier:envelope.source transaction:transaction];
|
||||
NSString *updateGroupInfo =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"GROUP_MEMBER_LEFT", @""), nameString];
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:oldGroupThread
|
||||
messageType:TSInfoMessageTypeGroupUpdate
|
||||
|
@ -1277,6 +1276,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return nil;
|
||||
}
|
||||
|
||||
// MJK FIXME - this `becomeConsistent...` call seems to have been remove in master.
|
||||
// to where?
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:oldGroupThread
|
||||
createdByRemoteRecipientId:envelope.source
|
||||
createdInExistingGroup:YES
|
||||
transaction:transaction];
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
|
||||
thread:oldGroupThread
|
||||
transaction:transaction];
|
||||
|
@ -1286,6 +1293,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
groupId,
|
||||
(unsigned long)timestamp);
|
||||
|
||||
// Legit usage of senderTimestamp when creating an incoming group message record
|
||||
TSIncomingMessage *incomingMessage =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
|
||||
inThread:oldGroupThread
|
||||
|
@ -1332,10 +1340,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
TSContactThread *thread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:thread
|
||||
createdByRemoteRecipientId:envelope.source
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
|
||||
thread:thread
|
||||
transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp when creating incoming message from received envelope
|
||||
TSIncomingMessage *incomingMessage =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
|
||||
inThread:thread
|
||||
|
@ -1454,10 +1469,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage
|
||||
transaction:transaction];
|
||||
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:incomingMessage
|
||||
contactsManager:self.contactsManager
|
||||
transaction:transaction];
|
||||
|
||||
// Update thread preview in inbox
|
||||
[thread touchWithTransaction:transaction];
|
||||
|
||||
|
|
|
@ -711,9 +711,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
OWSAssertDebug(message.recipientIds.count == 1);
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *recipientId in message.sendingRecipientIds) {
|
||||
[message updateWithReadRecipientId:recipientId
|
||||
readTimestamp:message.timestampForSorting
|
||||
transaction:transaction];
|
||||
[message updateWithReadRecipientId:recipientId readTimestamp:message.timestamp transaction:transaction];
|
||||
}
|
||||
}];
|
||||
successHandler();
|
||||
|
@ -1756,11 +1754,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
// TODO: Why is this necessary?
|
||||
[message save];
|
||||
} else if (message.groupMetaMessage == TSGroupMetaMessageQuit) {
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:message.timestamp
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupQuit
|
||||
customMessage:message.customMessage] save];
|
||||
} else {
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:message.timestamp
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupUpdate
|
||||
|
|
|
@ -15,8 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithThread:(TSThread *)thread
|
||||
{
|
||||
// These records aren't saved, but their timestamp is used in the event
|
||||
// of a failing message send to insert the error at the appropriate place.
|
||||
// MJK TODO - safe to remove senderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (instancetype)initWithContactThread:(TSContactThread *)contactThread
|
||||
verificationStateSyncMessage:(OWSVerificationStateSyncMessage *)verificationStateSyncMessage
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:contactThread
|
||||
messageBody:nil
|
||||
|
|
|
@ -71,7 +71,7 @@ extern NSString *const kIncomingMessageMarkedAsReadNotification;
|
|||
// This method can be called from any thread.
|
||||
- (void)messageWasReadLocally:(TSIncomingMessage *)message;
|
||||
|
||||
- (void)markAsReadLocallyBeforeTimestamp:(uint64_t)timestamp thread:(TSThread *)thread;
|
||||
- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread;
|
||||
|
||||
#pragma mark - Settings
|
||||
|
||||
|
|
|
@ -245,13 +245,13 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
|||
|
||||
#pragma mark - Mark as Read Locally
|
||||
|
||||
- (void)markAsReadLocallyBeforeTimestamp:(uint64_t)timestamp thread:(TSThread *)thread
|
||||
- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread
|
||||
{
|
||||
OWSAssertDebug(thread);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self markAsReadBeforeTimestamp:timestamp
|
||||
[self markAsReadBeforeSortId:sortId
|
||||
thread:thread
|
||||
readTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
wasLocal:YES
|
||||
|
@ -452,11 +452,8 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
|||
// Always re-mark the message as read to ensure any earlier read time is applied to disappearing messages.
|
||||
[message markAsReadAtTimestamp:readTimestamp sendReadReceipt:NO transaction:transaction];
|
||||
|
||||
// Also mark any messages appearing earlier in the thread as read.
|
||||
//
|
||||
// Use `timestampForSorting` which reflects local received order, rather than `timestamp`
|
||||
// which reflect sender time.
|
||||
[self markAsReadBeforeTimestamp:message.timestampForSorting
|
||||
// Also mark any unread messages appearing earlier in the thread as read as well.
|
||||
[self markAsReadBeforeSortId:message.sortId
|
||||
thread:[message threadWithTransaction:transaction]
|
||||
readTimestamp:readTimestamp
|
||||
wasLocal:NO
|
||||
|
@ -465,13 +462,13 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
|||
|
||||
#pragma mark - Mark As Read
|
||||
|
||||
- (void)markAsReadBeforeTimestamp:(uint64_t)timestamp
|
||||
- (void)markAsReadBeforeSortId:(uint64_t)sortId
|
||||
thread:(TSThread *)thread
|
||||
readTimestamp:(uint64_t)readTimestamp
|
||||
wasLocal:(BOOL)wasLocal
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(timestamp > 0);
|
||||
OWSAssertDebug(sortId > 0);
|
||||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
|
@ -490,8 +487,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
|||
return;
|
||||
}
|
||||
id<OWSReadTracking> possiblyRead = (id<OWSReadTracking>)object;
|
||||
|
||||
if (possiblyRead.timestampForSorting > timestamp) {
|
||||
if (possiblyRead.sortId > sortId) {
|
||||
*stop = YES;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
@property (nonatomic, readonly, getter=wasRead) BOOL read;
|
||||
|
||||
@property (nonatomic, readonly) uint64_t expireStartedAt;
|
||||
@property (nonatomic, readonly) uint64_t timestampForSorting;
|
||||
@property (nonatomic, readonly) uint64_t sortId;
|
||||
@property (nonatomic, readonly) NSString *uniqueThreadId;
|
||||
|
||||
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSErrorMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSUnknownContactBlockOfferMessage : TSErrorMessage
|
||||
|
||||
+ (instancetype)unknownContactBlockOfferMessage:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId;
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
__attribute__((deprecated)) @interface OWSUnknownContactBlockOfferMessage : TSErrorMessage
|
||||
|
||||
@property (nonatomic, readonly) NSString *contactId;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSUnknownContactBlockOfferMessage.h"
|
||||
|
@ -14,25 +14,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark -
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation OWSUnknownContactBlockOfferMessage
|
||||
|
||||
+ (instancetype)unknownContactBlockOfferMessage:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId
|
||||
{
|
||||
return [[OWSUnknownContactBlockOfferMessage alloc] initWithTimestamp:timestamp thread:thread contactId:contactId];
|
||||
}
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread contactId:(NSString *)contactId
|
||||
{
|
||||
self = [super initWithTimestamp:timestamp inThread:thread failedMessageType:TSErrorMessageUnknownContactBlockOffer];
|
||||
|
||||
if (self) {
|
||||
_contactId = contactId;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (BOOL)shouldUseReceiptDateForSorting
|
||||
{
|
||||
|
|
27
SignalServiceKit/src/Storage/IncrementingIdFinder.swift
Normal file
27
SignalServiceKit/src/Storage/IncrementingIdFinder.swift
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public class SSKIncrementingIdFinder: NSObject {
|
||||
|
||||
private static let collectionName = "IncrementingIdCollection"
|
||||
|
||||
@objc
|
||||
public class func previousId(key: String, transaction: YapDatabaseReadTransaction) -> UInt64 {
|
||||
let previousId: UInt64 = transaction.object(forKey: key, inCollection: collectionName) as? UInt64 ?? 0
|
||||
return previousId
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func nextId(key: String, transaction: YapDatabaseReadWriteTransaction) -> UInt64 {
|
||||
let previousId: UInt64 = transaction.object(forKey: key, inCollection: collectionName) as? UInt64 ?? 0
|
||||
let nextId: UInt64 = previousId + 1
|
||||
|
||||
transaction.setObject(nextId, forKey: key, inCollection: collectionName)
|
||||
Logger.debug("key: \(key) nextId: \(nextId)")
|
||||
return nextId
|
||||
}
|
||||
}
|
|
@ -188,6 +188,7 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
|
|||
//
|
||||
// All sync registrations must be done before all async registrations,
|
||||
// or the sync registrations will block on the async registrations.
|
||||
[TSDatabaseView asyncRegisterLegacyThreadInteractionsDatabaseView:self];
|
||||
[TSDatabaseView asyncRegisterThreadInteractionsDatabaseView:self];
|
||||
[TSDatabaseView asyncRegisterThreadDatabaseView:self];
|
||||
[TSDatabaseView asyncRegisterUnreadDatabaseView:self];
|
||||
|
|
|
@ -13,6 +13,8 @@ extern NSString *const TSSecondaryDevicesGroup;
|
|||
extern NSString *const TSThreadDatabaseViewExtensionName;
|
||||
|
||||
extern NSString *const TSMessageDatabaseViewExtensionName;
|
||||
extern NSString *const TSMessageDatabaseViewExtensionName_Legacy;
|
||||
|
||||
extern NSString *const TSUnreadDatabaseViewExtensionName;
|
||||
extern NSString *const TSUnseenDatabaseViewExtensionName;
|
||||
extern NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName;
|
||||
|
@ -45,6 +47,8 @@ extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName;
|
|||
+ (void)asyncRegisterThreadDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage;
|
||||
+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
// Instances of OWSReadTracking for wasRead is NO and shouldAffectUnreadCounts is YES.
|
||||
|
|
|
@ -24,7 +24,18 @@ NSString *const TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
|
|||
// YAPDB BUG: when changing from non-persistent to persistent view, we had to rename TSThreadDatabaseViewExtensionName
|
||||
// -> TSThreadDatabaseViewExtensionName2 to work around https://github.com/yapstudios/YapDatabase/issues/324
|
||||
NSString *const TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName2";
|
||||
NSString *const TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName";
|
||||
|
||||
// We sort interactions by a monotonically increasing counter.
|
||||
//
|
||||
// Previously we sorted the interactions database by local timestamp, which was problematic if the local clock changed.
|
||||
// We need to maintain the legacy extension for purposes of migration.
|
||||
//
|
||||
// The "Legacy" sorting extension name constant has the same value as always, so that it won't need to be rebuilt, while
|
||||
// the "Modern" sorting extension name constant has the same symbol name as we've always used for sorting interactions,
|
||||
// so that the callsites won't need to change.
|
||||
NSString *const TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName_Monotonic";
|
||||
NSString *const TSMessageDatabaseViewExtensionName_Legacy = @"TSMessageDatabaseViewExtensionName";
|
||||
|
||||
NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName = @"TSThreadOutgoingMessageDatabaseViewExtensionName";
|
||||
NSString *const TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
|
||||
NSString *const TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName";
|
||||
|
@ -100,7 +111,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
|
||||
[self registerMessageDatabaseViewWithName:TSUnreadDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
version:@"2"
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
|
@ -119,7 +130,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
|
||||
[self registerMessageDatabaseViewWithName:TSUnseenDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
version:@"2"
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
|
@ -147,10 +158,77 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
|
||||
[self registerMessageDatabaseViewWithName:TSThreadSpecialMessagesDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
version:@"2"
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssert(storage);
|
||||
|
||||
YapDatabaseView *existingView = [storage registeredExtension:TSMessageDatabaseViewExtensionName_Legacy];
|
||||
if (existingView) {
|
||||
OWSFailDebug(@"Registered database view twice: %@", TSMessageDatabaseViewExtensionName_Legacy);
|
||||
return;
|
||||
}
|
||||
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
if (![object isKindOfClass:[TSInteraction class]]) {
|
||||
OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object class], collection);
|
||||
return nil;
|
||||
}
|
||||
TSInteraction *interaction = (TSInteraction *)object;
|
||||
|
||||
return interaction.uniqueThreadId;
|
||||
}];
|
||||
|
||||
YapDatabaseViewSorting *viewSorting =
|
||||
[YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
|
||||
NSString *group,
|
||||
NSString *collection1,
|
||||
NSString *key1,
|
||||
id object1,
|
||||
NSString *collection2,
|
||||
NSString *key2,
|
||||
id object2) {
|
||||
if (![object1 isKindOfClass:[TSInteraction class]]) {
|
||||
OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object1 class], collection1);
|
||||
return NSOrderedSame;
|
||||
}
|
||||
if (![object2 isKindOfClass:[TSInteraction class]]) {
|
||||
OWSFailDebug(@"%@ Unexpected entity %@ in collection: %@", self.logTag, [object2 class], collection2);
|
||||
return NSOrderedSame;
|
||||
}
|
||||
TSInteraction *interaction1 = (TSInteraction *)object1;
|
||||
TSInteraction *interaction2 = (TSInteraction *)object2;
|
||||
|
||||
// Legit usage of timestampForLegacySorting since we're registering the
|
||||
// legacy extension
|
||||
uint64_t timestamp1 = interaction1.timestampForLegacySorting;
|
||||
uint64_t timestamp2 = interaction2.timestampForLegacySorting;
|
||||
|
||||
if (timestamp1 > timestamp2) {
|
||||
return NSOrderedDescending;
|
||||
} else if (timestamp1 < timestamp2) {
|
||||
return NSOrderedAscending;
|
||||
} else {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
}];
|
||||
|
||||
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new];
|
||||
options.isPersistent = YES;
|
||||
options.allowedCollections =
|
||||
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]];
|
||||
|
||||
YapDatabaseView *view =
|
||||
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"1" options:options];
|
||||
|
||||
[storage asyncRegisterExtension:view withName:TSMessageDatabaseViewExtensionName_Legacy];
|
||||
}
|
||||
|
||||
+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
|
@ -166,7 +244,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
|
||||
[self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
version:@"2"
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
|
@ -182,7 +260,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
|
||||
[self registerMessageDatabaseViewWithName:TSThreadOutgoingMessageDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"2"
|
||||
version:@"3"
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
|
@ -213,13 +291,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
}
|
||||
}
|
||||
|
||||
if (thread.archivalDate) {
|
||||
return ([self threadShouldBeInInbox:thread]) ? TSInboxGroup : TSArchiveGroup;
|
||||
} else if (thread.archivalDate) {
|
||||
return TSArchiveGroup;
|
||||
} else {
|
||||
return TSInboxGroup;
|
||||
}
|
||||
return [thread isArchivedWithTransaction:transaction] ? TSArchiveGroup : TSInboxGroup;
|
||||
}];
|
||||
|
||||
YapDatabaseViewSorting *viewSorting = [self threadSorting];
|
||||
|
@ -235,29 +307,6 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
[storage asyncRegisterExtension:databaseView withName:TSThreadDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a thread belongs to the archive or inbox
|
||||
*
|
||||
* @param thread TSThread
|
||||
*
|
||||
* @return Inbox if true, Archive if false
|
||||
*/
|
||||
|
||||
+ (BOOL)threadShouldBeInInbox:(TSThread *)thread {
|
||||
NSDate *lastMessageDate = thread.lastMessageDate;
|
||||
NSDate *archivalDate = thread.archivalDate;
|
||||
if (lastMessageDate && archivalDate) { // this is what is called
|
||||
return ([lastMessageDate timeIntervalSinceDate:archivalDate] > 0)
|
||||
? YES
|
||||
: NO; // if there hasn't been a new message since the archive date, it's in the archive. an issue is
|
||||
// that empty threads are always given with a lastmessage date of the present on every launch
|
||||
} else if (archivalDate) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (YapDatabaseViewSorting *)threadSorting {
|
||||
return [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
|
||||
NSString *group,
|
||||
|
@ -278,7 +327,16 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
TSThread *thread1 = (TSThread *)object1;
|
||||
TSThread *thread2 = (TSThread *)object2;
|
||||
if ([group isEqualToString:TSArchiveGroup] || [group isEqualToString:TSInboxGroup]) {
|
||||
return [thread1.lastMessageDate compare:thread2.lastMessageDate];
|
||||
|
||||
TSInteraction *_Nullable lastInteractionForInbox1 =
|
||||
[thread1 lastInteractionForInboxWithTransaction:transaction];
|
||||
NSDate *date1 = lastInteractionForInbox1 ? lastInteractionForInbox1.receivedAtDate : thread1.creationDate;
|
||||
|
||||
TSInteraction *_Nullable lastInteractionForInbox2 =
|
||||
[thread2 lastInteractionForInboxWithTransaction:transaction];
|
||||
NSDate *date2 = lastInteractionForInbox2 ? lastInteractionForInbox2.receivedAtDate : thread2.creationDate;
|
||||
|
||||
return [date1 compare:date2];
|
||||
}
|
||||
|
||||
return NSOrderedSame;
|
||||
|
@ -425,6 +483,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
return result;
|
||||
}
|
||||
|
||||
// MJK TODO - dynamic interactions
|
||||
+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(transaction);
|
||||
|
|
|
@ -218,6 +218,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark Reload
|
||||
|
||||
- (void)reload
|
||||
{
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
|
|
Loading…
Reference in a new issue