mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Tweak message cells.
This commit is contained in:
parent
98ac13f9be
commit
d425809fa3
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in a new issue