Refine view model diffing.
This commit is contained in:
parent
99c45cde1f
commit
90d8fb3d14
|
@ -340,6 +340,7 @@ private class MockConversationViewItem: NSObject, ConversationViewItem {
|
|||
var hasBodyTextActionContent: Bool = false
|
||||
var hasMediaActionContent: Bool = false
|
||||
var mediaAlbumItems: [ConversationMediaAlbumItem]?
|
||||
var hasCachedLayoutState: Bool = false
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
|
|
|
@ -577,7 +577,6 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
case OWSMessageCellType_Unknown:
|
||||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
return NO;
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
|
@ -588,6 +587,21 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasBodyMediaView {
|
||||
switch (self.cellType) {
|
||||
case OWSMessageCellType_Unknown:
|
||||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
return NO;
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
case OWSMessageCellType_ContactShare:
|
||||
case OWSMessageCellType_MediaAlbum:
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasFullWidthMediaView
|
||||
{
|
||||
return (self.hasBodyMediaWithThumbnail || self.cellType == OWSMessageCellType_ContactShare
|
||||
|
@ -601,8 +615,14 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
|
||||
- (BOOL)hasBottomFooter
|
||||
{
|
||||
BOOL shouldFooterOverlayMedia = (self.canFooterOverlayMedia && !self.hasBodyText);
|
||||
return !self.viewItem.shouldHideFooter && !shouldFooterOverlayMedia;
|
||||
BOOL shouldFooterOverlayMedia = (self.canFooterOverlayMedia && self.hasBodyMediaView && !self.hasBodyText);
|
||||
if (self.viewItem.shouldHideFooter) {
|
||||
return NO;
|
||||
} else if (shouldFooterOverlayMedia) {
|
||||
return NO;
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)insertAnyTextViewsIntoStackView:(NSArray<UIView *> *)textViews
|
||||
|
|
|
@ -91,6 +91,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
|
||||
- (void)clearCachedLayoutState;
|
||||
|
||||
@property (nonatomic, readonly) BOOL hasCachedLayoutState;
|
||||
|
||||
#pragma mark - Audio Playback
|
||||
|
||||
@property (nonatomic, weak) OWSAudioMessageView *lastAudioMessageView;
|
||||
|
|
|
@ -286,6 +286,10 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
self.cachedCellSize = nil;
|
||||
}
|
||||
|
||||
- (BOOL)hasCachedLayoutState {
|
||||
return self.cachedCellSize != nil;
|
||||
}
|
||||
|
||||
- (CGSize)cellSize
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
|
|
@ -569,7 +569,6 @@ static const int kYapDatabaseRangeMinLength = 0;
|
|||
// reloadViewItems.
|
||||
BOOL hasMalformedRowChange = NO;
|
||||
NSMutableSet<NSString *> *updatedItemSet = [NSMutableSet new];
|
||||
NSMutableSet<NSString *> *updatedNeighborItemSet = [NSMutableSet new];
|
||||
for (YapDatabaseViewRowChange *rowChange in rowChanges) {
|
||||
switch (rowChange.type) {
|
||||
case YapDatabaseViewChangeUpdate: {
|
||||
|
@ -579,17 +578,10 @@ static const int kYapDatabaseRangeMinLength = 0;
|
|||
if (viewItem) {
|
||||
[self reloadInteractionForViewItem:viewItem];
|
||||
[updatedItemSet addObject:viewItem.itemId];
|
||||
if (rowChange.changes == YapDatabaseViewChangedDependency) {
|
||||
[updatedNeighborItemSet addObject:viewItem.itemId];
|
||||
}
|
||||
} else {
|
||||
OWSLogError(@"Update is missing view item");
|
||||
hasMalformedRowChange = YES;
|
||||
}
|
||||
} else if (rowChange.indexPath && rowChange.originalIndex < self.viewItems.count) {
|
||||
// Do nothing, this is a pseudo-update generated due to
|
||||
// setCellDrawingDependencyOffsets.
|
||||
OWSAssertDebug(rowChange.changes == YapDatabaseViewChangedDependency);
|
||||
} else {
|
||||
OWSFailDebug(@"Update is missing collection key");
|
||||
hasMalformedRowChange = YES;
|
||||
|
@ -634,9 +626,7 @@ static const int kYapDatabaseRangeMinLength = 0;
|
|||
|
||||
OWSLogVerbose(@"self.viewItems.count: %zd -> %zd", oldItemIdList.count, self.viewItems.count);
|
||||
|
||||
[self updateViewWithOldItemIdList:oldItemIdList
|
||||
updatedItemSet:updatedItemSet
|
||||
updatedNeighborItemSet:updatedNeighborItemSet];
|
||||
[self updateViewWithOldItemIdList:oldItemIdList updatedItemSet:updatedItemSet];
|
||||
}
|
||||
|
||||
// A simpler version of the update logic we use when
|
||||
|
@ -662,15 +652,13 @@ static const int kYapDatabaseRangeMinLength = 0;
|
|||
|
||||
OWSLogVerbose(@"self.viewItems.count: %zd -> %zd", oldItemIdList.count, self.viewItems.count);
|
||||
|
||||
[self updateViewWithOldItemIdList:oldItemIdList updatedItemSet:[NSSet set] updatedNeighborItemSet:nil];
|
||||
[self updateViewWithOldItemIdList:oldItemIdList updatedItemSet:[NSSet set]];
|
||||
}
|
||||
|
||||
- (void)updateViewWithOldItemIdList:(NSArray<NSString *> *)oldItemIdList
|
||||
updatedItemSet:(NSSet<NSString *> *)updatedItemSet
|
||||
updatedNeighborItemSet:(nullable NSMutableSet<NSString *> *)updatedNeighborItemSet
|
||||
{
|
||||
updatedItemSet:(NSSet<NSString *> *)updatedItemSetParam {
|
||||
OWSAssertDebug(oldItemIdList);
|
||||
OWSAssertDebug(updatedItemSet);
|
||||
OWSAssertDebug(updatedItemSetParam);
|
||||
|
||||
if (!self.delegate.isObservingVMUpdates) {
|
||||
OWSLogVerbose(@"Skipping VM update.");
|
||||
|
@ -771,6 +759,33 @@ static const int kYapDatabaseRangeMinLength = 0;
|
|||
return [self.delegate conversationViewModelDidUpdate:ConversationUpdate.reloadUpdate];
|
||||
}
|
||||
|
||||
NSMutableSet<NSString *> *updatedItemSet = [updatedItemSetParam mutableCopy];
|
||||
NSMutableSet<NSString *> *updatedNeighborItemSet = [NSMutableSet new];
|
||||
for (NSString *itemId in newItemIdSet) {
|
||||
if (![oldItemIdSet containsObject:itemId]) {
|
||||
continue;
|
||||
}
|
||||
if ([insertedItemIdSet containsObject:itemId] || [updatedItemSet containsObject:itemId]) {
|
||||
continue;
|
||||
}
|
||||
OWSAssertDebug(![deletedItemIdSet containsObject:itemId]);
|
||||
|
||||
NSUInteger newIndex = [newItemIdList indexOfObject:itemId];
|
||||
if (newIndex == NSNotFound) {
|
||||
OWSFailDebug(@"Can't find index of holdover view item.");
|
||||
return [self.delegate conversationViewModelDidUpdate:ConversationUpdate.reloadUpdate];
|
||||
}
|
||||
id<ConversationViewItem> _Nullable viewItem = newViewItemMap[itemId];
|
||||
if (!viewItem) {
|
||||
OWSFailDebug(@"Can't find holdover view item.");
|
||||
return [self.delegate conversationViewModelDidUpdate:ConversationUpdate.reloadUpdate];
|
||||
}
|
||||
if (!viewItem.hasCachedLayoutState) {
|
||||
[updatedItemSet addObject:itemId];
|
||||
[updatedNeighborItemSet addObject:itemId];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Updates.
|
||||
//
|
||||
// NOTE: Order doesn't matter.
|
||||
|
@ -867,16 +882,6 @@ static const int kYapDatabaseRangeMinLength = 0;
|
|||
[[YapDatabaseViewMappings alloc] initWithGroups:@[] view:TSMessageDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
// Cells' appearance can depend on adjacent cells in both directions.
|
||||
//
|
||||
// TODO: We could do the same thing in our logic to generate "update items"
|
||||
// in updateViewWithOldItemIdList.
|
||||
[self.messageMappings setCellDrawingDependencyOffsets:[NSSet setWithArray:@[
|
||||
@(-1),
|
||||
@(+1),
|
||||
]]
|
||||
forGroup:self.thread.uniqueId];
|
||||
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self.messageMappings updateWithTransaction:transaction];
|
||||
}];
|
||||
|
|
Loading…
Reference in New Issue