2018-04-04 17:31:33 +02:00
|
|
|
//
|
2019-01-25 17:33:09 +01:00
|
|
|
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
2018-04-04 17:31:33 +02:00
|
|
|
//
|
|
|
|
|
|
|
|
#import "OWSQuotedMessageView.h"
|
|
|
|
#import "ConversationViewItem.h"
|
|
|
|
#import "Environment.h"
|
2018-07-07 00:13:25 +02:00
|
|
|
#import "OWSBubbleView.h"
|
2019-05-02 23:58:48 +02:00
|
|
|
#import "Session-Swift.h"
|
2018-04-04 17:31:33 +02:00
|
|
|
#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>
|
2019-10-09 03:40:39 +02:00
|
|
|
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
2018-04-04 17:31:33 +02:00
|
|
|
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
2018-08-10 18:36:07 +02:00
|
|
|
const CGFloat kRemotelySourcedContentGlyphLength = 16;
|
|
|
|
const CGFloat kRemotelySourcedContentRowMargin = 4;
|
2019-12-11 00:25:53 +01:00
|
|
|
const CGFloat kRemotelySourcedContentRowSpacing = 4;
|
2018-08-10 18:36:07 +02:00
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
@interface OWSQuotedMessageView ()
|
|
|
|
|
2018-04-06 22:53:16 +02:00
|
|
|
@property (nonatomic, readonly) OWSQuotedReplyModel *quotedMessage;
|
2018-04-04 20:42:39 +02:00
|
|
|
@property (nonatomic, nullable, readonly) DisplayableText *displayableQuotedText;
|
2018-06-28 19:28:14 +02:00
|
|
|
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
|
2018-04-04 20:42:39 +02:00
|
|
|
|
2018-04-09 23:48:31 +02:00
|
|
|
@property (nonatomic, readonly) BOOL isForPreview;
|
2018-04-12 01:20:27 +02:00
|
|
|
@property (nonatomic, readonly) BOOL isOutgoing;
|
2018-07-07 00:32:46 +02:00
|
|
|
@property (nonatomic, readonly) OWSDirectionalRectCorner sharpCorners;
|
2018-04-04 20:42:39 +02:00
|
|
|
|
2018-04-12 00:15:38 +02:00
|
|
|
@property (nonatomic, readonly) UILabel *quotedAuthorLabel;
|
|
|
|
@property (nonatomic, readonly) UILabel *quotedTextLabel;
|
2018-08-10 18:36:07 +02:00
|
|
|
@property (nonatomic, readonly) UILabel *quoteContentSourceLabel;
|
2018-04-12 00:15:38 +02:00
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
@end
|
|
|
|
|
2018-04-04 20:56:48 +02:00
|
|
|
#pragma mark -
|
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
@implementation OWSQuotedMessageView
|
|
|
|
|
2018-04-06 22:53:16 +02:00
|
|
|
+ (OWSQuotedMessageView *)quotedMessageViewForConversation:(OWSQuotedReplyModel *)quotedMessage
|
2018-04-04 20:42:39 +02:00
|
|
|
displayableQuotedText:(nullable DisplayableText *)displayableQuotedText
|
2018-06-28 19:28:14 +02:00
|
|
|
conversationStyle:(ConversationStyle *)conversationStyle
|
2018-04-12 01:20:27 +02:00
|
|
|
isOutgoing:(BOOL)isOutgoing
|
2018-07-07 00:32:46 +02:00
|
|
|
sharpCorners:(OWSDirectionalRectCorner)sharpCorners
|
2018-04-04 20:42:39 +02:00
|
|
|
{
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(quotedMessage);
|
2018-04-04 20:42:39 +02:00
|
|
|
|
2018-04-09 23:48:31 +02:00
|
|
|
return [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage
|
|
|
|
displayableQuotedText:displayableQuotedText
|
2018-06-28 19:28:14 +02:00
|
|
|
conversationStyle:conversationStyle
|
2018-04-12 01:20:27 +02:00
|
|
|
isForPreview:NO
|
2018-06-29 20:57:33 +02:00
|
|
|
isOutgoing:isOutgoing
|
2018-07-06 22:45:00 +02:00
|
|
|
sharpCorners:sharpCorners];
|
2018-04-04 20:42:39 +02:00
|
|
|
}
|
|
|
|
|
2018-04-06 22:53:16 +02:00
|
|
|
+ (OWSQuotedMessageView *)quotedMessageViewForPreview:(OWSQuotedReplyModel *)quotedMessage
|
2018-06-28 19:28:14 +02:00
|
|
|
conversationStyle:(ConversationStyle *)conversationStyle
|
2018-04-04 20:42:39 +02:00
|
|
|
{
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(quotedMessage);
|
2018-04-04 20:42:39 +02:00
|
|
|
|
|
|
|
DisplayableText *_Nullable displayableQuotedText = nil;
|
|
|
|
if (quotedMessage.body.length > 0) {
|
|
|
|
displayableQuotedText = [DisplayableText displayableText:quotedMessage.body];
|
|
|
|
}
|
|
|
|
|
2019-01-28 21:51:54 +01:00
|
|
|
OWSQuotedMessageView *instance = [[OWSQuotedMessageView alloc]
|
|
|
|
initWithQuotedMessage:quotedMessage
|
|
|
|
displayableQuotedText:displayableQuotedText
|
|
|
|
conversationStyle:conversationStyle
|
|
|
|
isForPreview:YES
|
|
|
|
isOutgoing:YES
|
|
|
|
sharpCorners:(OWSDirectionalRectCornerBottomLeading | OWSDirectionalRectCornerBottomTrailing)];
|
2018-04-12 00:15:38 +02:00
|
|
|
[instance createContents];
|
|
|
|
return instance;
|
2018-04-04 20:42:39 +02:00
|
|
|
}
|
|
|
|
|
2018-04-06 22:53:16 +02:00
|
|
|
- (instancetype)initWithQuotedMessage:(OWSQuotedReplyModel *)quotedMessage
|
2018-04-04 20:42:39 +02:00
|
|
|
displayableQuotedText:(nullable DisplayableText *)displayableQuotedText
|
2018-06-28 19:28:14 +02:00
|
|
|
conversationStyle:(ConversationStyle *)conversationStyle
|
2018-04-09 23:48:31 +02:00
|
|
|
isForPreview:(BOOL)isForPreview
|
2018-04-12 01:20:27 +02:00
|
|
|
isOutgoing:(BOOL)isOutgoing
|
2018-07-07 00:32:46 +02:00
|
|
|
sharpCorners:(OWSDirectionalRectCorner)sharpCorners
|
2018-04-04 17:31:33 +02:00
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
|
|
|
|
if (!self) {
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(quotedMessage);
|
2018-04-04 17:31:33 +02:00
|
|
|
|
2018-04-04 20:42:39 +02:00
|
|
|
_quotedMessage = quotedMessage;
|
|
|
|
_displayableQuotedText = displayableQuotedText;
|
2018-04-09 23:48:31 +02:00
|
|
|
_isForPreview = isForPreview;
|
2018-06-28 19:28:14 +02:00
|
|
|
_conversationStyle = conversationStyle;
|
2018-04-12 01:20:27 +02:00
|
|
|
_isOutgoing = isOutgoing;
|
2018-07-06 22:45:00 +02:00
|
|
|
_sharpCorners = sharpCorners;
|
2018-04-04 17:31:33 +02:00
|
|
|
|
2018-04-12 00:15:38 +02:00
|
|
|
_quotedAuthorLabel = [UILabel new];
|
|
|
|
_quotedTextLabel = [UILabel new];
|
2018-08-10 18:36:07 +02:00
|
|
|
_quoteContentSourceLabel = [UILabel new];
|
2018-04-09 23:15:56 +02:00
|
|
|
|
2018-04-04 20:42:39 +02:00
|
|
|
return self;
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-04 21:45:35 +02:00
|
|
|
- (BOOL)hasQuotedAttachment
|
|
|
|
{
|
2018-04-04 21:55:19 +02:00
|
|
|
return (self.quotedMessage.contentType.length > 0
|
2018-04-05 16:35:57 +02:00
|
|
|
&& ![OWSMimeTypeOversizeTextMessage isEqualToString:self.quotedMessage.contentType]);
|
2018-04-04 21:45:35 +02:00
|
|
|
}
|
|
|
|
|
2018-04-05 16:57:51 +02:00
|
|
|
- (BOOL)hasQuotedAttachmentThumbnailImage
|
2018-04-04 17:31:33 +02:00
|
|
|
{
|
2018-04-04 21:55:19 +02:00
|
|
|
return (self.quotedMessage.contentType.length > 0
|
2018-04-05 16:35:57 +02:00
|
|
|
&& ![OWSMimeTypeOversizeTextMessage isEqualToString:self.quotedMessage.contentType] &&
|
2018-04-04 20:42:39 +02:00
|
|
|
[TSAttachmentStream hasThumbnailForMimeType:self.quotedMessage.contentType]);
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-04 22:40:28 +02:00
|
|
|
- (UIColor *)highlightColor
|
|
|
|
{
|
2018-04-12 01:20:27 +02:00
|
|
|
BOOL isQuotingSelf = [NSObject isNullableObject:self.quotedMessage.authorId equalTo:TSAccountManager.localNumber];
|
2018-09-26 20:27:30 +02:00
|
|
|
return (isQuotingSelf ? [self.conversationStyle bubbleColorWithIsIncoming:NO]
|
2018-07-09 15:58:02 +02:00
|
|
|
: [self.conversationStyle quotingSelfHighlightColor]);
|
2018-04-04 22:40:28 +02:00
|
|
|
}
|
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
#pragma mark -
|
|
|
|
|
2018-06-29 17:31:22 +02:00
|
|
|
- (CGFloat)bubbleHMargin
|
|
|
|
{
|
2019-12-10 05:11:46 +01:00
|
|
|
return (self.isForPreview ? 0.f : LKValues.largeSpacing);
|
2018-06-29 17:31:22 +02:00
|
|
|
}
|
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
- (CGFloat)hSpacing
|
2018-06-29 17:31:22 +02:00
|
|
|
{
|
2018-06-29 18:00:10 +02:00
|
|
|
return 8.f;
|
2018-06-29 17:31:22 +02:00
|
|
|
}
|
|
|
|
|
2018-07-02 21:02:36 +02:00
|
|
|
- (CGFloat)vSpacing
|
|
|
|
{
|
2019-12-10 05:11:46 +01:00
|
|
|
return 4.f;
|
2018-07-02 21:02:36 +02:00
|
|
|
}
|
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
- (CGFloat)stripeThickness
|
2018-06-29 17:31:22 +02:00
|
|
|
{
|
2019-12-10 05:11:46 +01:00
|
|
|
return LKValues.accentLineThickness;
|
2018-06-29 17:31:22 +02:00
|
|
|
}
|
|
|
|
|
2018-08-10 18:36:07 +02:00
|
|
|
- (UIColor *)quoteBubbleBackgroundColor
|
|
|
|
{
|
|
|
|
return [self.conversationStyle quotedReplyBubbleColorWithIsIncoming:!self.isOutgoing];
|
|
|
|
}
|
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
- (void)createContents
|
|
|
|
{
|
2018-04-13 21:10:16 +02:00
|
|
|
// Ensure only called once.
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(self.subviews.count < 1);
|
2018-04-12 00:15:38 +02:00
|
|
|
|
2018-04-16 19:50:54 +02:00
|
|
|
self.userInteractionEnabled = YES;
|
2018-04-04 17:31:33 +02:00
|
|
|
self.layoutMargins = UIEdgeInsetsZero;
|
|
|
|
self.clipsToBounds = YES;
|
2019-12-11 00:25:53 +01:00
|
|
|
|
2018-06-29 17:31:22 +02:00
|
|
|
CAShapeLayer *maskLayer = [CAShapeLayer new];
|
2018-07-07 00:32:46 +02:00
|
|
|
OWSDirectionalRectCorner sharpCorners = self.sharpCorners;
|
2018-07-06 22:45:00 +02:00
|
|
|
|
2018-06-29 17:31:22 +02:00
|
|
|
OWSLayerView *innerBubbleView = [[OWSLayerView alloc]
|
|
|
|
initWithFrame:CGRectZero
|
|
|
|
layoutCallback:^(UIView *layerView) {
|
|
|
|
CGRect layerFrame = layerView.bounds;
|
|
|
|
|
2018-07-06 22:45:00 +02:00
|
|
|
const CGFloat bubbleLeft = 0.f;
|
|
|
|
const CGFloat bubbleRight = layerFrame.size.width;
|
|
|
|
const CGFloat bubbleTop = 0.f;
|
|
|
|
const CGFloat bubbleBottom = layerFrame.size.height;
|
|
|
|
|
2019-12-11 00:25:53 +01:00
|
|
|
const CGFloat sharpCornerRadius = 2;
|
2019-12-10 05:11:46 +01:00
|
|
|
const CGFloat wideCornerRadius = self.isForPreview ? 14 : 4;
|
2018-07-06 22:45:00 +02:00
|
|
|
|
2018-07-07 00:13:25 +02:00
|
|
|
UIBezierPath *bezierPath = [OWSBubbleView roundedBezierRectWithBubbleTop:bubbleTop
|
|
|
|
bubbleLeft:bubbleLeft
|
|
|
|
bubbleBottom:bubbleBottom
|
|
|
|
bubbleRight:bubbleRight
|
|
|
|
sharpCornerRadius:sharpCornerRadius
|
|
|
|
wideCornerRadius:wideCornerRadius
|
|
|
|
sharpCorners:sharpCorners];
|
2018-06-29 17:31:22 +02:00
|
|
|
|
|
|
|
maskLayer.path = bezierPath.CGPath;
|
|
|
|
}];
|
|
|
|
innerBubbleView.layer.mask = maskLayer;
|
2019-01-28 20:45:31 +01:00
|
|
|
if (self.isForPreview) {
|
2019-12-10 05:11:46 +01:00
|
|
|
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
|
|
|
|
BOOL wasSentByUser = [self.quotedMessage.authorId isEqual:userHexEncodedPublicKey];
|
|
|
|
innerBubbleView.backgroundColor = [self.conversationStyle quotedReplyBubbleColorWithIsIncoming:wasSentByUser];
|
2019-01-28 20:45:31 +01:00
|
|
|
} else {
|
|
|
|
innerBubbleView.backgroundColor = self.quoteBubbleBackgroundColor;
|
|
|
|
}
|
2018-06-29 17:31:22 +02:00
|
|
|
[self addSubview:innerBubbleView];
|
|
|
|
[innerBubbleView autoPinLeadingToSuperviewMarginWithInset:self.bubbleHMargin];
|
|
|
|
[innerBubbleView autoPinTrailingToSuperviewMarginWithInset:self.bubbleHMargin];
|
2018-06-29 18:00:10 +02:00
|
|
|
[innerBubbleView autoPinTopToSuperviewMargin];
|
2018-06-29 17:31:22 +02:00
|
|
|
[innerBubbleView autoPinBottomToSuperviewMargin];
|
2019-01-25 17:33:09 +01:00
|
|
|
[innerBubbleView setContentHuggingHorizontalLow];
|
|
|
|
[innerBubbleView setCompressionResistanceHorizontalLow];
|
2018-06-29 17:31:22 +02:00
|
|
|
|
|
|
|
UIStackView *hStackView = [UIStackView new];
|
|
|
|
hStackView.axis = UILayoutConstraintAxisHorizontal;
|
|
|
|
hStackView.spacing = self.hSpacing;
|
|
|
|
|
|
|
|
UIView *stripeView = [UIView new];
|
2019-01-25 22:48:54 +01:00
|
|
|
if (self.isForPreview) {
|
2019-12-10 05:11:46 +01:00
|
|
|
stripeView.backgroundColor = LKColors.accent;
|
2019-01-25 22:48:54 +01:00
|
|
|
} else {
|
|
|
|
stripeView.backgroundColor = [self.conversationStyle quotedReplyStripeColorWithIsIncoming:!self.isOutgoing];
|
|
|
|
}
|
2018-06-29 18:00:10 +02:00
|
|
|
[stripeView autoSetDimension:ALDimensionWidth toSize:self.stripeThickness];
|
2018-06-29 17:31:22 +02:00
|
|
|
[stripeView setContentHuggingHigh];
|
|
|
|
[stripeView setCompressionResistanceHigh];
|
|
|
|
[hStackView addArrangedSubview:stripeView];
|
|
|
|
|
|
|
|
UIStackView *vStackView = [UIStackView new];
|
|
|
|
vStackView.axis = UILayoutConstraintAxisVertical;
|
2018-06-29 18:00:10 +02:00
|
|
|
vStackView.layoutMargins = UIEdgeInsetsMake(self.textVMargin, 0, self.textVMargin, 0);
|
2018-06-29 17:31:22 +02:00
|
|
|
vStackView.layoutMarginsRelativeArrangement = YES;
|
2018-07-02 21:02:36 +02:00
|
|
|
vStackView.spacing = self.vSpacing;
|
2019-01-25 23:06:05 +01:00
|
|
|
[vStackView setContentHuggingHorizontalLow];
|
|
|
|
[vStackView setCompressionResistanceHorizontalLow];
|
2018-06-29 17:31:22 +02:00
|
|
|
[hStackView addArrangedSubview:vStackView];
|
|
|
|
|
|
|
|
UILabel *quotedAuthorLabel = [self configureQuotedAuthorLabel];
|
|
|
|
[vStackView addArrangedSubview:quotedAuthorLabel];
|
|
|
|
[quotedAuthorLabel autoSetDimension:ALDimensionHeight toSize:self.quotedAuthorHeight];
|
|
|
|
[quotedAuthorLabel setContentHuggingVerticalHigh];
|
|
|
|
[quotedAuthorLabel setContentHuggingHorizontalLow];
|
|
|
|
[quotedAuthorLabel setCompressionResistanceHorizontalLow];
|
|
|
|
|
|
|
|
UILabel *quotedTextLabel = [self configureQuotedTextLabel];
|
|
|
|
[vStackView addArrangedSubview:quotedTextLabel];
|
2019-01-28 21:51:54 +01:00
|
|
|
[quotedTextLabel setContentHuggingHorizontalLow];
|
|
|
|
[quotedTextLabel setCompressionResistanceHorizontalLow];
|
|
|
|
[quotedTextLabel setCompressionResistanceVerticalHigh];
|
2018-04-04 20:56:48 +02:00
|
|
|
|
2018-04-04 21:45:35 +02:00
|
|
|
if (self.hasQuotedAttachment) {
|
2018-06-29 17:31:22 +02:00
|
|
|
UIView *_Nullable quotedAttachmentView = nil;
|
2018-04-04 22:40:28 +02:00
|
|
|
UIImage *_Nullable thumbnailImage = [self tryToLoadThumbnailImage];
|
|
|
|
if (thumbnailImage) {
|
|
|
|
quotedAttachmentView = [self imageViewForImage:thumbnailImage];
|
2018-04-04 23:33:11 +02:00
|
|
|
quotedAttachmentView.clipsToBounds = YES;
|
2018-04-11 19:47:12 +02:00
|
|
|
quotedAttachmentView.backgroundColor = [UIColor whiteColor];
|
2018-04-16 21:36:02 +02:00
|
|
|
|
|
|
|
if (self.isVideoAttachment) {
|
2019-12-12 04:26:23 +01:00
|
|
|
UIImage *contentIcon = [UIImage imageNamed:@"Play"];
|
2018-04-16 21:36:02 +02:00
|
|
|
contentIcon = [contentIcon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
|
|
|
UIImageView *contentImageView = [self imageViewForImage:contentIcon];
|
2019-12-12 04:26:23 +01:00
|
|
|
contentImageView.tintColor = LKColors.text;
|
2018-04-16 21:36:02 +02:00
|
|
|
[quotedAttachmentView addSubview:contentImageView];
|
2019-12-12 04:26:23 +01:00
|
|
|
[contentImageView autoSetDimension:ALDimensionWidth toSize:16];
|
|
|
|
[contentImageView autoSetDimension:ALDimensionHeight toSize:16];
|
2018-04-16 21:36:02 +02:00
|
|
|
[contentImageView autoCenterInSuperview];
|
|
|
|
}
|
2018-04-16 19:50:54 +02:00
|
|
|
} else if (self.quotedMessage.thumbnailDownloadFailed) {
|
|
|
|
// TODO design review icon and color
|
|
|
|
UIImage *contentIcon =
|
|
|
|
[[UIImage imageNamed:@"btnRefresh--white"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
|
|
|
UIImageView *contentImageView = [self imageViewForImage:contentIcon];
|
|
|
|
contentImageView.contentMode = UIViewContentModeScaleAspectFit;
|
|
|
|
contentImageView.tintColor = UIColor.whiteColor;
|
2018-06-29 17:31:22 +02:00
|
|
|
|
2018-04-16 19:50:54 +02:00
|
|
|
quotedAttachmentView = [UIView containerView];
|
|
|
|
[quotedAttachmentView addSubview:contentImageView];
|
|
|
|
quotedAttachmentView.backgroundColor = self.highlightColor;
|
|
|
|
[contentImageView autoCenterInSuperview];
|
|
|
|
[contentImageView
|
|
|
|
autoSetDimensionsToSize:CGSizeMake(self.quotedAttachmentSize * 0.5f, self.quotedAttachmentSize * 0.5f)];
|
|
|
|
|
|
|
|
UITapGestureRecognizer *tapGesture =
|
|
|
|
[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapFailedThumbnailDownload:)];
|
|
|
|
[quotedAttachmentView addGestureRecognizer:tapGesture];
|
2018-06-29 17:31:22 +02:00
|
|
|
quotedAttachmentView.userInteractionEnabled = YES;
|
2018-04-04 22:40:28 +02:00
|
|
|
} else {
|
2018-06-29 17:31:22 +02:00
|
|
|
UIImage *contentIcon = [UIImage imageNamed:@"generic-attachment"];
|
2018-04-16 21:36:02 +02:00
|
|
|
UIImageView *contentImageView = [self imageViewForImage:contentIcon];
|
2018-06-29 17:31:22 +02:00
|
|
|
contentImageView.contentMode = UIViewContentModeScaleAspectFit;
|
|
|
|
|
|
|
|
UIView *wrapper = [UIView containerView];
|
|
|
|
[wrapper addSubview:contentImageView];
|
2018-04-04 22:40:28 +02:00
|
|
|
[contentImageView autoCenterInSuperview];
|
2018-06-29 18:00:10 +02:00
|
|
|
[contentImageView autoSetDimension:ALDimensionWidth toSize:self.quotedAttachmentSize * 0.5f];
|
2018-06-29 17:31:22 +02:00
|
|
|
quotedAttachmentView = wrapper;
|
2018-04-04 22:40:28 +02:00
|
|
|
}
|
|
|
|
|
2019-01-25 23:06:05 +01:00
|
|
|
[quotedAttachmentView autoPinToSquareAspectRatio];
|
2018-04-04 17:31:33 +02:00
|
|
|
[quotedAttachmentView setContentHuggingHigh];
|
|
|
|
[quotedAttachmentView setCompressionResistanceHigh];
|
2018-06-29 17:31:22 +02:00
|
|
|
[hStackView addArrangedSubview:quotedAttachmentView];
|
|
|
|
} else {
|
2018-06-29 23:09:51 +02:00
|
|
|
// If there's no attachment, add an empty view so that
|
|
|
|
// the stack view's spacing serves as a margin between
|
|
|
|
// the text views and the trailing edge.
|
2018-06-29 17:31:22 +02:00
|
|
|
UIView *emptyView = [UIView containerView];
|
|
|
|
[hStackView addArrangedSubview:emptyView];
|
|
|
|
[emptyView setContentHuggingHigh];
|
|
|
|
[emptyView autoSetDimension:ALDimensionWidth toSize:0.f];
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
2018-08-10 18:36:07 +02:00
|
|
|
|
2019-01-28 21:51:54 +01:00
|
|
|
UIView *contentView = hStackView;
|
|
|
|
[contentView setContentHuggingHorizontalLow];
|
|
|
|
[contentView setCompressionResistanceHorizontalLow];
|
2018-08-10 18:36:07 +02:00
|
|
|
|
|
|
|
if (self.quotedMessage.isRemotelySourced) {
|
2019-01-28 21:51:54 +01:00
|
|
|
UIStackView *quoteSourceWrapper = [[UIStackView alloc] initWithArrangedSubviews:@[
|
|
|
|
contentView,
|
|
|
|
[self buildRemoteContentSourceView],
|
|
|
|
]];
|
|
|
|
quoteSourceWrapper.axis = UILayoutConstraintAxisVertical;
|
|
|
|
contentView = quoteSourceWrapper;
|
|
|
|
[contentView setContentHuggingHorizontalLow];
|
|
|
|
[contentView setCompressionResistanceHorizontalLow];
|
2018-08-10 18:36:07 +02:00
|
|
|
}
|
|
|
|
|
2019-01-28 21:51:54 +01:00
|
|
|
if (self.isForPreview) {
|
|
|
|
UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
2019-12-10 05:11:46 +01:00
|
|
|
[cancelButton setImage:[UIImage imageNamed:@"X"] forState:UIControlStateNormal];
|
2019-12-11 00:25:53 +01:00
|
|
|
cancelButton.contentMode = UIViewContentModeScaleAspectFit;
|
2019-01-28 21:51:54 +01:00
|
|
|
[cancelButton addTarget:self action:@selector(didTapCancel) forControlEvents:UIControlEventTouchUpInside];
|
2019-12-11 00:25:53 +01:00
|
|
|
[cancelButton autoSetDimension:ALDimensionWidth toSize:14.f];
|
|
|
|
[cancelButton autoSetDimension:ALDimensionHeight toSize:14.f];
|
2019-01-28 21:51:54 +01:00
|
|
|
|
|
|
|
UIStackView *cancelStack = [[UIStackView alloc] initWithArrangedSubviews:@[ cancelButton ]];
|
|
|
|
cancelStack.axis = UILayoutConstraintAxisHorizontal;
|
|
|
|
cancelStack.alignment = UIStackViewAlignmentTop;
|
|
|
|
cancelStack.layoutMarginsRelativeArrangement = YES;
|
2019-12-11 00:25:53 +01:00
|
|
|
CGFloat hMarginLeading = 8;
|
|
|
|
CGFloat hMarginTrailing = 8;
|
|
|
|
cancelStack.layoutMargins = UIEdgeInsetsMake(8,
|
2019-01-28 21:51:54 +01:00
|
|
|
CurrentAppContext().isRTL ? hMarginTrailing : hMarginLeading,
|
|
|
|
0,
|
|
|
|
CurrentAppContext().isRTL ? hMarginLeading : hMarginTrailing);
|
|
|
|
|
|
|
|
UIStackView *cancelWrapper = [[UIStackView alloc] initWithArrangedSubviews:@[
|
|
|
|
contentView,
|
|
|
|
cancelStack,
|
|
|
|
]];
|
|
|
|
cancelWrapper.axis = UILayoutConstraintAxisHorizontal;
|
|
|
|
|
|
|
|
contentView = cancelWrapper;
|
|
|
|
[contentView setContentHuggingHorizontalLow];
|
|
|
|
[contentView setCompressionResistanceHorizontalLow];
|
|
|
|
}
|
|
|
|
|
|
|
|
[innerBubbleView addSubview:contentView];
|
|
|
|
[contentView ows_autoPinToSuperviewEdges];
|
2018-08-10 18:36:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIView *)buildRemoteContentSourceView
|
|
|
|
{
|
|
|
|
UIImage *glyphImage =
|
|
|
|
[[UIImage imageNamed:@"ic_broken_link"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(glyphImage);
|
|
|
|
OWSAssertDebug(CGSizeEqualToSize(
|
2018-08-10 18:36:07 +02:00
|
|
|
CGSizeMake(kRemotelySourcedContentGlyphLength, kRemotelySourcedContentGlyphLength), glyphImage.size));
|
|
|
|
UIImageView *glyphView = [[UIImageView alloc] initWithImage:glyphImage];
|
2019-12-11 00:25:53 +01:00
|
|
|
glyphView.tintColor = LKColors.text;
|
2018-08-10 18:36:07 +02:00
|
|
|
[glyphView
|
|
|
|
autoSetDimensionsToSize:CGSizeMake(kRemotelySourcedContentGlyphLength, kRemotelySourcedContentGlyphLength)];
|
|
|
|
|
|
|
|
UILabel *label = [self configureQuoteContentSourceLabel];
|
|
|
|
UIStackView *sourceRow = [[UIStackView alloc] initWithArrangedSubviews:@[ glyphView, label ]];
|
|
|
|
sourceRow.axis = UILayoutConstraintAxisHorizontal;
|
|
|
|
sourceRow.alignment = UIStackViewAlignmentCenter;
|
|
|
|
// TODO verify spacing w/ design
|
|
|
|
sourceRow.spacing = kRemotelySourcedContentRowSpacing;
|
|
|
|
sourceRow.layoutMarginsRelativeArrangement = YES;
|
|
|
|
|
2019-12-11 00:25:53 +01:00
|
|
|
const CGFloat leftMargin = 4;
|
2018-08-10 18:36:07 +02:00
|
|
|
sourceRow.layoutMargins = UIEdgeInsetsMake(kRemotelySourcedContentRowMargin,
|
|
|
|
leftMargin,
|
|
|
|
kRemotelySourcedContentRowMargin,
|
|
|
|
kRemotelySourcedContentRowMargin);
|
|
|
|
|
2019-12-11 00:25:53 +01:00
|
|
|
UIColor *backgroundColor = [LKColors.text colorWithAlphaComponent:LKValues.unimportantElementOpacity];
|
2018-08-10 18:36:07 +02:00
|
|
|
[sourceRow addBackgroundViewWithBackgroundColor:backgroundColor];
|
|
|
|
|
|
|
|
return sourceRow;
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-16 19:50:54 +02:00
|
|
|
- (void)didTapFailedThumbnailDownload:(UITapGestureRecognizer *)gestureRecognizer
|
|
|
|
{
|
2018-08-27 18:51:32 +02:00
|
|
|
OWSLogDebug(@"in didTapFailedThumbnailDownload");
|
2018-04-16 19:50:54 +02:00
|
|
|
|
|
|
|
if (!self.quotedMessage.thumbnailDownloadFailed) {
|
2018-08-27 18:12:53 +02:00
|
|
|
OWSFailDebug(@"thumbnailDownloadFailed was unexpectedly false");
|
2018-04-16 19:50:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!self.quotedMessage.thumbnailAttachmentPointer) {
|
2018-08-27 18:12:53 +02:00
|
|
|
OWSFailDebug(@"thumbnailAttachmentPointer was unexpectedly nil");
|
2018-04-16 19:50:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
[self.delegate didTapQuotedReply:self.quotedMessage
|
|
|
|
failedThumbnailDownloadAttachmentPointer:self.quotedMessage.thumbnailAttachmentPointer];
|
|
|
|
}
|
|
|
|
|
2018-04-04 22:40:28 +02:00
|
|
|
- (nullable UIImage *)tryToLoadThumbnailImage
|
|
|
|
{
|
2018-04-05 16:57:51 +02:00
|
|
|
if (!self.hasQuotedAttachmentThumbnailImage) {
|
2018-04-04 22:40:28 +02:00
|
|
|
return nil;
|
|
|
|
}
|
2018-04-06 16:59:23 +02:00
|
|
|
|
2018-04-06 22:53:16 +02:00
|
|
|
// TODO: Possibly ignore data that is too large.
|
|
|
|
UIImage *_Nullable image = self.quotedMessage.thumbnailImage;
|
|
|
|
// TODO: Possibly ignore images that are too large.
|
|
|
|
return image;
|
2018-04-04 22:40:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIImageView *)imageViewForImage:(UIImage *)image
|
|
|
|
{
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(image);
|
2018-04-04 22:40:28 +02:00
|
|
|
|
|
|
|
UIImageView *imageView = [UIImageView new];
|
|
|
|
imageView.image = image;
|
|
|
|
// We need to specify a contentMode since the size of the image
|
|
|
|
// might not match the aspect ratio of the view.
|
|
|
|
imageView.contentMode = UIViewContentModeScaleAspectFill;
|
|
|
|
// Use trilinear filters for better scaling quality at
|
|
|
|
// some performance cost.
|
|
|
|
imageView.layer.minificationFilter = kCAFilterTrilinear;
|
|
|
|
imageView.layer.magnificationFilter = kCAFilterTrilinear;
|
|
|
|
return imageView;
|
|
|
|
}
|
|
|
|
|
2018-04-12 00:15:38 +02:00
|
|
|
- (UILabel *)configureQuotedTextLabel
|
2018-04-04 23:33:11 +02:00
|
|
|
{
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(self.quotedTextLabel);
|
2018-04-12 00:15:38 +02:00
|
|
|
|
2018-04-04 23:33:11 +02:00
|
|
|
UIColor *textColor = self.quotedTextColor;
|
2018-07-18 04:20:31 +02:00
|
|
|
SUPPRESS_DEADSTORE_WARNING(textColor);
|
2018-04-04 23:33:11 +02:00
|
|
|
UIFont *font = self.quotedTextFont;
|
2018-07-18 04:20:31 +02:00
|
|
|
SUPPRESS_DEADSTORE_WARNING(font);
|
2018-04-04 23:33:11 +02:00
|
|
|
NSString *text = @"";
|
|
|
|
|
|
|
|
NSString *_Nullable fileTypeForSnippet = [self fileTypeForSnippet];
|
2018-04-06 16:59:23 +02:00
|
|
|
NSString *_Nullable sourceFilename = [self.quotedMessage.sourceFilename filterStringForDisplay];
|
2018-04-04 23:33:11 +02:00
|
|
|
|
|
|
|
if (self.displayableQuotedText.displayText.length > 0) {
|
|
|
|
text = self.displayableQuotedText.displayText;
|
|
|
|
textColor = self.quotedTextColor;
|
|
|
|
font = self.quotedTextFont;
|
|
|
|
} else if (fileTypeForSnippet) {
|
|
|
|
text = fileTypeForSnippet;
|
|
|
|
textColor = self.fileTypeTextColor;
|
|
|
|
font = self.fileTypeFont;
|
|
|
|
} else if (sourceFilename) {
|
|
|
|
text = sourceFilename;
|
|
|
|
textColor = self.filenameTextColor;
|
|
|
|
font = self.filenameFont;
|
2018-04-05 17:15:00 +02:00
|
|
|
} else {
|
|
|
|
text = NSLocalizedString(
|
|
|
|
@"QUOTED_REPLY_TYPE_ATTACHMENT", @"Indicates this message is a quoted reply to an attachment of unknown type.");
|
|
|
|
textColor = self.fileTypeTextColor;
|
|
|
|
font = self.fileTypeFont;
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
|
2018-06-29 19:18:23 +02:00
|
|
|
self.quotedTextLabel.numberOfLines = self.isForPreview ? 1 : 2;
|
2018-04-12 00:15:38 +02:00
|
|
|
self.quotedTextLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
|
|
|
self.quotedTextLabel.text = text;
|
|
|
|
self.quotedTextLabel.textColor = textColor;
|
|
|
|
self.quotedTextLabel.font = font;
|
2018-04-04 23:33:11 +02:00
|
|
|
|
2018-04-12 00:15:38 +02:00
|
|
|
return self.quotedTextLabel;
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
|
2018-08-10 18:36:07 +02:00
|
|
|
- (UILabel *)configureQuoteContentSourceLabel
|
|
|
|
{
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(self.quoteContentSourceLabel);
|
2018-08-10 18:36:07 +02:00
|
|
|
|
2019-12-11 00:25:53 +01:00
|
|
|
self.quoteContentSourceLabel.font = [UIFont systemFontOfSize:LKValues.smallFontSize];
|
|
|
|
self.quoteContentSourceLabel.textColor = LKColors.text;
|
2018-08-10 18:36:07 +02:00
|
|
|
self.quoteContentSourceLabel.text = NSLocalizedString(@"QUOTED_REPLY_CONTENT_FROM_REMOTE_SOURCE",
|
2018-09-27 02:09:34 +02:00
|
|
|
@"Footer label that appears below quoted messages when the quoted content was not derived locally. When the "
|
2018-08-10 18:36:07 +02:00
|
|
|
@"local user doesn't have a copy of the message being quoted, e.g. if it had since been deleted, we instead "
|
|
|
|
@"show the content specified by the sender.");
|
|
|
|
|
|
|
|
return self.quoteContentSourceLabel;
|
|
|
|
}
|
|
|
|
|
2018-04-04 23:33:11 +02:00
|
|
|
- (nullable NSString *)fileTypeForSnippet
|
|
|
|
{
|
|
|
|
// TODO: Are we going to use the filename? For all mimetypes?
|
|
|
|
NSString *_Nullable contentType = self.quotedMessage.contentType;
|
2018-04-05 17:15:00 +02:00
|
|
|
if (contentType.length < 1) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([MIMETypeUtil isAudio:contentType]) {
|
|
|
|
return NSLocalizedString(
|
|
|
|
@"QUOTED_REPLY_TYPE_AUDIO", @"Indicates this message is a quoted reply to an audio file.");
|
|
|
|
} else if ([MIMETypeUtil isVideo:contentType]) {
|
|
|
|
return NSLocalizedString(
|
|
|
|
@"QUOTED_REPLY_TYPE_VIDEO", @"Indicates this message is a quoted reply to a video file.");
|
2018-04-09 21:13:07 +02:00
|
|
|
} else if ([MIMETypeUtil isImage:contentType]) {
|
2018-04-04 23:33:11 +02:00
|
|
|
return NSLocalizedString(
|
|
|
|
@"QUOTED_REPLY_TYPE_IMAGE", @"Indicates this message is a quoted reply to an image file.");
|
2018-04-09 21:13:07 +02:00
|
|
|
} else if ([MIMETypeUtil isAnimated:contentType]) {
|
|
|
|
return NSLocalizedString(
|
|
|
|
@"QUOTED_REPLY_TYPE_GIF", @"Indicates this message is a quoted reply to animated GIF file.");
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2018-04-16 21:36:02 +02:00
|
|
|
- (BOOL)isAudioAttachment
|
|
|
|
{
|
|
|
|
// TODO: Are we going to use the filename? For all mimetypes?
|
|
|
|
NSString *_Nullable contentType = self.quotedMessage.contentType;
|
|
|
|
if (contentType.length < 1) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [MIMETypeUtil isAudio:contentType];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isVideoAttachment
|
|
|
|
{
|
|
|
|
// TODO: Are we going to use the filename? For all mimetypes?
|
|
|
|
NSString *_Nullable contentType = self.quotedMessage.contentType;
|
|
|
|
if (contentType.length < 1) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [MIMETypeUtil isVideo:contentType];
|
|
|
|
}
|
|
|
|
|
2018-04-12 00:15:38 +02:00
|
|
|
- (UILabel *)configureQuotedAuthorLabel
|
2018-04-04 23:33:11 +02:00
|
|
|
{
|
2018-09-06 19:01:24 +02:00
|
|
|
OWSAssertDebug(self.quotedAuthorLabel);
|
2018-04-12 00:15:38 +02:00
|
|
|
|
2018-04-11 17:47:33 +02:00
|
|
|
NSString *_Nullable localNumber = [TSAccountManager localNumber];
|
|
|
|
NSString *quotedAuthorText;
|
|
|
|
if ([localNumber isEqualToString:self.quotedMessage.authorId]) {
|
2018-04-12 01:20:27 +02:00
|
|
|
|
|
|
|
if (self.isOutgoing) {
|
2019-12-11 00:25:53 +01:00
|
|
|
quotedAuthorText = NSLocalizedString(@"You", @"");
|
2018-04-12 01:20:27 +02:00
|
|
|
} else {
|
2019-12-11 00:25:53 +01:00
|
|
|
quotedAuthorText = NSLocalizedString(@"You", @"");
|
2018-04-12 01:20:27 +02:00
|
|
|
}
|
2018-04-11 17:47:33 +02:00
|
|
|
} else {
|
2018-08-31 19:16:31 +02:00
|
|
|
OWSContactsManager *contactsManager = Environment.shared.contactsManager;
|
2019-09-11 08:25:33 +02:00
|
|
|
__block NSString *quotedAuthor = [contactsManager contactOrProfileNameForPhoneIdentifier:self.quotedMessage.authorId];
|
|
|
|
|
|
|
|
if (quotedAuthor == self.quotedMessage.authorId) {
|
|
|
|
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
2019-10-15 01:29:41 +02:00
|
|
|
LKPublicChat *publicChat = [LKDatabaseUtilities getPublicChatForThreadID:self.quotedMessage.threadId transaction:transaction];
|
|
|
|
if (publicChat != nil) {
|
|
|
|
quotedAuthor = [LKDisplayNameUtilities getPublicChatDisplayNameFor:self.quotedMessage.authorId in:publicChat.channel on:publicChat.server using:transaction];
|
2019-10-14 05:40:18 +02:00
|
|
|
} else {
|
|
|
|
quotedAuthor = [LKDisplayNameUtilities getPrivateChatDisplayNameFor:self.quotedMessage.authorId];
|
2019-10-09 03:40:39 +02:00
|
|
|
}
|
2019-09-11 08:25:33 +02:00
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2019-12-10 05:11:46 +01:00
|
|
|
quotedAuthorText = quotedAuthor;
|
2018-04-11 17:47:33 +02:00
|
|
|
}
|
2018-04-04 23:33:11 +02:00
|
|
|
|
2018-04-12 00:15:38 +02:00
|
|
|
self.quotedAuthorLabel.text = quotedAuthorText;
|
|
|
|
self.quotedAuthorLabel.font = self.quotedAuthorFont;
|
2018-06-29 17:31:22 +02:00
|
|
|
// TODO:
|
2018-04-12 00:15:38 +02:00
|
|
|
self.quotedAuthorLabel.textColor = [self quotedAuthorColor];
|
|
|
|
self.quotedAuthorLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
|
|
|
self.quotedAuthorLabel.numberOfLines = 1;
|
|
|
|
|
|
|
|
return self.quotedAuthorLabel;
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
#pragma mark - Measurement
|
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
- (CGFloat)textVMargin
|
|
|
|
{
|
|
|
|
return 7.f;
|
|
|
|
}
|
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
- (CGSize)sizeForMaxWidth:(CGFloat)maxWidth
|
|
|
|
{
|
|
|
|
CGSize result = CGSizeZero;
|
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
result.width += self.bubbleHMargin * 2 + self.stripeThickness + self.hSpacing * 2;
|
2018-04-04 17:31:33 +02:00
|
|
|
|
|
|
|
CGFloat thumbnailHeight = 0.f;
|
2018-04-04 21:45:35 +02:00
|
|
|
if (self.hasQuotedAttachment) {
|
2018-04-04 17:31:33 +02:00
|
|
|
result.width += self.quotedAttachmentSize;
|
|
|
|
|
|
|
|
thumbnailHeight += self.quotedAttachmentSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Quoted Author
|
2018-06-29 18:00:10 +02:00
|
|
|
CGFloat textWidth = 0.f;
|
|
|
|
CGFloat maxTextWidth = maxWidth - result.width;
|
2018-07-02 21:02:36 +02:00
|
|
|
CGFloat textHeight = self.textVMargin * 2 + self.quotedAuthorHeight + self.vSpacing;
|
2018-04-04 17:31:33 +02:00
|
|
|
{
|
2018-04-12 00:15:38 +02:00
|
|
|
UILabel *quotedAuthorLabel = [self configureQuotedAuthorLabel];
|
2018-04-04 17:31:33 +02:00
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
CGSize quotedAuthorSize = CGSizeCeil([quotedAuthorLabel sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)]);
|
|
|
|
textWidth = quotedAuthorSize.width;
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2018-04-12 00:15:38 +02:00
|
|
|
UILabel *quotedTextLabel = [self configureQuotedTextLabel];
|
2018-04-04 17:31:33 +02:00
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
CGSize textSize = CGSizeCeil([quotedTextLabel sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)]);
|
|
|
|
textWidth = MAX(textWidth, textSize.width);
|
|
|
|
textHeight += textSize.height;
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
2018-08-10 18:36:07 +02:00
|
|
|
if (self.quotedMessage.isRemotelySourced) {
|
|
|
|
UILabel *quoteContentSourceLabel = [self configureQuoteContentSourceLabel];
|
|
|
|
CGSize textSize = CGSizeCeil([quoteContentSourceLabel sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)]);
|
|
|
|
CGFloat sourceStackViewHeight = MAX(kRemotelySourcedContentGlyphLength, textSize.height);
|
|
|
|
|
|
|
|
textWidth
|
|
|
|
= MAX(textWidth, textSize.width + kRemotelySourcedContentGlyphLength + kRemotelySourcedContentRowSpacing);
|
|
|
|
result.height += kRemotelySourcedContentRowMargin * 2 + sourceStackViewHeight;
|
|
|
|
}
|
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
textWidth = MIN(textWidth, maxTextWidth);
|
2018-04-04 17:31:33 +02:00
|
|
|
result.width += textWidth;
|
2018-06-29 18:00:10 +02:00
|
|
|
result.height += MAX(textHeight, thumbnailHeight);
|
2018-04-04 17:31:33 +02:00
|
|
|
|
2018-06-29 18:00:10 +02:00
|
|
|
return CGSizeCeil(result);
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-04 23:33:11 +02:00
|
|
|
- (UIFont *)quotedAuthorFont
|
2018-04-04 17:31:33 +02:00
|
|
|
{
|
2019-12-10 05:11:46 +01:00
|
|
|
return [UIFont boldSystemFontOfSize:LKValues.smallFontSize];
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
2018-04-04 17:31:33 +02:00
|
|
|
|
2018-04-04 23:33:11 +02:00
|
|
|
- (UIColor *)quotedAuthorColor
|
|
|
|
{
|
2018-07-09 15:58:02 +02:00
|
|
|
return [self.conversationStyle quotedReplyAuthorColor];
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIColor *)quotedTextColor
|
|
|
|
{
|
2018-07-09 15:58:02 +02:00
|
|
|
return [self.conversationStyle quotedReplyTextColor];
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-04 23:33:11 +02:00
|
|
|
- (UIFont *)quotedTextFont
|
2018-04-04 17:31:33 +02:00
|
|
|
{
|
2019-12-10 05:11:46 +01:00
|
|
|
return [UIFont systemFontOfSize:LKValues.mediumFontSize];
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIColor *)fileTypeTextColor
|
|
|
|
{
|
2018-07-09 15:58:02 +02:00
|
|
|
return [self.conversationStyle quotedReplyAttachmentColor];
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIFont *)fileTypeFont
|
|
|
|
{
|
2019-12-11 04:07:27 +01:00
|
|
|
return self.quotedTextFont;
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIColor *)filenameTextColor
|
|
|
|
{
|
2018-07-09 15:58:02 +02:00
|
|
|
return [self.conversationStyle quotedReplyAttachmentColor];
|
2018-04-04 23:33:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIFont *)filenameFont
|
|
|
|
{
|
|
|
|
return self.quotedTextFont;
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (CGFloat)quotedAuthorHeight
|
|
|
|
{
|
|
|
|
return (CGFloat)ceil([self quotedAuthorFont].lineHeight * 1.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGFloat)quotedAttachmentSize
|
|
|
|
{
|
2018-06-29 18:00:10 +02:00
|
|
|
return 54.f;
|
2018-04-04 17:31:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-04 21:45:35 +02:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
- (CGSize)sizeThatFits:(CGSize)size
|
|
|
|
{
|
|
|
|
return [self sizeForMaxWidth:CGFLOAT_MAX];
|
|
|
|
}
|
|
|
|
|
2019-01-28 21:51:54 +01:00
|
|
|
- (void)didTapCancel
|
|
|
|
{
|
|
|
|
[self.delegate didCancelQuotedReply];
|
|
|
|
}
|
|
|
|
|
2018-04-04 17:31:33 +02:00
|
|
|
@end
|
|
|
|
|
|
|
|
NS_ASSUME_NONNULL_END
|