mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge branch 'charlesmchen/tweakNonMedia'
This commit is contained in:
commit
bcc0888745
17 changed files with 302 additions and 287 deletions
23
Signal/Images.xcassets/generic-attachment.imageset/Contents.json
vendored
Normal file
23
Signal/Images.xcassets/generic-attachment.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "File@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "File@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "File@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Signal/Images.xcassets/generic-attachment.imageset/File@1x.png
vendored
Normal file
BIN
Signal/Images.xcassets/generic-attachment.imageset/File@1x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 808 B |
BIN
Signal/Images.xcassets/generic-attachment.imageset/File@2x.png
vendored
Normal file
BIN
Signal/Images.xcassets/generic-attachment.imageset/File@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
Signal/Images.xcassets/generic-attachment.imageset/File@3x.png
vendored
Normal file
BIN
Signal/Images.xcassets/generic-attachment.imageset/File@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3 KiB |
|
@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@class ConversationViewItem;
|
||||
@class TSAttachmentStream;
|
||||
|
||||
@interface OWSAudioMessageView : UIView
|
||||
@interface OWSAudioMessageView : UIStackView
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream
|
||||
isIncoming:(BOOL)isIncoming
|
||||
|
|
|
@ -93,13 +93,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (void)setAudioIcon:(UIImage *)icon iconColor:(UIColor *)iconColor
|
||||
{
|
||||
OWSAssert(icon.size.height == self.iconSize);
|
||||
|
||||
icon = [icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
[_audioPlayPauseButton setImage:icon forState:UIControlStateNormal];
|
||||
[_audioPlayPauseButton setImage:icon forState:UIControlStateDisabled];
|
||||
_audioPlayPauseButton.imageView.tintColor = self.bubbleBackgroundColor;
|
||||
_audioPlayPauseButton.backgroundColor = iconColor;
|
||||
_audioPlayPauseButton.layer.cornerRadius
|
||||
= MIN(_audioPlayPauseButton.bounds.size.width, _audioPlayPauseButton.bounds.size.height) * 0.5f;
|
||||
_audioPlayPauseButton.layer.cornerRadius = self.iconSize * 0.5f;
|
||||
}
|
||||
|
||||
- (void)setAudioIconToPlay
|
||||
|
@ -127,29 +128,33 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (CGFloat)audioIconHMargin
|
||||
- (CGFloat)hMargin
|
||||
{
|
||||
return 12.f;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
- (CGFloat)audioIconHSpacing
|
||||
- (CGFloat)hSpacing
|
||||
{
|
||||
return 8.f;
|
||||
}
|
||||
|
||||
+ (CGFloat)audioIconVMargin
|
||||
+ (CGFloat)vMargin
|
||||
{
|
||||
return 12.f;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
- (CGFloat)audioIconVMargin
|
||||
- (CGFloat)vMargin
|
||||
{
|
||||
return [OWSAudioMessageView audioIconVMargin];
|
||||
return [OWSAudioMessageView vMargin];
|
||||
}
|
||||
|
||||
+ (CGFloat)bubbleHeight
|
||||
{
|
||||
return self.iconSize + self.audioIconVMargin * 2;
|
||||
CGFloat iconHeight = self.iconSize;
|
||||
CGFloat labelsHeight = ([OWSAudioMessageView labelFont].lineHeight * 2 +
|
||||
[OWSAudioMessageView audioProgressViewHeight] + [OWSAudioMessageView labelVSpacing] * 2);
|
||||
CGFloat contentHeight = MAX(iconHeight, labelsHeight);
|
||||
return contentHeight + self.vMargin * 2;
|
||||
}
|
||||
|
||||
- (CGFloat)bubbleHeight
|
||||
|
@ -195,36 +200,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
UIColor *textColor = [self audioTextColor];
|
||||
|
||||
self.backgroundColor = self.bubbleBackgroundColor;
|
||||
self.layoutMargins = UIEdgeInsetsZero;
|
||||
|
||||
// TODO: Verify that this layout works in RTL.
|
||||
const CGFloat kBubbleTailWidth = 6.f;
|
||||
|
||||
UIView *contentView = [UIView containerView];
|
||||
[self addSubview:contentView];
|
||||
[contentView autoPinLeadingToSuperviewMarginWithInset:self.isIncoming ? kBubbleTailWidth : 0.f];
|
||||
[contentView autoPinTrailingToSuperviewMarginWithInset:self.isIncoming ? 0.f : kBubbleTailWidth];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.audioIconVMargin];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.audioIconVMargin];
|
||||
self.axis = UILayoutConstraintAxisHorizontal;
|
||||
self.alignment = UIStackViewAlignmentCenter;
|
||||
self.spacing = self.hSpacing;
|
||||
|
||||
_audioPlayPauseButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
self.audioPlayPauseButton.enabled = NO;
|
||||
[contentView addSubview:self.audioPlayPauseButton];
|
||||
[self.audioPlayPauseButton autoPinLeadingToSuperviewMarginWithInset:self.audioIconHMargin];
|
||||
[self.audioPlayPauseButton autoVCenterInSuperview];
|
||||
[self.audioPlayPauseButton autoSetDimension:ALDimensionWidth toSize:self.iconSize];
|
||||
[self.audioPlayPauseButton autoSetDimension:ALDimensionHeight toSize:self.iconSize];
|
||||
[self addArrangedSubview:self.audioPlayPauseButton];
|
||||
[self.audioPlayPauseButton setContentHuggingHigh];
|
||||
|
||||
const CGFloat kLabelHSpacing = self.audioIconHSpacing;
|
||||
UIStackView *labelsView = [UIStackView new];
|
||||
labelsView.axis = UILayoutConstraintAxisVertical;
|
||||
labelsView.spacing = [OWSAudioMessageView labelVSpacing];
|
||||
[self addArrangedSubview:labelsView];
|
||||
|
||||
UIView *labelsView = [UIView containerView];
|
||||
[contentView addSubview:labelsView];
|
||||
[labelsView autoPinLeadingToTrailingEdgeOfView:self.audioPlayPauseButton offset:kLabelHSpacing];
|
||||
[labelsView autoPinTrailingToSuperviewMarginWithInset:self.audioIconHMargin];
|
||||
[labelsView autoVCenterInSuperview];
|
||||
|
||||
const CGFloat kLabelVSpacing = 2;
|
||||
NSString *filename = self.attachmentStream.sourceFilename;
|
||||
if (!filename) {
|
||||
filename = [[self.attachmentStream filePath] lastPathComponent];
|
||||
|
@ -243,34 +232,41 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
topLabel.text = topText;
|
||||
topLabel.textColor = [textColor colorWithAlphaComponent:0.85f];
|
||||
topLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
topLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(11.f, 13.f)];
|
||||
[labelsView addSubview:topLabel];
|
||||
[topLabel autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
||||
[topLabel autoPinWidthToSuperview];
|
||||
topLabel.font = [OWSAudioMessageView labelFont];
|
||||
[labelsView addArrangedSubview:topLabel];
|
||||
|
||||
const CGFloat kAudioProgressViewHeight = 12.f;
|
||||
AudioProgressView *audioProgressView = [AudioProgressView new];
|
||||
self.audioProgressView = audioProgressView;
|
||||
[self updateAudioProgressView];
|
||||
[labelsView addSubview:audioProgressView];
|
||||
[audioProgressView autoPinWidthToSuperview];
|
||||
[audioProgressView autoSetDimension:ALDimensionHeight toSize:kAudioProgressViewHeight];
|
||||
[audioProgressView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topLabel withOffset:kLabelVSpacing];
|
||||
[labelsView addArrangedSubview:audioProgressView];
|
||||
[audioProgressView autoSetDimension:ALDimensionHeight toSize:[OWSAudioMessageView audioProgressViewHeight]];
|
||||
|
||||
UILabel *bottomLabel = [UILabel new];
|
||||
self.audioBottomLabel = bottomLabel;
|
||||
[self updateAudioBottomLabel];
|
||||
bottomLabel.textColor = [textColor colorWithAlphaComponent:0.85f];
|
||||
bottomLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
bottomLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(11.f, 13.f)];
|
||||
[labelsView addSubview:bottomLabel];
|
||||
[bottomLabel autoPinWidthToSuperview];
|
||||
[bottomLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:audioProgressView withOffset:kLabelVSpacing];
|
||||
[bottomLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
bottomLabel.font = [OWSAudioMessageView labelFont];
|
||||
[labelsView addArrangedSubview:bottomLabel];
|
||||
|
||||
[self updateContents];
|
||||
}
|
||||
|
||||
+ (CGFloat)audioProgressViewHeight
|
||||
{
|
||||
return 12.f;
|
||||
}
|
||||
|
||||
+ (UIFont *)labelFont
|
||||
{
|
||||
return [UIFont ows_dynamicTypeCaption2Font];
|
||||
}
|
||||
|
||||
+ (CGFloat)labelVSpacing
|
||||
{
|
||||
return 2.f;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -29,6 +29,8 @@ const CGFloat kOWSMessageCellCornerRadius = 16;
|
|||
return self;
|
||||
}
|
||||
|
||||
self.layoutMargins = UIEdgeInsetsZero;
|
||||
|
||||
self.shapeLayer = [CAShapeLayer new];
|
||||
[self.layer addSublayer:self.shapeLayer];
|
||||
|
||||
|
|
|
@ -72,8 +72,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
]];
|
||||
buttonStackView.axis = UILayoutConstraintAxisVertical;
|
||||
buttonStackView.spacing = self.vSpacing;
|
||||
// Ensure all of the buttons have the same width.
|
||||
buttonStackView.alignment = UIStackViewAlignmentFill;
|
||||
|
||||
self.stackView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||
self.titleLabel,
|
||||
|
|
|
@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (CGFloat)iconHMargin
|
||||
- (CGFloat)hMargin
|
||||
{
|
||||
return 12.f;
|
||||
}
|
||||
|
@ -143,11 +143,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return 10.f;
|
||||
}
|
||||
|
||||
- (UIColor *)bubbleBackgroundColor
|
||||
{
|
||||
return self.isIncoming ? [UIColor ows_messageBubbleLightGrayColor] : [UIColor ows_materialBlueColor];
|
||||
}
|
||||
|
||||
+ (UIFont *)nameFont
|
||||
{
|
||||
return [UIFont ows_dynamicTypeBodyFont];
|
||||
|
@ -175,18 +170,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (void)createContents
|
||||
{
|
||||
self.backgroundColor = [UIColor colorWithRGBHex:0xefeff4];
|
||||
self.layoutMargins = UIEdgeInsetsZero;
|
||||
|
||||
// TODO: Verify that this layout works in RTL.
|
||||
const CGFloat kBubbleTailWidth = 6.f;
|
||||
|
||||
UIView *contentView = [UIView containerView];
|
||||
[self addSubview:contentView];
|
||||
[contentView autoPinLeadingToSuperviewMarginWithInset:self.isIncoming ? kBubbleTailWidth : 0.f];
|
||||
[contentView autoPinTrailingToSuperviewMarginWithInset:self.isIncoming ? 0.f : kBubbleTailWidth];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.vMargin];
|
||||
|
||||
AvatarImageView *avatarView = [AvatarImageView new];
|
||||
avatarView.image =
|
||||
[self.contactShare getAvatarImageWithDiameter:self.iconSize contactsManager:self.contactsManager];
|
||||
|
@ -226,23 +211,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[disclosureImageView setCompressionResistanceHigh];
|
||||
[disclosureImageView setContentHuggingHigh];
|
||||
|
||||
UIStackView *stackView = [UIStackView new];
|
||||
stackView.axis = UILayoutConstraintAxisHorizontal;
|
||||
stackView.spacing = self.iconHSpacing;
|
||||
stackView.alignment = UIStackViewAlignmentCenter;
|
||||
[contentView addSubview:stackView];
|
||||
[stackView autoPinLeadingToSuperviewMarginWithInset:self.iconHMargin];
|
||||
[stackView autoPinTrailingToSuperviewMarginWithInset:self.iconHMargin];
|
||||
[stackView autoVCenterInSuperview];
|
||||
// Ensure that the cell's contents never overflow the cell bounds.
|
||||
// We pin to the superview _edge_ and not _margin_ for the purposes
|
||||
// of overflow, so that changes to the margins do not trip these safe guards.
|
||||
[stackView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:0 relation:NSLayoutRelationGreaterThanOrEqual];
|
||||
[stackView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:0 relation:NSLayoutRelationGreaterThanOrEqual];
|
||||
UIStackView *hStackView = [UIStackView new];
|
||||
hStackView.axis = UILayoutConstraintAxisHorizontal;
|
||||
hStackView.spacing = self.iconHSpacing;
|
||||
hStackView.alignment = UIStackViewAlignmentCenter;
|
||||
hStackView.layoutMarginsRelativeArrangement = YES;
|
||||
hStackView.layoutMargins = UIEdgeInsetsMake(self.vMargin, self.hMargin, self.vMargin, self.hMargin);
|
||||
[hStackView addArrangedSubview:avatarView];
|
||||
[hStackView addArrangedSubview:labelsView];
|
||||
[hStackView addArrangedSubview:disclosureImageView];
|
||||
|
||||
[stackView addArrangedSubview:avatarView];
|
||||
[stackView addArrangedSubview:labelsView];
|
||||
[stackView addArrangedSubview:disclosureImageView];
|
||||
UIStackView *vStackView = [UIStackView new];
|
||||
vStackView.axis = UILayoutConstraintAxisVertical;
|
||||
vStackView.spacing = 0;
|
||||
[self addSubview:vStackView];
|
||||
[vStackView autoPinToSuperviewEdges];
|
||||
[vStackView addArrangedSubview:hStackView];
|
||||
|
||||
if ([OWSContactShareView hasAnyButton:self.contactShare contactsManager:self.contactsManager]) {
|
||||
UILabel *label = [UILabel new];
|
||||
|
@ -261,13 +245,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
label.textColor = UIColor.ows_materialBlueColor;
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.backgroundColor = [UIColor whiteColor];
|
||||
[self addSubview:label];
|
||||
[label autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:contentView withOffset:self.vMargin];
|
||||
[label autoPinWidthToSuperview];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
[vStackView addArrangedSubview:label];
|
||||
[label autoSetDimension:ALDimensionHeight toSize:OWSContactShareView.buttonHeight];
|
||||
} else {
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.vMargin];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSAttachmentStream;
|
||||
|
||||
@interface OWSGenericAttachmentView : UIView
|
||||
@interface OWSGenericAttachmentView : UIStackView
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream isIncoming:(BOOL)isIncoming;
|
||||
|
||||
|
|
|
@ -41,29 +41,33 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (CGFloat)iconHMargin
|
||||
- (CGFloat)hMargin
|
||||
{
|
||||
return 12.f;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
- (CGFloat)iconHSpacing
|
||||
- (CGFloat)hSpacing
|
||||
{
|
||||
return 8.f;
|
||||
}
|
||||
|
||||
+ (CGFloat)iconVMargin
|
||||
+ (CGFloat)vMargin
|
||||
{
|
||||
return 12.f;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
- (CGFloat)iconVMargin
|
||||
- (CGFloat)vMargin
|
||||
{
|
||||
return [OWSGenericAttachmentView iconVMargin];
|
||||
return [OWSGenericAttachmentView vMargin];
|
||||
}
|
||||
|
||||
+ (CGFloat)bubbleHeight
|
||||
{
|
||||
return self.iconSize + self.iconVMargin * 2;
|
||||
CGFloat iconHeight = self.iconHeight;
|
||||
CGFloat labelsHeight = ([OWSGenericAttachmentView topLabelFont].lineHeight +
|
||||
[OWSGenericAttachmentView bottomLabelFont].lineHeight + [OWSGenericAttachmentView labelVSpacing]);
|
||||
CGFloat contentHeight = MAX(iconHeight, labelsHeight);
|
||||
return contentHeight + self.vMargin * 2;
|
||||
}
|
||||
|
||||
- (CGFloat)bubbleHeight
|
||||
|
@ -71,19 +75,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [OWSGenericAttachmentView bubbleHeight];
|
||||
}
|
||||
|
||||
+ (CGFloat)iconSize
|
||||
+ (CGFloat)iconHeight
|
||||
{
|
||||
return 44.f;
|
||||
return 48.f;
|
||||
}
|
||||
|
||||
- (CGFloat)iconSize
|
||||
- (CGFloat)iconHeight
|
||||
{
|
||||
return [OWSGenericAttachmentView iconSize];
|
||||
}
|
||||
|
||||
- (CGFloat)vMargin
|
||||
{
|
||||
return 10.f;
|
||||
return [OWSGenericAttachmentView iconHeight];
|
||||
}
|
||||
|
||||
- (UIColor *)bubbleBackgroundColor
|
||||
|
@ -105,45 +104,26 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
UIColor *textColor = (self.isIncoming ? [UIColor colorWithWhite:0.2 alpha:1.f] : [UIColor whiteColor]);
|
||||
|
||||
self.backgroundColor = self.bubbleBackgroundColor;
|
||||
self.layoutMargins = UIEdgeInsetsZero;
|
||||
self.axis = UILayoutConstraintAxisHorizontal;
|
||||
self.alignment = UIStackViewAlignmentCenter;
|
||||
self.spacing = self.hSpacing;
|
||||
|
||||
// TODO: Verify that this layout works in RTL.
|
||||
const CGFloat kBubbleTailWidth = 6.f;
|
||||
|
||||
UIView *contentView = [UIView containerView];
|
||||
[self addSubview:contentView];
|
||||
[contentView autoPinLeadingToSuperviewMarginWithInset:self.isIncoming ? kBubbleTailWidth : 0.f];
|
||||
[contentView autoPinTrailingToSuperviewMarginWithInset:self.isIncoming ? 0.f : kBubbleTailWidth];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.vMargin];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.vMargin];
|
||||
|
||||
UIView *iconCircleView = [UIView containerView];
|
||||
iconCircleView.backgroundColor
|
||||
= (self.isIncoming ? [UIColor colorWithRGBHex:0x9e9e9e] : [self foregroundColorWithOpacity:0.15f]);
|
||||
iconCircleView.layer.cornerRadius = self.iconSize * 0.5f;
|
||||
[contentView addSubview:iconCircleView];
|
||||
[iconCircleView autoPinLeadingToSuperviewMarginWithInset:self.iconHMargin];
|
||||
[iconCircleView autoVCenterInSuperview];
|
||||
[iconCircleView autoSetDimension:ALDimensionWidth toSize:self.iconSize];
|
||||
[iconCircleView autoSetDimension:ALDimensionHeight toSize:self.iconSize];
|
||||
|
||||
UIImage *image = [UIImage imageNamed:@"attachment_file"];
|
||||
// attachment_file
|
||||
UIImage *image = [UIImage imageNamed:@"generic-attachment"];
|
||||
OWSAssert(image);
|
||||
OWSAssert(image.size.height == self.iconHeight);
|
||||
UIImageView *imageView = [UIImageView new];
|
||||
imageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
imageView.image = image;
|
||||
imageView.tintColor = self.bubbleBackgroundColor;
|
||||
[iconCircleView addSubview:imageView];
|
||||
[imageView autoCenterInSuperview];
|
||||
[self addArrangedSubview:imageView];
|
||||
[imageView setContentHuggingHigh];
|
||||
|
||||
const CGFloat kLabelHSpacing = self.iconHSpacing;
|
||||
UIView *labelsView = [UIView containerView];
|
||||
[contentView addSubview:labelsView];
|
||||
[labelsView autoPinLeadingToTrailingEdgeOfView:iconCircleView offset:kLabelHSpacing];
|
||||
[labelsView autoPinTrailingToSuperviewMarginWithInset:self.iconHMargin];
|
||||
[labelsView autoVCenterInSuperview];
|
||||
UIStackView *labelsView = [UIStackView new];
|
||||
labelsView.axis = UILayoutConstraintAxisVertical;
|
||||
labelsView.spacing = [OWSGenericAttachmentView labelVSpacing];
|
||||
labelsView.alignment = UIStackViewAlignmentLeading;
|
||||
[self addArrangedSubview:labelsView];
|
||||
|
||||
const CGFloat kLabelVSpacing = 2;
|
||||
NSString *topText = [self.attachmentStream.sourceFilename ows_stripped];
|
||||
if (topText.length < 1) {
|
||||
topText = [MIMETypeUtil fileExtensionForMIMEType:self.attachmentStream.contentType].uppercaseString;
|
||||
|
@ -155,10 +135,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
topLabel.text = topText;
|
||||
topLabel.textColor = textColor;
|
||||
topLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
topLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(13.f, 15.f)];
|
||||
[labelsView addSubview:topLabel];
|
||||
[topLabel autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
||||
[topLabel autoPinWidthToSuperview];
|
||||
topLabel.font = [OWSGenericAttachmentView topLabelFont];
|
||||
[labelsView addArrangedSubview:topLabel];
|
||||
|
||||
NSError *error;
|
||||
unsigned long long fileSize =
|
||||
|
@ -169,11 +147,23 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
bottomLabel.text = bottomText;
|
||||
bottomLabel.textColor = [textColor colorWithAlphaComponent:0.85f];
|
||||
bottomLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
bottomLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(11.f, 13.f)];
|
||||
[labelsView addSubview:bottomLabel];
|
||||
[bottomLabel autoPinWidthToSuperview];
|
||||
[bottomLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topLabel withOffset:kLabelVSpacing];
|
||||
[bottomLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
bottomLabel.font = [OWSGenericAttachmentView bottomLabelFont];
|
||||
[labelsView addArrangedSubview:bottomLabel];
|
||||
}
|
||||
|
||||
+ (UIFont *)topLabelFont
|
||||
{
|
||||
return [UIFont ows_dynamicTypeCaption1Font];
|
||||
}
|
||||
|
||||
+ (UIFont *)bottomLabelFont
|
||||
{
|
||||
return [UIFont ows_dynamicTypeCaption2Font];
|
||||
}
|
||||
|
||||
+ (CGFloat)labelVSpacing
|
||||
{
|
||||
return 2.f;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -27,6 +27,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic) OWSBubbleShapeView *mediaClipView;
|
||||
|
||||
@property (nonatomic) OWSBubbleShapeView *bubbleStrokeView;
|
||||
|
||||
@property (nonatomic) UIStackView *stackView;
|
||||
|
||||
@property (nonatomic) UILabel *senderNameLabel;
|
||||
|
@ -81,10 +83,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
self.mediaShadowView = [OWSBubbleShapeView bubbleShadowView];
|
||||
self.mediaClipView = [OWSBubbleShapeView bubbleClipView];
|
||||
self.bubbleStrokeView = [OWSBubbleShapeView bubbleDrawView];
|
||||
|
||||
self.stackView = [UIStackView new];
|
||||
self.stackView.axis = UILayoutConstraintAxisVertical;
|
||||
self.stackView.alignment = UIStackViewAlignmentFill;
|
||||
|
||||
self.senderNameLabel = [UILabel new];
|
||||
|
||||
|
@ -246,10 +248,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssert(self.viewItem.interaction);
|
||||
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
|
||||
|
||||
CGSize quotedMessageContentSize = [self quotedMessageSize];
|
||||
NSValue *_Nullable quotedMessageSize = [self quotedMessageSize];
|
||||
// TODO:
|
||||
CGSize bodyMediaContentSize = [self bodyMediaSize];
|
||||
CGSize bodyTextContentSize = [self bodyTextSizeWithIncludeMargins:NO];
|
||||
// CGSize bodyMediaContentSize = [self bodyMediaSize];
|
||||
NSValue *_Nullable bodyTextSize = [self bodyTextSize];
|
||||
|
||||
[self.bubbleView addSubview:self.stackView];
|
||||
[self.viewConstraints addObjectsFromArray:[self.stackView autoPinEdgesToSuperviewEdges]];
|
||||
|
@ -278,14 +280,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
self.quotedMessageView = quotedMessageView;
|
||||
[quotedMessageView createContents];
|
||||
[self.stackView addArrangedSubview:quotedMessageView];
|
||||
[self.viewConstraints
|
||||
addObject:[quotedMessageView autoSetDimension:ALDimensionHeight toSize:quotedMessageContentSize.height]];
|
||||
OWSAssert(quotedMessageSize);
|
||||
[self.viewConstraints addObject:[quotedMessageView autoSetDimension:ALDimensionHeight
|
||||
toSize:quotedMessageSize.CGSizeValue.height]];
|
||||
|
||||
[self.bubbleView addPartnerView:quotedMessageView.boundsStrokeView];
|
||||
}
|
||||
|
||||
UIView *_Nullable bodyMediaView = nil;
|
||||
BOOL hasThumbnailForBodyMedia = NO;
|
||||
switch (self.cellType) {
|
||||
case OWSMessageCellType_Unknown:
|
||||
case OWSMessageCellType_TextMessage:
|
||||
|
@ -294,17 +296,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
case OWSMessageCellType_StillImage:
|
||||
OWSAssert(self.viewItem.attachmentStream);
|
||||
bodyMediaView = [self loadViewForStillImage];
|
||||
hasThumbnailForBodyMedia = YES;
|
||||
break;
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
OWSAssert(self.viewItem.attachmentStream);
|
||||
bodyMediaView = [self loadViewForAnimatedImage];
|
||||
hasThumbnailForBodyMedia = YES;
|
||||
break;
|
||||
case OWSMessageCellType_Video:
|
||||
OWSAssert(self.viewItem.attachmentStream);
|
||||
bodyMediaView = [self loadViewForVideo];
|
||||
hasThumbnailForBodyMedia = YES;
|
||||
break;
|
||||
case OWSMessageCellType_Audio:
|
||||
OWSAssert(self.viewItem.attachmentStream);
|
||||
|
@ -325,51 +324,66 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssert(self.loadCellContentBlock);
|
||||
OWSAssert(self.unloadCellContentBlock);
|
||||
|
||||
// Flush any pending "text" subviews.
|
||||
[self insertAnyTextViewsIntoStackView:textViews];
|
||||
[textViews removeAllObjects];
|
||||
|
||||
bodyMediaView.clipsToBounds = YES;
|
||||
|
||||
self.bodyMediaView = bodyMediaView;
|
||||
bodyMediaView.userInteractionEnabled = NO;
|
||||
if (self.isMediaBeingSent) {
|
||||
// TODO:
|
||||
bodyMediaView.layer.opacity = 0.75f;
|
||||
}
|
||||
|
||||
if (hasThumbnailForBodyMedia) {
|
||||
// The "body media" view casts a shadow "downward" onto adjacent views,
|
||||
// so we use a "proxy" view to take its place within the v-stack
|
||||
// view and then insert the body media view above its proxy so that
|
||||
// it floats above the other content of the bubble view.
|
||||
if (self.hasFullWidthMediaView) {
|
||||
// Flush any pending "text" subviews.
|
||||
[self insertAnyTextViewsIntoStackView:textViews];
|
||||
[textViews removeAllObjects];
|
||||
|
||||
UIView *bodyProxyView = [UIView new];
|
||||
[self.stackView addArrangedSubview:bodyProxyView];
|
||||
if (self.hasBodyMediaWithThumbnail) {
|
||||
|
||||
[self addSubview:self.mediaShadowView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:bodyProxyView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:bodyProxyView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:bodyProxyView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:bodyProxyView];
|
||||
// The "body media" view casts a shadow "downward" onto adjacent views,
|
||||
// so we use a "proxy" view to take its place within the v-stack
|
||||
// view and then insert the body media view above its proxy so that
|
||||
// it floats above the other content of the bubble view.
|
||||
|
||||
[self.mediaShadowView addSubview:self.mediaClipView];
|
||||
[self.mediaClipView autoPinToSuperviewEdges];
|
||||
UIView *bodyProxyView = [UIView new];
|
||||
[self.stackView addArrangedSubview:bodyProxyView];
|
||||
|
||||
[self.mediaClipView addSubview:bodyMediaView];
|
||||
[bodyMediaView autoPinToSuperviewEdges];
|
||||
[self addSubview:self.mediaShadowView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:bodyProxyView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:bodyProxyView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:bodyProxyView];
|
||||
[self.mediaShadowView autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:bodyProxyView];
|
||||
|
||||
[self.bubbleView addPartnerView:self.mediaClipView];
|
||||
[self.bubbleView addPartnerView:self.mediaShadowView];
|
||||
[self.mediaShadowView addSubview:self.mediaClipView];
|
||||
[self.mediaClipView autoPinToSuperviewEdges];
|
||||
|
||||
// TODO: Constants
|
||||
// TODO: What's the difference between an inner and outer shadow?
|
||||
self.mediaShadowView.fillColor = self.bubbleColor;
|
||||
self.mediaShadowView.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||
self.mediaShadowView.layer.shadowOpacity = 0.12f;
|
||||
self.mediaShadowView.layer.shadowOffset = CGSizeMake(0.f, 0.f);
|
||||
self.mediaShadowView.layer.shadowRadius = 0.5f;
|
||||
[self.mediaClipView addSubview:bodyMediaView];
|
||||
[bodyMediaView autoPinToSuperviewEdges];
|
||||
|
||||
[self.bubbleView addPartnerView:self.mediaClipView];
|
||||
[self.bubbleView addPartnerView:self.mediaShadowView];
|
||||
|
||||
// TODO: Constants
|
||||
// TODO: What's the difference between an inner and outer shadow?
|
||||
self.mediaShadowView.fillColor = self.bubbleColor;
|
||||
self.mediaShadowView.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||
self.mediaShadowView.layer.shadowOpacity = 0.12f;
|
||||
self.mediaShadowView.layer.shadowOffset = CGSizeMake(0.f, 0.f);
|
||||
self.mediaShadowView.layer.shadowRadius = 0.5f;
|
||||
} else {
|
||||
OWSAssert(self.cellType == OWSMessageCellType_ContactShare);
|
||||
|
||||
[self.stackView addArrangedSubview:bodyMediaView];
|
||||
|
||||
// TODO: Constants.
|
||||
self.bubbleStrokeView.strokeColor = [UIColor lightGrayColor];
|
||||
self.bubbleStrokeView.strokeThickness = 1.f;
|
||||
[self.bubbleView addSubview:self.bubbleStrokeView];
|
||||
[self.bubbleStrokeView autoPinToSuperviewEdges];
|
||||
[self.bubbleView addPartnerView:self.bubbleStrokeView];
|
||||
}
|
||||
} else {
|
||||
[self.stackView addArrangedSubview:bodyMediaView];
|
||||
[textViews addObject:bodyMediaView];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,8 +393,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self configureBodyTextView];
|
||||
[textViews addObject:self.bodyTextView];
|
||||
|
||||
// TODO: Media?
|
||||
OWSAssert(bodyTextSize);
|
||||
[self.viewConstraints addObjectsFromArray:@[
|
||||
[self.bodyTextView autoSetDimension:ALDimensionHeight toSize:bodyTextContentSize.height],
|
||||
[self.bodyTextView autoSetDimension:ALDimensionHeight toSize:bodyTextSize.CGSizeValue.height],
|
||||
]];
|
||||
|
||||
UIView *_Nullable tapForMoreLabel = [self createTapForMoreLabelIfNecessary];
|
||||
|
@ -421,29 +437,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
]];
|
||||
}];
|
||||
|
||||
[self updateBubbleColorWithBodyMediaView:bodyMediaView];
|
||||
[self updateBubbleColor];
|
||||
}
|
||||
|
||||
- (void)updateBubbleColorWithBodyMediaView:(nullable UIView *)bodyMediaView
|
||||
- (void)updateBubbleColor
|
||||
{
|
||||
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
|
||||
|
||||
BOOL hasOnlyBodyMediaView = NO;
|
||||
switch (self.cellType) {
|
||||
case OWSMessageCellType_Unknown:
|
||||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
case OWSMessageCellType_ContactShare:
|
||||
break;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_Video:
|
||||
hasOnlyBodyMediaView = (bodyMediaView && self.stackView.subviews.count == 1);
|
||||
break;
|
||||
}
|
||||
BOOL hasOnlyBodyMediaView = (self.hasBodyMediaWithThumbnail && self.stackView.subviews.count == 1);
|
||||
if (!hasOnlyBodyMediaView) {
|
||||
self.bubbleView.bubbleColor = self.bubbleColor;
|
||||
} else {
|
||||
|
@ -461,7 +460,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [self.bubbleFactory bubbleColorWithMessage:message];
|
||||
}
|
||||
|
||||
- (BOOL)canFooterOverlayMedia
|
||||
- (BOOL)hasBodyMediaWithThumbnail
|
||||
{
|
||||
switch (self.cellType) {
|
||||
case OWSMessageCellType_Unknown:
|
||||
|
@ -480,6 +479,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasFullWidthMediaView
|
||||
{
|
||||
return (self.hasBodyMediaWithThumbnail || self.cellType == OWSMessageCellType_ContactShare);
|
||||
}
|
||||
|
||||
- (BOOL)canFooterOverlayMedia
|
||||
{
|
||||
return self.hasBodyMediaWithThumbnail;
|
||||
}
|
||||
|
||||
- (BOOL)hasBottomFooter
|
||||
{
|
||||
BOOL shouldFooterOverlayMedia = (self.canFooterOverlayMedia && !self.hasBodyText);
|
||||
return !self.viewItem.shouldHideFooter && !shouldFooterOverlayMedia;
|
||||
}
|
||||
|
||||
- (void)insertAnyTextViewsIntoStackView:(NSArray<UIView *> *)textViews
|
||||
{
|
||||
if (textViews.count < 1) {
|
||||
|
@ -488,7 +503,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
UIStackView *textStackView = [[UIStackView alloc] initWithArrangedSubviews:textViews];
|
||||
textStackView.axis = UILayoutConstraintAxisVertical;
|
||||
textStackView.alignment = UIStackViewAlignmentFill;
|
||||
// TODO: Review
|
||||
textStackView.spacing = self.textViewVSpacing;
|
||||
textStackView.layoutMarginsRelativeArrangement = YES;
|
||||
|
@ -930,13 +944,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
#pragma mark - Measurement
|
||||
|
||||
// Size of "message body" text, not quoted reply text.
|
||||
- (CGSize)bodyTextSizeWithIncludeMargins:(BOOL)includeMargins
|
||||
- (nullable NSValue *)bodyTextSize
|
||||
{
|
||||
OWSAssert(self.conversationStyle);
|
||||
OWSAssert(self.conversationStyle.maxMessageWidth > 0);
|
||||
|
||||
if (!self.hasBodyText) {
|
||||
return CGSizeZero;
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGFloat hMargins = self.conversationStyle.textInsetHorizontal * 2;
|
||||
|
@ -947,15 +961,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
const int kMaxIterations = 5;
|
||||
CGSize result = [self.bodyTextView compactSizeThatFitsMaxWidth:maxTextWidth maxIterations:kMaxIterations];
|
||||
|
||||
if (includeMargins) {
|
||||
result.width += hMargins;
|
||||
result.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom);
|
||||
}
|
||||
|
||||
return CGSizeCeil(result);
|
||||
return [NSValue valueWithCGSize:CGSizeCeil(result)];
|
||||
}
|
||||
|
||||
- (CGSize)bodyMediaSize
|
||||
- (nullable NSValue *)bodyMediaSize
|
||||
{
|
||||
OWSAssert(self.conversationStyle);
|
||||
OWSAssert(self.conversationStyle.maxMessageWidth > 0);
|
||||
|
@ -967,8 +976,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
case OWSMessageCellType_Unknown:
|
||||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage: {
|
||||
result = CGSizeZero;
|
||||
break;
|
||||
return nil;
|
||||
}
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
|
@ -1024,10 +1032,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
break;
|
||||
}
|
||||
|
||||
return CGSizeCeil(result);
|
||||
return [NSValue valueWithCGSize:CGSizeCeil(result)];
|
||||
}
|
||||
|
||||
- (CGSize)quotedMessageSize
|
||||
- (nullable NSValue *)quotedMessageSize
|
||||
{
|
||||
OWSAssert(self.conversationStyle);
|
||||
OWSAssert(self.conversationStyle.maxMessageWidth > 0);
|
||||
|
@ -1035,7 +1043,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
|
||||
|
||||
if (!self.isQuotedReply) {
|
||||
return CGSizeZero;
|
||||
return nil;
|
||||
}
|
||||
|
||||
BOOL isOutgoing = [self.viewItem.interaction isKindOfClass:TSOutgoingMessage.class];
|
||||
|
@ -1047,16 +1055,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
displayableQuotedText:displayableQuotedText
|
||||
isOutgoing:isOutgoing];
|
||||
CGSize result = [quotedMessageView sizeForMaxWidth:self.conversationStyle.maxMessageWidth];
|
||||
return CGSizeCeil(result);
|
||||
return [NSValue valueWithCGSize:CGSizeCeil(result)];
|
||||
}
|
||||
|
||||
- (CGSize)senderNameSizeWithBodyMediaSize:(CGSize)bodyMediaSize includeMargins:(BOOL)includeMargins
|
||||
- (nullable NSValue *)senderNameSize
|
||||
{
|
||||
OWSAssert(self.conversationStyle);
|
||||
OWSAssert(self.conversationStyle.maxMessageWidth > 0);
|
||||
|
||||
if (!self.shouldShowSenderName) {
|
||||
return CGSizeZero;
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGFloat hMargins = self.conversationStyle.textInsetHorizontal * 2;
|
||||
|
@ -1064,18 +1072,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self configureSenderNameLabel];
|
||||
CGSize result = CGSizeCeil([self.senderNameLabel sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)]);
|
||||
|
||||
BOOL hasSeparateTextStackView = (self.isQuotedReply || bodyMediaSize.width > 0 || bodyMediaSize.height > 0);
|
||||
|
||||
if (includeMargins) {
|
||||
result.width += hMargins;
|
||||
|
||||
if (hasSeparateTextStackView) {
|
||||
result.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom);
|
||||
} else {
|
||||
result.height += self.textViewVSpacing;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return [NSValue valueWithCGSize:result];
|
||||
}
|
||||
|
||||
- (CGSize)measureSize
|
||||
|
@ -1087,24 +1084,54 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
CGSize cellSize = CGSizeZero;
|
||||
|
||||
// TODO: Reflect "sender name" and "footer" layout.
|
||||
// shouldFooterOverlayMedia = self.canFooterOverlayMedia;
|
||||
NSMutableArray<NSValue *> *textViewSizes = [NSMutableArray new];
|
||||
|
||||
CGSize quotedMessageSize = [self quotedMessageSize];
|
||||
cellSize.width = MAX(cellSize.width, quotedMessageSize.width);
|
||||
cellSize.height += quotedMessageSize.height;
|
||||
NSValue *_Nullable senderNameSize = [self senderNameSize];
|
||||
if (senderNameSize) {
|
||||
[textViewSizes addObject:senderNameSize];
|
||||
}
|
||||
|
||||
CGSize bodyMediaSize = [self bodyMediaSize];
|
||||
cellSize.width = MAX(cellSize.width, bodyMediaSize.width);
|
||||
cellSize.height += bodyMediaSize.height;
|
||||
NSValue *_Nullable quotedMessageSize = [self quotedMessageSize];
|
||||
if (quotedMessageSize) {
|
||||
cellSize.width = MAX(cellSize.width, quotedMessageSize.CGSizeValue.width);
|
||||
cellSize.height += quotedMessageSize.CGSizeValue.height;
|
||||
}
|
||||
|
||||
CGSize senderNameSize = [self senderNameSizeWithBodyMediaSize:bodyMediaSize includeMargins:YES];
|
||||
cellSize.width = MAX(cellSize.width, senderNameSize.width);
|
||||
cellSize.height += senderNameSize.height;
|
||||
NSValue *_Nullable bodyMediaSize = [self bodyMediaSize];
|
||||
if (bodyMediaSize) {
|
||||
if (self.hasFullWidthMediaView) {
|
||||
cellSize.width = MAX(cellSize.width, bodyMediaSize.CGSizeValue.width);
|
||||
cellSize.height += bodyMediaSize.CGSizeValue.height;
|
||||
} else {
|
||||
[textViewSizes addObject:bodyMediaSize];
|
||||
bodyMediaSize = nil;
|
||||
}
|
||||
}
|
||||
|
||||
CGSize textContentSize = [self bodyTextSizeWithIncludeMargins:YES];
|
||||
cellSize.width = MAX(cellSize.width, textContentSize.width);
|
||||
cellSize.height += textContentSize.height;
|
||||
if (bodyMediaSize || quotedMessageSize) {
|
||||
if (textViewSizes.count > 0) {
|
||||
CGSize groupSize = [self sizeForTextViewGroup:textViewSizes];
|
||||
cellSize.width = MAX(cellSize.width, groupSize.width);
|
||||
cellSize.height += groupSize.height;
|
||||
[textViewSizes removeAllObjects];
|
||||
}
|
||||
}
|
||||
|
||||
NSValue *_Nullable bodyTextSize = [self bodyTextSize];
|
||||
if (bodyTextSize) {
|
||||
[textViewSizes addObject:bodyTextSize];
|
||||
}
|
||||
|
||||
if (self.hasBottomFooter) {
|
||||
CGSize footerSize = [self.footerView measureWithConversationViewItem:self.viewItem];
|
||||
[textViewSizes addObject:[NSValue valueWithCGSize:footerSize]];
|
||||
}
|
||||
|
||||
if (textViewSizes.count > 0) {
|
||||
CGSize groupSize = [self sizeForTextViewGroup:textViewSizes];
|
||||
cellSize.width = MAX(cellSize.width, groupSize.width);
|
||||
cellSize.height += groupSize.height;
|
||||
}
|
||||
|
||||
// Make sure the bubble is always wide enough to complete it's bubble shape.
|
||||
cellSize.width = MAX(cellSize.width, OWSBubbleView.minWidth);
|
||||
|
@ -1115,23 +1142,30 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
cellSize.height += self.tapForMoreHeight + self.textViewVSpacing;
|
||||
}
|
||||
|
||||
// TODO: Update this to reflect generic attachment, downloading attachments and
|
||||
// contact shares.
|
||||
BOOL shouldFooterOverlayMedia = (self.canFooterOverlayMedia && !self.hasBodyText);
|
||||
if (!self.viewItem.shouldHideFooter && !shouldFooterOverlayMedia) {
|
||||
CGSize footerSize = [self.footerView measureWithConversationViewItem:self.viewItem];
|
||||
cellSize.width = MAX(cellSize.width, footerSize.width + self.conversationStyle.textInsetHorizontal * 2);
|
||||
cellSize.height += self.textViewVSpacing + footerSize.height;
|
||||
if (!self.hasBodyText) {
|
||||
cellSize.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom);
|
||||
}
|
||||
}
|
||||
|
||||
cellSize = CGSizeCeil(cellSize);
|
||||
|
||||
return cellSize;
|
||||
}
|
||||
|
||||
- (CGSize)sizeForTextViewGroup:(NSArray<NSValue *> *)textViewSizes
|
||||
{
|
||||
OWSAssert(textViewSizes);
|
||||
OWSAssert(textViewSizes.count > 0);
|
||||
OWSAssert(self.conversationStyle);
|
||||
OWSAssert(self.conversationStyle.maxMessageWidth > 0);
|
||||
|
||||
CGSize result = CGSizeZero;
|
||||
for (NSValue *size in textViewSizes) {
|
||||
result.width = MAX(result.width, size.CGSizeValue.width);
|
||||
result.height += size.CGSizeValue.height;
|
||||
}
|
||||
result.height += self.textViewVSpacing * (textViewSizes.count - 1);
|
||||
result.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom);
|
||||
result.width += self.conversationStyle.textInsetHorizontal * 2;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (UIFont *)tapForMoreFont
|
||||
{
|
||||
return UIFont.ows_dynamicTypeCaption1Font;
|
||||
|
|
|
@ -176,6 +176,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
quotedAttachmentView.backgroundColor = self.highlightColor;
|
||||
quotedAttachmentView.layer.cornerRadius = self.quotedAttachmentSize * 0.5f;
|
||||
|
||||
// TODO: Use new icons.
|
||||
UIImage *contentIcon =
|
||||
[UIImage imageNamed:(self.isAudioAttachment ? @"attachment_audio" : @"attachment_file")];
|
||||
contentIcon = [contentIcon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
|
|
|
@ -122,6 +122,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.unreadLabel autoCenterInSuperview];
|
||||
[self.unreadLabel setContentHuggingHigh];
|
||||
[self.unreadLabel setCompressionResistanceHigh];
|
||||
|
||||
self.payloadView.userInteractionEnabled = NO;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
|
|
@ -11,7 +11,7 @@ extern const CGFloat kContactCellAvatarTextMargin;
|
|||
@class SignalAccount;
|
||||
@class TSThread;
|
||||
|
||||
@interface ContactCellView : UIView
|
||||
@interface ContactCellView : UIStackView
|
||||
|
||||
@property (nonatomic, nullable) NSString *accessoryMessage;
|
||||
|
||||
|
|
|
@ -78,28 +78,17 @@ const CGFloat kContactCellAvatarTextMargin = 12;
|
|||
self.subtitleLabel,
|
||||
]];
|
||||
self.nameContainerView.axis = UILayoutConstraintAxisVertical;
|
||||
self.nameContainerView.alignment = UIStackViewAlignmentFill;
|
||||
|
||||
[self.avatarView setContentHuggingHorizontalHigh];
|
||||
[self.nameContainerView setContentHuggingHorizontalLow];
|
||||
[self.accessoryViewContainer setContentHuggingHorizontalHigh];
|
||||
|
||||
UIStackView *hStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||
self.avatarView,
|
||||
self.nameContainerView,
|
||||
self.accessoryViewContainer,
|
||||
]];
|
||||
hStackView.axis = UILayoutConstraintAxisHorizontal;
|
||||
hStackView.spacing = kContactCellAvatarTextMargin;
|
||||
hStackView.distribution = UIStackViewDistributionFill;
|
||||
[self addSubview:hStackView];
|
||||
[hStackView autoVCenterInSuperview];
|
||||
[hStackView autoPinEdgeToSuperviewMargin:ALEdgeLeading];
|
||||
[hStackView autoPinEdgeToSuperviewMargin:ALEdgeTrailing];
|
||||
|
||||
// Ensure that the cell's contents never overflow the cell bounds.
|
||||
[hStackView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual];
|
||||
[hStackView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual];
|
||||
self.axis = UILayoutConstraintAxisHorizontal;
|
||||
self.spacing = kContactCellAvatarTextMargin;
|
||||
self.alignment = UIStackViewAlignmentCenter;
|
||||
[self addArrangedSubview:self.avatarView];
|
||||
[self addArrangedSubview:self.nameContainerView];
|
||||
[self addArrangedSubview:self.accessoryViewContainer];
|
||||
|
||||
[self configureFonts];
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
self.cellView = [ContactCellView new];
|
||||
[self.contentView addSubview:self.cellView];
|
||||
[self.cellView autoPinEdgesToSuperviewMargins];
|
||||
self.cellView.userInteractionEnabled = NO;
|
||||
}
|
||||
|
||||
- (void)configureWithSignalAccount:(SignalAccount *)signalAccount contactsManager:(OWSContactsManager *)contactsManager
|
||||
|
|
Loading…
Reference in a new issue