From 8b3d08c7e3e166b13013b93d5ebd386571a6ea6d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 19 Feb 2019 17:49:40 -0500 Subject: [PATCH] Introduce ConversationSnapshot. --- .../ConversationViewController.m | 26 +++++++++---- .../ConversationView/ConversationViewModel.h | 2 +- .../ConversationView/ConversationViewModel.m | 39 ++++++++++++------- SignalMessaging/utils/ThreadUtil.m | 15 +++++++ 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 891f994c2..a5c976bea 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -450,11 +450,11 @@ typedef enum : NSUInteger { NSString *_Nullable recipientId = notification.userInfo[kNSNotificationKey_ProfileRecipientId]; NSData *_Nullable groupId = notification.userInfo[kNSNotificationKey_ProfileGroupId]; if (recipientId.length > 0 && [self.thread.recipientIdentifiers containsObject:recipientId]) { - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } else if (groupId.length > 0 && self.thread.isGroupThread) { TSGroupThread *groupThread = (TSGroupThread *)self.thread; if ([groupThread.groupModel.groupId isEqualToData:groupId]) { - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; [self ensureBannerState]; } } @@ -868,6 +868,7 @@ typedef enum : NSUInteger { // Avoid layout corrupt issues and out-of-date message subtitles. self.lastReloadDate = [NSDate new]; [self.conversationViewModel viewDidResetContentAndLayout]; + [self tryToUpdateConversationSnapshot]; [self.collectionView.collectionViewLayout invalidateLayout]; [self.collectionView reloadData]; @@ -2437,7 +2438,7 @@ typedef enum : NSUInteger { - (void)contactsViewHelperDidUpdateContacts { - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } - (void)createConversationScrollButtons @@ -2475,7 +2476,7 @@ typedef enum : NSUInteger { _hasUnreadMessages = hasUnreadMessages; self.scrollDownButton.hasUnreadMessages = hasUnreadMessages; - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } - (void)scrollDownButtonTapped @@ -2620,7 +2621,7 @@ typedef enum : NSUInteger { [self showApprovalDialogForAttachment:attachment]; [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } - (void)messageWasSent:(TSOutgoingMessage *)message @@ -2980,7 +2981,7 @@ typedef enum : NSUInteger { [self messageWasSent:message]; if (didAddToProfileWhitelist) { - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } }]; } @@ -3626,7 +3627,7 @@ typedef enum : NSUInteger { [self messageWasSent:message]; if (didAddToProfileWhitelist) { - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } }); } @@ -4029,7 +4030,7 @@ typedef enum : NSUInteger { [self clearDraft]; if (didAddToProfileWhitelist) { - [self.conversationViewModel ensureDynamicInteractions]; + [self.conversationViewModel ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } } @@ -4927,6 +4928,15 @@ typedef enum : NSUInteger { #pragma mark - Conversation Snapshot +- (void)tryToUpdateConversationSnapshot +{ + if (!self.isObservingVMUpdates) { + return; + } + + [self updateConversationSnapshot]; +} + - (void)updateConversationSnapshot { ConversationSnapshot *conversationSnapshot = [ConversationSnapshot new]; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h index c4d781b3a..902413760 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h @@ -93,7 +93,7 @@ typedef NS_ENUM(NSUInteger, ConversationUpdateItemType) { focusMessageIdOnOpen:(nullable NSString *)focusMessageIdOnOpen delegate:(id)delegate NS_DESIGNATED_INITIALIZER; -- (void)ensureDynamicInteractions; +- (void)ensureDynamicInteractionsAndUpdateIfNecessary:(BOOL)updateIfNecessary; - (void)clearUnreadMessagesIndicator; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m index a5e589734..f1086644e 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m @@ -273,7 +273,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; { OWSAssertIsOnMainThread(); - [self ensureDynamicInteractions]; + [self ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } - (void)profileWhitelistDidChange:(NSNotification *)notification @@ -308,7 +308,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; self.typingIndicatorsSender = [self.typingIndicators typingRecipientIdForThread:self.thread]; self.collapseCutoffDate = [NSDate new]; - [self ensureDynamicInteractions]; + [self ensureDynamicInteractionsAndUpdateIfNecessary:NO]; [self.primaryStorage updateUIDatabaseConnectionToLatest]; [self createNewMessageMapping]; @@ -464,21 +464,32 @@ static const int kYapDatabaseRangeMaxLength = 25000; self.collapseCutoffDate = [NSDate new]; } -- (void)ensureDynamicInteractions +- (void)ensureDynamicInteractionsAndUpdateIfNecessary:(BOOL)updateIfNecessary { OWSAssertIsOnMainThread(); const int currentMaxRangeSize = (int)self.messageMapping.desiredLength; const int maxRangeSize = MAX(kConversationInitialMaxRangeSize, currentMaxRangeSize); - self.dynamicInteractions = [ThreadUtil ensureDynamicInteractionsForThread:self.thread - contactsManager:self.contactsManager - blockingManager:self.blockingManager - dbConnection:self.editingDatabaseConnection - hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator - lastUnreadIndicator:self.dynamicInteractions.unreadIndicator - focusMessageId:self.focusMessageIdOnOpen - maxRangeSize:maxRangeSize]; + ThreadDynamicInteractions *dynamicInteractions = + [ThreadUtil ensureDynamicInteractionsForThread:self.thread + contactsManager:self.contactsManager + blockingManager:self.blockingManager + dbConnection:self.editingDatabaseConnection + hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator + lastUnreadIndicator:self.dynamicInteractions.unreadIndicator + focusMessageId:self.focusMessageIdOnOpen + maxRangeSize:maxRangeSize]; + BOOL didChange = ![NSObject isNullableObject:self.dynamicInteractions equalTo:dynamicInteractions]; + self.dynamicInteractions = dynamicInteractions; + + if (didChange && updateIfNecessary) { + if (![self reloadViewItems]) { + OWSFailDebug(@"Failed to reload view items."); + } + + [self.delegate conversationViewModelDidUpdate:ConversationUpdate.reloadUpdate]; + } } - (nullable id)viewItemForUnreadMessagesIndicator @@ -519,7 +530,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; if (self.dynamicInteractions.unreadIndicator) { // If we've just cleared the "unread messages" indicator, // update the dynamic interactions. - [self ensureDynamicInteractions]; + [self ensureDynamicInteractionsAndUpdateIfNecessary:YES]; } } @@ -962,7 +973,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; self.collapseCutoffDate = [NSDate new]; - [self ensureDynamicInteractions]; + [self ensureDynamicInteractionsAndUpdateIfNecessary:NO]; if (![self reloadViewItems]) { OWSFailDebug(@"failed to reload view items in resetMapping."); @@ -1584,7 +1595,7 @@ static const int kYapDatabaseRangeMaxLength = 25000; self.collapseCutoffDate = [NSDate new]; - [self ensureDynamicInteractions]; + [self ensureDynamicInteractionsAndUpdateIfNecessary:NO]; if (![self reloadViewItems]) { OWSFailDebug(@"failed to reload view items in resetMapping."); diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index 2d5b182f3..f42badd4c 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -45,6 +45,21 @@ NS_ASSUME_NONNULL_BEGIN self.unreadIndicator = nil; } +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[ThreadDynamicInteractions class]]) { + return NO; + } + + ThreadDynamicInteractions *other = (ThreadDynamicInteractions *)object; + return ([NSObject isNullableObject:self.focusMessagePosition equalTo:other.focusMessagePosition] && + [NSObject isNullableObject:self.unreadIndicator equalTo:other.unreadIndicator]); +} + @end #pragma mark -