diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index 83ea4db32..089838cbe 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -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 diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index 26a4a2be9..0abe0763f 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -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 *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]; } } diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.m index a89e34c70..215eae8d1 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.m @@ -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]; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationStyle.swift b/Signal/src/ViewControllers/ConversationView/ConversationStyle.swift index ea7cb6576..26aedecf3 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationStyle.swift +++ b/Signal/src/ViewControllers/ConversationView/ConversationStyle.swift @@ -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)) } } diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m index 0e1132786..6aacf932f 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m @@ -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]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 6bd4c892e..d06533ff1 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -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.