diff --git a/src/Contacts/TSThread.m b/src/Contacts/TSThread.m index a056d098f..ccdfc564c 100644 --- a/src/Contacts/TSThread.m +++ b/src/Contacts/TSThread.m @@ -251,6 +251,19 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateWithLastMessage:(TSInteraction *)lastMessage transaction:(YapDatabaseReadWriteTransaction *)transaction { NSDate *lastMessageDate = [lastMessage receiptDateForSorting]; + if ([lastMessage isKindOfClass:[TSErrorMessage class]]) { + TSErrorMessage *errorMessage = (TSErrorMessage *)lastMessage; + if (errorMessage.errorType == TSErrorMessageNonBlockingIdentityChange) { + // Otherwise all group threads with the recipient will percolate to the top of the inbox, even though + // there was no meaningful interaction. + DDLogDebug(@"%@ not updating lastMessage for thread:%@ nonblocking identity change: %@", + self.tag, + self, + errorMessage.debugDescription); + return; + } + } + if (!_lastMessageDate || [lastMessageDate timeIntervalSinceDate:self.lastMessageDate] > 0) { _lastMessageDate = lastMessageDate; diff --git a/src/Contacts/Threads/TSGroupThread.h b/src/Contacts/Threads/TSGroupThread.h index 56b6d5a83..68a5a2004 100644 --- a/src/Contacts/Threads/TSGroupThread.h +++ b/src/Contacts/Threads/TSGroupThread.h @@ -1,5 +1,6 @@ -// Created by Frederic Jacobs on 16/11/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// #import "TSGroupModel.h" #import "TSThread.h" @@ -22,6 +23,9 @@ NS_ASSUME_NONNULL_BEGIN + (NSString *)threadIdFromGroupId:(NSData *)groupId; +// all group threads containing recipient as a member ++ (NSArray *)groupThreadsWithRecipientId:(NSString *)recipientId; + - (void)updateAvatarWithAttachmentStream:(TSAttachmentStream *)attachmentStream; @end diff --git a/src/Contacts/Threads/TSGroupThread.m b/src/Contacts/Threads/TSGroupThread.m index 327ce7f0f..b655ef169 100644 --- a/src/Contacts/Threads/TSGroupThread.m +++ b/src/Contacts/Threads/TSGroupThread.m @@ -1,5 +1,6 @@ -// Created by Frederic Jacobs on 16/11/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// #import "TSGroupThread.h" #import "NSData+Base64.h" @@ -85,6 +86,34 @@ NS_ASSUME_NONNULL_BEGIN return [NSData dataFromBase64String:[threadId substringWithRange:NSMakeRange(1, threadId.length - 1)]]; } + +// Group and Contact threads share a collection, this is a convenient way to enumerate *just* the group threads ++ (void)enumerateGroupThreadsUsingBlock:(void (^)(TSGroupThread *groupThread, BOOL *stop))block +{ + [self enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) { + if ([obj isKindOfClass:[TSGroupThread class]]) { + block((TSGroupThread *)obj, stop); + } + }]; +} + +// @returns all threads to which the recipient is a member. +// +// @note If this becomes a hotspot we can extract into a YapDB View. +// As is, the number of groups should be small (dozens, *maybe* hundreds), and we only enumerate them upon SN changes. ++ (NSArray *)groupThreadsWithRecipientId:(NSString *)recipientId +{ + NSMutableArray *groupThreads = [NSMutableArray new]; + + [self enumerateGroupThreadsUsingBlock:^(TSGroupThread *_Nonnull groupThread, BOOL *_Nonnull stop) { + if ([groupThread.groupModel.groupMemberIds containsObject:recipientId]) { + [groupThreads addObject:groupThread]; + } + }]; + + return [groupThreads copy]; +} + - (BOOL)isGroupThread { return true; diff --git a/src/Storage/AxolotlStore/TSStorageManager+IdentityKeyStore.m b/src/Storage/AxolotlStore/TSStorageManager+IdentityKeyStore.m index 95122b2dd..66b9bcf62 100644 --- a/src/Storage/AxolotlStore/TSStorageManager+IdentityKeyStore.m +++ b/src/Storage/AxolotlStore/TSStorageManager+IdentityKeyStore.m @@ -6,6 +6,7 @@ #import "TSAccountManager.h" #import "TSContactThread.h" #import "TSErrorMessage.h" +#import "TSGroupThread.h" #import "TSPrivacyPreferences.h" #import "TSStorageManager+IdentityKeyStore.h" #import "TSStorageManager+SessionStore.h" @@ -83,10 +84,19 @@ - (void)createIdentityChangeInfoMessageForRecipientId:(NSString *)recipientId { + UInt64 nowTimestamp = [NSDate ows_millisecondTimeStamp]; + TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - [[[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] + [[[TSErrorMessage alloc] initWithTimestamp:nowTimestamp inThread:contactThread failedMessageType:TSErrorMessageNonBlockingIdentityChange] save]; + + for (TSGroupThread *groupThread in [TSGroupThread groupThreadsWithRecipientId:recipientId]) { + [[[TSErrorMessage alloc] initWithTimestamp:nowTimestamp + inThread:groupThread + failedMessageType:TSErrorMessageNonBlockingIdentityChange] save]; + } } + @end