WIP: Send attachment info in protobuf (no thumbnails yet)

// FREEBIE
pull/1/head
Michael Kirk 7 years ago
parent 55c6d99d98
commit 51a4298c14

@ -43,7 +43,7 @@ class QuotedReplyPreview: UIView {
bodyLabel.font = .ows_footnote bodyLabel.font = .ows_footnote
bodyLabel.text = { bodyLabel.text = {
if let contentType = quotedReplyDraft.contentType() { if let contentType = quotedReplyDraft.contentType {
let emoji = TSAttachmentStream.emoji(forMimeType: contentType) let emoji = TSAttachmentStream.emoji(forMimeType: contentType)
return "\(emoji) \(quotedReplyDraft.body ?? "")" return "\(emoji) \(quotedReplyDraft.body ?? "")"
} else { } else {
@ -52,7 +52,7 @@ class QuotedReplyPreview: UIView {
}() }()
let thumbnailView: UIView? = { let thumbnailView: UIView? = {
if let image = quotedReplyDraft.thumbnailImage() { if let image = quotedReplyDraft.thumbnailImage {
let imageView = UIImageView(image: image) let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFill imageView.contentMode = .scaleAspectFill
imageView.autoPinToSquareAspectRatio() imageView.autoPinToSquareAspectRatio()

@ -36,6 +36,12 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey;
primaryStorage:(OWSPrimaryStorage *)primaryStorage primaryStorage:(OWSPrimaryStorage *)primaryStorage
transaction:(YapDatabaseReadWriteTransaction *)transaction NS_DESIGNATED_INITIALIZER; transaction:(YapDatabaseReadWriteTransaction *)transaction NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithQuotedAttachmentProtos:(NSArray<OWSSignalServiceProtosAttachmentPointer *> *)attachmentProtos
relay:(nullable NSString *)relay
networkManager:(TSNetworkManager *)networkManager
primaryStorage:(OWSPrimaryStorage *)primaryStorage
transaction:(YapDatabaseReadWriteTransaction *)transaction NS_DESIGNATED_INITIALIZER;
/* /*
* Retry fetching failed attachment download * Retry fetching failed attachment download
*/ */

@ -117,7 +117,6 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
return self; return self;
} }
// Remove this? // Remove this?
- (void)fetchAttachmentsForMessage:(nullable TSMessage *)message - (void)fetchAttachmentsForMessage:(nullable TSMessage *)message
primaryStorage:(OWSPrimaryStorage *)primaryStorage primaryStorage:(OWSPrimaryStorage *)primaryStorage

@ -38,6 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
- (nullable UIImage *)image; - (nullable UIImage *)image;
- (nullable UIImage *)thumbnailImage; - (nullable UIImage *)thumbnailImage;
- (nullable NSData *)thumbnailData;
#endif #endif
- (BOOL)isAnimated; - (BOOL)isAnimated;

@ -355,6 +355,24 @@ NS_ASSUME_NONNULL_BEGIN
return [UIImage imageWithContentsOfFile:self.thumbnailPath]; return [UIImage imageWithContentsOfFile:self.thumbnailPath];
} }
- (nullable NSData *)thumbnailData
{
NSString *thumbnailPath = self.thumbnailPath;
if (!thumbnailPath) {
OWSAssert(!self.isImage && !self.isVideo && !self.isAnimated);
return nil;
}
if (![[NSFileManager defaultManager] fileExistsAtPath:thumbnailPath]) {
OWSFail(@"%@ missing thumbnail for attachmentId: %@", self.logTag, self.uniqueId);
return nil;
}
return [NSData dataWithContentsOfFile:self.thumbnailPath];
}
- (void)ensureThumbnail - (void)ensureThumbnail
{ {
NSString *thumbnailPath = self.thumbnailPath; NSString *thumbnailPath = self.thumbnailPath;

@ -472,15 +472,23 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
[quoteBuilder setText:quotedMessage.body]; [quoteBuilder setText:quotedMessage.body];
} }
if (quotedMessage.attachmentInfos) { if (quotedMessage.quotedAttachments) {
NSMutableArray *thumbnailAttachments = [NSMutableArray new]; for (OWSAttachmentInfo *attachment in quotedMessage.quotedAttachments) {
// FIXME TODO if has thumbnail build proto for attachment stream hasQuotedAttachment = YES;
// but if no thumbnail we only set contentType/filename
// for (TSAttachmentStream *attachment in quotedMessage.thumbnailAttachments) { // Add non-thumbnail quoted attachment
OWSSignalServiceProtosAttachmentPointerBuilder *attachmentBuilder =
[OWSSignalServiceProtosAttachmentPointerBuilder new];
attachmentBuilder.contentType = attachment.contentType;
attachmentBuilder.fileName = attachment.sourceFilename;
[quoteBuilder addAttachments:[attachmentBuilder build]];
// FIXME handle thumbnail uploading. The proto changes for this are up in the air.
// OWSAssert([attachment isKindOfClass:[TSAttachmentStream class]]); // OWSAssert([attachment isKindOfClass:[TSAttachmentStream class]]);
// // [quoteBuilder addAttachments:[self buildProtoForAttachmentStream:attachment
// [quoteBuilder addAttachments:[self buildProtoForAttachmentStream:attachment filename:attachment.sourceFilename]];] // filename:attachment.sourceFilename]];]
// } }
} }
if (hasQuotedText || hasQuotedAttachment) { if (hasQuotedText || hasQuotedAttachment) {

@ -26,9 +26,9 @@ NS_ASSUME_NONNULL_BEGIN
// This is a MIME type. // This is a MIME type.
// //
// This property should be set IFF we are quoting an attachment message. // This property should be set IFF we are quoting an attachment message.
- (nullable NSString *)contentType; @property (nonatomic, readonly, nullable) NSString *contentType;
- (nullable NSString *)sourceFilename; @property (nonatomic, readonly, nullable) NSString *sourceFilename;
- (nullable UIImage *)thumbnailImage; @property (nonatomic, readonly, nullable) UIImage *thumbnailImage;
- (instancetype)initWithTimestamp:(uint64_t)timestamp - (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId authorId:(NSString *)authorId
@ -46,6 +46,11 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, nullable) NSString *attachmentId; @property (nonatomic, readonly, nullable) NSString *attachmentId;
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithAttachmentId:(nullable NSString *)attachmentId
contentType:(NSString *)contentType
sourceFilename:(NSString *)sourceFilename NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithAttachment:(TSAttachment *)attachment; - (instancetype)initWithAttachment:(TSAttachment *)attachment;
@end @end
@ -67,8 +72,8 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable NSString *)contentType; - (nullable NSString *)contentType;
- (nullable NSString *)sourceFilename; - (nullable NSString *)sourceFilename;
@property (atomic, readonly) NSArray<OWSAttachmentInfo *> *attachmentInfos; @property (atomic, readonly) NSArray<OWSAttachmentInfo *> *quotedAttachments;
- (void)addAttachment:(TSAttachmentStream *)attachment; //- (void)addAttachment:(TSAttachmentStream *)attachment;
- (BOOL)hasAttachments; - (BOOL)hasAttachments;
- (nullable TSAttachment *)firstAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction; - (nullable TSAttachment *)firstAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction;
@ -76,10 +81,18 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;
// used in message manager
- (instancetype)initWithTimestamp:(uint64_t)timestamp - (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId authorId:(NSString *)authorId
body:(NSString *_Nullable)body body:(NSString *_Nullable)body
attachments:(NSArray<TSAttachment *> *)attachments; quotedAttachmentInfos:(NSArray<OWSAttachmentInfo *> *)attachmentInfos;
// used by OWSAttachmentInfo#buildQuotedMessage
- (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
quotedAttachmentsForSending:(NSArray<TSAttachment *> *)attachments;
@end @end

@ -5,33 +5,41 @@
#import "TSQuotedMessage.h" #import "TSQuotedMessage.h"
#import "TSAttachment.h" #import "TSAttachment.h"
#import "TSAttachmentStream.h" #import "TSAttachmentStream.h"
#import <YapDatabase/YapDatabaseTransaction.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@implementation OWSAttachmentInfo @implementation OWSAttachmentInfo
- (instancetype)initWithAttachment:(TSAttachment *)attachment - (instancetype)initWithAttachment:(TSAttachment *)attachment
{
OWSAssert(attachment.uniqueId);
OWSAssert(attachment.contentType);
return [self initWithAttachmentId:attachment.uniqueId
contentType:attachment.contentType
sourceFilename:attachment.sourceFilename];
}
- (instancetype)initWithAttachmentId:(nullable NSString *)attachmentId
contentType:(NSString *)contentType
sourceFilename:(NSString *)sourceFilename
{ {
self = [super init]; self = [super init];
if (!self) { if (!self) {
return self; return self;
} }
OWSAssert(attachment.uniqueId); _attachmentId = attachmentId;
OWSAssert(attachment.contentType); _contentType = contentType;
_sourceFilename = sourceFilename;
_attachmentId = attachment.uniqueId;
_contentType = attachment.contentType;
// maybe nil
_sourceFilename = attachment.sourceFilename;
return self; return self;
} }
@end @end
// View Model which has already fetched any thumbnail attachment.
@implementation OWSQuotedReplyDraft @implementation OWSQuotedReplyDraft
// This is a MIME type. // This is a MIME type.
@ -47,7 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
return self.attachmentStream.sourceFilename; return self.attachmentStream.sourceFilename;
} }
- (nullable NSString *)thumbnailImage - (nullable UIImage *)thumbnailImage
{ {
return self.attachmentStream.thumbnailImage; return self.attachmentStream.thumbnailImage;
} }
@ -70,36 +78,52 @@ NS_ASSUME_NONNULL_BEGIN
return self; return self;
} }
- (TSQuotedMessage *)buildQuotedMessage
{
NSArray *attachments = self.attachmentStream ? @[ self.attachmentStream ] : @[];
return [[TSQuotedMessage alloc] initWithTimestamp:self.timestamp
authorId:self.authorId
body:self.body
quotedAttachmentsForSending:attachments];
}
@end @end
@interface TSQuotedMessage () @interface TSQuotedMessage ()
@property (atomic) NSArray<OWSAttachmentInfo *> *thumbnailAttachments; @property (atomic) NSArray<OWSAttachmentInfo *> *quotedAttachments;
@property (atomic) NSArray<TSAttachmentStream *> *quotedAttachmentsForSending;
@end @end
@implementation TSQuotedMessage @implementation TSQuotedMessage
- (instancetype)initOutgoingWithTimestamp:(uint64_t)timestamp - (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId authorId:(NSString *)authorId
body:(NSString *_Nullable)body body:(NSString *_Nullable)body
attachment:(TSAttachmentStream *_Nullable)attachmentStream quotedAttachmentInfos:(NSArray<OWSAttachmentInfo *> *)attachmentInfos
{ {
return [self initWithTimestamp:timestamp authorId:authorId body:body attachments:@[ attachmentStream ]]; OWSAssert(timestamp > 0);
OWSAssert(authorId.length > 0);
self = [super init];
if (!self) {
return nil;
} }
- (instancetype)initIncomingWithTimestamp:(uint64_t)timestamp _timestamp = timestamp;
authorId:(NSString *)authorId _authorId = authorId;
body:(NSString *_Nullable)body _body = body;
attachments:(NSArray<TSAttachment *> *)attachments _quotedAttachments = attachmentInfos;
{
return [self initWithTimestamp:timestamp authorId:authorId body:body attachments:attachments]; return self;
} }
- (instancetype)initWithTimestamp:(uint64_t)timestamp - (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId authorId:(NSString *)authorId
body:(NSString *_Nullable)body body:(NSString *_Nullable)body
attachments:(NSArray<TSAttachment *> *)attachments quotedAttachmentsForSending:(NSArray<TSAttachmentStream *> *)attachments
{ {
OWSAssert(timestamp > 0); OWSAssert(timestamp > 0);
OWSAssert(authorId.length > 0); OWSAssert(authorId.length > 0);
@ -117,104 +141,111 @@ NS_ASSUME_NONNULL_BEGIN
for (TSAttachment *attachment in attachments) { for (TSAttachment *attachment in attachments) {
[attachmentInfos addObject:[[OWSAttachmentInfo alloc] initWithAttachment:attachment]]; [attachmentInfos addObject:[[OWSAttachmentInfo alloc] initWithAttachment:attachment]];
} }
_thumbnailAttachments = [attachmentInfos copy]; _quotedAttachments = [attachmentInfos copy];
return self; return self;
} }
- (nullable TSAttachment *)firstAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction #pragma mark - Attachment (not necessarily with a thumbnail)
{
OWSAttachmentInfo *attachmentInfo = self.firstAttachmentInfo;
if (!attachmentInfo) {
return nil;
}
return [TSAttachment fetchObjectWithUniqueID:attachmentInfo.attachmentId];
}
- (nullable OWSAttachmentInfo *)firstAttachmentInfo - (nullable OWSAttachmentInfo *)firstAttachmentInfo
{ {
return self.attachmentInfos.firstObject; return self.quotedAttachments.firstObject;
}
- (nullable UIImage *)thumbnailImageWithTransaction:(YapDatabaseReadTransaction *)transaction
{
TSAttachmentStream *firstAttachment = (TSAttachmentStream *)self.firstThumbnailAttachment;
if (![firstAttachment isKindOfClass:[TSAttachmentStream class]]) {
return nil;
}
return firstAttachment.thumbnailImage;
} }
- (nullable NSString *)contentType - (nullable NSString *)contentType
{ {
OWSAttachmentInfo *firstAttachment = self.firstThumbnailAttachment; OWSAttachmentInfo *firstAttachment = self.firstAttachmentInfo;
return firstAttachment.contentType; return firstAttachment.contentType;
} }
- (nullable NSString *)sourceFilename - (nullable NSString *)sourceFilename
{ {
OWSAttachmentInfo *firstAttachment = self.firstThumbnailAttachment; OWSAttachmentInfo *firstAttachment = self.firstAttachmentInfo;
return firstAttachment.sourceFilename; return firstAttachment.sourceFilename;
} }
- (BOOL)hasThumbnailAttachments #pragma mark - Thumbnail
{
return self.thumbnailAttachments.count > 0;
}
- (void)addThumbnailAttachment:(TSAttachmentStream *)attachment
{
NSMutableArray<OWSAttachmentInfo *> *existingAttachments = [self.thumbnailAttachments mutableCopy];
OWSAttachmentInfo *attachmentInfo = [[OWSAttachmentInfo alloc] initWithAttachment:attachment];
[existingAttachments addObject:attachmentInfo];
self.thumbnailAttachments = [existingAttachments copy];
}
- (nullable OWSAttachmentInfo *)firstThumbnailAttachment
{
return self.thumbnailAttachments.firstObject;
}
//- (TSAttachmentStream *)thumbnailAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction //- (nullable TSAttachment *)firstAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
//{ //{
// OWSAttachmentInfo *attachmentInfo = self.firstAttachmentInfo;
// if (!attachmentInfo) {
// return nil;
// }
// //
// return [TSAttachment fetchObjectWithUniqueID:attachmentInfo.attachmentId];
//}
//- (nullable UIImage *)thumbnailImageWithTransaction:(YapDatabaseReadTransaction *)transaction
//{
// TSAttachmentStream *firstAttachment = (TSAttachmentStream *)self.firstAttachmentIn;
// if (![firstAttachment isKindOfClass:[TSAttachmentStream class]]) {
// return nil;
// } // }
- (void)createThumbnailAttachmentIfNecessaryWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
// OWSAssert([attachment isKindOfClass:[TSAttachmentStream class]]);
// UIImage *thumbnailImage = attachment.thumbnailImage;
// // Only some media types have thumbnails
// if (thumbnailImage) {
// // Copy the thumbnail to a new attachment.
// TSAttachmentStream *thumbnailAttachment =
// [[TSAttachmentStream alloc] initWithContentType:attachment.contentType
// byteCount:attachment.byteCount
// sourceFilename:attachment.sourceFilename];
// //
// NSError *error; // return firstAttachment.thumbnailImage;
// NSData *_Nullable data = [attachment readDataFromFileWithError:&error];
// if (!data || error) {
// DDLogError(@"%@ Couldn't load attachment data for message sent to self: %@.", self.logTag, error);
// } else {
// [thumbnailAttachment writeData:data error:&error];
// if (error) {
// DDLogError(
// @"%@ Couldn't copy attachment data for message sent to self: %@.", self.logTag, error);
// } else {
// [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
// [thumbnailAttachment saveWithTransaction:transaction];
// quotedMessage.attachments =
// [message saveWithTransaction:transaction];
// }];
//} //}
//- (BOOL)hasThumbnailAttachments
//{
// return self.thumbnailAttachments.count > 0;
//} //}
//
//- (void)addThumbnailAttachment:(TSAttachmentStream *)attachment
//{
// NSMutableArray<OWSAttachmentInfo *> *existingAttachments = [self.thumbnailAttachments mutableCopy];
//
// OWSAttachmentInfo *attachmentInfo = [[OWSAttachmentInfo alloc] initWithAttachment:attachment];
// [existingAttachments addObject:attachmentInfo];
//
// self.thumbnailAttachments = [existingAttachments copy];
//}
//
//- (nullable OWSAttachmentInfo *)firstThumbnailAttachment
//{
// return self.thumbnailAttachments.firstObject;
//}
//
//- (TSAttachmentStream *)thumbnailAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
//{
//
//}
//
- (void)createThumbnailAttachmentIfNecessaryWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
for (OWSAttachmentInfo *info in self.quotedAttachments) {
// TODO should we just cach an optional TSAttachment on the info?
OWSAssert(info.attachmentId);
TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:info.attachmentId transaction:transaction];
if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
return;
}
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachmentStream;
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:OWSMimeTypeJpeg
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 {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[thumbnailAttachment saveWithTransaction:transaction];
quotedMessage.attachments = [message saveWithTransaction:transaction];
}];
}
}
}
} }
@end @end

@ -1095,25 +1095,29 @@ NS_ASSUME_NONNULL_BEGIN
hasText = YES; hasText = YES;
} }
NSArray<TSAttachment *> *attachments; NSMutableArray<OWSAttachmentInfo *> *attachmentInfos = [NSMutableArray new];
for (OWSSignalServiceProtosAttachmentPointer *attachmentPointer in quoteProto.attachments) {
if (quoteProto.attachments.count == 0) { hasAttachment = YES;
attachments = @[]; OWSAttachmentInfo *attachmentInfo =
} else { [[OWSAttachmentInfo alloc] initWithAttachmentId:nil
OWSAttachmentsProcessor *attachmentsProcessor = contentType:attachmentPointer.contentType
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:quoteProto.attachments sourceFilename:attachmentPointer.fileName];
relay:envelope.relay [attachmentInfos addObject:attachmentInfo];
networkManager:self.networkManager
primaryStorage:self.primaryStorage
transaction:transaction];
if (!attachmentsProcessor.hasSupportedAttachments) {
attachments = @[];
} else {
attachments = attachmentsProcessor.supportedAttachmentPointers;
} }
// 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 alloc] initWithAttachmentProtos:quoteProto.attachments
// relay:envelope.relay
// networkManager:self.networkManager
// primaryStorage:self.primaryStorage
// transaction:transaction];
//
// if (!attachmentsProcessor.hasSupportedAttachments) {
// attachments = @[];
// } else {
// attachments = attachmentsProcessor.supportedAttachmentPointers;
// }
//
// [attachmentsProcessor fetchAttachmentsForMessage:nil // [attachmentsProcessor fetchAttachmentsForMessage:nil
// transaction:transaction // transaction:transaction
// success:^(TSAttachmentStream *attachmentStream) { // success:^(TSAttachmentStream *attachmentStream) {
@ -1128,9 +1132,6 @@ NS_ASSUME_NONNULL_BEGIN
// error); // error);
// }]; // }];
hasAttachment = YES;
}
if (!hasText && !hasAttachment) { if (!hasText && !hasAttachment) {
OWSFail(@"%@ quoted message has neither text nor attachment", self.logTag); OWSFail(@"%@ quoted message has neither text nor attachment", self.logTag);
return nil; return nil;
@ -1142,8 +1143,11 @@ NS_ASSUME_NONNULL_BEGIN
// sourceFilename:sourceFilename // sourceFilename:sourceFilename
// thumbnailData:thumbnailData // thumbnailData:thumbnailData
// contentType:contentType]; // contentType:contentType];
TSQuotedMessage *quotedMessage =
[[TSQuotedMessage alloc] initWithTimestamp:timestamp authorId:authorId body:body attachments:attachments]; TSQuotedMessage *quotedMessage = [[TSQuotedMessage alloc] initWithTimestamp:timestamp
authorId:authorId
body:body
quotedAttachmentInfos:attachmentInfos];
return quotedMessage; return quotedMessage;
} }

Loading…
Cancel
Save