Generate thumbnail when quoted attachment is available locally

// FREEBIE
pull/1/head
Michael Kirk 7 years ago
parent 351f9ea263
commit 42f454b075

@ -77,6 +77,8 @@ NS_ASSUME_NONNULL_BEGIN
// Marks attachment as having completed "lazy backup restore." // Marks attachment as having completed "lazy backup restore."
- (void)updateWithLazyRestoreComplete; - (void)updateWithLazyRestoreComplete;
- (nullable TSAttachmentStream *)cloneAsThumbnail;
@end @end
NS_ASSUME_NONNULL_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 @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -93,6 +93,7 @@ NS_ASSUME_NONNULL_BEGIN
return foundMessage; return foundMessage;
} }
// TODO get rid of this method and instead populate authorId in initWithCoder:
- (NSString *)messageAuthorId - (NSString *)messageAuthorId
{ {
// authorId isn't set on all legacy messages, so we take // 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 + (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
ofClass:(Class)clazz ofClass:(Class)clazz
withTransaction:(YapDatabaseReadWriteTransaction *)transaction; withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
filter:(BOOL (^_Nonnull)(TSInteraction *))filter
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
- (NSDate *)dateForSorting; - (NSDate *)dateForSorting;
- (uint64_t)timestampForSorting; - (uint64_t)timestampForSorting;

@ -69,7 +69,9 @@ NS_ASSUME_NONNULL_BEGIN
@end @end
@interface TSQuotedMessage : TSYapDatabaseObject // TODO make this a MantleModel not a YapDatabaseObject.
@interface TSQuotedMessage : MTLModel
@property (nonatomic, readonly) uint64_t timestamp; @property (nonatomic, readonly) uint64_t timestamp;
@property (nonatomic, readonly) NSString *authorId; @property (nonatomic, readonly) NSString *authorId;
@ -109,7 +111,6 @@ NS_ASSUME_NONNULL_BEGIN
body:(NSString *_Nullable)body body:(NSString *_Nullable)body
quotedAttachmentsForSending:(NSArray<TSAttachment *> *)attachments; quotedAttachmentsForSending:(NSArray<TSAttachment *> *)attachments;
@end @end
#pragma mark - #pragma mark -

@ -42,27 +42,27 @@ NS_ASSUME_NONNULL_BEGIN
// View Model which has already fetched any thumbnail attachment. // View Model which has already fetched any thumbnail attachment.
@implementation OWSQuotedReplyModel @implementation OWSQuotedReplyModel
// This is a MIME type. - (instancetype)initWithTimestamp:(uint64_t)timestamp
// authorId:(NSString *)authorId
// This property should be set IFF we are quoting an attachment message. body:(NSString *_Nullable)body
- (nullable NSString *)contentType attachmentStream:(nullable TSAttachmentStream *)attachmentStream
{ {
return self.attachmentStream.contentType; return [self initWithTimestamp:timestamp
authorId:authorId
body:body
thumbnailImage:attachmentStream.thumbnailImage
contentType:attachmentStream.contentType
sourceFilename:attachmentStream.sourceFilename
attachmentStream:attachmentStream];
} }
- (nullable NSString *)sourceFilename
{
return self.attachmentStream.sourceFilename;
}
- (nullable UIImage *)thumbnailImage
{
return self.attachmentStream.thumbnailImage;
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp - (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId authorId:(NSString *)authorId
body:(NSString *_Nullable)body body:(nullable NSString *)body
thumbnailImage:(nullable UIImage *)thumbnailImage
contentType:(nullable NSString *)contentType
sourceFilename:(nullable NSString *)sourceFilename
attachmentStream:(nullable TSAttachmentStream *)attachmentStream attachmentStream:(nullable TSAttachmentStream *)attachmentStream
{ {
self = [super init]; self = [super init];
@ -73,6 +73,11 @@ NS_ASSUME_NONNULL_BEGIN
_timestamp = timestamp; _timestamp = timestamp;
_authorId = authorId; _authorId = authorId;
_body = body; _body = body;
_thumbnailImage = thumbnailImage;
_contentType = contentType;
_sourceFilename = sourceFilename;
// rename to originalAttachmentStream?
_attachmentStream = attachmentStream; _attachmentStream = attachmentStream;
return self; return self;
@ -81,19 +86,28 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithQuotedMessage:(TSQuotedMessage *)quotedMessage - (instancetype)initWithQuotedMessage:(TSQuotedMessage *)quotedMessage
transaction:(YapDatabaseReadTransaction *)transaction transaction:(YapDatabaseReadTransaction *)transaction
{ {
TSAttachment *attachment = OWSAssert(quotedMessage.quotedAttachments.count <= 1);
[TSAttachment fetchObjectWithUniqueID:quotedMessage.quotedAttachments.firstObject.attachmentId OWSAttachmentInfo *attachmentInfo = quotedMessage.quotedAttachments.firstObject;
transaction:transaction];
UIImage *_Nullable thumbnailImage;
TSAttachmentStream *attachmentStream; if (attachmentInfo.thumbnailAttachmentId) {
if ([attachment isKindOfClass:[TSAttachmentStream class]]) { TSAttachment *attachment =
attachmentStream = (TSAttachmentStream *)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 return [self initWithTimestamp:quotedMessage.timestamp
authorId:quotedMessage.authorId authorId:quotedMessage.authorId
body:quotedMessage.body body:quotedMessage.body
attachmentStream:attachmentStream]; thumbnailImage:thumbnailImage
contentType:attachmentInfo.contentType
sourceFilename:attachmentInfo.sourceFilename
attachmentStream:nil];
} }
- (TSQuotedMessage *)buildQuotedMessage - (TSQuotedMessage *)buildQuotedMessage
@ -253,38 +267,21 @@ NS_ASSUME_NONNULL_BEGIN
if (![attachment isKindOfClass:[TSAttachmentStream class]]) { if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
continue; continue;
} }
TSAttachmentStream *sourceStream = (TSAttachmentStream *)attachment;
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; TSAttachmentStream *_Nullable thumbnailStream = [sourceStream cloneAsThumbnail];
NSData *thumbnailData = attachmentStream.thumbnailData; if (!thumbnailStream) {
// Only some media types have thumbnails continue;
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];
}
} }
}
if (thumbnailAttachments.count > 0) { [thumbnailStream saveWithTransaction:transaction];
// Save to record any self.quotedAttachments[].thumbnailAttachmentId info.thumbnailAttachmentId = thumbnailStream.uniqueId;
[self saveWithTransaction:transaction]; [thumbnailAttachments addObject:thumbnailStream];
} }
return [thumbnailAttachments copy]; return [thumbnailAttachments copy];
} }
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -35,6 +35,7 @@
#import "TSAccountManager.h" #import "TSAccountManager.h"
#import "TSAttachment.h" #import "TSAttachment.h"
#import "TSAttachmentPointer.h" #import "TSAttachmentPointer.h"
#import "TSAttachmentStream.h"
#import "TSContactThread.h" #import "TSContactThread.h"
#import "TSDatabaseView.h" #import "TSDatabaseView.h"
#import "TSGroupModel.h" #import "TSGroupModel.h"
@ -990,8 +991,10 @@ NS_ASSUME_NONNULL_BEGIN
return nil; return nil;
} }
TSQuotedMessage *_Nullable quotedMessage = TSQuotedMessage *_Nullable quotedMessage = [self quotedMessageForDataMessage:dataMessage
[self quotedMessageForDataMessage:dataMessage envelope:envelope transaction:transaction]; envelope:envelope
thread:oldGroupThread
transaction:transaction];
DDLogDebug(@"%@ incoming message from: %@ for group: %@ with timestamp: %lu", DDLogDebug(@"%@ incoming message from: %@ for group: %@ with timestamp: %lu",
self.logTag, self.logTag,
@ -1038,7 +1041,7 @@ NS_ASSUME_NONNULL_BEGIN
relay:envelope.relay]; relay:envelope.relay];
TSQuotedMessage *_Nullable quotedMessage = TSQuotedMessage *_Nullable quotedMessage =
[self quotedMessageForDataMessage:dataMessage envelope:envelope transaction:transaction]; [self quotedMessageForDataMessage:dataMessage envelope:envelope thread:thread transaction:transaction];
TSIncomingMessage *incomingMessage = TSIncomingMessage *incomingMessage =
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
@ -1059,6 +1062,7 @@ NS_ASSUME_NONNULL_BEGIN
- (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage - (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
envelope:(OWSSignalServiceProtosEnvelope *)envelope envelope:(OWSSignalServiceProtosEnvelope *)envelope
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
OWSAssert(dataMessage); OWSAssert(dataMessage);
@ -1097,8 +1101,46 @@ NS_ASSUME_NONNULL_BEGIN
[[OWSAttachmentInfo alloc] initWithAttachmentId:nil [[OWSAttachmentInfo alloc] initWithAttachmentId:nil
contentType:quotedAttachment.contentType contentType:quotedAttachment.contentType
sourceFilename:quotedAttachment.fileName]; 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]; [attachmentInfos addObject:attachmentInfo];
} }
// TODO - but only if the attachment can't be found locally. // TODO - but only if the attachment can't be found locally.
// OWSAttachmentsProcessor *attachmentsProcessor = // OWSAttachmentsProcessor *attachmentsProcessor =
// [[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:quoteProto.attachments // [[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:quoteProto.attachments

@ -333,8 +333,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
thumbnailAttachments = thumbnailAttachments =
[message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction]; [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 // 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 // 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. // if we ever actually want to send multiple, we should do more testing.

Loading…
Cancel
Save