Bubble collapse.
This commit is contained in:
parent
578f40d791
commit
3ca2c08b06
|
@ -40,6 +40,17 @@ const CGFloat kBubbleTextVInset = 10.f;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setHideTail:(BOOL)hideTail
|
||||
{
|
||||
BOOL didChange = _hideTail != hideTail;
|
||||
|
||||
_hideTail = hideTail;
|
||||
|
||||
if (didChange || !self.shapeLayer) {
|
||||
[self updateLayers];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
BOOL didChange = !CGSizeEqualToSize(self.frame.size, frame.size);
|
||||
|
@ -100,24 +111,25 @@ const CGFloat kBubbleTextVInset = 10.f;
|
|||
UIBezierPath *bezierPath = [self maskPath];
|
||||
|
||||
self.shapeLayer.fillColor = self.bubbleColor.CGColor;
|
||||
// self.shapeLayer.bounds = self.bounds;
|
||||
self.shapeLayer.path = bezierPath.CGPath;
|
||||
|
||||
// self.maskLayer.bounds = self.bounds;
|
||||
self.maskLayer.path = bezierPath.CGPath;
|
||||
}
|
||||
|
||||
- (UIBezierPath *)maskPath
|
||||
{
|
||||
return [self.class maskPathForSize:self.bounds.size isOutgoing:self.isOutgoing isRTL:self.isRTL];
|
||||
return [self.class maskPathForSize:self.bounds.size
|
||||
isOutgoing:self.isOutgoing
|
||||
hideTail:self.hideTail
|
||||
isRTL:self.isRTL];
|
||||
}
|
||||
|
||||
+ (UIBezierPath *)maskPathForSize:(CGSize)size isOutgoing:(BOOL)isOutgoing isRTL:(BOOL)isRTL
|
||||
+ (UIBezierPath *)maskPathForSize:(CGSize)size isOutgoing:(BOOL)isOutgoing hideTail:(BOOL)hideTail isRTL:(BOOL)isRTL
|
||||
{
|
||||
UIBezierPath *bezierPath = [UIBezierPath new];
|
||||
|
||||
CGFloat bubbleLeft = 0.f;
|
||||
CGFloat bubbleRight = size.width - kBubbleThornSideInset;
|
||||
CGFloat bubbleRight = size.width - (hideTail ? 0.f : kBubbleThornSideInset);
|
||||
CGFloat bubbleTop = 0.f;
|
||||
CGFloat bubbleBottom = size.height - kBubbleThornVInset;
|
||||
|
||||
|
@ -135,15 +147,17 @@ const CGFloat kBubbleTextVInset = 10.f;
|
|||
[bezierPath addQuadCurveToPoint:CGPointMake(bubbleLeft + kBubbleHRounding, bubbleTop)
|
||||
controlPoint:CGPointMake(bubbleLeft, bubbleTop)];
|
||||
|
||||
// Thorn Tip
|
||||
CGPoint thornTip = CGPointMake(size.width + 1, size.height);
|
||||
CGPoint thornA = CGPointMake(bubbleRight - kBubbleHRounding * 0.5f, bubbleBottom - kBubbleVRounding);
|
||||
CGPoint thornB = CGPointMake(bubbleRight, bubbleBottom - kBubbleVRounding);
|
||||
[bezierPath moveToPoint:thornTip];
|
||||
[bezierPath addQuadCurveToPoint:thornA controlPoint:CGPointMake(thornA.x, bubbleBottom)];
|
||||
[bezierPath addLineToPoint:thornB];
|
||||
[bezierPath addQuadCurveToPoint:thornTip controlPoint:CGPointMake(thornB.x, bubbleBottom)];
|
||||
[bezierPath addLineToPoint:thornTip];
|
||||
if (!hideTail) {
|
||||
// Thorn Tip
|
||||
CGPoint thornTip = CGPointMake(size.width + 1, size.height);
|
||||
CGPoint thornA = CGPointMake(bubbleRight - kBubbleHRounding * 0.5f, bubbleBottom - kBubbleVRounding);
|
||||
CGPoint thornB = CGPointMake(bubbleRight, bubbleBottom - kBubbleVRounding);
|
||||
[bezierPath moveToPoint:thornTip];
|
||||
[bezierPath addQuadCurveToPoint:thornA controlPoint:CGPointMake(thornA.x, bubbleBottom)];
|
||||
[bezierPath addLineToPoint:thornB];
|
||||
[bezierPath addQuadCurveToPoint:thornTip controlPoint:CGPointMake(thornB.x, bubbleBottom)];
|
||||
[bezierPath addLineToPoint:thornTip];
|
||||
}
|
||||
|
||||
// Horizontal Flip If Necessary
|
||||
BOOL shouldFlip = isOutgoing == isRTL;
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// TODO: Review all comments.
|
||||
|
||||
CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
{
|
||||
return CGSizeMake((CGFloat)ceil(size.width), (CGFloat)ceil(size.height));
|
||||
|
@ -308,7 +306,7 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
|||
// TODO: We might not need to hide it.
|
||||
self.bubbleView.hidden = NO;
|
||||
self.bubbleView.isOutgoing = self.isOutgoing;
|
||||
// TODO: Hide tails/thorns here?
|
||||
self.bubbleView.hideTail = self.viewItem.shouldHideBubbleTail;
|
||||
|
||||
if (self.shouldHaveFailedSendBadge) {
|
||||
self.failedSendBadgeView = [UIImageView new];
|
||||
|
@ -344,15 +342,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
|||
[self updateDateHeader];
|
||||
[self updateFooter];
|
||||
|
||||
// TODO: Do we need to pin the bubble size?
|
||||
{
|
||||
// - (CGSize)cellSizeForViewWidth:(int)viewWidth contentWidth:(int)contentWidth
|
||||
// CGSize mediaSize = [self bodyMediaSizeForContentWidth:self.contentWidth];
|
||||
// TODO:
|
||||
// [self.viewConstraints addObjectsFromArray:[self.mediaMaskingView
|
||||
// autoSetDimensionsToSize:mediaSize]];
|
||||
}
|
||||
|
||||
UIView *_Nullable lastSubview = nil;
|
||||
CGFloat bottomMargin = 0;
|
||||
UIView *_Nullable bodyMediaView = nil;
|
||||
|
@ -549,8 +538,7 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
|||
} else {
|
||||
DDLogError(@"%@ Failed to load cell media: %@", [self logTag], [self.attachmentStream mediaURL]);
|
||||
self.viewItem.didCellMediaFailToLoad = YES;
|
||||
[mediaView removeFromSuperview];
|
||||
// TODO: We need to hide/remove the media view.
|
||||
// TODO: Do we need to hide/remove the media view?
|
||||
[self showAttachmentErrorView:mediaView];
|
||||
}
|
||||
return cellMedia;
|
||||
|
@ -560,10 +548,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
|||
// * If cell is not visible, eagerly unload view contents.
|
||||
- (void)ensureMediaLoadState
|
||||
{
|
||||
// CGSize mediaSize = [self bodyMediaSizeForContentWidth:self.contentWidth];
|
||||
// TODO:
|
||||
// [self.viewConstraints addObjectsFromArray:[self.mediaMaskingView autoSetDimensionsToSize:mediaSize]];
|
||||
|
||||
if (!self.isCellVisible) {
|
||||
// Eagerly unload.
|
||||
if (self.unloadCellContentBlock) {
|
||||
|
@ -1092,8 +1076,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
|||
OWSAssert(self.mediaSize.height > 0);
|
||||
|
||||
// TODO: Adjust this behavior.
|
||||
// TODO: This behavior is a bit different than the old behavior defined
|
||||
// in JSQMediaItem+OWS.h. Let's discuss.
|
||||
|
||||
CGFloat contentAspectRatio = self.mediaSize.width / self.mediaSize.height;
|
||||
// Clamp the aspect ratio so that very thin/wide content is presented
|
||||
|
@ -1187,12 +1169,20 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
|||
|
||||
- (CGFloat)textLeadingMargin
|
||||
{
|
||||
return (self.isIncoming ? kBubbleTextHInset + kBubbleThornSideInset : kBubbleTextHInset);
|
||||
CGFloat result = kBubbleTextHInset;
|
||||
if (self.isIncoming && !self.viewItem.shouldHideBubbleTail) {
|
||||
result += kBubbleThornSideInset;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CGFloat)textTrailingMargin
|
||||
{
|
||||
return (self.isIncoming ? kBubbleTextHInset : kBubbleTextHInset + kBubbleThornSideInset);
|
||||
CGFloat result = kBubbleTextHInset;
|
||||
if (!self.isIncoming && !self.viewItem.shouldHideBubbleTail) {
|
||||
result += kBubbleThornSideInset;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CGFloat)textTopMargin
|
||||
|
|
|
@ -4463,8 +4463,10 @@ typedef enum : NSUInteger {
|
|||
// Update the "shouldShowDate" property of the view items.
|
||||
OWSInteractionType lastInteractionType = OWSInteractionType_Unknown;
|
||||
MessageRecipientStatus lastRecipientStatus = MessageRecipientStatusUploading;
|
||||
NSString *_Nullable lastIncomingSenderId = nil;
|
||||
for (ConversationViewItem *viewItem in viewItems.reverseObjectEnumerator) {
|
||||
BOOL shouldHideRecipientStatus = NO;
|
||||
BOOL shouldHideBubbleTail = NO;
|
||||
OWSInteractionType interactionType = viewItem.interaction.interactionType;
|
||||
|
||||
if (interactionType == OWSInteractionType_OutgoingMessage) {
|
||||
|
@ -4473,14 +4475,23 @@ typedef enum : NSUInteger {
|
|||
[MessageRecipientStatusUtils recipientStatusWithOutgoingMessage:outgoingMessage];
|
||||
|
||||
if (outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
|
||||
// always sow "failed to send" status
|
||||
// always show "failed to send" status
|
||||
shouldHideRecipientStatus = NO;
|
||||
} else {
|
||||
shouldHideRecipientStatus
|
||||
= (interactionType == lastInteractionType && recipientStatus == lastRecipientStatus);
|
||||
}
|
||||
|
||||
shouldHideBubbleTail = (interactionType == lastInteractionType && recipientStatus == lastRecipientStatus);
|
||||
|
||||
lastRecipientStatus = recipientStatus;
|
||||
} else if (interactionType == OWSInteractionType_IncomingMessage) {
|
||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)viewItem.interaction;
|
||||
NSString *incomingSenderId = incomingMessage.authorId;
|
||||
OWSAssert(incomingSenderId.length > 0);
|
||||
shouldHideBubbleTail = (interactionType == lastInteractionType &&
|
||||
[NSObject isNullableObject:lastIncomingSenderId equalTo:incomingSenderId]);
|
||||
lastIncomingSenderId = incomingSenderId;
|
||||
}
|
||||
lastInteractionType = interactionType;
|
||||
|
||||
|
@ -4491,6 +4502,7 @@ typedef enum : NSUInteger {
|
|||
[rowsThatChangedSize addObject:@(viewItem.previousRow)];
|
||||
}
|
||||
viewItem.shouldHideRecipientStatus = shouldHideRecipientStatus;
|
||||
viewItem.shouldHideBubbleTail = shouldHideBubbleTail;
|
||||
}
|
||||
|
||||
self.viewItems = viewItems;
|
||||
|
|
|
@ -46,6 +46,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
@property (nonatomic, readonly) BOOL hasBodyText;
|
||||
@property (nonatomic) BOOL shouldShowDate;
|
||||
@property (nonatomic) BOOL shouldHideRecipientStatus;
|
||||
@property (nonatomic) BOOL shouldHideBubbleTail;
|
||||
|
||||
@property (nonatomic) NSInteger row;
|
||||
// During updates, we sometimes need the previous row index
|
||||
|
|
|
@ -134,6 +134,17 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
[self clearCachedLayoutState];
|
||||
}
|
||||
|
||||
- (void)setShouldHideBubbleTail:(BOOL)shouldHideBubbleTail
|
||||
{
|
||||
if (_shouldHideBubbleTail == shouldHideBubbleTail) {
|
||||
return;
|
||||
}
|
||||
|
||||
_shouldHideBubbleTail = shouldHideBubbleTail;
|
||||
|
||||
[self clearCachedLayoutState];
|
||||
}
|
||||
|
||||
- (void)clearCachedLayoutState
|
||||
{
|
||||
self.cachedCellSize = nil;
|
||||
|
|
Loading…
Reference in New Issue