diff --git a/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m b/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m index 8bd9e2931..2be1073b7 100644 --- a/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m +++ b/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m @@ -31,8 +31,20 @@ NS_ASSUME_NONNULL_BEGIN - (CGSize)jsq_avatarSizeForMessageData:(id)messageData withLayout:(JSQMessagesCollectionViewFlowLayout *)layout; - (CGFloat)textBubbleWidthForLayout:(JSQMessagesCollectionViewFlowLayout *)layout; + +@end + +#pragma mark - + +@interface OWSMessagesBubblesSizeCalculator () + +@property (nonatomic) OWSSystemMessageCell *referenceSystemMessageCell; +@property (nonatomic) OWSUnreadIndicatorCell *referenceUnreadIndicatorCell; + @end +#pragma mark - + @implementation OWSMessagesBubblesSizeCalculator /** @@ -98,6 +110,7 @@ NS_ASSUME_NONNULL_BEGIN cacheKey:(id)cacheKey layout:(JSQMessagesCollectionViewFlowLayout *)layout { + OWSAssert([NSThread isMainThread]); OWSAssert(interaction); OWSAssert(cacheKey); @@ -106,8 +119,12 @@ NS_ASSUME_NONNULL_BEGIN return [cachedSize CGSizeValue]; } - CGSize result = - [OWSSystemMessageCell cellSizeForInteraction:interaction collectionViewWidth:layout.collectionView.width]; + if (!self.referenceSystemMessageCell) { + self.referenceSystemMessageCell = [OWSSystemMessageCell new]; + } + + CGSize result = [self.referenceSystemMessageCell cellSizeForInteraction:interaction + collectionViewWidth:layout.collectionView.width]; [self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey]; @@ -126,8 +143,12 @@ NS_ASSUME_NONNULL_BEGIN return [cachedSize CGSizeValue]; } - CGSize result = - [OWSUnreadIndicatorCell cellSizeForInteraction:interaction collectionViewWidth:layout.collectionView.width]; + if (!self.referenceUnreadIndicatorCell) { + self.referenceUnreadIndicatorCell = [OWSUnreadIndicatorCell new]; + } + + CGSize result = [self.referenceUnreadIndicatorCell cellSizeForInteraction:interaction + collectionViewWidth:layout.collectionView.width]; [self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey]; diff --git a/Signal/src/views/OWSSystemMessageCell.h b/Signal/src/views/OWSSystemMessageCell.h index 5ceb0f102..839c79804 100644 --- a/Signal/src/views/OWSSystemMessageCell.h +++ b/Signal/src/views/OWSSystemMessageCell.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)configureWithInteraction:(TSInteraction *)interaction; -+ (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth; +- (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth; @end diff --git a/Signal/src/views/OWSSystemMessageCell.m b/Signal/src/views/OWSSystemMessageCell.m index 1d66ee4be..ce7466af2 100644 --- a/Signal/src/views/OWSSystemMessageCell.m +++ b/Signal/src/views/OWSSystemMessageCell.m @@ -51,7 +51,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)commontInit { - OWSAssert(!self.imageView); + if (self.imageView) { + // Don't init twice. + return; + } [self setTranslatesAutoresizingMaskIntoConstraints:NO]; @@ -62,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN self.titleLabel = [UILabel new]; self.titleLabel.textColor = [UIColor colorWithRGBHex:0x403e3b]; - self.titleLabel.font = [OWSSystemMessageCell titleFont]; + self.titleLabel.font = [self titleFont]; self.titleLabel.numberOfLines = 0; self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; [self.contentView addSubview:self.titleLabel]; @@ -86,13 +89,13 @@ NS_ASSUME_NONNULL_BEGIN UIImage *icon = [self iconForInteraction:self.interaction]; self.imageView.image = [icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; self.imageView.tintColor = [self iconColorForInteraction:self.interaction]; - self.titleLabel.textColor = [OWSSystemMessageCell textColor]; - [OWSSystemMessageCell applyTitleForInteraction:self.interaction label:self.titleLabel]; + self.titleLabel.textColor = [self textColor]; + [self applyTitleForInteraction:self.interaction label:self.titleLabel]; [self setNeedsLayout]; } -+ (UIColor *)textColor +- (UIColor *)textColor { return [UIColor colorWithRGBHex:0x303030]; } @@ -162,7 +165,7 @@ NS_ASSUME_NONNULL_BEGIN return result; } -+ (void)applyTitleForInteraction:(TSInteraction *)interaction label:(UILabel *)label +- (void)applyTitleForInteraction:(TSInteraction *)interaction label:(UILabel *)label { OWSAssert(interaction); OWSAssert(label); @@ -204,32 +207,32 @@ NS_ASSUME_NONNULL_BEGIN } } -+ (UIFont *)titleFont +- (UIFont *)titleFont { return [UIFont ows_regularFontWithSize:13.f]; } -+ (CGFloat)hMargin +- (CGFloat)hMargin { return 25.f; } -+ (CGFloat)topVMargin +- (CGFloat)topVMargin { return 5.f; } -+ (CGFloat)bottomVMargin +- (CGFloat)bottomVMargin { return 5.f; } -+ (CGFloat)hSpacing +- (CGFloat)hSpacing { return 8.f; } -+ (CGFloat)iconSize +- (CGFloat)iconSize { return 20.f; } @@ -238,36 +241,32 @@ NS_ASSUME_NONNULL_BEGIN { [super layoutSubviews]; - CGFloat maxTitleWidth = (self.contentView.width - - ([OWSSystemMessageCell hMargin] * 2.f + [OWSSystemMessageCell hSpacing] + [OWSSystemMessageCell iconSize])); + CGFloat maxTitleWidth = (self.contentView.width - ([self hMargin] * 2.f + [self hSpacing] + [self iconSize])); CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)]; - CGFloat contentWidth = ([OWSSystemMessageCell iconSize] + [OWSSystemMessageCell hSpacing] + titleSize.width); + CGFloat contentWidth = ([self iconSize] + [self hSpacing] + titleSize.width); self.imageView.frame = CGRectMake(round((self.contentView.width - contentWidth) * 0.5f), - round((self.contentView.height - [OWSSystemMessageCell iconSize]) * 0.5f), - [OWSSystemMessageCell iconSize], - [OWSSystemMessageCell iconSize]); - self.titleLabel.frame = CGRectMake(round(self.imageView.right + [OWSSystemMessageCell hSpacing]), + round((self.contentView.height - [self iconSize]) * 0.5f), + [self iconSize], + [self iconSize]); + self.titleLabel.frame = CGRectMake(round(self.imageView.right + [self hSpacing]), round((self.contentView.height - titleSize.height) * 0.5f), ceil(titleSize.width + 1.f), ceil(titleSize.height + 1.f)); } -+ (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth +- (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth { CGSize result = CGSizeMake(collectionViewWidth, 0); result.height += self.topVMargin; result.height += self.bottomVMargin; - // Creating a UILabel to measure the layout is expensive, but it's the only - // reliable way to do it. - UILabel *label = [UILabel new]; - label.font = [self titleFont]; - [OWSSystemMessageCell applyTitleForInteraction:interaction label:label]; - label.numberOfLines = 0; - label.lineBreakMode = NSLineBreakByWordWrapping; + self.titleLabel.font = [self titleFont]; + [self applyTitleForInteraction:interaction label:self.titleLabel]; + self.titleLabel.numberOfLines = 0; + self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; CGFloat maxTitleWidth = (collectionViewWidth - ([self hMargin] * 2.f + [self hSpacing] + [self iconSize])); - CGSize titleSize = [label sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)]; + CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)]; CGFloat contentHeight = ceil(MAX([self iconSize], titleSize.height)); result.height += contentHeight; diff --git a/Signal/src/views/OWSUnreadIndicatorCell.h b/Signal/src/views/OWSUnreadIndicatorCell.h index 7b57af0dc..1d013bce5 100644 --- a/Signal/src/views/OWSUnreadIndicatorCell.h +++ b/Signal/src/views/OWSUnreadIndicatorCell.h @@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)configureWithInteraction:(TSUnreadIndicatorInteraction *)interaction; -+ (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction +- (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth; @end diff --git a/Signal/src/views/OWSUnreadIndicatorCell.m b/Signal/src/views/OWSUnreadIndicatorCell.m index 5d76dcb52..4322ff863 100644 --- a/Signal/src/views/OWSUnreadIndicatorCell.m +++ b/Signal/src/views/OWSUnreadIndicatorCell.m @@ -49,7 +49,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)commontInit { - OWSAssert(!self.bannerView); + if (self.bannerView) { + // Don't init twice. + return; + } [self setTranslatesAutoresizingMaskIntoConstraints:NO]; @@ -72,15 +75,15 @@ NS_ASSUME_NONNULL_BEGIN [self.bannerView addSubview:self.bannerBottomHighlightView2]; self.titleLabel = [UILabel new]; - self.titleLabel.text = [OWSUnreadIndicatorCell titleForInteraction:self.interaction]; + self.titleLabel.text = [self titleForInteraction:self.interaction]; self.titleLabel.textColor = [UIColor colorWithRGBHex:0x403e3b]; - self.titleLabel.font = [OWSUnreadIndicatorCell titleFont]; + self.titleLabel.font = [self titleFont]; [self.bannerView addSubview:self.titleLabel]; self.subtitleLabel = [UILabel new]; - self.subtitleLabel.text = [OWSUnreadIndicatorCell subtitleForInteraction:self.interaction]; + self.subtitleLabel.text = [self subtitleForInteraction:self.interaction]; self.subtitleLabel.textColor = [UIColor ows_infoMessageBorderColor]; - self.subtitleLabel.font = [OWSUnreadIndicatorCell subtitleFont]; + self.subtitleLabel.font = [self subtitleFont]; self.subtitleLabel.numberOfLines = 0; self.subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping; self.subtitleLabel.textAlignment = NSTextAlignmentCenter; @@ -103,23 +106,23 @@ NS_ASSUME_NONNULL_BEGIN [self setNeedsLayout]; } -+ (UIFont *)titleFont +- (UIFont *)titleFont { return [UIFont ows_regularFontWithSize:16.f]; } -+ (UIFont *)subtitleFont +- (UIFont *)subtitleFont { return [UIFont ows_regularFontWithSize:12.f]; } -+ (NSString *)titleForInteraction:(TSUnreadIndicatorInteraction *)interaction +- (NSString *)titleForInteraction:(TSUnreadIndicatorInteraction *)interaction { return NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR", @"Indicator that separates read from unread messages.") .uppercaseString; } -+ (NSString *)subtitleForInteraction:(TSUnreadIndicatorInteraction *)interaction +- (NSString *)subtitleForInteraction:(TSUnreadIndicatorInteraction *)interaction { if (!interaction.hasMoreUnseenMessages) { return nil; @@ -137,32 +140,32 @@ NS_ASSUME_NONNULL_BEGIN return [NSString stringWithFormat:subtitleFormat, loadMoreButtonName]; } -+ (CGFloat)subtitleHMargin +- (CGFloat)subtitleHMargin { return 20.f; } -+ (CGFloat)subtitleVSpacing +- (CGFloat)subtitleVSpacing { return 3.f; } -+ (CGFloat)titleInnerHMargin +- (CGFloat)titleInnerHMargin { return 10.f; } -+ (CGFloat)titleVMargin +- (CGFloat)titleVMargin { return 5.5f; } -+ (CGFloat)topVMargin +- (CGFloat)topVMargin { return 5.f; } -+ (CGFloat)bottomVMargin +- (CGFloat)bottomVMargin { return 5.f; } @@ -180,9 +183,9 @@ NS_ASSUME_NONNULL_BEGIN // This layout logic assumes that the cell insets are symmetrical and can be deduced // from the cell frame. CGRect bannerViewFrame = CGRectMake(-self.left, - round(OWSUnreadIndicatorCell.topVMargin), + round(self.topVMargin), round(self.width + self.left * 2.f), - round(self.titleLabel.height + OWSUnreadIndicatorCell.titleVMargin * 2.f)); + round(self.titleLabel.height + self.titleVMargin * 2.f)); self.bannerView.frame = [self convertRect:bannerViewFrame toView:self.contentView]; // The highlights should be 1px (not 1pt), so adapt their thickness to @@ -198,16 +201,15 @@ NS_ASSUME_NONNULL_BEGIN if (self.subtitleLabel.text.length > 0) { CGSize subtitleSize = [self.subtitleLabel - sizeThatFits:CGSizeMake( - self.contentView.width - [OWSUnreadIndicatorCell subtitleHMargin] * 2.f, CGFLOAT_MAX)]; + sizeThatFits:CGSizeMake(self.contentView.width - [self subtitleHMargin] * 2.f, CGFLOAT_MAX)]; self.subtitleLabel.frame = CGRectMake(round((self.contentView.width - subtitleSize.width) * 0.5f), - round(self.bannerView.bottom + OWSUnreadIndicatorCell.subtitleVSpacing), + round(self.bannerView.bottom + self.subtitleVSpacing), ceil(subtitleSize.width), ceil(subtitleSize.height)); } } -+ (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction +- (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth { CGSize result = CGSizeMake(collectionViewWidth, 0); @@ -220,7 +222,7 @@ NS_ASSUME_NONNULL_BEGIN // Creating a UILabel to measure the layout is expensive, but it's the only // reliable way to do it. Unread indicators should be rare, so this is acceptable. - UILabel *label = [UILabel new]; + UILabel *label = self.titleLabel; label.font = [self titleFont]; label.text = title; result.height += ceil([label sizeThatFits:CGSizeZero].height);