Tweak message cells.

This commit is contained in:
Matthew Chen 2018-06-22 14:53:33 -04:00
parent 98ac13f9be
commit d425809fa3
6 changed files with 25 additions and 169 deletions

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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
}
}

View file

@ -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];