Introduce message cell footer view.

pull/1/head
Matthew Chen 7 years ago
parent a769499f56
commit f363a196f3

@ -23,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) OWSBubbleView *bubbleView;
@property (nonatomic) UIStackView *stackView;
@property (nonatomic) OWSMessageTextView *bodyTextView;
@property (nonatomic, nullable) UIView *quotedMessageView;
@ -71,6 +73,12 @@ NS_ASSUME_NONNULL_BEGIN
[self addSubview:self.bubbleView];
[self.bubbleView autoPinEdgesToSuperviewEdges];
self.stackView = [UIStackView new];
self.stackView.axis = UILayoutConstraintAxisVertical;
self.stackView.alignment = UIStackViewAlignmentFill;
[self addSubview:self.stackView];
[self.stackView autoPinEdgesToSuperviewEdges];
self.bodyTextView = [self newTextView];
// Setting dataDetectorTypes is expensive. Do it just once.
self.bodyTextView.dataDetectorTypes
@ -248,6 +256,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
CGSize quotedMessageContentSize = [self quotedMessageSize];
// TODO:
CGSize bodyMediaContentSize = [self bodyMediaSize];
CGSize bodyTextContentSize = [self bodyTextSizeWithIncludeMargins:NO];
@ -260,12 +269,9 @@ NS_ASSUME_NONNULL_BEGIN
self.bubbleView.bubbleColor = nil;
}
UIView *_Nullable lastSubview = nil;
CGFloat bottomMargin = 0;
// CGFloat bottomMargin = 0;
if (self.isQuotedReply) {
OWSAssert(!lastSubview);
BOOL isOutgoing = [self.viewItem.interaction isKindOfClass:TSOutgoingMessage.class];
DisplayableText *_Nullable displayableQuotedText
= (self.viewItem.hasQuotedText ? self.viewItem.displayableQuotedText : nil);
@ -278,23 +284,11 @@ NS_ASSUME_NONNULL_BEGIN
self.quotedMessageView = quotedMessageView;
[quotedMessageView createContents];
[self.bubbleView addSubview:quotedMessageView];
[self.viewConstraints addObjectsFromArray:@[
[quotedMessageView autoPinLeadingToSuperviewMargin],
[quotedMessageView autoPinTrailingToSuperviewMargin],
]];
[self.stackView addArrangedSubview:quotedMessageView];
[self.viewConstraints
addObject:[quotedMessageView autoSetDimension:ALDimensionHeight toSize:quotedMessageContentSize.height]];
if (lastSubview) {
[self.viewConstraints
addObject:[quotedMessageView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastSubview]];
} else {
[self.viewConstraints addObject:[quotedMessageView autoPinEdgeToSuperviewEdge:ALEdgeTop]];
}
lastSubview = quotedMessageView;
bottomMargin = 0;
// bottomMargin = 0;
[self.bubbleView addPartnerView:quotedMessageView.boundsStrokeView];
}
@ -349,34 +343,28 @@ NS_ASSUME_NONNULL_BEGIN
bodyMediaView.layer.opacity = 0.75f;
}
[self.bubbleView addSubview:bodyMediaView];
// This layout can lead to extreme cropping of media content,
// e.g. a very tall portrait image + long caption. The media
// view will have "max width", so the image will be cropped to
// roughly a square.
// TODO: Myles is considering alternatives.
[self.viewConstraints addObjectsFromArray:@[
[bodyMediaView autoPinLeadingToSuperviewMarginWithInset:0],
[bodyMediaView autoPinTrailingToSuperviewMarginWithInset:0],
]];
// We need constraints to control the vertical sizing of the media view, but we use
// lower priority so that when a message only contains media it uses the exact bounds of
// the message view.
[NSLayoutConstraint
autoSetPriority:UILayoutPriorityDefaultLow
forConstraints:^{
[self.viewConstraints
addObject:[bodyMediaView autoSetDimension:ALDimensionHeight toSize:bodyMediaContentSize.height]];
}];
if (lastSubview) {
[self.viewConstraints
addObject:[bodyMediaView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastSubview withOffset:0]];
} else {
[self.viewConstraints addObject:[bodyMediaView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:0]];
}
lastSubview = bodyMediaView;
bottomMargin = 0;
[self.stackView addArrangedSubview:bodyMediaView];
// // This layout can lead to extreme cropping of media content,
// // e.g. a very tall portrait image + long caption. The media
// // view will have "max width", so the image will be cropped to
// // roughly a square.
// // TODO: Myles is considering alternatives.
// [self.viewConstraints addObjectsFromArray:@[
// [bodyMediaView autoPinLeadingToSuperviewMarginWithInset:0],
// [bodyMediaView autoPinTrailingToSuperviewMarginWithInset:0],
// ]];
// // We need constraints to control the vertical sizing of the media view, but we use
// // lower priority so that when a message only contains media it uses the exact bounds of
// // the message view.
// [NSLayoutConstraint
// autoSetPriority:UILayoutPriorityDefaultLow
// forConstraints:^{
// [self.viewConstraints
// addObject:[bodyMediaView autoSetDimension:ALDimensionHeight
// toSize:bodyMediaContentSize.height]];
// }];
// bottomMargin = 0;
BOOL shouldStrokeMediaView = ([bodyMediaView isKindOfClass:[UIImageView class]] ||
[bodyMediaView isKindOfClass:[OWSContactShareView class]]);
@ -395,70 +383,73 @@ NS_ASSUME_NONNULL_BEGIN
}
}
OWSDirectionalEdgeInsets *textInsets = self.conversationStyle.textInsets;
OWSAssert(textInsets);
OWSMessageTextView *_Nullable bodyTextView = nil;
UIStackView *_Nullable textStackView = [UIStackView new];
// We render malformed messages as "empty text" messages,
// so create a text view if there is no body media view.
if (self.hasBodyText || !bodyMediaView) {
bodyTextView = [self configureBodyTextView];
}
if (bodyTextView) {
[self.bubbleView addSubview:bodyTextView];
textStackView = [UIStackView new];
textStackView.axis = UILayoutConstraintAxisVertical;
textStackView.alignment = UIStackViewAlignmentFill;
// TODO: Review
textStackView.spacing = self.textViewVSpacing;
textStackView.layoutMarginsRelativeArrangement = YES;
textStackView.layoutMargins = UIEdgeInsetsMake(self.conversationStyle.textInsetTop,
self.conversationStyle.textInsetHorizontal,
self.conversationStyle.textInsetBottom,
self.conversationStyle.textInsetHorizontal);
[self.stackView addArrangedSubview:textStackView];
[textStackView addArrangedSubview:bodyTextView];
[self.viewConstraints addObjectsFromArray:@[
[bodyTextView autoPinLeadingToSuperviewMarginWithInset:textInsets.leading],
[bodyTextView autoPinTrailingToSuperviewMarginWithInset:textInsets.trailing],
[bodyTextView autoSetDimension:ALDimensionWidth toSize:bodyTextContentSize.width],
// [bodyTextView autoSetDimension:ALDimensionWidth toSize:bodyTextContentSize.width
// relation:NSLayoutRelationLessThanOrEqual],
[bodyTextView autoSetDimension:ALDimensionHeight toSize:bodyTextContentSize.height],
]];
if (lastSubview) {
[self.viewConstraints addObject:[bodyTextView autoPinEdge:ALEdgeTop
toEdge:ALEdgeBottom
ofView:lastSubview
withOffset:textInsets.top]];
} else {
[self.viewConstraints
addObject:[bodyTextView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:textInsets.top]];
UIView *_Nullable tapForMoreLabel = [self createTapForMoreLabelIfNecessary];
if (tapForMoreLabel) {
[textStackView addArrangedSubview:tapForMoreLabel];
[self.viewConstraints addObjectsFromArray:@[
// [tapForMoreLabel autoPinEdge:ALEdgeTop
// toEdge:ALEdgeBottom ofView:lastSubview],
[tapForMoreLabel autoSetDimension:ALDimensionHeight toSize:self.tapForMoreHeight],
]];
}
lastSubview = bodyTextView;
bottomMargin = textInsets.bottom;
}
UIView *_Nullable tapForMoreLabel = [self createTapForMoreLabelIfNecessary];
if (tapForMoreLabel) {
OWSAssert(lastSubview);
OWSAssert(lastSubview == bodyTextView);
[self.bubbleView addSubview:tapForMoreLabel];
OWSMessageFooterView *footerView = self.footerView;
[footerView configureWithConversationViewItem:self.viewItem];
if (textStackView) {
[textStackView addArrangedSubview:self.footerView];
} else if (bodyMediaView) {
[bodyMediaView addSubview:footerView];
bodyMediaView.layoutMargins = UIEdgeInsetsZero;
[self.viewConstraints addObjectsFromArray:@[
[tapForMoreLabel autoPinLeadingToSuperviewMarginWithInset:textInsets.leading],
[tapForMoreLabel autoPinTrailingToSuperviewMarginWithInset:textInsets.trailing],
[tapForMoreLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastSubview],
[tapForMoreLabel autoSetDimension:ALDimensionHeight toSize:self.tapForMoreHeight],
[footerView autoPinLeadingToSuperviewMarginWithInset:self.conversationStyle.textInsetHorizontal],
[footerView autoPinTrailingToSuperviewMarginWithInset:self.conversationStyle.textInsetHorizontal],
[footerView autoPinBottomToSuperviewMarginWithInset:self.conversationStyle.textInsetBottom],
]];
lastSubview = tapForMoreLabel;
bottomMargin = textInsets.bottom;
// TODO: Drop shadow.
} else {
// Display footer over media.
OWSFail(@"%@ could not display footer.", self.logTag);
}
OWSMessageFooterView *footerView = self.footerView;
[footerView configureWithConversationViewItem:self.viewItem];
if (self.footerView) {
[self.bubbleView addSubview:self.footerView];
// TODO: Should we do this for media content too?
if (textStackView) {
CGSize bubbleSize = [self measureSize];
[self.viewConstraints addObjectsFromArray:@[
[tapForMoreLabel autoPinLeadingToSuperviewMarginWithInset:textInsets.leading],
[tapForMoreLabel autoPinTrailingToSuperviewMarginWithInset:textInsets.trailing],
[tapForMoreLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastSubview],
[tapForMoreLabel autoSetDimension:ALDimensionHeight toSize:self.tapForMoreHeight],
[self autoSetDimension:ALDimensionWidth toSize:bubbleSize.width relation:NSLayoutRelationLessThanOrEqual],
// [bodyTextView autoSetDimension:ALDimensionHeight
// toSize:bodyTextContentSize.height],
]];
lastSubview = tapForMoreLabel;
bottomMargin = textInsets.bottom;
}
OWSAssert(lastSubview);
[self.viewConstraints addObjectsFromArray:@[
[lastSubview autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:bottomMargin],
]];
}
// We now eagerly create our view hierarchy (to do this exactly once per cell usage)
@ -498,6 +489,11 @@ NS_ASSUME_NONNULL_BEGIN
return cellMedia;
}
- (CGFloat)textViewVSpacing
{
return 5.f;
}
#pragma mark - Load / Unload
- (void)loadContent
@ -881,10 +877,7 @@ NS_ASSUME_NONNULL_BEGIN
return CGSizeZero;
}
OWSDirectionalEdgeInsets *textInsets = self.conversationStyle.textInsets;
OWSAssert(textInsets);
CGFloat hMargins = textInsets.leading + textInsets.trailing;
CGFloat hMargins = self.conversationStyle.textInsetHorizontal * 2;
const int maxTextWidth = (int)floor(self.conversationStyle.maxMessageWidth - hMargins);
@ -895,7 +888,7 @@ NS_ASSUME_NONNULL_BEGIN
if (includeMargins) {
result.width += hMargins;
result.height += textInsets.top + textInsets.bottom;
result.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom);
}
return CGSizeCeil(result);
@ -1023,13 +1016,15 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(cellSize.width > 0 && cellSize.height > 0);
if (self.hasTapForMore) {
cellSize.height += self.tapForMoreHeight;
cellSize.height += self.tapForMoreHeight + self.textViewVSpacing;
}
if (self.hasFooter) {
// TODO: Update this to reflect generic attachment, downloading attachments and
// contact shares.
if (self.hasFooter && self.hasBodyText) {
CGSize footerSize = [self.footerView measureWithConversationViewItem:self.viewItem];
cellSize.width = MAX(cellSize.width, footerSize.width);
cellSize.height += self.footerVSpacing + footerSize.height;
cellSize.height += self.textViewVSpacing + footerSize.height;
}
cellSize = CGSizeCeil(cellSize);
@ -1053,11 +1048,6 @@ NS_ASSUME_NONNULL_BEGIN
return (CGFloat)ceil([self tapForMoreFont].lineHeight * 1.25);
}
- (CGFloat)footerVSpacing
{
return 10.f;
}
#pragma mark -
- (UIColor *)bodyTextColor

@ -24,7 +24,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) OWSMessageBubbleView *messageBubbleView;
@property (nonatomic) UILabel *dateHeaderLabel;
@property (nonatomic) AvatarImageView *avatarView;
@property (nonatomic) OWSMessageFooterView *footerView2;
@property (nonatomic, nullable) NSMutableArray<NSLayoutConstraint *> *viewConstraints;
@property (nonatomic) BOOL isPresentingMenuController;
@ -56,20 +55,12 @@ NS_ASSUME_NONNULL_BEGIN
self.messageBubbleView = [OWSMessageBubbleView new];
[self.contentView addSubview:self.messageBubbleView];
self.footerView = [UIView containerView];
[self.contentView addSubview:self.footerView];
self.dateHeaderLabel = [UILabel new];
self.dateHeaderLabel.font = self.dateHeaderDateFont;
self.dateHeaderLabel.textAlignment = NSTextAlignmentCenter;
self.dateHeaderLabel.textColor = [UIColor lightGrayColor];
[self.contentView addSubview:self.dateHeaderLabel];
self.footerLabel = [UILabel new];
self.footerLabel.font = UIFont.ows_dynamicTypeCaption2Font;
self.footerLabel.textColor = [UIColor lightGrayColor];
[self.footerView addSubview:self.footerLabel];
self.avatarView = [[AvatarImageView alloc] init];
[self.contentView addSubview:self.avatarView];
[self.avatarView autoSetDimension:ALDimensionWidth toSize:self.avatarSize];
@ -77,12 +68,10 @@ NS_ASSUME_NONNULL_BEGIN
// Hide these views by default.
self.dateHeaderLabel.hidden = YES;
self.footerLabel.hidden = YES;
self.avatarView.hidden = YES;
[self.messageBubbleView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.dateHeaderLabel];
[self.footerView autoPinEdgeToSuperviewEdge:ALEdgeBottom];
[self.messageBubbleView autoPinBottomToSuperviewMarginWithInset:0];
self.contentView.userInteractionEnabled = YES;
@ -158,7 +147,6 @@ NS_ASSUME_NONNULL_BEGIN
// Update label fonts to honor dynamic type size.
self.dateHeaderLabel.font = self.dateHeaderDateFont;
self.footerLabel.font = UIFont.ows_dynamicTypeCaption2Font;
if (self.isIncoming) {
[self.viewConstraints addObjectsFromArray:@[
@ -179,7 +167,6 @@ NS_ASSUME_NONNULL_BEGIN
}
[self updateDateHeader];
[self updateFooter];
if ([self updateAvatarView]) {
CGFloat avatarBottomMargin = round(self.conversationStyle.lastTextLineAxis - self.avatarSize * 0.5f);
@ -275,132 +262,6 @@ NS_ASSUME_NONNULL_BEGIN
}
}
- (BOOL)shouldShowFooter
{
BOOL shouldShowFooter = NO;
if (self.message.shouldStartExpireTimer) {
shouldShowFooter = YES;
} else if (self.isOutgoing) {
shouldShowFooter = !self.viewItem.shouldHideRecipientStatus;
} else if (self.viewItem.isGroupThread) {
shouldShowFooter = YES;
} else {
shouldShowFooter = NO;
}
return shouldShowFooter;
}
- (CGFloat)footerHeight
{
if (!self.shouldShowFooter) {
return 0.f;
}
return ceil(MAX(kExpirationTimerViewSize, self.footerLabel.font.lineHeight));
}
- (CGFloat)footerVSpacing
{
return 0.f;
}
- (void)updateFooter
{
OWSAssert(self.conversationStyle);
OWSAssert(self.viewItem.interaction.interactionType == OWSInteractionType_IncomingMessage
|| self.viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage);
TSMessage *message = self.message;
BOOL hasExpirationTimer = message.shouldStartExpireTimer;
NSAttributedString *attributedText = nil;
if (self.isOutgoing) {
if (!self.viewItem.shouldHideRecipientStatus || hasExpirationTimer) {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)message;
NSString *statusMessage =
[MessageRecipientStatusUtils receiptMessageWithOutgoingMessage:outgoingMessage referenceView:self];
attributedText = [[NSAttributedString alloc] initWithString:statusMessage attributes:@{}];
}
} else if (self.viewItem.isGroupThread) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.viewItem.interaction;
attributedText = [self.delegate attributedContactOrProfileNameForPhoneIdentifier:incomingMessage.authorId];
}
if (!hasExpirationTimer &&
!attributedText) {
self.footerLabel.hidden = YES;
[self.viewConstraints addObjectsFromArray:@[
[self.footerView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.messageBubbleView],
[self.footerView autoSetDimension:ALDimensionHeight toSize:0],
]];
return;
}
[self.viewConstraints addObjectsFromArray:@[
(self.isIncoming
? [self.footerView autoPinLeadingToSuperviewMarginWithInset:self.conversationStyle.gutterLeading]
: [self.footerView autoPinTrailingToSuperviewMarginWithInset:self.conversationStyle.gutterTrailing]),
]];
[self.viewConstraints addObject:[self.footerView autoPinEdge:ALEdgeTop
toEdge:ALEdgeBottom
ofView:self.messageBubbleView
withOffset:self.footerVSpacing]];
if (hasExpirationTimer) {
uint64_t expirationTimestamp = message.expiresAt;
uint32_t expiresInSeconds = message.expiresInSeconds;
self.expirationTimerView = [[OWSExpirationTimerView alloc] initWithExpiration:expirationTimestamp
initialDurationSeconds:expiresInSeconds];
[self.footerView addSubview:self.expirationTimerView];
}
if (attributedText) {
self.footerLabel.attributedText = attributedText;
self.footerLabel.hidden = NO;
}
// Footer labels can extend past the message bubble, but
// we want to leave spaces for an expiration timer and
// include padding so that they still visually "cling" to the
// appropriate incoming/outgoing edge.
const CGFloat maxFooterLabelWidth = self.conversationStyle.maxFooterWidth;
if (hasExpirationTimer &&
attributedText) {
[self.viewConstraints addObjectsFromArray:@[
[self.expirationTimerView autoVCenterInSuperview],
[self.footerLabel autoVCenterInSuperview],
(self.isIncoming ? [self.expirationTimerView autoPinLeadingToSuperviewMargin]
: [self.expirationTimerView autoPinTrailingToSuperviewMargin]),
(self.isIncoming ? [self.footerLabel autoPinLeadingToTrailingEdgeOfView:self.expirationTimerView]
: [self.footerLabel autoPinTrailingToLeadingEdgeOfView:self.expirationTimerView]),
[self.footerLabel autoSetDimension:ALDimensionWidth
toSize:maxFooterLabelWidth
relation:NSLayoutRelationLessThanOrEqual],
[self.footerView autoSetDimension:ALDimensionHeight toSize:self.footerHeight],
]];
} else if (hasExpirationTimer) {
[self.viewConstraints addObjectsFromArray:@[
[self.expirationTimerView autoVCenterInSuperview],
(self.isIncoming ? [self.expirationTimerView autoPinLeadingToSuperviewMargin]
: [self.expirationTimerView autoPinTrailingToSuperviewMargin]),
[self.footerView autoSetDimension:ALDimensionHeight toSize:self.footerHeight],
]];
} else if (attributedText) {
[self.viewConstraints addObjectsFromArray:@[
[self.footerLabel autoVCenterInSuperview],
(self.isIncoming ? [self.footerLabel autoPinLeadingToSuperviewMargin]
: [self.footerLabel autoPinTrailingToSuperviewMargin]),
[self.footerView autoSetDimension:ALDimensionHeight toSize:self.footerHeight],
[self.footerLabel autoSetDimension:ALDimensionWidth
toSize:maxFooterLabelWidth
relation:NSLayoutRelationLessThanOrEqual],
]];
} else {
OWSFail(@"%@ Cell unexpectedly has neither expiration timer nor footer text.", self.logTag);
}
}
- (UIFont *)dateHeaderDateFont
{
return UIFont.ows_dynamicTypeCaption1Font.ows_mediumWeight;
@ -498,10 +359,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(cellSize.width > 0 && cellSize.height > 0);
cellSize.height += self.dateHeaderHeight;
if (self.shouldShowFooter) {
cellSize.height += self.footerVSpacing;
cellSize.height += self.footerHeight;
}
cellSize = CGSizeCeil(cellSize);
@ -532,15 +389,9 @@ NS_ASSUME_NONNULL_BEGIN
self.dateHeaderLabel.text = nil;
self.dateHeaderLabel.hidden = YES;
self.footerLabel.text = nil;
self.footerLabel.hidden = YES;
self.avatarView.image = nil;
self.avatarView.hidden = YES;
[self.expirationTimerView clearAnimations];
[self.expirationTimerView removeFromSuperview];
self.expirationTimerView = nil;
[self hideMenuControllerIfNecessary];
[[NSNotificationCenter defaultCenter] removeObserver:self];
@ -559,15 +410,7 @@ NS_ASSUME_NONNULL_BEGIN
[self ensureMediaLoadState];
if (isCellVisible) {
if (self.message.shouldStartExpireTimer) {
[self.expirationTimerView ensureAnimations];
} else {
[self.expirationTimerView clearAnimations];
}
} else {
[self.expirationTimerView clearAnimations];
if (!isCellVisible) {
[self hideMenuControllerIfNecessary];
}
}

@ -4,7 +4,6 @@
#import "OWSMessageFooterView.h"
#import "DateUtil.h"
#import "OWSExpirationTimerView.h"
#import "Signal-Swift.h"
NS_ASSUME_NONNULL_BEGIN
@ -39,6 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
self.timestampLabel = [UILabel new];
// TODO: Color
self.timestampLabel.textColor = [UIColor lightGrayColor];
[self addSubview:self.timestampLabel];
self.statusLabel = [UILabel new];
// TODO: Color
@ -56,6 +56,7 @@ NS_ASSUME_NONNULL_BEGIN
]];
statusStackView.axis = UILayoutConstraintAxisHorizontal;
statusStackView.spacing = self.hSpacing;
[self addSubview:statusStackView];
[self.timestampLabel autoPinEdgeToSuperviewEdge:ALEdgeLeading];
[statusStackView autoPinEdgeToSuperviewEdge:ALEdgeTrailing];

@ -4,34 +4,6 @@
import Foundation
@objc
public class OWSDirectionalEdgeInsets: NSObject {
@objc public let leading: CGFloat
@objc public let trailing: CGFloat
@objc public let top: CGFloat
@objc public let bottom: CGFloat
@objc
public required init(top: CGFloat = 0,
leading: CGFloat = 0,
bottom: CGFloat = 0,
trailing: CGFloat = 0) {
self.leading = leading
self.trailing = trailing
self.top = top
self.bottom = bottom
super.init()
}
static var zero = OWSDirectionalEdgeInsets(top: 0,
leading: 0,
bottom: 0,
trailing: 0)
}
@objc
public class ConversationStyle: NSObject {
@ -70,7 +42,9 @@ public class ConversationStyle: NSObject {
// message status inside the message bubbles.
@objc public var maxFooterWidth: CGFloat = 0
@objc public var textInsets = OWSDirectionalEdgeInsets.zero
@objc public var textInsetTop: CGFloat = 0
@objc public var textInsetBottom: CGFloat = 0
@objc public var textInsetHorizontal: CGFloat = 0
// We want to align "group sender" avatars with the v-center of the
// "last line" of the message body text - or where it would be for
@ -130,16 +104,13 @@ public class ConversationStyle: NSObject {
let messageTextFont = UIFont.ows_dynamicTypeBody
// Don't include the distance from the "cap height" to the top of the UILabel
// in the top margin.
let textInsetTop = max(0, 12 - (messageTextFont.ascender - messageTextFont.capHeight))
textInsetTop = max(0, 12 - (messageTextFont.ascender - messageTextFont.capHeight))
// Don't include the distance from the "baseline" to the bottom of the UILabel
// (e.g. the descender) in the top margin. Note that UIFont.descender is a
// negative value.
let textInsetBottom = max(0, 12 - abs(messageTextFont.descender))
textInsetBottom = max(0, 12 - abs(messageTextFont.descender))
textInsetHorizontal = 12
textInsets = OWSDirectionalEdgeInsets(top: textInsetTop,
leading: 12,
bottom: textInsetBottom,
trailing: 12)
lastTextLineAxis = CGFloat(round(12 + messageTextFont.capHeight * 0.5))
}
}

@ -74,6 +74,8 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
for (OWSSignalServiceProtosAttachmentPointer *attachmentProto in attachmentProtos) {
TSAttachmentPointer *pointer = [TSAttachmentPointer attachmentPointerFromProto:attachmentProto relay:relay];
DDLogVerbose(@"%@ ---- creating attachment: %@", self.logTag, pointer.uniqueId);
[DDLog flushLog];
[attachmentIds addObject:pointer.uniqueId];
[pointer saveWithTransaction:transaction];
[attachmentPointers addObject:pointer];

@ -561,6 +561,9 @@ NS_ASSUME_NONNULL_BEGIN
return;
}
DDLogVerbose(@"%@ ---- creating message: %@", self.logTag, attachmentsProcessor.attachmentIds);
[DDLog flushLog];
TSIncomingMessage *_Nullable createdMessage = [self handleReceivedEnvelope:envelope
withDataMessage:dataMessage
attachmentIds:attachmentsProcessor.attachmentIds
@ -1107,6 +1110,9 @@ NS_ASSUME_NONNULL_BEGIN
return;
}
DDLogVerbose(@"%@ ---- creating message 2: %@", self.logTag, incomingMessage.attachmentIds);
[DDLog flushLog];
[incomingMessage saveWithTransaction:transaction];
// Any messages sent from the current user - from this device or another - should be automatically marked as read.

Loading…
Cancel
Save