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.text = {
if let contentType = quotedReplyDraft.contentType() {
if let contentType = quotedReplyDraft.contentType {
let emoji = TSAttachmentStream.emoji(forMimeType: contentType)
return "\(emoji) \(quotedReplyDraft.body ?? "")"
} else {
@ -52,7 +52,7 @@ class QuotedReplyPreview: UIView {
}()
let thumbnailView: UIView? = {
if let image = quotedReplyDraft.thumbnailImage() {
if let image = quotedReplyDraft.thumbnailImage {
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFill
imageView.autoPinToSquareAspectRatio()

@ -36,6 +36,12 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey;
primaryStorage:(OWSPrimaryStorage *)primaryStorage
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
*/

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

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

@ -355,6 +355,24 @@ NS_ASSUME_NONNULL_BEGIN
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
{
NSString *thumbnailPath = self.thumbnailPath;

@ -472,15 +472,23 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
[quoteBuilder setText:quotedMessage.body];
}
if (quotedMessage.attachmentInfos) {
NSMutableArray *thumbnailAttachments = [NSMutableArray new];
// FIXME TODO if has thumbnail build proto for attachment stream
// but if no thumbnail we only set contentType/filename
// for (TSAttachmentStream *attachment in quotedMessage.thumbnailAttachments) {
// OWSAssert([attachment isKindOfClass:[TSAttachmentStream class]]);
//
// [quoteBuilder addAttachments:[self buildProtoForAttachmentStream:attachment filename:attachment.sourceFilename]];]
// }
if (quotedMessage.quotedAttachments) {
for (OWSAttachmentInfo *attachment in quotedMessage.quotedAttachments) {
hasQuotedAttachment = YES;
// 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]]);
// [quoteBuilder addAttachments:[self buildProtoForAttachmentStream:attachment
// filename:attachment.sourceFilename]];]
}
}
if (hasQuotedText || hasQuotedAttachment) {

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

@ -5,33 +5,41 @@
#import "TSQuotedMessage.h"
#import "TSAttachment.h"
#import "TSAttachmentStream.h"
#import <YapDatabase/YapDatabaseTransaction.h>
NS_ASSUME_NONNULL_BEGIN
@implementation OWSAttachmentInfo
- (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];
if (!self) {
return self;
}
OWSAssert(attachment.uniqueId);
OWSAssert(attachment.contentType);
_attachmentId = attachment.uniqueId;
_contentType = attachment.contentType;
// maybe nil
_sourceFilename = attachment.sourceFilename;
_attachmentId = attachmentId;
_contentType = contentType;
_sourceFilename = sourceFilename;
return self;
}
@end
// View Model which has already fetched any thumbnail attachment.
@implementation OWSQuotedReplyDraft
// This is a MIME type.
@ -47,7 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
return self.attachmentStream.sourceFilename;
}
- (nullable NSString *)thumbnailImage
- (nullable UIImage *)thumbnailImage
{
return self.attachmentStream.thumbnailImage;
}
@ -70,36 +78,52 @@ NS_ASSUME_NONNULL_BEGIN
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
@interface TSQuotedMessage ()
@property (atomic) NSArray<OWSAttachmentInfo *> *thumbnailAttachments;
@property (atomic) NSArray<OWSAttachmentInfo *> *quotedAttachments;
@property (atomic) NSArray<TSAttachmentStream *> *quotedAttachmentsForSending;
@end
@implementation TSQuotedMessage
- (instancetype)initOutgoingWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
attachment:(TSAttachmentStream *_Nullable)attachmentStream
- (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
quotedAttachmentInfos:(NSArray<OWSAttachmentInfo *> *)attachmentInfos
{
return [self initWithTimestamp:timestamp authorId:authorId body:body attachments:@[ attachmentStream ]];
}
OWSAssert(timestamp > 0);
OWSAssert(authorId.length > 0);
- (instancetype)initIncomingWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
attachments:(NSArray<TSAttachment *> *)attachments
{
return [self initWithTimestamp:timestamp authorId:authorId body:body attachments:attachments];
self = [super init];
if (!self) {
return nil;
}
_timestamp = timestamp;
_authorId = authorId;
_body = body;
_quotedAttachments = attachmentInfos;
return self;
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
attachments:(NSArray<TSAttachment *> *)attachments
quotedAttachmentsForSending:(NSArray<TSAttachmentStream *> *)attachments
{
OWSAssert(timestamp > 0);
OWSAssert(authorId.length > 0);
@ -117,104 +141,111 @@ NS_ASSUME_NONNULL_BEGIN
for (TSAttachment *attachment in attachments) {
[attachmentInfos addObject:[[OWSAttachmentInfo alloc] initWithAttachment:attachment]];
}
_thumbnailAttachments = [attachmentInfos copy];
_quotedAttachments = [attachmentInfos copy];
return self;
}
- (nullable TSAttachment *)firstAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
{
OWSAttachmentInfo *attachmentInfo = self.firstAttachmentInfo;
if (!attachmentInfo) {
return nil;
}
return [TSAttachment fetchObjectWithUniqueID:attachmentInfo.attachmentId];
}
#pragma mark - Attachment (not necessarily with a thumbnail)
- (nullable OWSAttachmentInfo *)firstAttachmentInfo
{
return self.attachmentInfos.firstObject;
}
- (nullable UIImage *)thumbnailImageWithTransaction:(YapDatabaseReadTransaction *)transaction
{
TSAttachmentStream *firstAttachment = (TSAttachmentStream *)self.firstThumbnailAttachment;
if (![firstAttachment isKindOfClass:[TSAttachmentStream class]]) {
return nil;
}
return firstAttachment.thumbnailImage;
return self.quotedAttachments.firstObject;
}
- (nullable NSString *)contentType
{
OWSAttachmentInfo *firstAttachment = self.firstThumbnailAttachment;
OWSAttachmentInfo *firstAttachment = self.firstAttachmentInfo;
return firstAttachment.contentType;
}
- (nullable NSString *)sourceFilename
{
OWSAttachmentInfo *firstAttachment = self.firstThumbnailAttachment;
OWSAttachmentInfo *firstAttachment = self.firstAttachmentInfo;
return firstAttachment.sourceFilename;
}
- (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;
}
#pragma mark - Thumbnail
//- (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;
// }
//
// return firstAttachment.thumbnailImage;
//}
//- (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
{
// 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;
// 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];
// }];
// }
// }
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

@ -1095,41 +1095,42 @@ NS_ASSUME_NONNULL_BEGIN
hasText = YES;
}
NSArray<TSAttachment *> *attachments;
if (quoteProto.attachments.count == 0) {
attachments = @[];
} else {
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;
}
// TODO - but only if the attachment can't be found locally.
// [attachmentsProcessor fetchAttachmentsForMessage:nil
// transaction:transaction
// success:^(TSAttachmentStream *attachmentStream) {
// [groupThread
// updateAvatarWithAttachmentStream:attachmentStream];
// }
// failure:^(NSError *error) {
// DDLogError(@"%@ failed to fetch attachments for group
// avatar sent at: %llu. with error: %@",
// self.logTag,
// envelope.timestamp,
// error);
// }];
NSMutableArray<OWSAttachmentInfo *> *attachmentInfos = [NSMutableArray new];
for (OWSSignalServiceProtosAttachmentPointer *attachmentPointer in quoteProto.attachments) {
hasAttachment = YES;
OWSAttachmentInfo *attachmentInfo =
[[OWSAttachmentInfo alloc] initWithAttachmentId:nil
contentType:attachmentPointer.contentType
sourceFilename:attachmentPointer.fileName];
[attachmentInfos addObject:attachmentInfo];
}
// 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
// transaction:transaction
// success:^(TSAttachmentStream *attachmentStream) {
// [groupThread
// updateAvatarWithAttachmentStream:attachmentStream];
// }
// failure:^(NSError *error) {
// DDLogError(@"%@ failed to fetch attachments for group
// avatar sent at: %llu. with error: %@",
// self.logTag,
// envelope.timestamp,
// error);
// }];
if (!hasText && !hasAttachment) {
OWSFail(@"%@ quoted message has neither text nor attachment", self.logTag);
@ -1142,8 +1143,11 @@ NS_ASSUME_NONNULL_BEGIN
// sourceFilename:sourceFilename
// thumbnailData:thumbnailData
// 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;
}

Loading…
Cancel
Save