Avoid unnecessary conversation screen updates

This commit is contained in:
Niels Andriesse 2021-08-03 15:36:54 +10:00
parent e6949a5ae8
commit 7f0b87a2b2
11 changed files with 56 additions and 14 deletions

View File

@ -169,6 +169,7 @@
B8269D2925C7A4B400488AB4 /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8269D2825C7A4B400488AB4 /* InputView.swift */; };
B8269D3325C7A8C600488AB4 /* InputViewButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8269D3225C7A8C600488AB4 /* InputViewButton.swift */; };
B8269D3D25C7B34D00488AB4 /* InputTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8269D3C25C7B34D00488AB4 /* InputTextView.swift */; };
B82A0C3826B9098200C1BCE3 /* MessageInvalidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82A0C3726B9098200C1BCE3 /* MessageInvalidator.swift */; };
B82B40882399EB0E00A248E7 /* LandingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B40872399EB0E00A248E7 /* LandingVC.swift */; };
B82B408A2399EC0600A248E7 /* FakeChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B40892399EC0600A248E7 /* FakeChatView.swift */; };
B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408B239A068800A248E7 /* RegisterVC.swift */; };
@ -1149,6 +1150,7 @@
B8269D2825C7A4B400488AB4 /* InputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputView.swift; sourceTree = "<group>"; };
B8269D3225C7A8C600488AB4 /* InputViewButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputViewButton.swift; sourceTree = "<group>"; };
B8269D3C25C7B34D00488AB4 /* InputTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputTextView.swift; sourceTree = "<group>"; };
B82A0C3726B9098200C1BCE3 /* MessageInvalidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageInvalidator.swift; sourceTree = "<group>"; };
B82B40872399EB0E00A248E7 /* LandingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandingVC.swift; sourceTree = "<group>"; };
B82B40892399EC0600A248E7 /* FakeChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeChatView.swift; sourceTree = "<group>"; };
B82B408B239A068800A248E7 /* RegisterVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterVC.swift; sourceTree = "<group>"; };
@ -3115,6 +3117,7 @@
C33FDBC1255A581700E217F9 /* General.swift */,
B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */,
B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */,
B82A0C3726B9098200C1BCE3 /* MessageInvalidator.swift */,
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */,
C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */,
C3A71D4825589FF20043A11F /* NSData+messagePadding.m */,
@ -4746,6 +4749,7 @@
C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */,
C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */,
C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */,
B82A0C3826B9098200C1BCE3 /* MessageInvalidator.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -368,9 +368,9 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
shouldScrollToBottom = self.isCloseToBottom
}
case .update:
// FIXME: This is called many times when a message is inserted, leading to bad performance
shouldScrollToBottom = self.isCloseToBottom // Check this * before * reloading the row
print("[Test] UPDATE")
self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .none)
shouldScrollToBottom = self.isCloseToBottom
default: preconditionFailure()
}
}

View File

@ -822,9 +822,13 @@ NS_ASSUME_NONNULL_BEGIN
OWSFailDebug(@"Can't find holdover view item.");
return [self.delegate conversationViewModelDidUpdate:ConversationUpdate.reloadUpdate];
}
if (!viewItem.hasCachedLayoutState) {
[updatedItemSet addObject:itemId];
[updatedNeighborItemSet addObject:itemId];
if ([viewItem.interaction isKindOfClass:TSMessage.class]) {
TSMessage *message = (TSMessage *)viewItem.interaction;
if ([MessageInvalidator isInvalidated:message]) {
[updatedItemSet addObject:itemId];
[updatedNeighborItemSet addObject:itemId];
}
}
}
@ -864,6 +868,10 @@ NS_ASSUME_NONNULL_BEGIN
oldViewItemCount:oldItemIdList.count
updatedNeighborItemSet:updatedNeighborItemSet];
for (NSString *itemID in updatedItemSet) {
[MessageInvalidator markAsUpdated:itemID];
}
return [self.delegate
conversationViewModelDidUpdate:[ConversationUpdate diffUpdateWithUpdateItems:updateItems
shouldAnimateUpdates:shouldAnimateUpdates]];

View File

@ -1002,7 +1002,7 @@ CGFloat kIconViewLength = 24;
UISwitch *uiSwitch = (UISwitch *)sender;
BOOL isEnabled = uiSwitch.isOn;
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[(TSGroupThread *)self.thread setisOnlyNotifyingForMentions:isEnabled withTransaction:transaction];
[(TSGroupThread *)self.thread setIsOnlyNotifyingForMentions:isEnabled withTransaction:transaction];
}];
}

View File

@ -70,7 +70,7 @@ final class DownloadAttachmentModal : Modal {
contact.isTrusted = true
Storage.write(with: { transaction in
Storage.shared.setContact(contact, using: transaction)
message.touch(with: transaction)
MessageInvalidator.invalidate(message, with: transaction)
}, completion: {
Storage.shared.resumeAttachmentDownloadJobsIfNeeded(for: message.uniqueThreadId)
})

View File

@ -67,7 +67,7 @@ extension Storage {
pointer.state = state
pointer.save(with: transaction)
guard let tsMessage = TSMessage.fetch(uniqueId: tsMessageID, transaction: transaction) else { return }
tsMessage.touch(with: transaction)
MessageInvalidator.invalidate(tsMessage, with: transaction)
}
/// Also touches the associated message.
@ -75,7 +75,7 @@ extension Storage {
let transaction = transaction as! YapDatabaseReadWriteTransaction
stream.save(with: transaction)
guard let tsMessage = TSMessage.fetch(uniqueId: tsMessageID, transaction: transaction) else { return }
tsMessage.touch(with: transaction)
MessageInvalidator.invalidate(tsMessage, with: transaction)
}
private static let receivedMessageTimestampsCollection = "ReceivedMessageTimestampsCollection"

View File

@ -118,12 +118,14 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N
delegate?.handleJobSucceeded(self)
SNMessagingKitConfiguration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID)
Storage.shared.write(with: { transaction in
var interaction: TSInteraction?
var message: TSMessage?
let transaction = transaction as! YapDatabaseReadWriteTransaction
TSDatabaseSecondaryIndexes.enumerateMessages(withTimestamp: self.message.sentTimestamp!, with: { _, key, _ in
interaction = TSInteraction.fetch(uniqueId: key, transaction: transaction)
message = TSMessage.fetch(uniqueId: key, transaction: transaction)
}, using: transaction)
interaction?.touch(with: transaction) // To refresh the associated message cell and hide the loader
if let message = message {
MessageInvalidator.invalidate(message, with: transaction)
}
}, completion: { })
}

View File

@ -340,6 +340,7 @@ public final class MessageSender : NSObject {
recipients.forEach { recipient in
tsMessage.update(withSentRecipient: recipient, wasSentByUD: true, transaction: transaction)
}
MessageInvalidator.invalidate(tsMessage, with: transaction)
// Start the disappearing messages timer if needed
OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction)
}

View File

@ -45,7 +45,7 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId;
transaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)setGroupModel:(TSGroupModel *)newGroupModel withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)setisOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)setIsOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)leaveGroupWithSneakyTransaction;
- (void)leaveGroupWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;

View File

@ -208,7 +208,7 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific
}];
}
- (void)setisOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction
- (void)setIsOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
self.isOnlyNotifyingForMentions = isOnlyNotifyingForMentions;

View File

@ -0,0 +1,27 @@
/// A message is invalidated when it needs to be re-rendered in the UI. Examples of when this happens include:
///
/// When the sent or read status of a message is updated.
/// When an attachment is uploaded or downloaded.
@objc public final class MessageInvalidator : NSObject {
private static var invalidatedMessages: Set<String> = []
@objc public static let shared = MessageInvalidator()
private override init() { }
@objc public static func invalidate(_ message: TSMessage, with transaction: YapDatabaseReadWriteTransaction) {
guard let id = message.uniqueId else { return }
invalidatedMessages.insert(id)
message.touch(with: transaction)
}
@objc public static func isInvalidated(_ message: TSMessage) -> Bool {
guard let id = message.uniqueId else { return false }
return invalidatedMessages.contains(id)
}
@objc public static func markAsUpdated(_ id: String) {
invalidatedMessages.remove(id)
}
}