Refine appearance of quoted reply message cells.
This commit is contained in:
parent
3343b4ec58
commit
10b4ade55a
@ -42,6 +42,7 @@
|
||||
340FC8CD20518C77007AEB0F /* OWSBackupJob.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8CC20518C76007AEB0F /* OWSBackupJob.m */; };
|
||||
340FC8D0205BF2FA007AEB0F /* OWSBackupIO.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8CE205BF2FA007AEB0F /* OWSBackupIO.m */; };
|
||||
341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */ = {isa = PBXBuildFile; fileRef = 341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */; };
|
||||
34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */; };
|
||||
3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430FE171F7751D4000EC51B /* GiphyAPI.swift */; };
|
||||
34330A5A1E7875FB00DF2FB9 /* fontawesome-webfont.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34330A591E7875FB00DF2FB9 /* fontawesome-webfont.ttf */; };
|
||||
34330A5C1E787A9800DF2FB9 /* dripicons-v2.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34330A5B1E787A9800DF2FB9 /* dripicons-v2.ttf */; };
|
||||
@ -602,6 +603,8 @@
|
||||
341458471FBE11C4005ABCF9 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = translations/fa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
341F2C0D1F2B8AE700D07D6B /* DebugUIMisc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMisc.h; sourceTree = "<group>"; };
|
||||
341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMisc.m; sourceTree = "<group>"; };
|
||||
34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQuotedMessageView.m; sourceTree = "<group>"; };
|
||||
34277A5D20751BDC006049F2 /* OWSQuotedMessageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQuotedMessageView.h; sourceTree = "<group>"; };
|
||||
3430FE171F7751D4000EC51B /* GiphyAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GiphyAPI.swift; sourceTree = "<group>"; };
|
||||
34330A591E7875FB00DF2FB9 /* fontawesome-webfont.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "fontawesome-webfont.ttf"; sourceTree = "<group>"; };
|
||||
34330A5B1E787A9800DF2FB9 /* dripicons-v2.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "dripicons-v2.ttf"; sourceTree = "<group>"; };
|
||||
@ -1665,6 +1668,8 @@
|
||||
34D1F0A21F867BFC0066283D /* OWSMessageCell.m */,
|
||||
34DBF000206BD5A400025978 /* OWSMessageTextView.h */,
|
||||
34DBEFFF206BD5A400025978 /* OWSMessageTextView.m */,
|
||||
34277A5D20751BDC006049F2 /* OWSQuotedMessageView.h */,
|
||||
34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */,
|
||||
34D1F0A51F867BFC0066283D /* OWSSystemMessageCell.h */,
|
||||
34D1F0A61F867BFC0066283D /* OWSSystemMessageCell.m */,
|
||||
34D1F0A71F867BFC0066283D /* OWSUnreadIndicatorCell.h */,
|
||||
@ -3251,6 +3256,7 @@
|
||||
34D1F0C01F8EC1760066283D /* MessageRecipientStatusUtils.swift in Sources */,
|
||||
45F659731E1BD99C00444429 /* CallKitCallUIAdaptee.swift in Sources */,
|
||||
45BB93381E688E14001E3939 /* UIDevice+featureSupport.swift in Sources */,
|
||||
34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */,
|
||||
458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */,
|
||||
45F32C242057297A00A300D5 /* MessageDetailViewController.swift in Sources */,
|
||||
34D1F0841F8678AA0066283D /* ConversationInputToolbar.m in Sources */,
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#import "OWSExpirationTimerView.h"
|
||||
#import "OWSGenericAttachmentView.h"
|
||||
#import "OWSMessageTextView.h"
|
||||
#import "OWSQuotedMessageView.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import "UIColor+OWS.h"
|
||||
#import <JSQMessagesViewController/JSQMessagesTimestampFormatter.h>
|
||||
@ -21,11 +22,6 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
{
|
||||
return CGSizeMake((CGFloat)ceil(size.width), (CGFloat)ceil(size.height));
|
||||
}
|
||||
|
||||
@interface OWSMessageCell ()
|
||||
|
||||
// The nullable properties are created as needed.
|
||||
@ -266,23 +262,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
return self.viewItem.hasQuotedAttachment;
|
||||
}
|
||||
|
||||
- (BOOL)hasQuotedAttachmentThumbnail
|
||||
{
|
||||
// This should always be valid for the appropriate cell types.
|
||||
OWSAssert(self.viewItem);
|
||||
|
||||
return (self.viewItem.hasQuotedAttachment &&
|
||||
[TSAttachmentStream hasThumbnailForMimeType:self.viewItem.quotedAttachmentMimetype]);
|
||||
}
|
||||
|
||||
- (nullable DisplayableText *)displayableQuotedText
|
||||
{
|
||||
// This should always be valid for the appropriate cell types.
|
||||
OWSAssert(self.viewItem.displayableQuotedText);
|
||||
|
||||
return self.viewItem.displayableQuotedText;
|
||||
}
|
||||
|
||||
- (TSMessage *)message
|
||||
{
|
||||
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
|
||||
@ -382,31 +361,26 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
if (self.isQuotedReply) {
|
||||
OWSAssert(!lastSubview);
|
||||
|
||||
UIView *quotedMessageView = [self createQuotedMessageView];
|
||||
|
||||
OWSQuotedMessageView *quotedMessageView =
|
||||
[[OWSQuotedMessageView alloc] initWithViewItem:self.viewItem textMessageFont:self.textMessageFont];
|
||||
[quotedMessageView createContents];
|
||||
[self.bubbleView addSubview:quotedMessageView];
|
||||
|
||||
CGFloat leadingMargin = self.quotedBubbleLeadingMargin;
|
||||
CGFloat trailingMargin = self.quotedBubbleTrailingMargin;
|
||||
|
||||
CGFloat bubbleLeadingMargin = (self.isIncoming ? kBubbleThornSideInset : 0.f);
|
||||
CGFloat bubbleTrailingMargin = (self.isIncoming ? 0.f : kBubbleThornSideInset);
|
||||
[self.viewConstraints addObjectsFromArray:@[
|
||||
[quotedMessageView autoPinLeadingToSuperviewMarginWithInset:leadingMargin],
|
||||
[quotedMessageView autoPinTrailingToSuperviewMarginWithInset:trailingMargin],
|
||||
[quotedMessageView autoPinLeadingToSuperviewMarginWithInset:bubbleLeadingMargin],
|
||||
[quotedMessageView autoPinTrailingToSuperviewMarginWithInset:bubbleTrailingMargin],
|
||||
]];
|
||||
|
||||
if (lastSubview) {
|
||||
[self.viewConstraints addObject:[quotedMessageView autoPinEdge:ALEdgeTop
|
||||
toEdge:ALEdgeBottom
|
||||
ofView:lastSubview
|
||||
withOffset:self.quotedMessageTopInset]];
|
||||
[self.viewConstraints
|
||||
addObject:[quotedMessageView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastSubview]];
|
||||
} else {
|
||||
[self.viewConstraints addObject:[quotedMessageView autoPinEdgeToSuperviewEdge:ALEdgeTop
|
||||
withInset:self.quotedMessageTopInset]];
|
||||
[self.viewConstraints addObject:[quotedMessageView autoPinEdgeToSuperviewEdge:ALEdgeTop]];
|
||||
}
|
||||
lastSubview = quotedMessageView;
|
||||
bottomMargin = 0;
|
||||
|
||||
// TODO: Consider stroking the quoted thumbnail.
|
||||
}
|
||||
|
||||
UIView *_Nullable bodyMediaView = nil;
|
||||
@ -783,19 +757,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
return [UIFont systemFontOfSize:12.0f];
|
||||
}
|
||||
|
||||
- (UILabel *)createQuotedTextLabel
|
||||
{
|
||||
UILabel *quotedTextLabel = [UILabel new];
|
||||
quotedTextLabel.numberOfLines = 3;
|
||||
quotedTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
quotedTextLabel.text = self.displayableQuotedText.displayText;
|
||||
quotedTextLabel.textColor = self.quotedTextColor;
|
||||
|
||||
// Honor dynamic type in the message bodies.
|
||||
quotedTextLabel.font = self.textMessageFont;
|
||||
return quotedTextLabel;
|
||||
}
|
||||
|
||||
- (OWSMessageTextView *)configureBodyTextView
|
||||
{
|
||||
OWSAssert(self.hasBodyText);
|
||||
@ -861,87 +822,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
return tapForMoreLabel;
|
||||
}
|
||||
|
||||
- (UIView *)createQuotedMessageView
|
||||
{
|
||||
OWSAssert(self.isQuotedReply);
|
||||
|
||||
UIView *quotedMessageView = [UIView containerView];
|
||||
quotedMessageView.userInteractionEnabled = NO;
|
||||
quotedMessageView.clipsToBounds = YES;
|
||||
// TODO:
|
||||
quotedMessageView.layer.cornerRadius = 3.f;
|
||||
quotedMessageView.backgroundColor = [UIColor colorWithRGBHex:0xe2f7fa];
|
||||
|
||||
UIView *quoteStripView = [UIView containerView];
|
||||
quoteStripView.backgroundColor = (self.isIncoming ? [UIColor whiteColor] : [UIColor colorWithRGBHex:0x007884]);
|
||||
quoteStripView.userInteractionEnabled = NO;
|
||||
[quotedMessageView addSubview:quoteStripView];
|
||||
[quoteStripView autoPinHeightToSuperview];
|
||||
[quoteStripView autoPinLeadingToSuperviewMargin];
|
||||
[quoteStripView autoSetDimension:ALDimensionWidth toSize:self.quotedReplyStripeThickness];
|
||||
[quoteStripView setContentHuggingHigh];
|
||||
[quoteStripView setCompressionResistanceHigh];
|
||||
|
||||
UIView *_Nullable quotedThumbnailView = nil;
|
||||
if (self.hasQuotedAttachmentThumbnail) {
|
||||
// TODO:
|
||||
quotedThumbnailView = [UIView containerView];
|
||||
quotedThumbnailView.userInteractionEnabled = NO;
|
||||
quotedThumbnailView.backgroundColor = [UIColor redColor];
|
||||
[quotedMessageView addSubview:quotedThumbnailView];
|
||||
[quotedThumbnailView autoPinTopToSuperviewMargin];
|
||||
[quotedThumbnailView autoPinTrailingToSuperviewMargin];
|
||||
[quotedThumbnailView autoSetDimension:ALDimensionWidth toSize:self.quotedThumbnailSize];
|
||||
[quotedThumbnailView autoSetDimension:ALDimensionHeight toSize:self.quotedThumbnailSize];
|
||||
[quotedThumbnailView setContentHuggingHigh];
|
||||
[quotedThumbnailView setCompressionResistanceHigh];
|
||||
}
|
||||
|
||||
OWSContactsManager *contactsManager = Environment.current.contactsManager;
|
||||
NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.viewItem.quotedRecipientId];
|
||||
|
||||
UILabel *quotedAuthorLabel = [UILabel new];
|
||||
quotedAuthorLabel.text = quotedAuthor;
|
||||
quotedAuthorLabel.font = self.quotedAuthorFont;
|
||||
quotedAuthorLabel.textColor
|
||||
= (self.isIncoming ? [UIColor colorWithRGBHex:0xd84315] : [UIColor colorWithRGBHex:0x007884]);
|
||||
quotedAuthorLabel.numberOfLines = 1;
|
||||
quotedAuthorLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
[quotedMessageView addSubview:quotedAuthorLabel];
|
||||
[quotedAuthorLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.quotedContentTopInset];
|
||||
[quotedAuthorLabel autoPinLeadingToTrailingEdgeOfView:quoteStripView offset:self.quotedReplyStripeHSpacing];
|
||||
if (quotedThumbnailView) {
|
||||
[quotedAuthorLabel autoPinTrailingToLeadingEdgeOfView:quotedThumbnailView offset:self.quotedThumbnailHSpacing];
|
||||
} else {
|
||||
[quotedAuthorLabel autoPinTrailingToSuperviewMarginWithInset:self.quotedContentTrailingMargin];
|
||||
}
|
||||
[quotedAuthorLabel autoSetDimension:ALDimensionHeight toSize:self.quotedAuthorHeight];
|
||||
[quotedAuthorLabel setContentHuggingLow];
|
||||
[quotedAuthorLabel setCompressionResistanceLow];
|
||||
|
||||
if (self.hasQuotedText) {
|
||||
UILabel *quotedTextLabel = [self createQuotedTextLabel];
|
||||
|
||||
[quotedMessageView addSubview:quotedTextLabel];
|
||||
[quotedTextLabel autoPinEdge:ALEdgeTop
|
||||
toEdge:ALEdgeBottom
|
||||
ofView:quotedAuthorLabel
|
||||
withOffset:self.quotedAuthorBottomSpacing];
|
||||
[quotedTextLabel autoPinLeadingToTrailingEdgeOfView:quoteStripView offset:self.quotedReplyStripeHSpacing];
|
||||
if (quotedThumbnailView) {
|
||||
[quotedTextLabel autoPinTrailingToLeadingEdgeOfView:quotedThumbnailView
|
||||
offset:self.quotedThumbnailHSpacing];
|
||||
} else {
|
||||
[quotedTextLabel autoPinTrailingToSuperviewMarginWithInset:self.quotedContentTrailingMargin];
|
||||
}
|
||||
[quotedTextLabel autoPinBottomToSuperviewMarginWithInset:self.quotedContentBottomInset];
|
||||
[quotedTextLabel setContentHuggingLow];
|
||||
[quotedTextLabel setCompressionResistanceLow];
|
||||
}
|
||||
|
||||
return quotedMessageView;
|
||||
}
|
||||
|
||||
- (UIView *)loadViewForStillImage
|
||||
{
|
||||
OWSAssert(self.attachmentStream);
|
||||
@ -1290,73 +1170,15 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
OWSAssert(self.viewItem);
|
||||
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
|
||||
|
||||
CGSize result = CGSizeZero;
|
||||
|
||||
if (!self.isQuotedReply) {
|
||||
return result;
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
result.width += self.quotedMessageHInset;
|
||||
result.width += self.quotedReplyStripeThickness;
|
||||
result.width += self.quotedReplyStripeHSpacing;
|
||||
|
||||
result.height += self.quotedMessageTopInset;
|
||||
|
||||
CGFloat thumbnailHeight = 0.f;
|
||||
if (self.hasQuotedAttachmentThumbnail) {
|
||||
result.width += self.quotedThumbnailHSpacing;
|
||||
result.width += self.quotedThumbnailSize;
|
||||
|
||||
thumbnailHeight = self.quotedThumbnailSize;
|
||||
} else {
|
||||
result.width += self.quotedContentTrailingMargin;
|
||||
}
|
||||
|
||||
result.width += self.quotedMessageHInset;
|
||||
|
||||
// Once we've determined everything _except_ the size of the text
|
||||
// content (i.e. the quoted author and the quoted text (if any)),
|
||||
// we can determine the size of the text content.
|
||||
OWSQuotedMessageView *quotedMessageView =
|
||||
[[OWSQuotedMessageView alloc] initWithViewItem:self.viewItem textMessageFont:self.textMessageFont];
|
||||
const int maxMessageWidth = [self maxMessageWidthForContentWidth:contentWidth];
|
||||
CGFloat maxTextWidth = (maxMessageWidth - (self.textTrailingMargin + self.textLeadingMargin + result.width));
|
||||
CGFloat textWidth = 0.f;
|
||||
|
||||
// Author
|
||||
{
|
||||
OWSContactsManager *contactsManager = Environment.current.contactsManager;
|
||||
NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.viewItem.quotedRecipientId];
|
||||
|
||||
UILabel *quotedAuthorLabel = [UILabel new];
|
||||
quotedAuthorLabel.text = quotedAuthor;
|
||||
quotedAuthorLabel.font = self.quotedAuthorFont;
|
||||
quotedAuthorLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
quotedAuthorLabel.numberOfLines = 1;
|
||||
|
||||
CGSize quotedAuthorSize = CGSizeCeil([quotedAuthorLabel sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)]);
|
||||
|
||||
textWidth = MAX(textWidth, quotedAuthorSize.width);
|
||||
result.height += self.quotedContentTopInset;
|
||||
result.height += self.quotedAuthorHeight;
|
||||
}
|
||||
|
||||
if (self.hasQuotedText) {
|
||||
UILabel *quotedTextLabel = [self createQuotedTextLabel];
|
||||
|
||||
CGSize textSize = CGSizeCeil([quotedTextLabel sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)]);
|
||||
|
||||
textWidth = MAX(textWidth, textSize.width);
|
||||
result.height += self.quotedAuthorBottomSpacing;
|
||||
result.height += textSize.height;
|
||||
}
|
||||
|
||||
result.width += textWidth;
|
||||
result.height += self.quotedContentBottomInset;
|
||||
|
||||
result.height = MAX(result.height, thumbnailHeight);
|
||||
|
||||
if (includeMargins) {
|
||||
result.width += kBubbleThornSideInset;
|
||||
}
|
||||
CGSize result = [quotedMessageView sizeForMaxWidth:maxMessageWidth - kBubbleThornSideInset];
|
||||
result.width += kBubbleThornSideInset;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1418,82 +1240,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
return (CGFloat)ceil([self tapForMoreFont].lineHeight * 1.25);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (UIFont *)quotedAuthorFont
|
||||
{
|
||||
return [UIFont ows_regularFontWithSize:10.f];
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedAuthorHeight
|
||||
{
|
||||
return (CGFloat)ceil([self quotedAuthorFont].lineHeight * 1.25);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedAuthorBottomSpacing
|
||||
{
|
||||
return 2.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedContentTopInset
|
||||
{
|
||||
return 3.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedContentBottomInset
|
||||
{
|
||||
return 3.f;
|
||||
}
|
||||
|
||||
// Distance from top edge of "quoted message" bubble to top of message bubble.
|
||||
// TODO:
|
||||
- (CGFloat)quotedMessageTopInset
|
||||
{
|
||||
return 3.f;
|
||||
}
|
||||
|
||||
// Distance from side of "quoted message" bubble to side of message bubble.
|
||||
// TODO:
|
||||
- (CGFloat)quotedMessageHInset
|
||||
{
|
||||
return 3.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedReplyStripeThickness
|
||||
{
|
||||
return 3.f;
|
||||
}
|
||||
|
||||
// The spacing between the vertical "quoted reply stripe"
|
||||
// and the quoted message content.
|
||||
// TODO:
|
||||
- (CGFloat)quotedReplyStripeHSpacing
|
||||
{
|
||||
return 10.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedThumbnailSize
|
||||
{
|
||||
return 30.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedThumbnailHSpacing
|
||||
{
|
||||
return 10.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedContentTrailingMargin
|
||||
{
|
||||
return 10.f;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)isIncoming
|
||||
@ -1524,24 +1270,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CGFloat)quotedBubbleLeadingMargin
|
||||
{
|
||||
CGFloat result = self.quotedMessageHInset;
|
||||
if (self.isIncoming) {
|
||||
result += kBubbleThornSideInset;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CGFloat)quotedBubbleTrailingMargin
|
||||
{
|
||||
CGFloat result = self.quotedMessageHInset;
|
||||
if (!self.isIncoming) {
|
||||
result += kBubbleThornSideInset;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CGFloat)textTopMargin
|
||||
{
|
||||
return kBubbleTextVInset;
|
||||
@ -1557,11 +1285,6 @@ CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
return self.isIncoming ? [UIColor blackColor] : [UIColor whiteColor];
|
||||
}
|
||||
|
||||
- (UIColor *)quotedTextColor
|
||||
{
|
||||
return [UIColor blackColor];
|
||||
}
|
||||
|
||||
- (BOOL)isMediaBeingSent
|
||||
{
|
||||
if (self.isIncoming) {
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationViewItem;
|
||||
@class TSQuotedMessage;
|
||||
|
||||
@interface OWSQuotedMessageView : UIView
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithViewItem:(ConversationViewItem *)viewItem
|
||||
// quotedMessage:(TSQuotedMessage *)quotedMessage
|
||||
textMessageFont:(UIFont *)textMessageFont;
|
||||
|
||||
// Only needs to be called if we're going to render this instance.
|
||||
- (void)createContents;
|
||||
|
||||
// Measurement
|
||||
- (CGSize)sizeForMaxWidth:(CGFloat)maxWidth;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -0,0 +1,347 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSQuotedMessageView.h"
|
||||
#import "ConversationViewItem.h"
|
||||
#import "Environment.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import <SignalMessaging/OWSContactsManager.h>
|
||||
#import <SignalMessaging/SignalMessaging-Swift.h>
|
||||
#import <SignalMessaging/UIColor+OWS.h>
|
||||
#import <SignalMessaging/UIView+OWS.h>
|
||||
#import <SignalServiceKit/TSAttachmentStream.h>
|
||||
#import <SignalServiceKit/TSMessage.h>
|
||||
#import <SignalServiceKit/TSQuotedMessage.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSQuotedMessageView ()
|
||||
|
||||
@property (nonatomic, readonly) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, readonly) UIFont *textMessageFont;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSQuotedMessageView
|
||||
|
||||
- (instancetype)initWithViewItem:(ConversationViewItem *)viewItem
|
||||
// quotedMessage:(TSQuotedMessage *)quotedMessage
|
||||
textMessageFont:(UIFont *)textMessageFont
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
OWSAssert(viewItem);
|
||||
// OWSAssert(quotedMessage);
|
||||
OWSAssert(textMessageFont);
|
||||
|
||||
_viewItem = viewItem;
|
||||
// _quotedMessage = quotedMessage;
|
||||
_textMessageFont = textMessageFont;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isIncoming
|
||||
{
|
||||
return self.viewItem.interaction.interactionType == OWSInteractionType_IncomingMessage;
|
||||
}
|
||||
|
||||
- (BOOL)hasQuotedAttachmentThumbnail
|
||||
{
|
||||
// This should always be valid for the appropriate cell types.
|
||||
OWSAssert(self.viewItem);
|
||||
|
||||
return (self.viewItem.hasQuotedAttachment &&
|
||||
[TSAttachmentStream hasThumbnailForMimeType:self.viewItem.quotedAttachmentMimetype]);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)createContents
|
||||
{
|
||||
OWSAssert(self.viewItem.isQuotedReply);
|
||||
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
self.userInteractionEnabled = NO;
|
||||
self.layoutMargins = UIEdgeInsetsZero;
|
||||
self.clipsToBounds = YES;
|
||||
|
||||
UIView *_Nullable quotedAttachmentView = nil;
|
||||
// TODO:
|
||||
// if (self.hasQuotedAttachmentThumbnail)
|
||||
{
|
||||
// TODO:
|
||||
quotedAttachmentView = [UIView containerView];
|
||||
quotedAttachmentView.userInteractionEnabled = NO;
|
||||
quotedAttachmentView.backgroundColor = [UIColor redColor];
|
||||
[self addSubview:quotedAttachmentView];
|
||||
[quotedAttachmentView autoPinTrailingToSuperviewMarginWithInset:self.quotedContentHInset];
|
||||
[quotedAttachmentView autoVCenterInSuperview];
|
||||
[quotedAttachmentView autoSetDimension:ALDimensionWidth toSize:self.quotedAttachmentSize];
|
||||
[quotedAttachmentView autoSetDimension:ALDimensionHeight toSize:self.quotedAttachmentSize];
|
||||
[quotedAttachmentView setContentHuggingHigh];
|
||||
[quotedAttachmentView setCompressionResistanceHigh];
|
||||
|
||||
// TODO: Consider stroking the quoted thumbnail.
|
||||
}
|
||||
|
||||
OWSContactsManager *contactsManager = Environment.current.contactsManager;
|
||||
NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.viewItem.quotedRecipientId];
|
||||
|
||||
UILabel *quotedAuthorLabel = [UILabel new];
|
||||
{
|
||||
quotedAuthorLabel.text = quotedAuthor;
|
||||
quotedAuthorLabel.font = self.quotedAuthorFont;
|
||||
quotedAuthorLabel.textColor
|
||||
= (self.isIncoming ? [UIColor colorWithRGBHex:0xd84315] : [UIColor colorWithRGBHex:0x007884]);
|
||||
quotedAuthorLabel.numberOfLines = 1;
|
||||
quotedAuthorLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
[self addSubview:quotedAuthorLabel];
|
||||
[quotedAuthorLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.quotedAuthorTopInset];
|
||||
[quotedAuthorLabel autoPinLeadingToSuperviewMarginWithInset:self.quotedContentHInset];
|
||||
if (quotedAttachmentView) {
|
||||
[quotedAuthorLabel autoPinTrailingToLeadingEdgeOfView:quotedAttachmentView
|
||||
offset:self.quotedAttachmentHSpacing];
|
||||
} else {
|
||||
[quotedAuthorLabel autoPinTrailingToSuperviewMarginWithInset:self.quotedContentHInset];
|
||||
}
|
||||
[quotedAuthorLabel autoSetDimension:ALDimensionHeight toSize:self.quotedAuthorHeight];
|
||||
[quotedAuthorLabel setContentHuggingLow];
|
||||
[quotedAuthorLabel setCompressionResistanceLow];
|
||||
}
|
||||
|
||||
{
|
||||
// Stripe and text container.
|
||||
UIView *stripeAndTextContainer = [UIView containerView];
|
||||
[self addSubview:stripeAndTextContainer];
|
||||
[stripeAndTextContainer autoPinEdge:ALEdgeTop
|
||||
toEdge:ALEdgeBottom
|
||||
ofView:quotedAuthorLabel
|
||||
withOffset:self.quotedAuthorBottomSpacing];
|
||||
[stripeAndTextContainer autoPinLeadingToSuperviewMarginWithInset:self.quotedContentHInset];
|
||||
if (quotedAttachmentView) {
|
||||
[stripeAndTextContainer autoPinTrailingToLeadingEdgeOfView:quotedAttachmentView
|
||||
offset:self.quotedAttachmentHSpacing];
|
||||
} else {
|
||||
[stripeAndTextContainer autoPinTrailingToSuperviewMarginWithInset:self.quotedContentHInset];
|
||||
}
|
||||
[stripeAndTextContainer autoPinBottomToSuperviewMarginWithInset:self.quotedContentHInset];
|
||||
[stripeAndTextContainer setContentHuggingLow];
|
||||
[stripeAndTextContainer setCompressionResistanceLow];
|
||||
|
||||
// Stripe.
|
||||
UIView *quoteStripView = [UIView containerView];
|
||||
quoteStripView.backgroundColor = (self.isIncoming ? [UIColor whiteColor] : [UIColor colorWithRGBHex:0x007884]);
|
||||
quoteStripView.userInteractionEnabled = NO;
|
||||
[stripeAndTextContainer addSubview:quoteStripView];
|
||||
[quoteStripView autoPinHeightToSuperview];
|
||||
[quoteStripView autoPinLeadingToSuperviewMargin];
|
||||
[quoteStripView autoSetDimension:ALDimensionWidth toSize:self.quotedReplyStripeThickness];
|
||||
[quoteStripView setContentHuggingVerticalLow];
|
||||
[quoteStripView setContentHuggingHorizontalHigh];
|
||||
[quoteStripView setCompressionResistanceHigh];
|
||||
|
||||
// Text.
|
||||
UILabel *quotedTextLabel = [self createQuotedTextLabel];
|
||||
[stripeAndTextContainer addSubview:quotedTextLabel];
|
||||
[quotedTextLabel autoPinTopToSuperviewMarginWithInset:self.quotedReplyStripeVExtension];
|
||||
[quotedTextLabel autoPinBottomToSuperviewMarginWithInset:self.quotedReplyStripeVExtension];
|
||||
[quotedTextLabel autoPinLeadingToTrailingEdgeOfView:quoteStripView offset:self.quotedReplyStripeHSpacing];
|
||||
[quotedTextLabel autoPinTrailingToSuperviewMargin];
|
||||
[quotedTextLabel setContentHuggingLow];
|
||||
[quotedTextLabel setCompressionResistanceLow];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Measurement
|
||||
|
||||
// TODO: Class method?
|
||||
- (CGSize)sizeForMaxWidth:(CGFloat)maxWidth
|
||||
{
|
||||
OWSAssert(self.viewItem);
|
||||
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
|
||||
|
||||
CGSize result = CGSizeZero;
|
||||
|
||||
if (!self.viewItem.isQuotedReply) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.width += self.quotedContentHInset;
|
||||
|
||||
CGFloat thumbnailHeight = 0.f;
|
||||
if (self.hasQuotedAttachmentThumbnail) {
|
||||
result.width += self.quotedAttachmentHSpacing;
|
||||
result.width += self.quotedAttachmentSize;
|
||||
|
||||
thumbnailHeight += self.quotedAttachmentMinVInset;
|
||||
thumbnailHeight += self.quotedAttachmentSize;
|
||||
thumbnailHeight += self.quotedAttachmentMinVInset;
|
||||
}
|
||||
|
||||
result.width += self.quotedContentHInset;
|
||||
|
||||
// Quoted Author
|
||||
CGFloat quotedAuthorWidth = 0.f;
|
||||
{
|
||||
CGFloat maxQuotedAuthorWidth = maxWidth - result.width;
|
||||
|
||||
OWSContactsManager *contactsManager = Environment.current.contactsManager;
|
||||
NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.viewItem.quotedRecipientId];
|
||||
|
||||
UILabel *quotedAuthorLabel = [UILabel new];
|
||||
quotedAuthorLabel.text = quotedAuthor;
|
||||
quotedAuthorLabel.font = self.quotedAuthorFont;
|
||||
quotedAuthorLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
quotedAuthorLabel.numberOfLines = 1;
|
||||
|
||||
CGSize quotedAuthorSize
|
||||
= CGSizeCeil([quotedAuthorLabel sizeThatFits:CGSizeMake(maxQuotedAuthorWidth, CGFLOAT_MAX)]);
|
||||
|
||||
quotedAuthorWidth = quotedAuthorSize.width;
|
||||
|
||||
result.height += self.quotedAuthorTopInset;
|
||||
result.height += self.quotedAuthorHeight;
|
||||
result.height += self.quotedAuthorBottomSpacing;
|
||||
}
|
||||
|
||||
CGFloat quotedTextWidth = 0.f;
|
||||
{
|
||||
CGFloat maxQuotedTextWidth
|
||||
= (maxWidth - (result.width + self.quotedReplyStripeThickness + self.quotedReplyStripeHSpacing));
|
||||
|
||||
UILabel *quotedTextLabel = [self createQuotedTextLabel];
|
||||
|
||||
CGSize textSize = CGSizeCeil([quotedTextLabel sizeThatFits:CGSizeMake(maxQuotedTextWidth, CGFLOAT_MAX)]);
|
||||
|
||||
quotedTextWidth = textSize.width + self.quotedReplyStripeThickness + self.quotedReplyStripeHSpacing;
|
||||
result.height += self.quotedAuthorBottomSpacing;
|
||||
result.height += textSize.height + self.quotedReplyStripeVExtension * 2;
|
||||
}
|
||||
|
||||
CGFloat textWidth = MAX(quotedAuthorWidth, quotedTextWidth);
|
||||
result.width += textWidth;
|
||||
|
||||
result.height += self.quotedTextBottomInset;
|
||||
result.height = MAX(result.height, thumbnailHeight);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (UILabel *)createQuotedTextLabel
|
||||
{
|
||||
UILabel *quotedTextLabel = [UILabel new];
|
||||
quotedTextLabel.numberOfLines = 3;
|
||||
quotedTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
quotedTextLabel.text = self.quotedSnippet;
|
||||
quotedTextLabel.textColor = self.quotedTextColor;
|
||||
|
||||
// Honor dynamic type in the message bodies.
|
||||
quotedTextLabel.font = self.textMessageFont;
|
||||
return quotedTextLabel;
|
||||
}
|
||||
|
||||
- (UIColor *)quotedTextColor
|
||||
{
|
||||
return [UIColor blackColor];
|
||||
}
|
||||
|
||||
- (NSString *)quotedSnippet
|
||||
{
|
||||
if (self.viewItem.hasQuotedText && self.viewItem.displayableQuotedText.displayText.length > 0) {
|
||||
return self.viewItem.displayableQuotedText.displayText;
|
||||
} else {
|
||||
NSString *mimeType = self.viewItem.quotedAttachmentMimetype;
|
||||
|
||||
if (mimeType.length > 0) {
|
||||
return [TSAttachment emojiForMimeType:mimeType];
|
||||
}
|
||||
}
|
||||
|
||||
return @"";
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (UIFont *)quotedAuthorFont
|
||||
{
|
||||
return [UIFont ows_regularFontWithSize:10.f];
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedAuthorHeight
|
||||
{
|
||||
return (CGFloat)ceil([self quotedAuthorFont].lineHeight * 1.f);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedAuthorTopInset
|
||||
{
|
||||
return 4.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedAuthorBottomSpacing
|
||||
{
|
||||
return 2.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedTextBottomInset
|
||||
{
|
||||
return 5.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedReplyStripeThickness
|
||||
{
|
||||
return 3.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedReplyStripeVExtension
|
||||
{
|
||||
return 5.f;
|
||||
}
|
||||
|
||||
// The spacing between the vertical "quoted reply stripe"
|
||||
// and the quoted message content.
|
||||
// TODO:
|
||||
- (CGFloat)quotedReplyStripeHSpacing
|
||||
{
|
||||
return 8.f;
|
||||
}
|
||||
|
||||
// Distance from top edge of "quoted message" bubble to top of message bubble.
|
||||
// TODO:
|
||||
- (CGFloat)quotedAttachmentMinVInset
|
||||
{
|
||||
return 10.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedAttachmentSize
|
||||
{
|
||||
return 30.f;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
- (CGFloat)quotedAttachmentHSpacing
|
||||
{
|
||||
return 10.f;
|
||||
}
|
||||
|
||||
// Distance from sides of the quoted content to the sides of the message bubble.
|
||||
// TODO:
|
||||
- (CGFloat)quotedContentHInset
|
||||
{
|
||||
return 8.f;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -125,4 +125,11 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value);
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Macros
|
||||
|
||||
CG_INLINE CGSize CGSizeCeil(CGSize size)
|
||||
{
|
||||
return CGSizeMake((CGFloat)ceil(size.width), (CGFloat)ceil(size.height));
|
||||
}
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
Loading…
Reference in New Issue
Block a user