parent
e77292c2a9
commit
65efa7f836
|
@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
isIncoming:(BOOL)isIncoming
|
||||
viewItem:(ConversationViewItem *)viewItem;
|
||||
|
||||
- (void)createContentsForSize:(CGSize)viewSize;
|
||||
- (void)createContents;
|
||||
|
||||
+ (CGFloat)bubbleHeight;
|
||||
|
||||
|
|
|
@ -193,34 +193,46 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return (self.attachmentStream.isVoiceMessage || self.attachmentStream.sourceFilename.length < 1);
|
||||
}
|
||||
|
||||
- (void)createContentsForSize:(CGSize)viewSize
|
||||
- (void)createContents
|
||||
{
|
||||
UIColor *textColor = [self audioTextColor];
|
||||
|
||||
self.backgroundColor = self.bubbleBackgroundColor;
|
||||
self.layoutMargins = UIEdgeInsetsZero;
|
||||
|
||||
// TODO: Verify that this layout works in RTL.
|
||||
const CGFloat kBubbleTailWidth = 6.f;
|
||||
CGRect contentFrame = CGRectMake(self.isIncoming ? kBubbleTailWidth : 0.f,
|
||||
self.audioIconVMargin,
|
||||
viewSize.width - kBubbleTailWidth - self.audioIconHMargin,
|
||||
viewSize.height - self.audioIconVMargin * 2);
|
||||
|
||||
CGRect iconFrame = CGRectMake((CGFloat)round(contentFrame.origin.x + self.audioIconHMargin),
|
||||
(CGFloat)round(contentFrame.origin.y + (contentFrame.size.height - self.iconSize) * 0.5f),
|
||||
self.iconSize,
|
||||
self.iconSize);
|
||||
_audioPlayPauseButton = [[UIButton alloc] initWithFrame:iconFrame];
|
||||
_audioPlayPauseButton.enabled = NO;
|
||||
[self addSubview:_audioPlayPauseButton];
|
||||
UIView *contentView = [UIView containerView];
|
||||
[self addSubview:contentView];
|
||||
[contentView autoPinLeadingToSuperviewWithMargin:self.isIncoming ? kBubbleTailWidth : 0.f];
|
||||
[contentView autoPinTrailingToSuperviewWithMargin:self.isIncoming ? 0.f : kBubbleTailWidth];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.audioIconVMargin];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.audioIconVMargin];
|
||||
|
||||
_audioPlayPauseButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
self.audioPlayPauseButton.enabled = NO;
|
||||
[contentView addSubview:self.audioPlayPauseButton];
|
||||
[self.audioPlayPauseButton autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:self.audioIconHMargin];
|
||||
[self.audioPlayPauseButton autoVCenterInSuperview];
|
||||
[self.audioPlayPauseButton autoSetDimension:ALDimensionWidth toSize:self.iconSize];
|
||||
[self.audioPlayPauseButton autoSetDimension:ALDimensionHeight toSize:self.iconSize];
|
||||
|
||||
const CGFloat kLabelHSpacing = self.audioIconHSpacing;
|
||||
|
||||
UIView *labelsView = [UIView containerView];
|
||||
[contentView addSubview:labelsView];
|
||||
[labelsView autoPinLeadingToTrailingOfView:self.audioPlayPauseButton margin:kLabelHSpacing];
|
||||
[labelsView autoPinEdgeToSuperviewEdge:ALEdgeRight];
|
||||
[labelsView autoVCenterInSuperview];
|
||||
|
||||
const CGFloat kLabelVSpacing = 2;
|
||||
NSString *filename = self.attachmentStream.sourceFilename;
|
||||
if (!filename) {
|
||||
filename = [[self.attachmentStream filePath] lastPathComponent];
|
||||
}
|
||||
NSString *topText = [[filename stringByDeletingPathExtension]
|
||||
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
if (topText.length < 1) {
|
||||
topText = [MIMETypeUtil fileExtensionForMIMEType:self.attachmentStream.contentType].uppercaseString;
|
||||
}
|
||||
|
@ -235,13 +247,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
topLabel.textColor = [textColor colorWithAlphaComponent:0.85f];
|
||||
topLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
topLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(11.f, 13.f)];
|
||||
[topLabel sizeToFit];
|
||||
[self addSubview:topLabel];
|
||||
topLabel.textAlignment = NSTextAlignmentLeft;
|
||||
[labelsView addSubview:topLabel];
|
||||
[topLabel autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
||||
[topLabel autoPinWidthToSuperview];
|
||||
|
||||
const CGFloat kAudioProgressViewHeight = 12.f;
|
||||
AudioProgressView *audioProgressView = [AudioProgressView new];
|
||||
self.audioProgressView = audioProgressView;
|
||||
[self updateAudioProgressView];
|
||||
[self addSubview:audioProgressView];
|
||||
[labelsView addSubview:audioProgressView];
|
||||
[audioProgressView autoPinWidthToSuperview];
|
||||
[audioProgressView autoSetDimension:ALDimensionHeight toSize:kAudioProgressViewHeight];
|
||||
[audioProgressView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topLabel withOffset:kLabelVSpacing];
|
||||
|
||||
UILabel *bottomLabel = [UILabel new];
|
||||
self.audioBottomLabel = bottomLabel;
|
||||
|
@ -249,25 +267,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
bottomLabel.textColor = [textColor colorWithAlphaComponent:0.85f];
|
||||
bottomLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
bottomLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(11.f, 13.f)];
|
||||
[bottomLabel sizeToFit];
|
||||
[self addSubview:bottomLabel];
|
||||
|
||||
const CGFloat topLabelHeight = (CGFloat)ceil(topLabel.font.lineHeight);
|
||||
const CGFloat kAudioProgressViewHeight = 12.f;
|
||||
const CGFloat bottomLabelHeight = (CGFloat)ceil(bottomLabel.font.lineHeight);
|
||||
CGRect labelsBounds = CGRectZero;
|
||||
labelsBounds.origin.x = (CGFloat)round(iconFrame.origin.x + iconFrame.size.width + kLabelHSpacing);
|
||||
labelsBounds.size.width = contentFrame.origin.x + contentFrame.size.width - labelsBounds.origin.x;
|
||||
labelsBounds.size.height = topLabelHeight + kAudioProgressViewHeight + bottomLabelHeight + kLabelVSpacing * 2;
|
||||
labelsBounds.origin.y
|
||||
= (CGFloat)round(contentFrame.origin.y + (contentFrame.size.height - labelsBounds.size.height) * 0.5f);
|
||||
|
||||
CGFloat y = labelsBounds.origin.y;
|
||||
topLabel.frame = CGRectMake(labelsBounds.origin.x, labelsBounds.origin.y, labelsBounds.size.width, topLabelHeight);
|
||||
y += topLabelHeight + kLabelVSpacing;
|
||||
audioProgressView.frame = CGRectMake(labelsBounds.origin.x, y, labelsBounds.size.width, kAudioProgressViewHeight);
|
||||
y += kAudioProgressViewHeight + kLabelVSpacing;
|
||||
bottomLabel.frame = CGRectMake(labelsBounds.origin.x, y, labelsBounds.size.width, bottomLabelHeight);
|
||||
bottomLabel.textAlignment = NSTextAlignmentLeft;
|
||||
[labelsView addSubview:bottomLabel];
|
||||
[bottomLabel autoPinWidthToSuperview];
|
||||
[bottomLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:audioProgressView withOffset:kLabelVSpacing];
|
||||
[bottomLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
|
||||
[self updateContents];
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream isIncoming:(BOOL)isIncoming;
|
||||
|
||||
- (void)createContentsForSize:(CGSize)viewSize;
|
||||
- (void)createContents;
|
||||
|
||||
+ (CGFloat)bubbleHeight;
|
||||
|
||||
|
|
|
@ -98,32 +98,43 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [self.textColor blendWithColor:self.bubbleBackgroundColor alpha:alpha];
|
||||
}
|
||||
|
||||
- (void)createContentsForSize:(CGSize)viewSize
|
||||
- (void)createContents
|
||||
{
|
||||
UIColor *textColor = (self.isIncoming ? [UIColor colorWithWhite:0.2 alpha:1.f] : [UIColor whiteColor]);
|
||||
|
||||
self.backgroundColor = self.bubbleBackgroundColor;
|
||||
self.layoutMargins = UIEdgeInsetsZero;
|
||||
|
||||
// TODO: Verify that this layout works in RTL.
|
||||
const CGFloat kBubbleTailWidth = 6.f;
|
||||
CGRect contentFrame = CGRectMake(self.isIncoming ? kBubbleTailWidth : 0.f,
|
||||
self.vMargin,
|
||||
viewSize.width - kBubbleTailWidth - self.iconHMargin,
|
||||
viewSize.height - self.vMargin * 2);
|
||||
|
||||
UIView *contentView = [UIView containerView];
|
||||
[self addSubview:contentView];
|
||||
[contentView autoPinLeadingToSuperviewWithMargin:self.isIncoming ? kBubbleTailWidth : 0.f];
|
||||
[contentView autoPinTrailingToSuperviewWithMargin:self.isIncoming ? 0.f : kBubbleTailWidth];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.vMargin];
|
||||
[contentView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.vMargin];
|
||||
|
||||
UIImage *image = [UIImage imageNamed:@"generic-attachment-small"];
|
||||
OWSAssert(image);
|
||||
UIImageView *imageView = [UIImageView new];
|
||||
CGRect iconFrame = CGRectMake(round(contentFrame.origin.x + self.iconHMargin),
|
||||
round(contentFrame.origin.y + (contentFrame.size.height - self.iconSize) * 0.5f),
|
||||
self.iconSize,
|
||||
self.iconSize);
|
||||
imageView.frame = iconFrame;
|
||||
imageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
imageView.tintColor = self.bubbleBackgroundColor;
|
||||
imageView.backgroundColor
|
||||
= (self.isIncoming ? [UIColor colorWithRGBHex:0x9e9e9e] : [self foregroundColorWithOpacity:0.15f]);
|
||||
imageView.layer.cornerRadius = MIN(imageView.bounds.size.width, imageView.bounds.size.height) * 0.5f;
|
||||
[self addSubview:imageView];
|
||||
[contentView addSubview:imageView];
|
||||
[imageView autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:self.iconHMargin];
|
||||
[imageView autoVCenterInSuperview];
|
||||
[imageView autoSetDimension:ALDimensionWidth toSize:self.iconSize];
|
||||
[imageView autoSetDimension:ALDimensionHeight toSize:self.iconSize];
|
||||
|
||||
const CGFloat kLabelHSpacing = self.iconHSpacing;
|
||||
UIView *labelsView = [UIView containerView];
|
||||
[contentView addSubview:labelsView];
|
||||
[labelsView autoPinLeadingToTrailingOfView:imageView margin:kLabelHSpacing];
|
||||
[labelsView autoPinEdgeToSuperviewEdge:ALEdgeRight];
|
||||
[labelsView autoVCenterInSuperview];
|
||||
|
||||
NSString *filename = self.attachmentStream.sourceFilename;
|
||||
if (!filename) {
|
||||
|
@ -145,19 +156,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
fileTypeLabel.font = [UIFont ows_mediumFontWithSize:20.f];
|
||||
fileTypeLabel.adjustsFontSizeToFitWidth = YES;
|
||||
fileTypeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
CGRect fileTypeLabelFrame = CGRectZero;
|
||||
fileTypeLabelFrame.size = [fileTypeLabel sizeThatFits:CGSizeZero];
|
||||
// This dimension depends on the space within the icon boundaries.
|
||||
fileTypeLabelFrame.size.width = 15.f;
|
||||
// Center on icon.
|
||||
fileTypeLabelFrame.origin.x
|
||||
= round(iconFrame.origin.x + (iconFrame.size.width - fileTypeLabelFrame.size.width) * 0.5f);
|
||||
fileTypeLabelFrame.origin.y
|
||||
= round(iconFrame.origin.y + (iconFrame.size.height - fileTypeLabelFrame.size.height) * 0.5f);
|
||||
fileTypeLabel.frame = fileTypeLabelFrame;
|
||||
[self addSubview:fileTypeLabel];
|
||||
[imageView addSubview:fileTypeLabel];
|
||||
[imageView autoCenterInSuperview];
|
||||
[imageView autoSetDimension:ALDimensionWidth toSize:15.f];
|
||||
|
||||
const CGFloat kLabelHSpacing = self.iconHSpacing;
|
||||
const CGFloat kLabelVSpacing = 2;
|
||||
NSString *topText =
|
||||
[self.attachmentStream.sourceFilename stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
@ -172,8 +175,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
topLabel.textColor = textColor;
|
||||
topLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
topLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(13.f, 15.f)];
|
||||
[topLabel sizeToFit];
|
||||
[self addSubview:topLabel];
|
||||
topLabel.textAlignment = NSTextAlignmentLeft;
|
||||
[labelsView addSubview:topLabel];
|
||||
[topLabel autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
||||
[topLabel autoPinWidthToSuperview];
|
||||
|
||||
NSError *error;
|
||||
unsigned long long fileSize =
|
||||
|
@ -185,21 +190,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
bottomLabel.textColor = [textColor colorWithAlphaComponent:0.85f];
|
||||
bottomLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
bottomLabel.font = [UIFont ows_regularFontWithSize:ScaleFromIPhone5To7Plus(11.f, 13.f)];
|
||||
[bottomLabel sizeToFit];
|
||||
[self addSubview:bottomLabel];
|
||||
|
||||
CGRect topLabelFrame = CGRectZero;
|
||||
topLabelFrame.size = topLabel.bounds.size;
|
||||
topLabelFrame.origin.x = round(iconFrame.origin.x + iconFrame.size.width + kLabelHSpacing);
|
||||
topLabelFrame.origin.y = round(contentFrame.origin.y
|
||||
+ (contentFrame.size.height - (topLabel.frame.size.height + bottomLabel.frame.size.height + kLabelVSpacing))
|
||||
* 0.5f);
|
||||
topLabelFrame.size.width = round((contentFrame.origin.x + contentFrame.size.width) - topLabelFrame.origin.x);
|
||||
topLabel.frame = topLabelFrame;
|
||||
|
||||
CGRect bottomLabelFrame = topLabelFrame;
|
||||
bottomLabelFrame.origin.y += topLabelFrame.size.height + kLabelVSpacing;
|
||||
bottomLabel.frame = bottomLabelFrame;
|
||||
[labelsView addSubview:bottomLabel];
|
||||
[bottomLabel autoPinWidthToSuperview];
|
||||
[bottomLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topLabel withOffset:kLabelVSpacing];
|
||||
[bottomLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -243,7 +243,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
case OWSMessageCellType_GenericAttachment: {
|
||||
self.attachmentView =
|
||||
[[OWSGenericAttachmentView alloc] initWithAttachment:self.attachmentStream isIncoming:self.isIncoming];
|
||||
[self.attachmentView createContentsForSize:self.bounds.size];
|
||||
[self.attachmentView createContents];
|
||||
[self replaceBubbleWithView:self.attachmentView];
|
||||
[self addAttachmentUploadViewIfNecessary:self.attachmentView];
|
||||
break;
|
||||
|
@ -254,6 +254,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
[self ensureViewMediaState];
|
||||
|
||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// NSLog(@"---- %@", self.viewItem.interaction.debugDescription);
|
||||
// NSLog(@"cell: %@", NSStringFromCGRect(self.frame));
|
||||
|
@ -263,6 +265,116 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// });
|
||||
}
|
||||
|
||||
- (nullable id)tryToLoadCellMedia:(nullable id (^)())loadCellMediaBlock mediaView:(UIView *)mediaView
|
||||
{
|
||||
OWSAssert(self.attachmentStream);
|
||||
OWSAssert(mediaView);
|
||||
|
||||
if (self.viewItem.didCellMediaFailToLoad) {
|
||||
return nil;
|
||||
}
|
||||
id _Nullable cellMedia = self.viewItem.cachedCellMedia;
|
||||
if (cellMedia) {
|
||||
DDLogVerbose(@"%@ cell media cache hit", self.logTag);
|
||||
return cellMedia;
|
||||
}
|
||||
cellMedia = loadCellMediaBlock();
|
||||
if (cellMedia) {
|
||||
DDLogVerbose(@"%@ cell media cache miss", self.logTag);
|
||||
self.viewItem.cachedCellMedia = cellMedia;
|
||||
} else {
|
||||
DDLogError(@"%@ Failed to load cell media: %@", [self logTag], [self.attachmentStream mediaURL]);
|
||||
self.viewItem.didCellMediaFailToLoad = YES;
|
||||
[mediaView removeFromSuperview];
|
||||
// TODO: We need to hide/remove the media view.
|
||||
[self showAttachmentErrorView];
|
||||
}
|
||||
return cellMedia;
|
||||
}
|
||||
|
||||
// We want to lazy-load expensive view contents and eagerly unload if the
|
||||
// cell is no longer visible.
|
||||
- (void)ensureViewMediaState
|
||||
{
|
||||
if (!self.isCellVisible) {
|
||||
// Eagerly unload.
|
||||
if (self.stillImageView.image || self.animatedImageView.image) {
|
||||
DDLogError(@"%@ ---- ensureViewMediaState unloading[%zd]: %@",
|
||||
self.logTag,
|
||||
self.viewItem.row,
|
||||
self.viewItem.interaction.description);
|
||||
}
|
||||
self.stillImageView.image = nil;
|
||||
self.animatedImageView.image = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (self.cellType) {
|
||||
case OWSMessageCellType_StillImage: {
|
||||
if (self.stillImageView.image) {
|
||||
return;
|
||||
}
|
||||
DDLogError(@"%@ ---- ensureViewMediaState loading[%zd]: %@",
|
||||
self.logTag,
|
||||
self.viewItem.row,
|
||||
self.viewItem.interaction.description);
|
||||
self.stillImageView.image = [self tryToLoadCellMedia:^{
|
||||
OWSAssert([self.attachmentStream isImage]);
|
||||
return self.attachmentStream.image;
|
||||
}
|
||||
mediaView:self.stillImageView];
|
||||
break;
|
||||
}
|
||||
case OWSMessageCellType_AnimatedImage: {
|
||||
if (self.animatedImageView.image) {
|
||||
return;
|
||||
}
|
||||
DDLogError(@"%@ ---- ensureViewMediaState loading[%zd]: %@",
|
||||
self.logTag,
|
||||
self.viewItem.row,
|
||||
self.viewItem.interaction.description);
|
||||
self.animatedImageView.image = [self tryToLoadCellMedia:^{
|
||||
OWSAssert([self.attachmentStream isAnimated]);
|
||||
|
||||
NSString *_Nullable filePath = [self.attachmentStream filePath];
|
||||
YYImage *_Nullable animatedImage = nil;
|
||||
if (filePath && [NSData ows_isValidImageAtPath:filePath]) {
|
||||
animatedImage = [YYImage imageWithContentsOfFile:filePath];
|
||||
}
|
||||
return animatedImage;
|
||||
}
|
||||
mediaView:self.animatedImageView];
|
||||
break;
|
||||
}
|
||||
case OWSMessageCellType_Audio:
|
||||
// TODO: Lazy load audio length in audio cells.
|
||||
// [self loadForAudioDisplay];
|
||||
break;
|
||||
case OWSMessageCellType_Video: {
|
||||
if (self.stillImageView.image) {
|
||||
return;
|
||||
}
|
||||
DDLogError(@"%@ ---- ensureViewMediaState loading[%zd]: %@",
|
||||
self.logTag,
|
||||
self.viewItem.row,
|
||||
self.viewItem.interaction.description);
|
||||
self.stillImageView.image = [self tryToLoadCellMedia:^{
|
||||
OWSAssert([self.attachmentStream isVideo]);
|
||||
|
||||
return self.attachmentStream.image;
|
||||
}
|
||||
mediaView:self.stillImageView];
|
||||
break;
|
||||
}
|
||||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
// Inexpensive cell types don't need to lazy-load or eagerly-unload.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateDateHeader
|
||||
{
|
||||
OWSAssert(self.contentWidth > 0);
|
||||
|
@ -454,14 +566,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssert(self.attachmentStream);
|
||||
OWSAssert([self.attachmentStream isImage]);
|
||||
|
||||
UIImage *_Nullable image = self.attachmentStream.image;
|
||||
if (!image) {
|
||||
DDLogError(@"%@ Could not load image: %@", [self logTag], [self.attachmentStream mediaURL]);
|
||||
[self showAttachmentErrorView];
|
||||
return;
|
||||
}
|
||||
|
||||
self.stillImageView = [[UIImageView alloc] initWithImage:image];
|
||||
self.stillImageView = [UIImageView new];
|
||||
// We need to specify a contentMode since the size of the image
|
||||
// might not match the aspect ratio of the view.
|
||||
self.stillImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
|
@ -478,19 +583,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssert(self.attachmentStream);
|
||||
OWSAssert([self.attachmentStream isAnimated]);
|
||||
|
||||
NSString *_Nullable filePath = [self.attachmentStream filePath];
|
||||
YYImage *_Nullable animatedImage = nil;
|
||||
if (filePath && [NSData ows_isValidImageAtPath:filePath]) {
|
||||
animatedImage = [YYImage imageWithContentsOfFile:filePath];
|
||||
}
|
||||
if (!animatedImage) {
|
||||
DDLogError(@"%@ Could not load animated image: %@", [self logTag], [self.attachmentStream mediaURL]);
|
||||
[self showAttachmentErrorView];
|
||||
return;
|
||||
}
|
||||
|
||||
self.animatedImageView = [[YYAnimatedImageView alloc] init];
|
||||
self.animatedImageView.image = animatedImage;
|
||||
// We need to specify a contentMode since the size of the image
|
||||
// might not match the aspect ratio of the view.
|
||||
self.animatedImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
|
@ -507,7 +600,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
isIncoming:self.isIncoming
|
||||
viewItem:self.viewItem];
|
||||
self.viewItem.lastAudioMessageView = self.audioMessageView;
|
||||
[self.audioMessageView createContentsForSize:self.bounds.size];
|
||||
[self.audioMessageView createContents];
|
||||
[self replaceBubbleWithView:self.audioMessageView];
|
||||
[self addAttachmentUploadViewIfNecessary:self.audioMessageView];
|
||||
}
|
||||
|
@ -517,16 +610,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssert(self.attachmentStream);
|
||||
OWSAssert([self.attachmentStream isVideo]);
|
||||
|
||||
// CGSize size = [self mediaViewDisplaySize];
|
||||
|
||||
UIImage *_Nullable image = self.attachmentStream.image;
|
||||
if (!image) {
|
||||
DDLogError(@"%@ Could not load image: %@", [self logTag], [self.attachmentStream mediaURL]);
|
||||
[self showAttachmentErrorView];
|
||||
return;
|
||||
}
|
||||
|
||||
self.stillImageView = [[UIImageView alloc] initWithImage:image];
|
||||
self.stillImageView = [UIImageView new];
|
||||
// We need to specify a contentMode since the size of the image
|
||||
// might not match the aspect ratio of the view.
|
||||
self.stillImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
|
@ -616,25 +700,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.payloadView updateMask];
|
||||
}
|
||||
|
||||
//// TODO:
|
||||
//- (void)setFrame:(CGRect)frame {
|
||||
// [super setFrame:frame];
|
||||
//
|
||||
// DDLogError(@"setFrame: %@ %@ %@", self.viewItem.interaction.uniqueId, self.viewItem.interaction.description,
|
||||
// NSStringFromCGRect(frame));
|
||||
//}
|
||||
//
|
||||
//// TODO:
|
||||
//- (void)setBounds:(CGRect)bounds {
|
||||
// [super setBounds:bounds];
|
||||
//
|
||||
// DDLogError(@"setBounds: %@ %@ %@", self.viewItem.interaction.uniqueId, self.viewItem.interaction.description,
|
||||
// NSStringFromCGRect(bounds));
|
||||
//}
|
||||
|
||||
- (void)showAttachmentErrorView
|
||||
{
|
||||
// TODO: We could do a better job of indicating that the image could not be loaded.
|
||||
OWSAssert(!self.customView);
|
||||
|
||||
// TODO: We could do a better job of indicating that the media could not be loaded.
|
||||
self.customView = [UIView new];
|
||||
self.customView.backgroundColor = [UIColor colorWithWhite:0.85f alpha:1.f];
|
||||
self.customView.userInteractionEnabled = NO;
|
||||
|
@ -862,6 +932,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return;
|
||||
}
|
||||
|
||||
[self ensureViewMediaState];
|
||||
|
||||
if (isCellVisible) {
|
||||
if (self.message.shouldStartExpireTimer) {
|
||||
[self.expirationTimerView ensureAnimations];
|
||||
|
|
|
@ -86,6 +86,13 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
- (nullable TSAttachmentPointer *)attachmentPointer;
|
||||
- (CGSize)contentSize;
|
||||
|
||||
// A generic property that cells can use to cache their loaded
|
||||
// media. This cache is volatile and will get evacuated based
|
||||
// on scroll state, so that we only retain state for a sliding
|
||||
// window of cells that are almost on-screen.
|
||||
@property (nonatomic) id cachedCellMedia;
|
||||
@property (nonatomic) BOOL didCellMediaFailToLoad;
|
||||
|
||||
// TODO:
|
||||
//// Cells will request that this adapter clear its cached media views,
|
||||
//// but the adapter should only honor requests from the last cell to
|
||||
|
|
Loading…
Reference in New Issue