Generate thumbnail when quoted attachment is available locally
// FREEBIE
This commit is contained in:
parent
351f9ea263
commit
42f454b075
|
@ -77,6 +77,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// Marks attachment as having completed "lazy backup restore."
|
||||
- (void)updateWithLazyRestoreComplete;
|
||||
|
||||
- (nullable TSAttachmentStream *)cloneAsThumbnail;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -677,6 +677,31 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}];
|
||||
}
|
||||
|
||||
- (nullable TSAttachmentStream *)cloneAsThumbnail
|
||||
{
|
||||
NSData *thumbnailData = self.thumbnailData;
|
||||
// Only some media types have thumbnails
|
||||
if (!thumbnailData) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Copy the thumbnail to a new attachment.
|
||||
NSString *thumbnailName = [NSString stringWithFormat:@"quoted-thumbnail-%@", self.sourceFilename];
|
||||
TSAttachmentStream *thumbnailAttachment =
|
||||
[[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"
|
||||
byteCount:(uint32_t)thumbnailData.length
|
||||
sourceFilename:thumbnailName];
|
||||
|
||||
NSError *error;
|
||||
BOOL success = [thumbnailAttachment writeData:thumbnailData error:&error];
|
||||
if (!success || error) {
|
||||
DDLogError(@"%@ Couldn't copy attachment data for message sent to self: %@.", self.logTag, error);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return thumbnailAttachment;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -93,6 +93,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return foundMessage;
|
||||
}
|
||||
|
||||
// TODO get rid of this method and instead populate authorId in initWithCoder:
|
||||
- (NSString *)messageAuthorId
|
||||
{
|
||||
// authorId isn't set on all legacy messages, so we take
|
||||
|
|
|
@ -42,6 +42,9 @@ typedef NS_ENUM(NSInteger, OWSInteractionType) {
|
|||
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
|
||||
ofClass:(Class)clazz
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
|
||||
filter:(BOOL (^_Nonnull)(TSInteraction *))filter
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
- (NSDate *)dateForSorting;
|
||||
- (uint64_t)timestampForSorting;
|
||||
|
|
|
@ -69,7 +69,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@end
|
||||
|
||||
@interface TSQuotedMessage : TSYapDatabaseObject
|
||||
// TODO make this a MantleModel not a YapDatabaseObject.
|
||||
|
||||
@interface TSQuotedMessage : MTLModel
|
||||
|
||||
@property (nonatomic, readonly) uint64_t timestamp;
|
||||
@property (nonatomic, readonly) NSString *authorId;
|
||||
|
@ -109,7 +111,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
body:(NSString *_Nullable)body
|
||||
quotedAttachmentsForSending:(NSArray<TSAttachment *> *)attachments;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
@ -42,28 +42,28 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// View Model which has already fetched any thumbnail attachment.
|
||||
@implementation OWSQuotedReplyModel
|
||||
|
||||
// This is a MIME type.
|
||||
//
|
||||
// This property should be set IFF we are quoting an attachment message.
|
||||
- (nullable NSString *)contentType
|
||||
{
|
||||
return self.attachmentStream.contentType;
|
||||
}
|
||||
|
||||
- (nullable NSString *)sourceFilename
|
||||
{
|
||||
return self.attachmentStream.sourceFilename;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)thumbnailImage
|
||||
{
|
||||
return self.attachmentStream.thumbnailImage;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
authorId:(NSString *)authorId
|
||||
body:(NSString *_Nullable)body
|
||||
attachmentStream:(nullable TSAttachmentStream *)attachmentStream
|
||||
{
|
||||
return [self initWithTimestamp:timestamp
|
||||
authorId:authorId
|
||||
body:body
|
||||
thumbnailImage:attachmentStream.thumbnailImage
|
||||
contentType:attachmentStream.contentType
|
||||
sourceFilename:attachmentStream.sourceFilename
|
||||
attachmentStream:attachmentStream];
|
||||
}
|
||||
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
authorId:(NSString *)authorId
|
||||
body:(nullable NSString *)body
|
||||
thumbnailImage:(nullable UIImage *)thumbnailImage
|
||||
contentType:(nullable NSString *)contentType
|
||||
sourceFilename:(nullable NSString *)sourceFilename
|
||||
attachmentStream:(nullable TSAttachmentStream *)attachmentStream
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
|
@ -73,6 +73,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
_timestamp = timestamp;
|
||||
_authorId = authorId;
|
||||
_body = body;
|
||||
_thumbnailImage = thumbnailImage;
|
||||
_contentType = contentType;
|
||||
_sourceFilename = sourceFilename;
|
||||
|
||||
// rename to originalAttachmentStream?
|
||||
_attachmentStream = attachmentStream;
|
||||
|
||||
return self;
|
||||
|
@ -81,19 +86,28 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (instancetype)initWithQuotedMessage:(TSQuotedMessage *)quotedMessage
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
TSAttachment *attachment =
|
||||
[TSAttachment fetchObjectWithUniqueID:quotedMessage.quotedAttachments.firstObject.attachmentId
|
||||
transaction:transaction];
|
||||
OWSAssert(quotedMessage.quotedAttachments.count <= 1);
|
||||
OWSAttachmentInfo *attachmentInfo = quotedMessage.quotedAttachments.firstObject;
|
||||
|
||||
TSAttachmentStream *attachmentStream;
|
||||
if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
attachmentStream = (TSAttachmentStream *)attachment;
|
||||
UIImage *_Nullable thumbnailImage;
|
||||
if (attachmentInfo.thumbnailAttachmentId) {
|
||||
TSAttachment *attachment =
|
||||
[TSAttachment fetchObjectWithUniqueID:attachmentInfo.thumbnailAttachmentId transaction:transaction];
|
||||
|
||||
TSAttachmentStream *attachmentStream;
|
||||
if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
attachmentStream = (TSAttachmentStream *)attachment;
|
||||
thumbnailImage = attachmentStream.image;
|
||||
}
|
||||
}
|
||||
|
||||
return [self initWithTimestamp:quotedMessage.timestamp
|
||||
authorId:quotedMessage.authorId
|
||||
body:quotedMessage.body
|
||||
attachmentStream:attachmentStream];
|
||||
thumbnailImage:thumbnailImage
|
||||
contentType:attachmentInfo.contentType
|
||||
sourceFilename:attachmentInfo.sourceFilename
|
||||
attachmentStream:nil];
|
||||
}
|
||||
|
||||
- (TSQuotedMessage *)buildQuotedMessage
|
||||
|
@ -253,38 +267,21 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
continue;
|
||||
}
|
||||
TSAttachmentStream *sourceStream = (TSAttachmentStream *)attachment;
|
||||
|
||||
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment;
|
||||
NSData *thumbnailData = attachmentStream.thumbnailData;
|
||||
// Only some media types have thumbnails
|
||||
if (thumbnailData) {
|
||||
// Copy the thumbnail to a new attachment.
|
||||
NSString *thumbnailName =
|
||||
[NSString stringWithFormat:@"quoted-thumbnail-%@", attachmentStream.sourceFilename];
|
||||
TSAttachmentStream *thumbnailAttachment =
|
||||
[[TSAttachmentStream alloc] initWithContentType:@"image/jpeg"
|
||||
byteCount:attachmentStream.byteCount
|
||||
sourceFilename:thumbnailName];
|
||||
|
||||
NSError *error;
|
||||
[thumbnailAttachment writeData:thumbnailData error:&error];
|
||||
if (error) {
|
||||
DDLogError(@"%@ Couldn't copy attachment data for message sent to self: %@.", self.logTag, error);
|
||||
} else {
|
||||
[thumbnailAttachment saveWithTransaction:transaction];
|
||||
info.thumbnailAttachmentId = thumbnailAttachment.uniqueId;
|
||||
[thumbnailAttachments addObject:thumbnailAttachment];
|
||||
}
|
||||
TSAttachmentStream *_Nullable thumbnailStream = [sourceStream cloneAsThumbnail];
|
||||
if (!thumbnailStream) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (thumbnailAttachments.count > 0) {
|
||||
// Save to record any self.quotedAttachments[].thumbnailAttachmentId
|
||||
[self saveWithTransaction:transaction];
|
||||
[thumbnailStream saveWithTransaction:transaction];
|
||||
info.thumbnailAttachmentId = thumbnailStream.uniqueId;
|
||||
[thumbnailAttachments addObject:thumbnailStream];
|
||||
}
|
||||
|
||||
return [thumbnailAttachments copy];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#import "TSAccountManager.h"
|
||||
#import "TSAttachment.h"
|
||||
#import "TSAttachmentPointer.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import "TSContactThread.h"
|
||||
#import "TSDatabaseView.h"
|
||||
#import "TSGroupModel.h"
|
||||
|
@ -990,8 +991,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return nil;
|
||||
}
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage =
|
||||
[self quotedMessageForDataMessage:dataMessage envelope:envelope transaction:transaction];
|
||||
TSQuotedMessage *_Nullable quotedMessage = [self quotedMessageForDataMessage:dataMessage
|
||||
envelope:envelope
|
||||
thread:oldGroupThread
|
||||
transaction:transaction];
|
||||
|
||||
DDLogDebug(@"%@ incoming message from: %@ for group: %@ with timestamp: %lu",
|
||||
self.logTag,
|
||||
|
@ -1038,7 +1041,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
relay:envelope.relay];
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage =
|
||||
[self quotedMessageForDataMessage:dataMessage envelope:envelope transaction:transaction];
|
||||
[self quotedMessageForDataMessage:dataMessage envelope:envelope thread:thread transaction:transaction];
|
||||
|
||||
TSIncomingMessage *incomingMessage =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
|
||||
|
@ -1059,6 +1062,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
|
||||
envelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
thread:(TSThread *)thread
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(dataMessage);
|
||||
|
@ -1097,8 +1101,46 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[[OWSAttachmentInfo alloc] initWithAttachmentId:nil
|
||||
contentType:quotedAttachment.contentType
|
||||
sourceFilename:quotedAttachment.fileName];
|
||||
|
||||
TSMessage *_Nullable quotedMessage = (TSMessage *)[TSInteraction
|
||||
interactionsWithTimestamp:timestamp
|
||||
filter:^BOOL(TSInteraction *interaction) {
|
||||
|
||||
if (![thread.uniqueId isEqual:interaction.uniqueThreadId]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ([interaction isKindOfClass:[TSIncomingMessage class]]) {
|
||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)interaction;
|
||||
return [authorId isEqual:incomingMessage.messageAuthorId];
|
||||
} else if ([interaction isKindOfClass:[TSOutgoingMessage class]]) {
|
||||
return [authorId isEqual:[TSAccountManager localNumber]];
|
||||
} else {
|
||||
// ignore other interaction types
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
withTransaction:transaction]
|
||||
.firstObject;
|
||||
|
||||
// We still have the existing quoted message locally.
|
||||
// Derive any thumbnail locally rather than fetching one over the network.
|
||||
if (quotedMessage) {
|
||||
TSAttachment *attachment = [quotedMessage attachmentWithTransaction:transaction];
|
||||
if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
TSAttachmentStream *sourceStream = (TSAttachmentStream *)attachment;
|
||||
|
||||
TSAttachmentStream *thumbnailStream = [sourceStream cloneAsThumbnail];
|
||||
[thumbnailStream saveWithTransaction:transaction];
|
||||
attachmentInfo.thumbnailAttachmentId = thumbnailStream.uniqueId;
|
||||
}
|
||||
}
|
||||
|
||||
[attachmentInfos addObject:attachmentInfo];
|
||||
}
|
||||
|
||||
|
||||
// TODO - but only if the attachment can't be found locally.
|
||||
// OWSAttachmentsProcessor *attachmentsProcessor =
|
||||
// [[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:quoteProto.attachments
|
||||
|
|
|
@ -333,8 +333,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
thumbnailAttachments =
|
||||
[message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction];
|
||||
if (thumbnailAttachments.count > 0) {
|
||||
[message touchWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
// Though we currently only ever expect at most one thumbnail, the proto data model
|
||||
// suggests this could change. The logic is intended to work with multiple, but
|
||||
// if we ever actually want to send multiple, we should do more testing.
|
||||
|
|
Loading…
Reference in New Issue