Render single media as albums.
This commit is contained in:
parent
1b49fa294f
commit
cd224a1590
|
@ -433,6 +433,11 @@ private class MockConversationViewItem: NSObject, ConversationViewItem {
|
|||
owsFailDebug("unexpected invocation")
|
||||
return nil
|
||||
}
|
||||
|
||||
func mediaAlbumHasFailedAttachment() -> Bool {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private class MockIncomingMessage: TSIncomingMessage {
|
||||
|
|
|
@ -187,14 +187,6 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
return (TSMessage *)self.viewItem.interaction;
|
||||
}
|
||||
|
||||
- (CGSize)mediaSize
|
||||
{
|
||||
// This should always be valid for the appropriate cell types.
|
||||
OWSAssertDebug(self.viewItem.mediaSize.width > 0 && self.viewItem.mediaSize.height > 0);
|
||||
|
||||
return self.viewItem.mediaSize;
|
||||
}
|
||||
|
||||
- (BOOL)isQuotedReply
|
||||
{
|
||||
// This should always be valid for the appropriate cell types.
|
||||
|
@ -232,10 +224,7 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
return YES;
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_Video:
|
||||
// Is there a caption?
|
||||
return self.hasBodyText;
|
||||
case OWSMessageCellType_ContactShare:
|
||||
|
@ -305,12 +294,6 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
break;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Video:
|
||||
OWSAssertDebug(self.viewItem.attachmentStream);
|
||||
bodyMediaView = [self loadViewForMedia];
|
||||
break;
|
||||
case OWSMessageCellType_Audio:
|
||||
OWSAssertDebug(self.viewItem.attachmentStream);
|
||||
bodyMediaView = [self loadViewForAudio];
|
||||
|
@ -595,10 +578,6 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
return NO;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Video:
|
||||
return YES;
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
|
@ -796,38 +775,21 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
[albumView unloadMedia];
|
||||
};
|
||||
|
||||
// Only apply "inner shadow" for single media, not albums.
|
||||
if (albumView.itemViews.count == 1) {
|
||||
UIView *itemView = albumView.itemViews.firstObject;
|
||||
OWSBubbleShapeView *innerShadowView = [[OWSBubbleShapeView alloc]
|
||||
initInnerShadowWithColor:(Theme.isDarkThemeEnabled ? UIColor.ows_whiteColor : UIColor.ows_blackColor)
|
||||
radius:0.5f
|
||||
opacity:0.15f];
|
||||
[itemView addSubview:innerShadowView];
|
||||
[self.bubbleView addPartnerView:innerShadowView];
|
||||
[self.viewConstraints addObjectsFromArray:[innerShadowView ows_autoPinToSuperviewEdges]];
|
||||
}
|
||||
|
||||
return albumView;
|
||||
}
|
||||
|
||||
- (UIView *)loadViewForMedia
|
||||
{
|
||||
OWSAssertDebug(self.attachmentStream);
|
||||
OWSAssertDebug([self.attachmentStream isVisualMedia]);
|
||||
|
||||
ConversationMediaView *mediaView =
|
||||
[[ConversationMediaView alloc] initWithMediaCache:self.cellMediaCache
|
||||
attachment:self.attachmentStream
|
||||
isOutgoing:self.isOutgoing
|
||||
maxMessageWidth:self.conversationStyle.maxMessageWidth];
|
||||
self.loadCellContentBlock = ^{
|
||||
[mediaView loadMedia];
|
||||
};
|
||||
self.unloadCellContentBlock = ^{
|
||||
[mediaView unloadMedia];
|
||||
};
|
||||
[self addAttachmentUploadViewIfNecessary];
|
||||
|
||||
OWSBubbleShapeView *innerShadowView = [[OWSBubbleShapeView alloc]
|
||||
initInnerShadowWithColor:(Theme.isDarkThemeEnabled ? UIColor.ows_whiteColor : UIColor.ows_blackColor)
|
||||
radius:0.5f
|
||||
opacity:0.15f];
|
||||
[mediaView addSubview:innerShadowView];
|
||||
[self.bubbleView addPartnerView:innerShadowView];
|
||||
[self.viewConstraints addObjectsFromArray:[innerShadowView ows_autoPinToSuperviewEdges]];
|
||||
|
||||
return mediaView;
|
||||
}
|
||||
|
||||
- (UIView *)loadViewForAudio
|
||||
{
|
||||
OWSAssertDebug(self.attachmentStream);
|
||||
|
@ -990,43 +952,6 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
case OWSMessageCellType_OversizeTextMessage: {
|
||||
return nil;
|
||||
}
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Video: {
|
||||
OWSAssertDebug(self.mediaSize.width > 0);
|
||||
OWSAssertDebug(self.mediaSize.height > 0);
|
||||
|
||||
// TODO: Adjust this behavior.
|
||||
|
||||
CGFloat contentAspectRatio = self.mediaSize.width / self.mediaSize.height;
|
||||
// Clamp the aspect ratio so that very thin/wide content is presented
|
||||
// in a reasonable way.
|
||||
const CGFloat minAspectRatio = 0.35f;
|
||||
const CGFloat maxAspectRatio = 1 / minAspectRatio;
|
||||
contentAspectRatio = MAX(minAspectRatio, MIN(maxAspectRatio, contentAspectRatio));
|
||||
|
||||
const CGFloat maxMediaWidth = maxMessageWidth;
|
||||
const CGFloat maxMediaHeight = maxMessageWidth;
|
||||
CGFloat mediaWidth = maxMediaHeight * contentAspectRatio;
|
||||
CGFloat mediaHeight = maxMediaHeight;
|
||||
if (mediaWidth > maxMediaWidth) {
|
||||
mediaWidth = maxMediaWidth;
|
||||
mediaHeight = maxMediaWidth / contentAspectRatio;
|
||||
}
|
||||
|
||||
// We don't want to blow up small images unnecessarily.
|
||||
const CGFloat kMinimumSize = 150.f;
|
||||
CGFloat shortSrcDimension = MIN(self.mediaSize.width, self.mediaSize.height);
|
||||
CGFloat shortDstDimension = MIN(mediaWidth, mediaHeight);
|
||||
if (shortDstDimension > kMinimumSize && shortDstDimension > shortSrcDimension) {
|
||||
CGFloat factor = kMinimumSize / shortDstDimension;
|
||||
mediaWidth *= factor;
|
||||
mediaHeight *= factor;
|
||||
}
|
||||
|
||||
result = CGSizeRound(CGSizeMake(mediaWidth, mediaHeight));
|
||||
break;
|
||||
}
|
||||
case OWSMessageCellType_Audio:
|
||||
result = CGSizeMake(maxMessageWidth, OWSAudioMessageView.bubbleHeight);
|
||||
break;
|
||||
|
@ -1049,6 +974,42 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
case OWSMessageCellType_MediaAlbum:
|
||||
result = [OWSMediaAlbumCellView layoutSizeForMaxMessageWidth:maxMessageWidth
|
||||
items:self.viewItem.mediaAlbumItems];
|
||||
|
||||
if (self.viewItem.mediaAlbumItems.count == 1) {
|
||||
// Honor the content aspect ratio for single media.
|
||||
ConversationMediaAlbumItem *mediaAlbumItem = self.viewItem.mediaAlbumItems.firstObject;
|
||||
if (mediaAlbumItem.attachmentStream && mediaAlbumItem.mediaSize.width > 0
|
||||
&& mediaAlbumItem.mediaSize.height > 0) {
|
||||
CGSize mediaSize = mediaAlbumItem.mediaSize;
|
||||
CGFloat contentAspectRatio = mediaSize.width / mediaSize.height;
|
||||
// Clamp the aspect ratio so that very thin/wide content is presented
|
||||
// in a reasonable way.
|
||||
const CGFloat minAspectRatio = 0.35f;
|
||||
const CGFloat maxAspectRatio = 1 / minAspectRatio;
|
||||
contentAspectRatio = MAX(minAspectRatio, MIN(maxAspectRatio, contentAspectRatio));
|
||||
|
||||
const CGFloat maxMediaWidth = maxMessageWidth;
|
||||
const CGFloat maxMediaHeight = maxMessageWidth;
|
||||
CGFloat mediaWidth = maxMediaHeight * contentAspectRatio;
|
||||
CGFloat mediaHeight = maxMediaHeight;
|
||||
if (mediaWidth > maxMediaWidth) {
|
||||
mediaWidth = maxMediaWidth;
|
||||
mediaHeight = maxMediaWidth / contentAspectRatio;
|
||||
}
|
||||
|
||||
// We don't want to blow up small images unnecessarily.
|
||||
const CGFloat kMinimumSize = 150.f;
|
||||
CGFloat shortSrcDimension = MIN(mediaSize.width, mediaSize.height);
|
||||
CGFloat shortDstDimension = MIN(mediaWidth, mediaHeight);
|
||||
if (shortDstDimension > kMinimumSize && shortDstDimension > shortSrcDimension) {
|
||||
CGFloat factor = kMinimumSize / shortDstDimension;
|
||||
mediaWidth *= factor;
|
||||
mediaHeight *= factor;
|
||||
}
|
||||
|
||||
result = CGSizeRound(CGSizeMake(mediaWidth, mediaHeight));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1367,35 +1328,11 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
break;
|
||||
case OWSMessageCellType_StillImage:
|
||||
OWSAssertDebug(self.bodyMediaView);
|
||||
OWSAssertDebug(self.viewItem.attachmentStream);
|
||||
|
||||
[self.delegate didTapImageViewItem:self.viewItem
|
||||
attachmentStream:self.viewItem.attachmentStream
|
||||
imageView:self.bodyMediaView];
|
||||
break;
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
OWSAssertDebug(self.bodyMediaView);
|
||||
OWSAssertDebug(self.viewItem.attachmentStream);
|
||||
|
||||
[self.delegate didTapImageViewItem:self.viewItem
|
||||
attachmentStream:self.viewItem.attachmentStream
|
||||
imageView:self.bodyMediaView];
|
||||
break;
|
||||
case OWSMessageCellType_Audio:
|
||||
OWSAssertDebug(self.viewItem.attachmentStream);
|
||||
|
||||
[self.delegate didTapAudioViewItem:self.viewItem attachmentStream:self.viewItem.attachmentStream];
|
||||
return;
|
||||
case OWSMessageCellType_Video:
|
||||
OWSAssertDebug(self.bodyMediaView);
|
||||
OWSAssertDebug(self.viewItem.attachmentStream);
|
||||
|
||||
[self.delegate didTapVideoViewItem:self.viewItem
|
||||
attachmentStream:self.viewItem.attachmentStream
|
||||
imageView:self.bodyMediaView];
|
||||
return;
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
OWSAssertDebug(self.viewItem.attachmentStream);
|
||||
|
||||
|
@ -1413,10 +1350,33 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
case OWSMessageCellType_ContactShare:
|
||||
[self.delegate didTapContactShareViewItem:self.viewItem];
|
||||
break;
|
||||
case OWSMessageCellType_MediaAlbum:
|
||||
case OWSMessageCellType_MediaAlbum: {
|
||||
OWSAssertDebug(self.bodyMediaView);
|
||||
OWSAssertDebug(self.viewItem.mediaAlbumItems.count > 0);
|
||||
|
||||
if (self.viewItem.mediaAlbumHasFailedAttachment) {
|
||||
[self.delegate didTapFailedIncomingAttachment:self.viewItem];
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We might be able to get rid of this.
|
||||
if (self.viewItem.mediaAlbumItems.count == 1) {
|
||||
ConversationMediaAlbumItem *mediaAlbumItem = self.viewItem.mediaAlbumItems.firstObject;
|
||||
if (!mediaAlbumItem.attachmentStream.isValidVisualMedia) {
|
||||
// Do nothing.
|
||||
} else if (mediaAlbumItem.attachmentStream.isAnimated || mediaAlbumItem.attachmentStream.isImage) {
|
||||
[self.delegate didTapImageViewItem:self.viewItem
|
||||
attachmentStream:mediaAlbumItem.attachmentStream
|
||||
imageView:self.bodyMediaView];
|
||||
return;
|
||||
} else if (mediaAlbumItem.attachmentStream.isVideo) {
|
||||
[self.delegate didTapVideoViewItem:self.viewItem
|
||||
attachmentStream:mediaAlbumItem.attachmentStream
|
||||
imageView:self.bodyMediaView];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For now, use first valid attachment.
|
||||
TSAttachmentStream *_Nullable attachmentStream = self.viewItem.firstValidAlbumAttachment;
|
||||
if (!attachmentStream) {
|
||||
|
@ -1428,6 +1388,7 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
attachmentStream:attachmentStream
|
||||
imageView:self.bodyMediaView];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,7 @@ typedef NS_ENUM(NSInteger, OWSMessageCellType) {
|
|||
OWSMessageCellType_Unknown,
|
||||
OWSMessageCellType_TextMessage,
|
||||
OWSMessageCellType_OversizeTextMessage,
|
||||
OWSMessageCellType_StillImage,
|
||||
OWSMessageCellType_AnimatedImage,
|
||||
OWSMessageCellType_Audio,
|
||||
OWSMessageCellType_Video,
|
||||
OWSMessageCellType_GenericAttachment,
|
||||
OWSMessageCellType_DownloadingAttachment,
|
||||
OWSMessageCellType_ContactShare,
|
||||
|
@ -108,7 +105,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
@property (nonatomic, readonly, nullable) DisplayableText *displayableBodyText;
|
||||
@property (nonatomic, readonly, nullable) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic, readonly, nullable) TSAttachmentPointer *attachmentPointer;
|
||||
@property (nonatomic, readonly) CGSize mediaSize;
|
||||
@property (nonatomic, readonly, nullable) NSArray<ConversationMediaAlbumItem *> *mediaAlbumItems;
|
||||
|
||||
@property (nonatomic, readonly, nullable) DisplayableText *displayableQuotedText;
|
||||
|
@ -146,6 +142,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
|
||||
- (nullable TSAttachmentStream *)firstValidAlbumAttachment;
|
||||
|
||||
- (BOOL)mediaAlbumHasFailedAttachment;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
@ -25,14 +25,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
return @"OWSMessageCellType_TextMessage";
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
return @"OWSMessageCellType_OversizeTextMessage";
|
||||
case OWSMessageCellType_StillImage:
|
||||
return @"OWSMessageCellType_StillImage";
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
return @"OWSMessageCellType_AnimatedImage";
|
||||
case OWSMessageCellType_Audio:
|
||||
return @"OWSMessageCellType_Audio";
|
||||
case OWSMessageCellType_Video:
|
||||
return @"OWSMessageCellType_Video";
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
return @"OWSMessageCellType_GenericAttachment";
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
|
@ -94,7 +88,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
@property (nonatomic, nullable) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic, nullable) TSAttachmentPointer *attachmentPointer;
|
||||
@property (nonatomic, nullable) ContactShareViewModel *contactShare;
|
||||
@property (nonatomic) CGSize mediaSize;
|
||||
@property (nonatomic, nullable) NSArray<ConversationMediaAlbumItem *> *mediaAlbumItems;
|
||||
@property (nonatomic, nullable) NSString *systemMessageText;
|
||||
@property (nonatomic, nullable) TSThread *incomingMessageAuthorThread;
|
||||
|
@ -156,7 +149,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
self.displayableBodyText = nil;
|
||||
self.attachmentStream = nil;
|
||||
self.attachmentPointer = nil;
|
||||
self.mediaSize = CGSizeZero;
|
||||
self.displayableQuotedText = nil;
|
||||
self.quotedReply = nil;
|
||||
self.systemMessageText = nil;
|
||||
|
@ -573,9 +565,24 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
if ([message isMediaAlbumWithTransaction:transaction]) {
|
||||
OWSAssertDebug(attachments.count > 0);
|
||||
NSArray<ConversationMediaAlbumItem *> *mediaAlbumItems = [self mediaAlbumItemsForAttachments:attachments];
|
||||
|
||||
if (mediaAlbumItems.count == 1) {
|
||||
ConversationMediaAlbumItem *mediaAlbumItem = mediaAlbumItems.firstObject;
|
||||
if (mediaAlbumItem.attachmentStream && !mediaAlbumItem.attachmentStream.isValidVisualMedia) {
|
||||
OWSLogWarn(@"Treating invalid media as generic attachment.");
|
||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.mediaAlbumItems = mediaAlbumItems;
|
||||
self.messageCellType = OWSMessageCellType_MediaAlbum;
|
||||
NSString *_Nullable albumTitle = [message bodyTextWithTransaction:transaction];
|
||||
if (!albumTitle && mediaAlbumItems.count == 1) {
|
||||
// If the album contains only one option, use its caption as the
|
||||
// the album title.
|
||||
albumTitle = mediaAlbumItems.firstObject.caption;
|
||||
}
|
||||
if (albumTitle) {
|
||||
self.displayableBodyText = [self displayableBodyTextForText:albumTitle interactionId:message.uniqueId];
|
||||
}
|
||||
|
@ -593,41 +600,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
self.messageCellType = OWSMessageCellType_OversizeTextMessage;
|
||||
self.displayableBodyText = [self displayableBodyTextForOversizeTextAttachment:self.attachmentStream
|
||||
interactionId:message.uniqueId];
|
||||
} else if ([self.attachmentStream isAnimated] || [self.attachmentStream isImage] ||
|
||||
[self.attachmentStream isVideo]) {
|
||||
if ([self.attachmentStream isAnimated]) {
|
||||
if (![self.attachmentStream isValidImage]) {
|
||||
OWSLogWarn(@"Treating invalid image as generic attachment.");
|
||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||
return;
|
||||
}
|
||||
|
||||
self.messageCellType = OWSMessageCellType_AnimatedImage;
|
||||
} else if ([self.attachmentStream isImage]) {
|
||||
if (![self.attachmentStream isValidImage]) {
|
||||
OWSLogWarn(@"Treating invalid image as generic attachment.");
|
||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||
return;
|
||||
}
|
||||
|
||||
self.messageCellType = OWSMessageCellType_StillImage;
|
||||
} else if ([self.attachmentStream isVideo]) {
|
||||
if (![self.attachmentStream isValidVideo]) {
|
||||
OWSLogWarn(@"Treating invalid video as generic attachment.");
|
||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||
return;
|
||||
}
|
||||
|
||||
self.messageCellType = OWSMessageCellType_Video;
|
||||
} else {
|
||||
OWSFailDebug(@"unexpected attachment type.");
|
||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||
return;
|
||||
}
|
||||
self.mediaSize = [self.attachmentStream imageSize];
|
||||
if (self.mediaSize.width <= 0 || self.mediaSize.height <= 0) {
|
||||
self.messageCellType = OWSMessageCellType_GenericAttachment;
|
||||
}
|
||||
} else if ([self.attachmentStream isAudio]) {
|
||||
CGFloat audioDurationSeconds = [self.attachmentStream audioDurationSeconds];
|
||||
if (audioDurationSeconds > 0) {
|
||||
|
@ -825,14 +797,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
return _attachmentPointer;
|
||||
}
|
||||
|
||||
- (CGSize)mediaSize
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(self.hasViewState);
|
||||
|
||||
return _mediaSize;
|
||||
}
|
||||
|
||||
- (nullable DisplayableText *)displayableQuotedText
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
@ -850,10 +814,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
switch (self.messageCellType) {
|
||||
case OWSMessageCellType_TextMessage:
|
||||
case OWSMessageCellType_OversizeTextMessage:
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_Video:
|
||||
case OWSMessageCellType_MediaAlbum:
|
||||
case OWSMessageCellType_GenericAttachment: {
|
||||
OWSAssertDebug(self.displayableBodyText);
|
||||
|
@ -886,10 +847,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
OWSFailDebug(@"No media to copy");
|
||||
break;
|
||||
}
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_Video:
|
||||
case OWSMessageCellType_GenericAttachment: {
|
||||
[self copyAttachmentToPasteboard:self.attachmentStream];
|
||||
break;
|
||||
|
@ -899,6 +857,14 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
break;
|
||||
}
|
||||
case OWSMessageCellType_MediaAlbum: {
|
||||
if (self.mediaAlbumItems.count == 1) {
|
||||
ConversationMediaAlbumItem *mediaAlbumItem = self.mediaAlbumItems.firstObject;
|
||||
if (mediaAlbumItem.attachmentStream && mediaAlbumItem.attachmentStream.isValidVisualMedia) {
|
||||
[self copyAttachmentToPasteboard:mediaAlbumItem.attachmentStream];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OWSFailDebug(@"Can't copy media album");
|
||||
break;
|
||||
}
|
||||
|
@ -931,10 +897,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
case OWSMessageCellType_ContactShare:
|
||||
OWSFailDebug(@"No media to share.");
|
||||
break;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_Video:
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
[AttachmentSharing showShareUIForAttachment:self.attachmentStream];
|
||||
break;
|
||||
|
@ -947,7 +910,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
OWSAssertDebug(self.mediaAlbumItems);
|
||||
NSMutableArray<TSAttachmentStream *> *attachmentStreams = [NSMutableArray new];
|
||||
for (ConversationMediaAlbumItem *mediaAlbumItem in self.mediaAlbumItems) {
|
||||
if (mediaAlbumItem.attachmentStream) {
|
||||
if (mediaAlbumItem.attachmentStream && mediaAlbumItem.attachmentStream.isValidVisualMedia) {
|
||||
[attachmentStreams addObject:mediaAlbumItem.attachmentStream];
|
||||
}
|
||||
}
|
||||
|
@ -969,17 +932,19 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
case OWSMessageCellType_OversizeTextMessage:
|
||||
case OWSMessageCellType_ContactShare:
|
||||
return NO;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
return YES;
|
||||
case OWSMessageCellType_Audio:
|
||||
return NO;
|
||||
case OWSMessageCellType_Video:
|
||||
return UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(self.attachmentStream.originalFilePath);
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
case OWSMessageCellType_MediaAlbum:
|
||||
case OWSMessageCellType_MediaAlbum: {
|
||||
if (self.mediaAlbumItems.count == 1) {
|
||||
ConversationMediaAlbumItem *mediaAlbumItem = self.mediaAlbumItems.firstObject;
|
||||
if (mediaAlbumItem.attachmentStream && mediaAlbumItem.attachmentStream.isValidVisualMedia) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -991,13 +956,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
case OWSMessageCellType_OversizeTextMessage:
|
||||
case OWSMessageCellType_ContactShare:
|
||||
return NO;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
return YES;
|
||||
case OWSMessageCellType_Audio:
|
||||
return NO;
|
||||
case OWSMessageCellType_Video:
|
||||
return UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(self.attachmentStream.originalFilePath);
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
case OWSMessageCellType_DownloadingAttachment:
|
||||
return NO;
|
||||
|
@ -1006,6 +966,9 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
if (!mediaAlbumItem.attachmentStream) {
|
||||
continue;
|
||||
}
|
||||
if (!mediaAlbumItem.attachmentStream.isValidVisualMedia) {
|
||||
continue;
|
||||
}
|
||||
if (mediaAlbumItem.attachmentStream.isImage || mediaAlbumItem.attachmentStream.isAnimated) {
|
||||
return YES;
|
||||
}
|
||||
|
@ -1030,33 +993,9 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
case OWSMessageCellType_ContactShare:
|
||||
OWSFailDebug(@"Cannot save text data.");
|
||||
break;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage: {
|
||||
NSData *data = [NSData dataWithContentsOfURL:[self.attachmentStream originalMediaURL]];
|
||||
if (!data) {
|
||||
OWSFailDebug(@"Could not load image data");
|
||||
return;
|
||||
}
|
||||
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
||||
[library writeImageDataToSavedPhotosAlbum:data
|
||||
metadata:nil
|
||||
completionBlock:^(NSURL *assetURL, NSError *error) {
|
||||
if (error) {
|
||||
OWSLogWarn(@"Error Saving image to photo album: %@", error);
|
||||
}
|
||||
}];
|
||||
break;
|
||||
}
|
||||
case OWSMessageCellType_Audio:
|
||||
OWSFailDebug(@"Cannot save media data.");
|
||||
break;
|
||||
case OWSMessageCellType_Video:
|
||||
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(self.attachmentStream.originalFilePath)) {
|
||||
UISaveVideoAtPathToSavedPhotosAlbum(self.attachmentStream.originalFilePath, self, nil, nil);
|
||||
} else {
|
||||
OWSFailDebug(@"Could not save incompatible video data.");
|
||||
}
|
||||
break;
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
OWSFailDebug(@"Cannot save media data.");
|
||||
break;
|
||||
|
@ -1071,6 +1010,9 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
if (!mediaAlbumItem.attachmentStream) {
|
||||
continue;
|
||||
}
|
||||
if (!mediaAlbumItem.attachmentStream.isValidVisualMedia) {
|
||||
continue;
|
||||
}
|
||||
if (mediaAlbumItem.attachmentStream.isImage || mediaAlbumItem.attachmentStream.isAnimated) {
|
||||
NSData *data = [NSData dataWithContentsOfURL:[mediaAlbumItem.attachmentStream originalMediaURL]];
|
||||
if (!data) {
|
||||
|
@ -1115,21 +1057,33 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
case OWSMessageCellType_OversizeTextMessage:
|
||||
case OWSMessageCellType_ContactShare:
|
||||
return NO;
|
||||
case OWSMessageCellType_StillImage:
|
||||
case OWSMessageCellType_AnimatedImage:
|
||||
case OWSMessageCellType_Audio:
|
||||
case OWSMessageCellType_Video:
|
||||
case OWSMessageCellType_GenericAttachment:
|
||||
return self.attachmentStream != nil;
|
||||
case OWSMessageCellType_DownloadingAttachment: {
|
||||
return NO;
|
||||
}
|
||||
case OWSMessageCellType_MediaAlbum:
|
||||
// TODO: I suspect we need separate "can save media", "can share media", etc. methods.
|
||||
return self.firstValidAlbumAttachment != nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)mediaAlbumHasFailedAttachment
|
||||
{
|
||||
OWSAssertDebug(self.messageCellType == OWSMessageCellType_MediaAlbum);
|
||||
OWSAssertDebug(self.mediaAlbumItems.count > 0);
|
||||
|
||||
for (ConversationMediaAlbumItem *mediaAlbumItem in self.mediaAlbumItems) {
|
||||
if ([mediaAlbumItem.attachment isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)mediaAlbumItem.attachment;
|
||||
if (attachmentPointer.state == TSAttachmentPointerStateFailed) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -225,7 +225,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
- (BOOL)isMediaAlbumWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
NSArray<TSAttachment *> *attachments = [self attachmentsWithTransaction:transaction];
|
||||
if (attachments.count < 2) {
|
||||
if (attachments.count < 1) {
|
||||
return NO;
|
||||
}
|
||||
for (TSAttachment *attachment in attachments) {
|
||||
|
|
Loading…
Reference in New Issue