Merge branch 'charlesmchen/intraCellSpacing'

pull/1/head
Matthew Chen 7 years ago
commit 8362c2648e

@ -465,6 +465,13 @@ typedef enum : NSUInteger {
return; return;
} }
// Cells' appearance can depend on adjacent cells in both directions.
[self.messageMappings setCellDrawingDependencyOffsets:[NSSet setWithArray:@[
@(-1),
@(+1),
]]
forGroup:self.thread.uniqueId];
// We need to impose the range restrictions on the mappings immediately to avoid // We need to impose the range restrictions on the mappings immediately to avoid
// doing a great deal of unnecessary work and causing a perf hotspot. // doing a great deal of unnecessary work and causing a perf hotspot.
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
@ -3303,11 +3310,19 @@ typedef enum : NSUInteger {
case YapDatabaseViewChangeUpdate: { case YapDatabaseViewChangeUpdate: {
YapCollectionKey *collectionKey = rowChange.collectionKey; YapCollectionKey *collectionKey = rowChange.collectionKey;
if (collectionKey.key) { if (collectionKey.key) {
ConversationViewItem *viewItem = self.viewItemCache[collectionKey.key]; ConversationViewItem *_Nullable viewItem = self.viewItemCache[collectionKey.key];
if (viewItem) {
[self reloadInteractionForViewItem:viewItem]; [self reloadInteractionForViewItem:viewItem];
} else { } else {
hasMalformedRowChange = YES; hasMalformedRowChange = YES;
} }
} else if (rowChange.indexPath && rowChange.originalIndex < self.viewItems.count) {
// Do nothing, this is a pseudo-update generated due to
// setCellDrawingDependencyOffsets.
OWSAssert(rowChange.changes == YapDatabaseViewChangedDependency);
} else {
hasMalformedRowChange = YES;
}
break; break;
} }
case YapDatabaseViewChangeDelete: { case YapDatabaseViewChangeDelete: {
@ -3332,7 +3347,8 @@ typedef enum : NSUInteger {
if (hasMalformedRowChange) { if (hasMalformedRowChange) {
// These errors seems to be very rare; they can only be reproduced // These errors seems to be very rare; they can only be reproduced
// using the more extreme actions in the debug UI. // using the more extreme actions in the debug UI.
DDLogError(@"%@ hasMalformedRowChange", self.logTag); OWSProdLogAndFail(@"%@ hasMalformedRowChange", self.logTag);
[self reloadViewItems];
[self.collectionView reloadData]; [self.collectionView reloadData];
[self updateLastVisibleTimestamp]; [self updateLastVisibleTimestamp];
[self cleanUpUnreadIndicatorIfNecessary]; [self cleanUpUnreadIndicatorIfNecessary];
@ -3340,7 +3356,7 @@ typedef enum : NSUInteger {
} }
NSUInteger oldViewItemCount = self.viewItems.count; NSUInteger oldViewItemCount = self.viewItems.count;
NSMutableSet<NSNumber *> *rowsThatChangedSize = [[self reloadViewItems] mutableCopy]; [self reloadViewItems];
BOOL wasAtBottom = [self isScrolledToBottom]; BOOL wasAtBottom = [self isScrolledToBottom];
// We want sending messages to feel snappy. So, if the only // We want sending messages to feel snappy. So, if the only
@ -3372,8 +3388,6 @@ typedef enum : NSUInteger {
rowChange.newIndexPath, rowChange.newIndexPath,
rowChange.finalIndex); rowChange.finalIndex);
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]]; [self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
// We don't want to reload a row that we just inserted.
[rowsThatChangedSize removeObject:@(rowChange.originalIndex)];
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex]; ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
if ([viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) { if ([viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) {
@ -3392,8 +3406,6 @@ typedef enum : NSUInteger {
rowChange.newIndexPath, rowChange.newIndexPath,
rowChange.finalIndex); rowChange.finalIndex);
[self.collectionView moveItemAtIndexPath:rowChange.indexPath toIndexPath:rowChange.newIndexPath]; [self.collectionView moveItemAtIndexPath:rowChange.indexPath toIndexPath:rowChange.newIndexPath];
// We don't want to reload a row that we just moved.
[rowsThatChangedSize removeObject:@(rowChange.originalIndex)];
break; break;
} }
case YapDatabaseViewChangeUpdate: { case YapDatabaseViewChangeUpdate: {
@ -3402,23 +3414,10 @@ typedef enum : NSUInteger {
rowChange.indexPath, rowChange.indexPath,
rowChange.finalIndex); rowChange.finalIndex);
[self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]]; [self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]];
// We don't want to reload a row that we've already reloaded.
[rowsThatChangedSize removeObject:@(rowChange.originalIndex)];
break; break;
} }
} }
} }
// The changes performed above may affect the size of neighboring cells,
// as they may affect which cells show "date" headers or "status" footers.
NSMutableArray<NSIndexPath *> *rowsToReload = [NSMutableArray new];
for (NSNumber *row in rowsThatChangedSize) {
DDLogVerbose(@"rowsToReload: %@", row);
[rowsToReload addObject:[NSIndexPath indexPathForRow:row.integerValue inSection:0]];
}
if (rowsToReload.count > 0) {
[self.collectionView reloadItemsAtIndexPaths:rowsToReload];
}
}; };
DDLogVerbose(@"self.viewItems.count: %zd -> %zd", oldViewItemCount, self.viewItems.count); DDLogVerbose(@"self.viewItems.count: %zd -> %zd", oldViewItemCount, self.viewItems.count);
@ -4775,11 +4774,7 @@ typedef enum : NSUInteger {
// This is a key method. It builds or rebuilds the list of // This is a key method. It builds or rebuilds the list of
// cell view models. // cell view models.
// - (void)reloadViewItems
// Returns a list of the rows which may have changed size and
// need to be reloaded if we're doing an incremental update
// of the view.
- (NSSet<NSNumber *> *)reloadViewItems
{ {
NSMutableArray<ConversationViewItem *> *viewItems = [NSMutableArray new]; NSMutableArray<ConversationViewItem *> *viewItems = [NSMutableArray new];
NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemCache = [NSMutableDictionary new]; NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemCache = [NSMutableDictionary new];
@ -4809,23 +4804,18 @@ typedef enum : NSUInteger {
} }
ConversationViewItem *_Nullable viewItem = self.viewItemCache[interaction.uniqueId]; ConversationViewItem *_Nullable viewItem = self.viewItemCache[interaction.uniqueId];
if (viewItem) { if (!viewItem) {
viewItem.previousRow = viewItem.row;
} else {
viewItem = [[ConversationViewItem alloc] initWithInteraction:interaction viewItem = [[ConversationViewItem alloc] initWithInteraction:interaction
isGroupThread:isGroupThread isGroupThread:isGroupThread
transaction:transaction transaction:transaction
conversationStyle:self.conversationStyle]; conversationStyle:self.conversationStyle];
} }
viewItem.row = (NSInteger)row;
[viewItems addObject:viewItem]; [viewItems addObject:viewItem];
OWSAssert(!viewItemCache[interaction.uniqueId]); OWSAssert(!viewItemCache[interaction.uniqueId]);
viewItemCache[interaction.uniqueId] = viewItem; viewItemCache[interaction.uniqueId] = viewItem;
} }
}]; }];
NSMutableSet<NSNumber *> *rowsThatChangedSize = [NSMutableSet new];
// Update the "shouldShowDate" property of the view items. // Update the "shouldShowDate" property of the view items.
BOOL shouldShowDateOnNextViewItem = YES; BOOL shouldShowDateOnNextViewItem = YES;
uint64_t previousViewItemTimestamp = 0; uint64_t previousViewItemTimestamp = 0;
@ -4865,12 +4855,6 @@ typedef enum : NSUInteger {
shouldShowDateOnNextViewItem = NO; shouldShowDateOnNextViewItem = NO;
} }
// If this is an existing view item and it has changed size,
// note that so that we can reload this cell while doing
// incremental updates.
if (viewItem.shouldShowDate != shouldShowDate && viewItem.previousRow != NSNotFound) {
[rowsThatChangedSize addObject:@(viewItem.previousRow)];
}
viewItem.shouldShowDate = shouldShowDate; viewItem.shouldShowDate = shouldShowDate;
previousViewItemTimestamp = viewItem.interaction.timestampForSorting; previousViewItemTimestamp = viewItem.interaction.timestampForSorting;
@ -4910,20 +4894,12 @@ typedef enum : NSUInteger {
} }
lastInteractionType = interactionType; lastInteractionType = interactionType;
// If this is an existing view item and it has changed size,
// note that so that we can reload this cell while doing
// incremental updates.
if (viewItem.shouldHideRecipientStatus != shouldHideRecipientStatus && viewItem.previousRow != NSNotFound) {
[rowsThatChangedSize addObject:@(viewItem.previousRow)];
}
viewItem.shouldHideRecipientStatus = shouldHideRecipientStatus; viewItem.shouldHideRecipientStatus = shouldHideRecipientStatus;
viewItem.shouldHideAvatar = shouldHideAvatar; viewItem.shouldHideAvatar = shouldHideAvatar;
} }
self.viewItems = viewItems; self.viewItems = viewItems;
self.viewItemCache = viewItemCache; self.viewItemCache = viewItemCache;
return [rowsThatChangedSize copy];
} }
// Whenever an interaction is modified, we need to reload it from the DB // Whenever an interaction is modified, we need to reload it from the DB

@ -60,14 +60,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
// Used to suppress "group sender" avatars. // Used to suppress "group sender" avatars.
@property (nonatomic) BOOL shouldHideAvatar; @property (nonatomic) BOOL shouldHideAvatar;
@property (nonatomic) NSInteger row;
// During updates, we sometimes need the previous row index
// (before this update) of this item.
//
// If NSNotFound, this view item was just created in the
// previous update.
@property (nonatomic) NSInteger previousRow;
@property (nonatomic, readonly) ConversationStyle *conversationStyle; @property (nonatomic, readonly) ConversationStyle *conversationStyle;
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;

@ -92,8 +92,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
_interaction = interaction; _interaction = interaction;
_isGroupThread = isGroupThread; _isGroupThread = isGroupThread;
_conversationStyle = conversationStyle; _conversationStyle = conversationStyle;
self.row = NSNotFound;
self.previousRow = NSNotFound;
[self ensureViewState:transaction]; [self ensureViewState:transaction];
@ -271,8 +269,21 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
return 0.f; return 0.f;
} }
// "Bubble Collapse". Adjacent messages with the same author should be close together.
if (self.interaction.interactionType == OWSInteractionType_IncomingMessage
&& previousLayoutItem.interaction.interactionType == OWSInteractionType_IncomingMessage) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.interaction;
TSIncomingMessage *previousIncomingMessage = (TSIncomingMessage *)previousLayoutItem.interaction;
if ([incomingMessage.authorId isEqualToString:previousIncomingMessage.authorId]) {
return 2.f;
}
} else if (self.interaction.interactionType == OWSInteractionType_OutgoingMessage
&& previousLayoutItem.interaction.interactionType == OWSInteractionType_OutgoingMessage) {
return 2.f;
}
// TODO: // TODO:
return 4.f; return 10.f;
} }
- (ConversationViewCell *)dequeueCellForCollectionView:(UICollectionView *)collectionView - (ConversationViewCell *)dequeueCellForCollectionView:(UICollectionView *)collectionView

@ -233,7 +233,6 @@ NS_ASSUME_NONNULL_BEGIN
relation:NSLayoutRelationGreaterThanOrEqual], relation:NSLayoutRelationGreaterThanOrEqual],
[self.unreadBadge autoSetDimension:ALDimensionHeight toSize:unreadBadgeHeight], [self.unreadBadge autoSetDimension:ALDimensionHeight toSize:unreadBadgeHeight],
]]; ]];
}]; }];
const CGFloat kMinVMargin = 5; const CGFloat kMinVMargin = 5;

@ -526,7 +526,7 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
NSError *error; NSError *error;
BOOL wasScheduled = [self.websocket sendDataNoCopy:messageData error:&error]; BOOL wasScheduled = [self.websocket sendDataNoCopy:messageData error:&error];
if (!wasScheduled || error) { if (!wasScheduled || error) {
OWSProdLogAndFail(@"%@ could not serialize request JSON: %@", self.logTag, error); OWSProdLogAndFail(@"%@ could not send socket request: %@", self.logTag, error);
[socketMessage didFailBeforeSending]; [socketMessage didFailBeforeSending];
return; return;
} }

Loading…
Cancel
Save