Sharp corners

This commit is contained in:
Michael Kirk 2018-07-06 13:08:56 -06:00
parent f19d3374ec
commit 68c7abcbb9
5 changed files with 72 additions and 42 deletions

View File

@ -25,8 +25,7 @@ extern const CGFloat kOWSMessageCellCornerRadius_Small;
@property (nonatomic, nullable) UIColor *bubbleColor;
@property (nonatomic) BOOL useSmallCorners_Top;
@property (nonatomic) BOOL useSmallCorners_Bottom;
@property (nonatomic) UIRectCorner sharpCorners;
- (UIBezierPath *)maskPath;

View File

@ -101,16 +101,9 @@ const CGFloat kOWSMessageCellCornerRadius_Small = 2;
[CATransaction commit];
}
- (void)setUseSmallCorners_Top:(BOOL)useSmallCorners_Top
- (void)setSharpCorners:(UIRectCorner)sharpCorners
{
_useSmallCorners_Top = useSmallCorners_Top;
[self updateLayers];
}
- (void)setUseSmallCorners_Bottom:(BOOL)useSmallCorners_Bottom
{
_useSmallCorners_Bottom = useSmallCorners_Bottom;
_sharpCorners = sharpCorners;
[self updateLayers];
}
@ -139,14 +132,10 @@ const CGFloat kOWSMessageCellCornerRadius_Small = 2;
- (UIBezierPath *)maskPath
{
return [self.class maskPathForSize:self.bounds.size
useSmallCorners_Top:self.useSmallCorners_Top
useSmallCorners_Bottom:self.useSmallCorners_Bottom];
return [self.class maskPathForSize:self.bounds.size sharpCorners:self.sharpCorners];
}
+ (UIBezierPath *)maskPathForSize:(CGSize)size
useSmallCorners_Top:(BOOL)useSmallCorners_Top
useSmallCorners_Bottom:(BOOL)useSmallCorners_Bottom
+ (UIBezierPath *)maskPathForSize:(CGSize)size sharpCorners:(UIRectCorner)sharpCorners
{
CGRect bounds = CGRectZero;
bounds.size = size;
@ -157,41 +146,48 @@ const CGFloat kOWSMessageCellCornerRadius_Small = 2;
CGFloat bubbleRight = size.width;
CGFloat bubbleTop = 0.f;
CGFloat bubbleBottom = size.height;
CGFloat topRounding = (useSmallCorners_Top ? kOWSMessageCellCornerRadius_Small : kOWSMessageCellCornerRadius_Large);
CGFloat bottomRounding
= (useSmallCorners_Bottom ? kOWSMessageCellCornerRadius_Small : kOWSMessageCellCornerRadius_Large);
CGFloat topLeftRounding
= (sharpCorners & UIRectCornerTopLeft) ? kOWSMessageCellCornerRadius_Small : kOWSMessageCellCornerRadius_Large;
CGFloat topRightRounding
= (sharpCorners & UIRectCornerTopRight) ? kOWSMessageCellCornerRadius_Small : kOWSMessageCellCornerRadius_Large;
CGFloat bottomRightRounding = (sharpCorners & UIRectCornerBottomRight) ? kOWSMessageCellCornerRadius_Small
: kOWSMessageCellCornerRadius_Large;
CGFloat bottomLeftRounding = (sharpCorners & UIRectCornerBottomLeft) ? kOWSMessageCellCornerRadius_Small
: kOWSMessageCellCornerRadius_Large;
const CGFloat topAngle = 3.0f * M_PI_2;
const CGFloat rightAngle = 0.0f;
const CGFloat bottomAngle = M_PI_2;
const CGFloat leftAngle = M_PI;
[bezierPath moveToPoint:CGPointMake(bubbleLeft + topRounding, bubbleTop)];
// starting just to the right of the top left corner and working clockwise
[bezierPath moveToPoint:CGPointMake(bubbleLeft + topLeftRounding, bubbleTop)];
// top right corner
[bezierPath addArcWithCenter:CGPointMake(bubbleRight - topRounding, bubbleTop + topRounding)
radius:topRounding
[bezierPath addArcWithCenter:CGPointMake(bubbleRight - topRightRounding, bubbleTop + topRightRounding)
radius:topRightRounding
startAngle:topAngle
endAngle:rightAngle
clockwise:true];
// bottom right corner
[bezierPath addArcWithCenter:CGPointMake(bubbleRight - bottomRounding, bubbleBottom - bottomRounding)
radius:bottomRounding
[bezierPath addArcWithCenter:CGPointMake(bubbleRight - bottomRightRounding, bubbleBottom - bottomRightRounding)
radius:bottomRightRounding
startAngle:rightAngle
endAngle:bottomAngle
clockwise:true];
// bottom left corner
[bezierPath addArcWithCenter:CGPointMake(bubbleLeft + bottomRounding, bubbleBottom - bottomRounding)
radius:bottomRounding
[bezierPath addArcWithCenter:CGPointMake(bubbleLeft + bottomLeftRounding, bubbleBottom - bottomLeftRounding)
radius:bottomLeftRounding
startAngle:bottomAngle
endAngle:leftAngle
clockwise:true];
// top left corner
[bezierPath addArcWithCenter:CGPointMake(bubbleLeft + topRounding, bubbleTop + topRounding)
radius:topRounding
[bezierPath addArcWithCenter:CGPointMake(bubbleLeft + topLeftRounding, bubbleTop + topLeftRounding)
radius:topLeftRounding
startAngle:leftAngle
endAngle:topAngle
clockwise:true];
@ -228,11 +224,7 @@ const CGFloat kOWSMessageCellCornerRadius_Small = 2;
- (CGFloat)minWidth
{
if (self.useSmallCorners_Top && self.useSmallCorners_Bottom) {
return (kOWSMessageCellCornerRadius_Small * 2);
} else {
return (kOWSMessageCellCornerRadius_Large * 2);
}
return (kOWSMessageCellCornerRadius_Large * 2);
}
@end

View File

@ -268,7 +268,6 @@ NS_ASSUME_NONNULL_BEGIN
[self.stackView addArrangedSubview:spacerView];
}
BOOL isOutgoing = [self.viewItem.interaction isKindOfClass:TSOutgoingMessage.class];
DisplayableText *_Nullable displayableQuotedText
= (self.viewItem.hasQuotedText ? self.viewItem.displayableQuotedText : nil);
@ -276,7 +275,7 @@ NS_ASSUME_NONNULL_BEGIN
[OWSQuotedMessageView quotedMessageViewForConversation:self.viewItem.quotedReply
displayableQuotedText:displayableQuotedText
conversationStyle:self.conversationStyle
isOutgoing:isOutgoing
isOutgoing:self.isOutgoing
sharesTopBorderWithMessageBubble:!self.shouldShowSenderName];
quotedMessageView.delegate = self;
@ -561,10 +560,17 @@ NS_ASSUME_NONNULL_BEGIN
- (void)configureBubbleRounding
{
self.bubbleView.useSmallCorners_Top
= (self.hasBodyMediaWithThumbnail && !self.shouldShowSenderName && !self.isQuotedReply);
self.bubbleView.useSmallCorners_Bottom
= (self.hasBodyMediaWithThumbnail && !self.hasBodyText && !self.hasBottomFooter);
UIRectCorner sharpCorners = 0;
if (!self.viewItem.isFirstInCluster) {
sharpCorners = sharpCorners | (self.isIncoming ? UIRectCornerTopLeft : UIRectCornerTopRight);
}
if (!self.viewItem.isLastInCluster) {
sharpCorners = sharpCorners | (self.isIncoming ? UIRectCornerBottomLeft : UIRectCornerBottomRight);
}
self.bubbleView.sharpCorners = sharpCorners;
}
- (void)updateBubbleColor
@ -1199,7 +1205,6 @@ NS_ASSUME_NONNULL_BEGIN
return nil;
}
BOOL isOutgoing = [self.viewItem.interaction isKindOfClass:TSOutgoingMessage.class];
DisplayableText *_Nullable displayableQuotedText
= (self.viewItem.hasQuotedText ? self.viewItem.displayableQuotedText : nil);
@ -1207,7 +1212,7 @@ NS_ASSUME_NONNULL_BEGIN
[OWSQuotedMessageView quotedMessageViewForConversation:self.viewItem.quotedReply
displayableQuotedText:displayableQuotedText
conversationStyle:self.conversationStyle
isOutgoing:isOutgoing
isOutgoing:self.isOutgoing
sharesTopBorderWithMessageBubble:NO];
CGSize result = [quotedMessageView sizeForMaxWidth:self.conversationStyle.maxMessageWidth];
return [NSValue valueWithCGSize:CGSizeCeil(result)];

View File

@ -4865,6 +4865,8 @@ typedef enum : NSUInteger {
ConversationViewItem *_Nullable nextViewItem = (i + 1 < viewItems.count ? viewItems[i + 1] : nil);
BOOL shouldShowSenderAvatar = NO;
BOOL shouldHideFooter = NO;
BOOL isFirstInCluster = YES;
BOOL isLastInCluster = YES;
NSAttributedString *_Nullable senderName = nil;
OWSInteractionType interactionType = viewItem.interaction.interactionType;
@ -4888,6 +4890,18 @@ typedef enum : NSUInteger {
&& receiptStatus == nextReceiptStatus
&& outgoingMessage.messageState != TSOutgoingMessageStateFailed && !nextViewItem.shouldShowDate);
}
// clustering
if (previousViewItem == nil) {
isFirstInCluster = YES;
} else {
isFirstInCluster = previousViewItem.interaction.interactionType != OWSInteractionType_OutgoingMessage;
}
if (nextViewItem == nil) {
isLastInCluster = YES;
} else {
isLastInCluster = nextViewItem.interaction.interactionType != OWSInteractionType_OutgoingMessage;
}
} else if (interactionType == OWSInteractionType_IncomingMessage) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)viewItem.interaction;
@ -4909,6 +4923,22 @@ typedef enum : NSUInteger {
[NSObject isNullableObject:nextIncomingSenderId equalTo:incomingSenderId];
}
// clustering
if (previousViewItem == nil
|| previousViewItem.interaction.interactionType != OWSInteractionType_IncomingMessage) {
isFirstInCluster = YES;
} else {
TSIncomingMessage *previousIncomingMessage = (TSIncomingMessage *)previousViewItem.interaction;
isFirstInCluster = ![incomingSenderId isEqual:previousIncomingMessage.authorId];
}
if (nextViewItem == nil || nextViewItem.interaction.interactionType != OWSInteractionType_IncomingMessage) {
isLastInCluster = YES;
} else {
TSIncomingMessage *nextIncomingMessage = (TSIncomingMessage *)nextViewItem.interaction;
isLastInCluster = ![incomingSenderId isEqual:nextIncomingMessage.authorId];
}
if (viewItem.isGroupThread) {
// Show the sender name for incoming group messages unless
// the previous message has the same sender name and
@ -4944,6 +4974,8 @@ typedef enum : NSUInteger {
}
}
viewItem.isFirstInCluster = isFirstInCluster;
viewItem.isLastInCluster = isLastInCluster;
viewItem.shouldShowSenderAvatar = shouldShowSenderAvatar;
viewItem.shouldHideFooter = shouldHideFooter;
viewItem.senderName = senderName;

View File

@ -58,6 +58,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
@property (nonatomic) BOOL shouldShowSenderAvatar;
@property (nonatomic, nullable) NSAttributedString *senderName;
@property (nonatomic) BOOL shouldHideFooter;
@property (nonatomic) BOOL isFirstInCluster;
@property (nonatomic) BOOL isLastInCluster;
@property (nonatomic, readonly) ConversationStyle *conversationStyle;