diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index c1161dd74a..6926b40f14 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -38,6 +38,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) BOOL isPresentingMenuController; +@property (nonatomic, readonly) OWSMessageCellType messageCellType; + @end #pragma mark - @@ -59,6 +61,8 @@ NS_ASSUME_NONNULL_BEGIN // Ensure only called once. OWSAssertDebug(!self.messageBubbleView); + _messageCellType = OWSMessageCellType_Unknown; + self.layoutMargins = UIEdgeInsetsZero; self.contentView.layoutMargins = UIEdgeInsetsZero; @@ -119,11 +123,6 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Convenience Accessors -- (OWSMessageCellType)cellType -{ - return self.viewItem.messageCellType; -} - - (TSMessage *)message { OWSAssertDebug([self.viewItem.interaction isKindOfClass:[TSMessage class]]); @@ -152,9 +151,9 @@ NS_ASSUME_NONNULL_BEGIN - (OWSMessageView *)messageView { - if (self.cellType == OWSMessageCellType_StickerMessage) { + if (self.messageCellType == OWSMessageCellType_StickerMessage) { return self.messageStickerView; - } else if (self.cellType == OWSMessageCellType_ViewOnce) { + } else if (self.messageCellType == OWSMessageCellType_ViewOnce) { return self.messageViewOnceView; } else { return self.messageBubbleView; @@ -180,6 +179,21 @@ NS_ASSUME_NONNULL_BEGIN self.sendFailureBadgeView.hidden = !self.shouldHaveSendFailureBadge; } +- (void)setViewItem:(nullable id)viewItem +{ + OWSAssertIsOnMainThread(); + + [super setViewItem:viewItem]; + + if (viewItem) { + if (!self.hasPreparedForDisplay) { + _messageCellType = viewItem.messageCellType; + } else { + OWSAssertDebug(self.messageCellType == viewItem.messageCellType); + } + } +} + // This will only ever be called *once* and should prepare for displaying a specific // type of message cell. Future reused cells will always use the same type. - (void)prepareForDisplay @@ -640,7 +654,7 @@ NS_ASSUME_NONNULL_BEGIN // Right now, only stickers need the reply button to fade in. // If we add other message types that don't have bubbles, // we should add them here. - return self.cellType == OWSMessageCellType_StickerMessage; + return self.messageCellType == OWSMessageCellType_StickerMessage; } - (void)setIsReplyActive:(BOOL)isReplyActive diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.swift b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.swift index 2d39a35769..6b86dd195d 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.swift @@ -6,24 +6,6 @@ import Foundation @objc extension OWSMessageCell { - var messageCellType: OWSMessageCellType { - if let viewItem = viewItem { return viewItem.messageCellType } - - // If accessed before the reuseIdentifier is defined, we don't know - // what type of thing this is. In practice, this will only happen - // while we're measuring the cell in which case we have nothing to - // really cleanup. TODO: maybe should fail here sometimes. - guard let reuseIdentifier = reuseIdentifier else { return .unknown } - - let components = reuseIdentifier.split(separator: "-") - guard components.count == 3 else { - owsFailDebug("unexpected reuseIdentifier") - return .unknown - } - - return OWSMessageCellType(stringValue: String(components[1])) - } - class func cellReuseIdentifier(forMessageCellType cellType: OWSMessageCellType, isOutgoingMessage: Bool) -> String { // We use dashes instead of underscores as separators here since `OWSMessageCellType` // stringValue contains underscores. diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m index 1febfbee5e..b6b4248365 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m @@ -538,13 +538,13 @@ NSString *NSStringForViewOnceMessageState(ViewOnceMessageState cellType) // For performance reasons, we cache one instance of each kind of // cell and uses these cells for measurement. - static NSMutableDictionary *measurementCellCache = nil; + static NSMutableDictionary *measurementCellCache = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ measurementCellCache = [NSMutableDictionary new]; }); - NSNumber *cellCacheKey = @(self.interaction.interactionType); + NSString *cellCacheKey = self.cellReuseIdentifier; ConversationViewCell *_Nullable measurementCell = measurementCellCache[cellCacheKey]; if (!measurementCell) { switch (self.interaction.interactionType) { @@ -616,12 +616,9 @@ NSString *NSStringForViewOnceMessageState(ViewOnceMessageState cellType) } } -- (ConversationViewCell *)dequeueCellForCollectionView:(UICollectionView *)collectionView - indexPath:(NSIndexPath *)indexPath +- (nullable NSString *)cellReuseIdentifier { OWSAssertIsOnMainThread(); - OWSAssertDebug(collectionView); - OWSAssertDebug(indexPath); OWSAssertDebug(self.interaction); switch (self.interaction.interactionType) { @@ -629,41 +626,43 @@ NSString *NSStringForViewOnceMessageState(ViewOnceMessageState cellType) OWSFailDebug(@"Unknown interaction type."); return nil; case OWSInteractionType_IncomingMessage: - return [collectionView - dequeueReusableCellWithReuseIdentifier:[OWSMessageCell - cellReuseIdentifierForMessageCellType:self.messageCellType - isOutgoingMessage:NO] - forIndexPath:indexPath]; + return [OWSMessageCell cellReuseIdentifierForMessageCellType:self.messageCellType isOutgoingMessage:NO]; case OWSInteractionType_OutgoingMessage: - return [collectionView - dequeueReusableCellWithReuseIdentifier:[OWSMessageCell - cellReuseIdentifierForMessageCellType:self.messageCellType - isOutgoingMessage:YES] - forIndexPath:indexPath]; + return [OWSMessageCell cellReuseIdentifierForMessageCellType:self.messageCellType isOutgoingMessage:YES]; case OWSInteractionType_Error: case OWSInteractionType_Info: case OWSInteractionType_Call: - return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSSystemMessageCell cellReuseIdentifier] - forIndexPath:indexPath]; + return [OWSSystemMessageCell cellReuseIdentifier]; case OWSInteractionType_Offer: - return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier] - forIndexPath:indexPath]; + return [OWSContactOffersCell cellReuseIdentifier]; case OWSInteractionType_TypingIndicator: - return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSTypingIndicatorCell cellReuseIdentifier] - forIndexPath:indexPath]; + return [OWSTypingIndicatorCell cellReuseIdentifier]; case OWSInteractionType_ThreadDetails: - return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSThreadDetailsCell cellReuseIdentifier] - forIndexPath:indexPath]; + return [OWSThreadDetailsCell cellReuseIdentifier]; case OWSInteractionType_UnreadIndicator: - return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSUnreadIndicatorCell cellReuseIdentifier] - forIndexPath:indexPath]; + return [OWSUnreadIndicatorCell cellReuseIdentifier]; case OWSInteractionType_DateHeader: - return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSDateHeaderCell cellReuseIdentifier] - forIndexPath:indexPath]; + return [OWSDateHeaderCell cellReuseIdentifier]; } } +- (ConversationViewCell *)dequeueCellForCollectionView:(UICollectionView *)collectionView + indexPath:(NSIndexPath *)indexPath +{ + OWSAssertIsOnMainThread(); + OWSAssertDebug(collectionView); + OWSAssertDebug(indexPath); + + NSString *_Nullable cellReuseIdentifier = self.cellReuseIdentifier; + if (!cellReuseIdentifier) { + OWSFailDebug(@"Unknown cell type."); + return nil; + } + + return [collectionView dequeueReusableCellWithReuseIdentifier:cellReuseIdentifier forIndexPath:indexPath]; +} + - (nullable TSAttachmentStream *)firstValidAlbumAttachment { OWSAssertDebug(self.mediaAlbumItems.count > 0);