|
|
|
@ -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];
|
|
|
|
|