diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.h b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.h index 17e2d20a5..312006882 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.h +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.h @@ -8,10 +8,6 @@ NS_ASSUME_NONNULL_BEGIN extern const CGFloat kOWSMessageCellCornerRadius; -extern const CGFloat kBubbleVRounding; -extern const CGFloat kBubbleHRounding; -extern const CGFloat kBubbleThornSideInset; -extern const CGFloat kBubbleThornVInset; extern const CGFloat kBubbleTextHInset; extern const CGFloat kBubbleTextTopInset; extern const CGFloat kBubbleTextBottomInset; @@ -30,10 +26,6 @@ extern const CGFloat kBubbleTextBottomInset; @interface OWSBubbleView : UIView -@property (nonatomic) BOOL isOutgoing; -@property (nonatomic) BOOL hideTail; -@property (nonatomic) BOOL isTruncated; - @property (nonatomic, nullable) UIColor *bubbleColor; - (UIBezierPath *)maskPath; diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.m index 88e49856d..85d3c6649 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleView.m @@ -9,10 +9,6 @@ NS_ASSUME_NONNULL_BEGIN const CGFloat kOWSMessageCellCornerRadius = 18; -const CGFloat kBubbleVRounding = kOWSMessageCellCornerRadius; -const CGFloat kBubbleHRounding = kOWSMessageCellCornerRadius; -const CGFloat kBubbleThornSideInset = 5.f; -const CGFloat kBubbleThornVInset = 0; const CGFloat kBubbleTextHInset = 10.f; const CGFloat kBubbleTextTopInset = 8.f; const CGFloat kBubbleTextBottomInset = 6.f; @@ -48,39 +44,6 @@ const CGFloat kBubbleTextBottomInset = 6.f; return self; } -- (void)setIsOutgoing:(BOOL)isOutgoing -{ - BOOL didChange = _isOutgoing != isOutgoing; - - _isOutgoing = isOutgoing; - - if (didChange) { - [self updateLayers]; - } -} - -- (void)setHideTail:(BOOL)hideTail -{ - BOOL didChange = _hideTail != hideTail; - - _hideTail = hideTail; - - if (didChange) { - [self updateLayers]; - } -} - -- (void)setIsTruncated:(BOOL)isTruncated -{ - BOOL didChange = _isTruncated != isTruncated; - - _isTruncated = isTruncated; - - if (didChange) { - [self updateLayers]; - } -} - - (void)setFrame:(CGRect)frame { // We only need to update our layers if the _size_ of this view @@ -165,64 +128,14 @@ const CGFloat kBubbleTextBottomInset = 6.f; - (UIBezierPath *)maskPath { - return [self.class maskPathForSize:self.bounds.size - isOutgoing:self.isOutgoing - hideTail:self.hideTail - isTruncated:self.isTruncated - isRTL:self.isRTL]; + return [self.class maskPathForSize:self.bounds.size]; } + (UIBezierPath *)maskPathForSize:(CGSize)size - isOutgoing:(BOOL)isOutgoing - hideTail:(BOOL)hideTail - isTruncated:(BOOL)isTruncated - isRTL:(BOOL)isRTL { - UIBezierPath *bezierPath = [UIBezierPath new]; - - CGFloat bubbleLeft = 0.f; - CGFloat bubbleRight = size.width - kBubbleThornSideInset; - CGFloat bubbleTop = 0.f; - CGFloat bubbleBottom = size.height - kBubbleThornVInset; - - [bezierPath moveToPoint:CGPointMake(bubbleLeft + kBubbleHRounding, bubbleTop)]; - [bezierPath addLineToPoint:CGPointMake(bubbleRight - kBubbleHRounding, bubbleTop)]; - [bezierPath addQuadCurveToPoint:CGPointMake(bubbleRight, bubbleTop + kBubbleVRounding) - controlPoint:CGPointMake(bubbleRight, bubbleTop)]; - [bezierPath addLineToPoint:CGPointMake(bubbleRight, bubbleBottom - kBubbleVRounding)]; - - if (hideTail) { - [bezierPath addQuadCurveToPoint:CGPointMake(bubbleRight - kBubbleHRounding, bubbleBottom) - controlPoint:CGPointMake(bubbleRight, bubbleBottom)]; - } else { - // Thorn Tip - CGPoint thornTip = CGPointMake(size.width + 1, size.height); - CGPoint thornB = CGPointMake(bubbleRight, bubbleBottom - kBubbleVRounding); - // Approximate intersection of the thorn and the bubble edge. - CGPoint thornPrime - = CGPointMake(bubbleRight - kBubbleHRounding * 0.25f, bubbleBottom - kBubbleVRounding * 0.25f); - CGPoint thornPrimeA = CGPointMake(thornPrime.x, bubbleBottom - kBubbleVRounding * 0.08f); - - [bezierPath addQuadCurveToPoint:thornTip controlPoint:CGPointMake(thornB.x, bubbleBottom)]; - [bezierPath addQuadCurveToPoint:thornPrime controlPoint:thornPrimeA]; - [bezierPath addQuadCurveToPoint:CGPointMake(bubbleRight - kBubbleHRounding, bubbleBottom) - controlPoint:thornPrimeA]; - } - - [bezierPath addLineToPoint:CGPointMake(bubbleLeft + kBubbleHRounding, bubbleBottom)]; - [bezierPath addQuadCurveToPoint:CGPointMake(bubbleLeft, bubbleBottom - kBubbleVRounding) - controlPoint:CGPointMake(bubbleLeft, bubbleBottom)]; - [bezierPath addLineToPoint:CGPointMake(bubbleLeft, bubbleTop + kBubbleVRounding)]; - [bezierPath addQuadCurveToPoint:CGPointMake(bubbleLeft + kBubbleHRounding, bubbleTop) - controlPoint:CGPointMake(bubbleLeft, bubbleTop)]; - - // Horizontal Flip If Necessary - BOOL shouldFlip = isOutgoing == isRTL; - if (shouldFlip) { - CGAffineTransform flipTransform = CGAffineTransformMakeTranslation(size.width, 0.0); - flipTransform = CGAffineTransformScale(flipTransform, -1.0, 1.0); - [bezierPath applyTransform:flipTransform]; - } + CGRect bounds = CGRectZero; + bounds.size = size; + UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:kOWSMessageCellCornerRadius]; return bezierPath; } @@ -255,7 +168,7 @@ const CGFloat kBubbleTextBottomInset = 6.f; + (CGFloat)minWidth { - return (kBubbleHRounding * 2 + kBubbleThornSideInset); + return (kOWSMessageCellCornerRadius * 2); } @end diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index 5b63a8638..008ca2cc6 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -246,9 +246,6 @@ NS_ASSUME_NONNULL_BEGIN CGSize bodyMediaContentSize = [self bodyMediaSize]; CGSize bodyTextContentSize = [self bodyTextSize:NO]; - self.bubbleView.isOutgoing = self.isOutgoing; - self.bubbleView.hideTail = self.viewItem.shouldHideBubbleTail && !self.alwaysShowBubbleTail; - if ([self.viewItem.interaction isKindOfClass:[TSMessage class]] && self.hasBubbleBackground) { TSMessage *message = (TSMessage *)self.viewItem.interaction; self.bubbleView.bubbleColor = [self.bubbleFactory bubbleColorWithMessage:message]; @@ -278,11 +275,9 @@ NS_ASSUME_NONNULL_BEGIN [quotedMessageView createContents]; [self.bubbleView addSubview:quotedMessageView]; - CGFloat bubbleLeadingMargin = (self.isIncoming ? kBubbleThornSideInset : 0.f); - CGFloat bubbleTrailingMargin = (self.isIncoming ? 0.f : kBubbleThornSideInset); [self.viewConstraints addObjectsFromArray:@[ - [quotedMessageView autoPinLeadingToSuperviewMarginWithInset:bubbleLeadingMargin], - [quotedMessageView autoPinTrailingToSuperviewMarginWithInset:bubbleTrailingMargin], + [quotedMessageView autoPinLeadingToSuperviewMargin], + [quotedMessageView autoPinTrailingToSuperviewMargin], ]]; [self.viewConstraints addObject:[quotedMessageView autoSetDimension:ALDimensionHeight toSize:quotedMessageContentSize.height]]; @@ -1026,18 +1021,12 @@ NS_ASSUME_NONNULL_BEGIN - (CGFloat)textLeadingMargin { CGFloat result = kBubbleTextHInset; - if (self.isIncoming) { - result += kBubbleThornSideInset; - } return result; } - (CGFloat)textTrailingMargin { CGFloat result = kBubbleTextHInset; - if (!self.isIncoming) { - result += kBubbleThornSideInset; - } return result; } @@ -1048,7 +1037,7 @@ NS_ASSUME_NONNULL_BEGIN - (CGFloat)textBottomMargin { - return kBubbleTextBottomInset + kBubbleThornVInset; + return kBubbleTextBottomInset; } - (UIColor *)bodyTextColor diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index b96ab982e..f319f5381 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -20,11 +20,9 @@ NS_ASSUME_NONNULL_BEGIN // * MessageView (message) // * dateHeaderLabel (above message) // * footerView (below message) -// * failedSendBadgeView ("trailing" beside message) @property (nonatomic) OWSMessageBubbleView *messageBubbleView; @property (nonatomic) UILabel *dateHeaderLabel; -@property (nonatomic, nullable) UIImageView *failedSendBadgeView; @property (nonatomic) UIView *footerView; @property (nonatomic) UILabel *footerLabel; @property (nonatomic, nullable) OWSExpirationTimerView *expirationTimerView; @@ -53,12 +51,11 @@ NS_ASSUME_NONNULL_BEGIN self.preservesSuperviewLayoutMargins = NO; self.contentView.preservesSuperviewLayoutMargins = NO; - - _viewConstraints = [NSMutableArray new]; - self.layoutMargins = UIEdgeInsetsZero; self.contentView.layoutMargins = UIEdgeInsetsZero; + _viewConstraints = [NSMutableArray new]; + self.messageBubbleView = [OWSMessageBubbleView new]; [self.contentView addSubview:self.messageBubbleView]; @@ -112,28 +109,6 @@ NS_ASSUME_NONNULL_BEGIN return NSStringFromClass([self class]); } -- (BOOL)shouldHaveFailedSendBadge -{ - if (![self.viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) { - return NO; - } - TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.viewItem.interaction; - return outgoingMessage.messageState == TSOutgoingMessageStateFailed; -} - -- (UIImage *)failedSendBadge -{ - UIImage *image = [UIImage imageNamed:@"message_send_failure"]; - OWSAssert(image); - OWSAssert(image.size.width == self.failedSendBadgeSize && image.size.height == self.failedSendBadgeSize); - return image; -} - -- (CGFloat)failedSendBadgeSize -{ - return 20.f; -} - #pragma mark - Convenience Accessors - (OWSMessageCellType)cellType @@ -177,25 +152,19 @@ NS_ASSUME_NONNULL_BEGIN self.dateHeaderLabel.font = self.dateHeaderDateFont; self.footerLabel.font = UIFont.ows_dynamicTypeCaption2Font; - if (self.shouldHaveFailedSendBadge) { - self.failedSendBadgeView = [UIImageView new]; - self.failedSendBadgeView.image = - [self.failedSendBadge imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; - self.failedSendBadgeView.tintColor = [UIColor ows_destructiveRedColor]; - [self.contentView addSubview:self.failedSendBadgeView]; - + if (self.isIncoming) { [self.viewConstraints addObjectsFromArray:@[ - [self.messageBubbleView autoPinLeadingToSuperviewMargin], - [self.failedSendBadgeView autoPinLeadingToTrailingEdgeOfView:self.messageBubbleView], - [self.failedSendBadgeView autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.messageBubbleView], - [self.failedSendBadgeView autoPinTrailingToSuperviewMargin], - [self.failedSendBadgeView autoSetDimension:ALDimensionWidth toSize:self.failedSendBadgeSize], - [self.failedSendBadgeView autoSetDimension:ALDimensionHeight toSize:self.failedSendBadgeSize], + [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:self.layoutInfo.gutterLeading], + [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeTrailing + withInset:self.layoutInfo.gutterTrailing + relation:NSLayoutRelationGreaterThanOrEqual], ]]; } else { [self.viewConstraints addObjectsFromArray:@[ - [self.messageBubbleView autoPinLeadingToSuperviewMargin], - [self.messageBubbleView autoPinTrailingToSuperviewMargin], + [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeLeading + withInset:self.layoutInfo.gutterLeading + relation:NSLayoutRelationGreaterThanOrEqual], + [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:self.layoutInfo.gutterTrailing], ]]; } @@ -313,6 +282,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateFooter { + OWSAssert(self.layoutInfo); OWSAssert(self.viewItem.interaction.interactionType == OWSInteractionType_IncomingMessage || self.viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage); @@ -342,10 +312,8 @@ NS_ASSUME_NONNULL_BEGIN } [self.viewConstraints addObjectsFromArray:@[ - (self.isIncoming ? [self.footerView autoPinLeadingToSuperviewMarginWithInset:kBubbleThornSideInset] - : [self.footerView autoPinTrailingToSuperviewMarginWithInset:kBubbleThornSideInset]), - (self.isIncoming ? [self.footerView autoPinTrailingToSuperviewMargin] - : [self.footerView autoPinLeadingToSuperviewMargin]), + (self.isIncoming ? [self.footerView autoPinLeadingToSuperviewMarginWithInset:self.layoutInfo.gutterLeading] + : [self.footerView autoPinTrailingToSuperviewMarginWithInset:self.layoutInfo.gutterTrailing]), ]]; [self.viewConstraints addObject:[self.footerView autoPinEdge:ALEdgeTop @@ -418,7 +386,6 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Measurement - - (CGSize)cellSize { OWSAssert(self.layoutInfo); @@ -441,10 +408,6 @@ NS_ASSUME_NONNULL_BEGIN cellSize.height += self.footerHeight; } - if (self.shouldHaveFailedSendBadge) { - cellSize.width += self.failedSendBadgeSize; - } - cellSize = CGSizeCeil(cellSize); return cellSize; @@ -474,8 +437,6 @@ NS_ASSUME_NONNULL_BEGIN self.dateHeaderLabel.text = nil; self.dateHeaderLabel.hidden = YES; - [self.failedSendBadgeView removeFromSuperview]; - self.failedSendBadgeView = nil; self.footerLabel.text = nil; self.footerLabel.hidden = YES; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationLayoutInfo.swift b/Signal/src/ViewControllers/ConversationView/ConversationLayoutInfo.swift index b473192bc..97c7f7093 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationLayoutInfo.swift +++ b/Signal/src/ViewControllers/ConversationView/ConversationLayoutInfo.swift @@ -68,6 +68,7 @@ public class ConversationLayoutInfo: NSObject { fullWidthContentWidth = viewWidth - (fullWidthGutterLeading + fullWidthGutterTrailing) maxMessageWidth = floor(contentWidth * 0.8) - maxFooterWidth = floor(contentWidth - 100) + // TODO: Should this be different? + maxFooterWidth = maxMessageWidth - 10 } } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m index 104a2fae2..bde70a820 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m @@ -114,7 +114,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(layoutSize.width <= viewWidth); layoutSize.width = MIN(viewWidth, layoutSize.width); - // All cell are "full width" and are responsible for aligning their own content. + // All cells are "full width" and are responsible for aligning their own content. CGRect itemFrame = CGRectMake(0, y, viewWidth, layoutSize.height); NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];