Tweak message cells.

pull/1/head
Matthew Chen 7 years ago
parent 98ac13f9be
commit d425809fa3

@ -8,10 +8,6 @@ NS_ASSUME_NONNULL_BEGIN
extern const CGFloat kOWSMessageCellCornerRadius; 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 kBubbleTextHInset;
extern const CGFloat kBubbleTextTopInset; extern const CGFloat kBubbleTextTopInset;
extern const CGFloat kBubbleTextBottomInset; extern const CGFloat kBubbleTextBottomInset;
@ -30,10 +26,6 @@ extern const CGFloat kBubbleTextBottomInset;
@interface OWSBubbleView : UIView @interface OWSBubbleView : UIView
@property (nonatomic) BOOL isOutgoing;
@property (nonatomic) BOOL hideTail;
@property (nonatomic) BOOL isTruncated;
@property (nonatomic, nullable) UIColor *bubbleColor; @property (nonatomic, nullable) UIColor *bubbleColor;
- (UIBezierPath *)maskPath; - (UIBezierPath *)maskPath;

@ -9,10 +9,6 @@ NS_ASSUME_NONNULL_BEGIN
const CGFloat kOWSMessageCellCornerRadius = 18; 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 kBubbleTextHInset = 10.f;
const CGFloat kBubbleTextTopInset = 8.f; const CGFloat kBubbleTextTopInset = 8.f;
const CGFloat kBubbleTextBottomInset = 6.f; const CGFloat kBubbleTextBottomInset = 6.f;
@ -48,39 +44,6 @@ const CGFloat kBubbleTextBottomInset = 6.f;
return self; 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 - (void)setFrame:(CGRect)frame
{ {
// We only need to update our layers if the _size_ of this view // We only need to update our layers if the _size_ of this view
@ -165,64 +128,14 @@ const CGFloat kBubbleTextBottomInset = 6.f;
- (UIBezierPath *)maskPath - (UIBezierPath *)maskPath
{ {
return [self.class maskPathForSize:self.bounds.size return [self.class maskPathForSize:self.bounds.size];
isOutgoing:self.isOutgoing
hideTail:self.hideTail
isTruncated:self.isTruncated
isRTL:self.isRTL];
} }
+ (UIBezierPath *)maskPathForSize:(CGSize)size + (UIBezierPath *)maskPathForSize:(CGSize)size
isOutgoing:(BOOL)isOutgoing
hideTail:(BOOL)hideTail
isTruncated:(BOOL)isTruncated
isRTL:(BOOL)isRTL
{ {
UIBezierPath *bezierPath = [UIBezierPath new]; CGRect bounds = CGRectZero;
bounds.size = size;
CGFloat bubbleLeft = 0.f; UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:kOWSMessageCellCornerRadius];
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];
}
return bezierPath; return bezierPath;
} }
@ -255,7 +168,7 @@ const CGFloat kBubbleTextBottomInset = 6.f;
+ (CGFloat)minWidth + (CGFloat)minWidth
{ {
return (kBubbleHRounding * 2 + kBubbleThornSideInset); return (kOWSMessageCellCornerRadius * 2);
} }
@end @end

@ -246,9 +246,6 @@ NS_ASSUME_NONNULL_BEGIN
CGSize bodyMediaContentSize = [self bodyMediaSize]; CGSize bodyMediaContentSize = [self bodyMediaSize];
CGSize bodyTextContentSize = [self bodyTextSize:NO]; 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) { if ([self.viewItem.interaction isKindOfClass:[TSMessage class]] && self.hasBubbleBackground) {
TSMessage *message = (TSMessage *)self.viewItem.interaction; TSMessage *message = (TSMessage *)self.viewItem.interaction;
self.bubbleView.bubbleColor = [self.bubbleFactory bubbleColorWithMessage:message]; self.bubbleView.bubbleColor = [self.bubbleFactory bubbleColorWithMessage:message];
@ -278,11 +275,9 @@ NS_ASSUME_NONNULL_BEGIN
[quotedMessageView createContents]; [quotedMessageView createContents];
[self.bubbleView addSubview:quotedMessageView]; [self.bubbleView addSubview:quotedMessageView];
CGFloat bubbleLeadingMargin = (self.isIncoming ? kBubbleThornSideInset : 0.f);
CGFloat bubbleTrailingMargin = (self.isIncoming ? 0.f : kBubbleThornSideInset);
[self.viewConstraints addObjectsFromArray:@[ [self.viewConstraints addObjectsFromArray:@[
[quotedMessageView autoPinLeadingToSuperviewMarginWithInset:bubbleLeadingMargin], [quotedMessageView autoPinLeadingToSuperviewMargin],
[quotedMessageView autoPinTrailingToSuperviewMarginWithInset:bubbleTrailingMargin], [quotedMessageView autoPinTrailingToSuperviewMargin],
]]; ]];
[self.viewConstraints [self.viewConstraints
addObject:[quotedMessageView autoSetDimension:ALDimensionHeight toSize:quotedMessageContentSize.height]]; addObject:[quotedMessageView autoSetDimension:ALDimensionHeight toSize:quotedMessageContentSize.height]];
@ -1026,18 +1021,12 @@ NS_ASSUME_NONNULL_BEGIN
- (CGFloat)textLeadingMargin - (CGFloat)textLeadingMargin
{ {
CGFloat result = kBubbleTextHInset; CGFloat result = kBubbleTextHInset;
if (self.isIncoming) {
result += kBubbleThornSideInset;
}
return result; return result;
} }
- (CGFloat)textTrailingMargin - (CGFloat)textTrailingMargin
{ {
CGFloat result = kBubbleTextHInset; CGFloat result = kBubbleTextHInset;
if (!self.isIncoming) {
result += kBubbleThornSideInset;
}
return result; return result;
} }
@ -1048,7 +1037,7 @@ NS_ASSUME_NONNULL_BEGIN
- (CGFloat)textBottomMargin - (CGFloat)textBottomMargin
{ {
return kBubbleTextBottomInset + kBubbleThornVInset; return kBubbleTextBottomInset;
} }
- (UIColor *)bodyTextColor - (UIColor *)bodyTextColor

@ -20,11 +20,9 @@ NS_ASSUME_NONNULL_BEGIN
// * MessageView (message) // * MessageView (message)
// * dateHeaderLabel (above message) // * dateHeaderLabel (above message)
// * footerView (below message) // * footerView (below message)
// * failedSendBadgeView ("trailing" beside message)
@property (nonatomic) OWSMessageBubbleView *messageBubbleView; @property (nonatomic) OWSMessageBubbleView *messageBubbleView;
@property (nonatomic) UILabel *dateHeaderLabel; @property (nonatomic) UILabel *dateHeaderLabel;
@property (nonatomic, nullable) UIImageView *failedSendBadgeView;
@property (nonatomic) UIView *footerView; @property (nonatomic) UIView *footerView;
@property (nonatomic) UILabel *footerLabel; @property (nonatomic) UILabel *footerLabel;
@property (nonatomic, nullable) OWSExpirationTimerView *expirationTimerView; @property (nonatomic, nullable) OWSExpirationTimerView *expirationTimerView;
@ -53,12 +51,11 @@ NS_ASSUME_NONNULL_BEGIN
self.preservesSuperviewLayoutMargins = NO; self.preservesSuperviewLayoutMargins = NO;
self.contentView.preservesSuperviewLayoutMargins = NO; self.contentView.preservesSuperviewLayoutMargins = NO;
_viewConstraints = [NSMutableArray new];
self.layoutMargins = UIEdgeInsetsZero; self.layoutMargins = UIEdgeInsetsZero;
self.contentView.layoutMargins = UIEdgeInsetsZero; self.contentView.layoutMargins = UIEdgeInsetsZero;
_viewConstraints = [NSMutableArray new];
self.messageBubbleView = [OWSMessageBubbleView new]; self.messageBubbleView = [OWSMessageBubbleView new];
[self.contentView addSubview:self.messageBubbleView]; [self.contentView addSubview:self.messageBubbleView];
@ -112,28 +109,6 @@ NS_ASSUME_NONNULL_BEGIN
return NSStringFromClass([self class]); 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 #pragma mark - Convenience Accessors
- (OWSMessageCellType)cellType - (OWSMessageCellType)cellType
@ -177,25 +152,19 @@ NS_ASSUME_NONNULL_BEGIN
self.dateHeaderLabel.font = self.dateHeaderDateFont; self.dateHeaderLabel.font = self.dateHeaderDateFont;
self.footerLabel.font = UIFont.ows_dynamicTypeCaption2Font; self.footerLabel.font = UIFont.ows_dynamicTypeCaption2Font;
if (self.shouldHaveFailedSendBadge) { if (self.isIncoming) {
self.failedSendBadgeView = [UIImageView new];
self.failedSendBadgeView.image =
[self.failedSendBadge imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.failedSendBadgeView.tintColor = [UIColor ows_destructiveRedColor];
[self.contentView addSubview:self.failedSendBadgeView];
[self.viewConstraints addObjectsFromArray:@[ [self.viewConstraints addObjectsFromArray:@[
[self.messageBubbleView autoPinLeadingToSuperviewMargin], [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:self.layoutInfo.gutterLeading],
[self.failedSendBadgeView autoPinLeadingToTrailingEdgeOfView:self.messageBubbleView], [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeTrailing
[self.failedSendBadgeView autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.messageBubbleView], withInset:self.layoutInfo.gutterTrailing
[self.failedSendBadgeView autoPinTrailingToSuperviewMargin], relation:NSLayoutRelationGreaterThanOrEqual],
[self.failedSendBadgeView autoSetDimension:ALDimensionWidth toSize:self.failedSendBadgeSize],
[self.failedSendBadgeView autoSetDimension:ALDimensionHeight toSize:self.failedSendBadgeSize],
]]; ]];
} else { } else {
[self.viewConstraints addObjectsFromArray:@[ [self.viewConstraints addObjectsFromArray:@[
[self.messageBubbleView autoPinLeadingToSuperviewMargin], [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeLeading
[self.messageBubbleView autoPinTrailingToSuperviewMargin], withInset:self.layoutInfo.gutterLeading
relation:NSLayoutRelationGreaterThanOrEqual],
[self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:self.layoutInfo.gutterTrailing],
]]; ]];
} }
@ -313,6 +282,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)updateFooter - (void)updateFooter
{ {
OWSAssert(self.layoutInfo);
OWSAssert(self.viewItem.interaction.interactionType == OWSInteractionType_IncomingMessage OWSAssert(self.viewItem.interaction.interactionType == OWSInteractionType_IncomingMessage
|| self.viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage); || self.viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage);
@ -342,10 +312,8 @@ NS_ASSUME_NONNULL_BEGIN
} }
[self.viewConstraints addObjectsFromArray:@[ [self.viewConstraints addObjectsFromArray:@[
(self.isIncoming ? [self.footerView autoPinLeadingToSuperviewMarginWithInset:kBubbleThornSideInset] (self.isIncoming ? [self.footerView autoPinLeadingToSuperviewMarginWithInset:self.layoutInfo.gutterLeading]
: [self.footerView autoPinTrailingToSuperviewMarginWithInset:kBubbleThornSideInset]), : [self.footerView autoPinTrailingToSuperviewMarginWithInset:self.layoutInfo.gutterTrailing]),
(self.isIncoming ? [self.footerView autoPinTrailingToSuperviewMargin]
: [self.footerView autoPinLeadingToSuperviewMargin]),
]]; ]];
[self.viewConstraints addObject:[self.footerView autoPinEdge:ALEdgeTop [self.viewConstraints addObject:[self.footerView autoPinEdge:ALEdgeTop
@ -418,7 +386,6 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Measurement #pragma mark - Measurement
- (CGSize)cellSize - (CGSize)cellSize
{ {
OWSAssert(self.layoutInfo); OWSAssert(self.layoutInfo);
@ -441,10 +408,6 @@ NS_ASSUME_NONNULL_BEGIN
cellSize.height += self.footerHeight; cellSize.height += self.footerHeight;
} }
if (self.shouldHaveFailedSendBadge) {
cellSize.width += self.failedSendBadgeSize;
}
cellSize = CGSizeCeil(cellSize); cellSize = CGSizeCeil(cellSize);
return cellSize; return cellSize;
@ -474,8 +437,6 @@ NS_ASSUME_NONNULL_BEGIN
self.dateHeaderLabel.text = nil; self.dateHeaderLabel.text = nil;
self.dateHeaderLabel.hidden = YES; self.dateHeaderLabel.hidden = YES;
[self.failedSendBadgeView removeFromSuperview];
self.failedSendBadgeView = nil;
self.footerLabel.text = nil; self.footerLabel.text = nil;
self.footerLabel.hidden = YES; self.footerLabel.hidden = YES;

@ -68,6 +68,7 @@ public class ConversationLayoutInfo: NSObject {
fullWidthContentWidth = viewWidth - (fullWidthGutterLeading + fullWidthGutterTrailing) fullWidthContentWidth = viewWidth - (fullWidthGutterLeading + fullWidthGutterTrailing)
maxMessageWidth = floor(contentWidth * 0.8) maxMessageWidth = floor(contentWidth * 0.8)
maxFooterWidth = floor(contentWidth - 100) // TODO: Should this be different?
maxFooterWidth = maxMessageWidth - 10
} }
} }

@ -114,7 +114,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(layoutSize.width <= viewWidth); OWSAssert(layoutSize.width <= viewWidth);
layoutSize.width = MIN(viewWidth, layoutSize.width); 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); CGRect itemFrame = CGRectMake(0, y, viewWidth, layoutSize.height);
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];

Loading…
Cancel
Save