WIP: towards avatar attachment streams

// FREEBIE
This commit is contained in:
Michael Kirk 2018-04-05 12:01:53 -04:00
parent 53af41fcc6
commit 0b8b3b4f16
21 changed files with 348 additions and 316 deletions

2
Pods

@ -1 +1 @@
Subproject commit 7d20c06f10623230848be112f493804b108e6aa1
Subproject commit e54eb900c0c4be9646d4c7ed800c8ea45d275686

View File

@ -209,11 +209,9 @@ NS_ASSUME_NONNULL_BEGIN
if (!self.hasQuotedAttachmentThumbnailImage) {
return nil;
}
if (!self.quotedMessage.thumbnailData) {
return nil;
}
// TODO: Possibly ignore data that is too large.
UIImage *_Nullable image = [UIImage imageWithData:self.quotedMessage.thumbnailData];
UIImage *_Nullable image = self.quotedMessage.thumbnailImage;
// TODO: Possibly ignore images that are too large.
return image;
}
@ -241,7 +239,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *text = @"";
NSString *_Nullable fileTypeForSnippet = [self fileTypeForSnippet];
NSString *_Nullable sourceFilename = [self.quotedMessage.sourceFilename filterStringForDisplay];
NSString *_Nullable sourceFilename = [self.quotedMessage.firstThumbnailAttachment.sourceFilename filterStringForDisplay];
if (self.displayableQuotedText.displayText.length > 0) {
text = self.displayableQuotedText.displayText;

View File

@ -43,7 +43,7 @@ class QuotedReplyPreview: UIView {
bodyLabel.font = .ows_footnote
bodyLabel.text = {
if let contentType = quotedMessage.contentType {
if let contentType = quotedMessage.contentType() {
let emoji = TSAttachmentStream.emoji(forMimeType: contentType)
return "\(emoji) \(quotedMessage.body ?? "")"
} else {
@ -52,16 +52,15 @@ class QuotedReplyPreview: UIView {
}()
let thumbnailView: UIView? = {
// FIXME TODO
// if let image = quotedMessage.thumbnailImage() {
// let imageView = UIImageView(image: image)
// imageView.contentMode = .scaleAspectFill
// imageView.autoPinToSquareAspectRatio()
// imageView.layer.cornerRadius = 3.0
// imageView.clipsToBounds = true
//
// return imageView
// }
if let image = quotedMessage.thumbnailImage() {
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFill
imageView.autoPinToSquareAspectRatio()
imageView.layer.cornerRadius = 3.0
imageView.clipsToBounds = true
return imageView
}
return nil
}()

View File

@ -79,9 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAttachmentsProcessor *attachmentsProcessor =
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:transcript.attachmentPointerProtos
timestamp:transcript.timestamp
relay:transcript.relay
thread:thread
networkManager:self.networkManager
primaryStorage:self.primaryStorage
transaction:transaction];

View File

@ -25,14 +25,13 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey;
@property (nullable, nonatomic, readonly) NSArray<NSString *> *attachmentIds;
@property (nonatomic, readonly) NSArray<NSString *> *supportedAttachmentIds;
@property (nonatomic, readonly) NSArray<TSAttachmentPointer *> *supportedAttachmentPointers;
@property (nonatomic, readonly) BOOL hasSupportedAttachments;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithAttachmentProtos:(NSArray<OWSSignalServiceProtosAttachmentPointer *> *)attachmentProtos
timestamp:(uint64_t)timestamp
relay:(nullable NSString *)relay
thread:(TSThread *)thread
networkManager:(TSNetworkManager *)networkManager
primaryStorage:(OWSPrimaryStorage *)primaryStorage
transaction:(YapDatabaseReadWriteTransaction *)transaction NS_DESIGNATED_INITIALIZER;

View File

@ -36,7 +36,6 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
@property (nonatomic, readonly) TSNetworkManager *networkManager;
@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage;
@property (nonatomic, readonly) NSArray<TSAttachmentPointer *> *supportedAttachmentPointers;
@end
@ -61,9 +60,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
}
- (instancetype)initWithAttachmentProtos:(NSArray<OWSSignalServiceProtosAttachmentPointer *> *)attachmentProtos
timestamp:(uint64_t)timestamp
relay:(nullable NSString *)relay
thread:(TSThread *)thread
networkManager:(TSNetworkManager *)networkManager
primaryStorage:(OWSPrimaryStorage *)primaryStorage
transaction:(YapDatabaseReadWriteTransaction *)transaction
@ -120,6 +117,8 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
return self;
}
// Remove this?
- (void)fetchAttachmentsForMessage:(nullable TSMessage *)message
primaryStorage:(OWSPrimaryStorage *)primaryStorage
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler

View File

@ -370,7 +370,7 @@ NS_ASSUME_NONNULL_BEGIN
if (![[NSFileManager defaultManager] fileExistsAtPath:self.mediaURL.path]) {
DDLogError(@"%@ while generating thumbnail, source file doesn't exist: %@", self.logTag, self.mediaURL);
// If we're not lazy-restoring this message, the attachment should exist on disk.
OWSAssert(self.lazyRestoreFragmentId);
// OWSAssert(self.lazyRestoreFragmentId);
return;
}

View File

@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
}
OWSSignalServiceProtosAttachmentPointer *attachmentProto =
[self buildAttachmentProtoForAttachmentId:self.attachmentIds[0] filename:nil];
[self buildProtoForAttachmentId:self.attachmentIds[0] filename:nil];
OWSSignalServiceProtosSyncMessageContactsBuilder *contactsBuilder =
[OWSSignalServiceProtosSyncMessageContactsBuilder new];

View File

@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
(unsigned long)self.attachmentIds.count);
}
OWSSignalServiceProtosAttachmentPointer *attachmentProto =
[self buildAttachmentProtoForAttachmentId:self.attachmentIds[0] filename:nil];
[self buildProtoForAttachmentId:self.attachmentIds[0] filename:nil];
OWSSignalServiceProtosSyncMessageGroupsBuilder *groupsBuilder =
[OWSSignalServiceProtosSyncMessageGroupsBuilder new];

View File

@ -132,8 +132,8 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) {
* @return
* An attachment pointer protobuf suitable for including in various container protobuf builders
*/
- (OWSSignalServiceProtosAttachmentPointer *)buildAttachmentProtoForAttachmentId:(NSString *)attachmentId
filename:(nullable NSString *)filename;
- (OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentId:(NSString *)attachmentId
filename:(nullable NSString *)filename;
- (BOOL)shouldBeSaved;

View File

@ -415,8 +415,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
case TSGroupMessageNew: {
if (gThread.groupModel.groupImage != nil && self.attachmentIds.count == 1) {
attachmentWasGroupAvatar = YES;
[groupBuilder
setAvatar:[self buildAttachmentProtoForAttachmentId:self.attachmentIds[0] filename:nil]];
[groupBuilder setAvatar:[self buildProtoForAttachmentId:self.attachmentIds[0] filename:nil]];
}
[groupBuilder setMembersArray:gThread.groupModel.groupMemberIds];
@ -437,7 +436,7 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
NSMutableArray *attachments = [NSMutableArray new];
for (NSString *attachmentId in self.attachmentIds) {
NSString *_Nullable sourceFilename = self.attachmentFilenameMap[attachmentId];
[attachments addObject:[self buildAttachmentProtoForAttachmentId:attachmentId filename:sourceFilename]];
[attachments addObject:[self buildProtoForAttachmentId:attachmentId filename:sourceFilename]];
}
[builder setAttachmentsArray:attachments];
}
@ -456,14 +455,15 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
[quoteBuilder setText:quotedMessage.body];
}
if (quotedMessage.thumbnailAttachmentIds.count > 0) {
if (quotedMessage.attachmentInfos) {
NSMutableArray *thumbnailAttachments = [NSMutableArray new];
for (NSString *attachmentId in quotedMessage.thumbnailAttachmentIds) {
hasQuotedAttachment = YES;
NSString *_Nullable sourceFilename = quotedMessage.thumbnailAttachmentFilenameMap[attachmentId];
[thumbnailAttachments addObject:[self buildAttachmentProtoForAttachmentId:attachmentId filename:sourceFilename]];
}
[quoteBuilder setAttachmentsArray:thumbnailAttachments];
// 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 (hasQuotedText || hasQuotedAttachment) {
@ -498,8 +498,8 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
return !self.hasSyncedTranscript;
}
- (OWSSignalServiceProtosAttachmentPointer *)buildAttachmentProtoForAttachmentId:(NSString *)attachmentId
filename:(nullable NSString *)filename
- (OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentId:(NSString *)attachmentId
filename:(nullable NSString *)filename
{
OWSAssert(attachmentId.length > 0);
@ -509,7 +509,12 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
return nil;
}
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment;
return [self buildProtoForAttachmentStream:attachmentStream filename:filename];
}
- (OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentStream:(TSAttachmentStream *)attachmentStream
filename:(nullable NSString *)filename
{
OWSSignalServiceProtosAttachmentPointerBuilder *builder = [OWSSignalServiceProtosAttachmentPointerBuilder new];
[builder setId:attachmentStream.serverId];
OWSAssert(attachmentStream.contentType.length > 0);

View File

@ -3,10 +3,23 @@
//
#import <SignalServiceKit/TSYapDatabaseObject.h>
#import <Mantle/MTLModel.h>
NS_ASSUME_NONNULL_BEGIN
@class TSAttachment;
@class TSAttachmentStream;
@interface OWSAttachmentInfo: MTLModel
@property (nonatomic, readonly, nullable) NSString *contentType;
@property (nonatomic, readonly, nullable) NSString *sourceFilename;
@property (nonatomic, readonly, nullable) NSString *attachmentId;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithAttachment:(TSAttachment *)attachment;
@end
@interface TSQuotedMessage : TSYapDatabaseObject
@ -17,31 +30,32 @@ NS_ASSUME_NONNULL_BEGIN
// or attachment with caption.
@property (nullable, nonatomic, readonly) NSString *body;
//// This property can be set IFF we are quoting an attachment message, but it is optional.
//@property (nullable, nonatomic, readonly) NSData *thumbnailData;
#pragma mark - Attachments
// This is a MIME type.
//
// This property should be set IFF we are quoting an attachment message.
@property (nullable, nonatomic, readonly) NSString *contentType;
- (nullable NSString *)contentType;
- (nullable NSString *)sourceFilename;
@property (atomic, readonly) NSArray<OWSAttachmentInfo *> *attachmentInfos;
- (void)addAttachment:(TSAttachmentStream *)attachment;
- (BOOL)hasAttachments;
- (nullable TSAttachment *)firstAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (nullable UIImage *)thumbnailImageWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
sourceFilename:(NSString *_Nullable)sourceFilename
thumbnailData:(NSData *_Nullable)thumbnailData
contentType:(NSString *_Nullable)contentType;
- (instancetype)initOutgoingWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
attachment:(TSAttachmentStream *_Nullable)attachmentStream;
#pragma mark - Attachments
@property (nonatomic, readonly) NSArray<NSString *> *thumbnailAttachmentIds;
// A map of attachment id-to-"source" filename.
@property (nonatomic, readonly) NSMutableDictionary<NSString *, NSString *> *thumbnailAttachmentFilenameMap;
- (BOOL)hasThumbnailAttachments;
- (nullable TSAttachment *)firstThumbnailAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (instancetype)initIncomingWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
attachments:(NSArray<TSAttachment *> *)attachments;
@end

View File

@ -4,74 +4,171 @@
#import "TSQuotedMessage.h"
#import "TSAttachment.h"
#import "TSAttachmentStream.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TSQuotedMessage
@implementation OWSAttachmentInfo
- (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
sourceFilename:(NSString *_Nullable)sourceFilename
thumbnailData:(NSData *_Nullable)thumbnailData
contentType:(NSString *_Nullable)contentType
- (instancetype)initWithAttachment:(TSAttachment *)attachment
{
self = [super initWithUniqueId:[NSUUID UUID].UUIDString];
self = [super init];
if (!self) {
return self;
}
OWSAssert(timestamp > 0);
OWSAssert(authorId.length > 0);
_timestamp = timestamp;
_authorId = authorId;
_body = body;
// TODO get source filename from attachment
// _sourceFilename = sourceFilename;
// _thumbnailData = thumbnailData;
_contentType = contentType;
return self;
}
// TODO maybe this should live closer to the view
- (nullable UIImage *)thumbnailImage
{
// if (self.thumbnailData.length == 0) {
// return nil;
// }
//
// // PERF TODO cache
// return [UIImage imageWithData:self.thumbnailData];
return nil;
}
//- (void)setThumbnailAttachmentId:(NSString *)thumbnailAttachmentId
//{
// _thumbnailAttachmentId = thumbnailAttachmentId;
//}
//
//- (BOOL)hasThumbnailAttachment
//{
// return self.thumbnailAttachmentId.length > 0;
//}
//
- (BOOL)hasThumbnailAttachments
{
return self.thumbnailAttachmentIds.count > 0;
}
- (nullable TSAttachment *)firstThumbnailAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction;
{
if (!self.hasThumbnailAttachments) {
return nil;
}
return [TSAttachment fetchObjectWithUniqueID:self.thumbnailAttachmentIds.firstObject transaction:transaction];
OWSAssert(attachment.uniqueId);
OWSAssert(attachment.contentType);
_attachmentId = attachment.uniqueId;
_contentType = attachment.contentType;
// maybe nil
_sourceFilename = attachment.sourceFilename;
return self;
}
@end
@interface TSQuotedMessage ()
@property (atomic) NSArray<OWSAttachmentInfo *> *thumbnailAttachments;
@end
@implementation TSQuotedMessage
- (instancetype)initOutgoingWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
attachment:(TSAttachmentStream *_Nullable)attachmentStream
{
return [self initWithTimestamp:timestamp authorId:authorId body:body attachments:@[ attachmentStream ]];
}
- (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];
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp
authorId:(NSString *)authorId
body:(NSString *_Nullable)body
attachments:(NSArray<TSAttachment *> *)attachments
{
OWSAssert(timestamp > 0);
OWSAssert(authorId.length > 0);
self = [super init];
if (!self) {
return nil;
}
_timestamp = timestamp;
_authorId = authorId;
_body = body;
NSMutableArray *attachmentInfos = [NSMutableArray new];
for (TSAttachment *attachment in attachments) {
[attachmentInfos addObject:[[OWSAttachmentInfo alloc] initWithAttachment:attachment]];
}
_thumbnailAttachments = [attachmentInfos copy];
return self;
}
- (nullable TSAttachment *)firstAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
{
OWSAttachmentInfo *attachmentInfo = self.firstAttachmentInfo;
if (!attachmentInfo) {
return nil;
}
return [TSAttachment fetchObjectWithUniqueID:attachmentInfo.attachmentId];
}
- (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;
}
- (nullable NSString *)contentType
{
OWSAttachmentInfo *firstAttachment = self.firstThumbnailAttachment;
return firstAttachment.contentType;
}
- (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];
// }];
// }
// }
}
@end
NS_ASSUME_NONNULL_END

View File

@ -33,6 +33,8 @@
#import "OWSSyncGroupsRequestMessage.h"
#import "ProfileManagerProtocol.h"
#import "TSAccountManager.h"
#import "TSAttachment.h"
#import "TSAttachmentPointer.h"
#import "TSContactThread.h"
#import "TSDatabaseView.h"
#import "TSGroupModel.h"
@ -512,9 +514,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(groupThread);
OWSAttachmentsProcessor *attachmentsProcessor =
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:@[ dataMessage.group.avatar ]
timestamp:envelope.timestamp
relay:envelope.relay
thread:groupThread
networkManager:self.networkManager
primaryStorage:self.primaryStorage
transaction:transaction];
@ -552,9 +552,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAttachmentsProcessor *attachmentsProcessor =
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:dataMessage.attachments
timestamp:envelope.timestamp
relay:envelope.relay
thread:thread
networkManager:self.networkManager
primaryStorage:self.primaryStorage
transaction:transaction];
@ -993,7 +991,8 @@ NS_ASSUME_NONNULL_BEGIN
return nil;
}
TSQuotedMessage *_Nullable quotedMessage = [self quotedMessageForDataMessage:dataMessage];
TSQuotedMessage *_Nullable quotedMessage =
[self quotedMessageForDataMessage:dataMessage envelope:envelope transaction:transaction];
DDLogDebug(@"%@ incoming message from: %@ for group: %@ with timestamp: %lu",
self.logTag,
@ -1041,7 +1040,8 @@ NS_ASSUME_NONNULL_BEGIN
transaction:transaction
relay:envelope.relay];
TSQuotedMessage *_Nullable quotedMessage = [self quotedMessageForDataMessage:dataMessage];
TSQuotedMessage *_Nullable quotedMessage =
[self quotedMessageForDataMessage:dataMessage envelope:envelope transaction:transaction];
TSIncomingMessage *incomingMessage =
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
@ -1063,6 +1063,8 @@ NS_ASSUME_NONNULL_BEGIN
}
- (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
envelope:(OWSSignalServiceProtosEnvelope *)envelope
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(dataMessage);
@ -1093,22 +1095,39 @@ NS_ASSUME_NONNULL_BEGIN
hasText = YES;
}
NSString *_Nullable sourceFilename = nil;
NSData *_Nullable thumbnailData = nil;
NSString *_Nullable contentType = nil;
NSArray<TSAttachment *> *attachments;
if (quoteProto.attachments.count > 0) {
OWSSignalServiceProtosAttachmentPointer *attachmentProto = quoteProto.attachments.firstObject;
if ([attachmentProto hasContentType] && attachmentProto.contentType.length > 0) {
contentType = attachmentProto.contentType;
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 ([attachmentProto hasFileName] && attachmentProto.fileName.length > 0) {
sourceFilename = attachmentProto.fileName;
}
if ([attachmentProto hasThumbnail] && attachmentProto.thumbnail.length > 0) {
thumbnailData = [attachmentProto thumbnail];
}
if (!attachmentsProcessor.hasSupportedAttachments) {
attachments = @[];
} else {
attachments = attachmentsProcessor.supportedAttachmentPointers;
}
// TODO
// [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);
// }];
hasAttachment = YES;
}
@ -1117,12 +1136,17 @@ NS_ASSUME_NONNULL_BEGIN
return nil;
}
TSQuotedMessage *quotedMessage = [[TSQuotedMessage alloc] initWithTimestamp:timestamp
authorId:authorId
body:body
sourceFilename:sourceFilename
thumbnailData:thumbnailData
contentType:contentType];
// TSQuotedMessage *quotedMessage = [[TSQuotedMessage alloc] initIncomingWithTimestamp:timestamp
// authorId:authorId
// body:body
// sourceFilename:sourceFilename
// thumbnailData:thumbnailData
// contentType:contentType];
TSQuotedMessage *quotedMessage = [[TSQuotedMessage alloc] initIncomingWithTimestamp:timestamp
authorId:authorId
body:body
attachments:attachments];
return quotedMessage;
}

View File

@ -319,124 +319,37 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (message.hasAttachments) {
OWSUploadOperation *uploadAttachmentOperation =
[[OWSUploadOperation alloc] initWithAttachmentId:message.attachmentIds.firstObject
message:message
dbConnection:self.dbConnection];
[sendMessageOperation addDependency:uploadAttachmentOperation];
[sendingQueue addOperation:uploadAttachmentOperation];
}
// if (message.quotedMessage.hasThumbnailAttachments) {
// OWSUploadOperation *uploadQuoteThumbnailOperation = [[OWSUploadOperation alloc]
// initWithAttachmentId:message.attachmentIds.firstObject
// message:message
// dbConnection:self.dbConnection];
// [sendMessageOperation addDependency:uploadAttachmentOperation];
// [sendingQueue addOperation:uploadQuoteThumbnailOperation];
// }
if (message.quotedMessage) {
// TODO do we want a different thumbnail size for quotes vs the gallery? This seems reasonable,
// and has the advantage of already having been generated.
__block TSAttachmentStream *attachment;
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[message.quotedMessage createThumbnailAttachmentIfNecessaryWithTransaction:transaction];
attachment = (TSAttachmentStream *)[message.quotedMessage thumbnailAttachmentWithTransaction:transaction];
}];
if (attachment) {
OWSUploadOperation *uploadQuoteThumbnailOperation =
[[OWSUploadOperation alloc] initWithAttachmentId:thumbnailAttachment.uniqueId
dbConnection:self.dbConnection];
// TODO put attachment uploads on a (lowly) concurrent queue
[sendMessageOperation addDependency:uploadQuoteThumbnailOperation];
[sendingQueue addOperation:uploadQuoteThumbnailOperation];
}
}
[sendingQueue addOperation:sendMessageOperation];
});
}
//- (void)attemptToSendMessage:(TSOutgoingMessage *)message
// success:(void (^)(void))successHandler
// failure:(RetryableFailureHandler)failureHandler
//{
// [self ensureAnyAttachmentsUploaded:message
// success:^() {
// [self sendMessageToService:message
// success:successHandler
// failure:^(NSError *error) {
// DDLogDebug(
// @"%@ Message send attempt failed: %@", self.logTag, message.debugDescription);
// failureHandler(error);
// }];
// }
// failure:^(NSError *error) {
// DDLogDebug(@"%@ Attachment upload attempt failed: %@", self.logTag, message.debugDescription);
// failureHandler(error);
// }];
//}
//- (void)ensureAnyAttachmentsUploaded:(TSOutgoingMessage *)message
// success:(void (^)(void))successHandler
// failure:(RetryableFailureHandler)failureHandler
//{
// if (!message.hasAttachments) {
// return successHandler();
// }
//
// TSAttachmentStream *attachmentStream =
// [TSAttachmentStream fetchObjectWithUniqueID:message.attachmentIds.firstObject];
//
// if (!attachmentStream) {
// OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotLoadAttachment]);
// NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
// // Not finding local attachment is a terminal failure.
// [error setIsRetryable:NO];
// return failureHandler(error);
// }
//
// [OWSUploadingService uploadAttachmentStream:attachmentStream
// message:message
// networkManager:self.networkManager
// success:successHandler
// failure:failureHandler];
//}
//- (void)ensureAnyQuotedThumbnailUploaded:(TSOutgoingMessage *)message
// success:(void (^)(void))successHandler
// failure:(RetryableFailureHandler)failureHandler
//{
// if (!message.hasAttachments) {
// return successHandler();
// }
//
// TSAttachmentStream *attachmentStream =
// [TSAttachmentStream fetchObjectWithUniqueID:message.attachmentIds.firstObject];
//
// if (!attachmentStream) {
// OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotLoadAttachment]);
// NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
// // Not finding local attachment is a terminal failure.
// [error setIsRetryable:NO];
// return failureHandler(error);
// }
//
// if (message.quotedMessage.hasThumbnailAttachment) {
// DDLogDebug(@"%@ uploading thumbnail for message: %llu", self.logTag, message.timestamp);
//
// __block TSAttachmentStream *thumbnailAttachmentStream;
// [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
// thumbnailAttachmentStream = [message.quotedMessage thumbnailAttachmentWithTransaction:transaction];
// }];
//
// if (!thumbnailAttachmentStream) {
// OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotLoadAttachment]);
// NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
// // Not finding local attachment is a terminal failure.
// [error setIsRetryable:NO];
// return failureHandler(error);
// }
//
// [self.uploadingService uploadAttachmentStream:attachmentStream
// message:message
// success:^() {
// [self.uploadingService uploadAttachmentStream:attachmentStream
// message:message
// success:successHandler
// failure:failureHandler];
// }
// failure:failureHandler];
//
// }
// [self.uploadingService uploadAttachmentStream:attachmentStream
// message:message
// success:successHandler
// failure:failureHandler];
//
//
//}
- (void)enqueueTemporaryAttachment:(DataSource *)dataSource
contentType:(NSString *)contentType
inMessage:(TSOutgoingMessage *)message

View File

@ -141,63 +141,55 @@ NS_ASSUME_NONNULL_BEGIN
NSString *_Nullable quotedText = message.body;
BOOL hasText = quotedText.length > 0;
BOOL hasAttachment = NO;
NSString *_Nullable sourceFilename = nil;
NSData *_Nullable thumbnailData = nil;
NSString *_Nullable contentType = nil;
if (message.attachmentIds.count > 0) {
NSString *attachmentId = message.attachmentIds[0];
TSAttachment *_Nullable attachment =
[TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction];
if (attachment) {
// If the attachment is "oversize text", try to treat it appropriately.
if (!hasText && [OWSMimeTypeOversizeTextMessage isEqualToString:attachment.contentType] &&
[attachment isKindOfClass:[TSAttachmentStream class]]) {
hasText = YES;
quotedText = @"";
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment;
NSData *_Nullable oversizeTextData = [NSData dataWithContentsOfFile:attachmentStream.filePath];
if (oversizeTextData) {
// We don't need to include the entire text body of the message, just
// enough to render a snippet. kOversizeTextMessageSizeThreshold is our
// limit on how long text should be in protos since they'll be stored in
// the database. We apply this constant here for the same reasons.
NSString *_Nullable oversizeText =
[[NSString alloc] initWithData:oversizeTextData encoding:NSUTF8StringEncoding];
// First, truncate to the rough max characters.
NSString *_Nullable truncatedText =
[oversizeText substringToIndex:kOversizeTextMessageSizeThreshold - 1];
// But kOversizeTextMessageSizeThreshold is in _bytes_, not characters,
// so we need to continue to trim the string until it fits.
while (truncatedText && truncatedText.length > 0 &&
[truncatedText dataUsingEncoding:NSUTF8StringEncoding].length
>= kOversizeTextMessageSizeThreshold) {
// A very coarse binary search by halving is acceptable, since
// kOversizeTextMessageSizeThreshold is much longer than our target
// length of "three short lines of text on any device we might
// display this on.
//
// The search will always converge since in the worst case (namely
// a single character which in utf-8 is >= 1024 bytes) the loop will
// exit when the string is empty.
truncatedText = [truncatedText substringToIndex:oversizeText.length / 2];
}
if ([truncatedText dataUsingEncoding:NSUTF8StringEncoding].length
< kOversizeTextMessageSizeThreshold) {
quotedText = truncatedText;
} else {
OWSFail(@"%@ Missing valid text snippet.", self.logTag);
}
TSAttachment *_Nullable attachment = [message attachmentWithTransaction:transaction];
TSAttachmentStream *quotedAttachment;
if (attachment && [attachment isKindOfClass:[TSAttachmentStream class]]) {
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment;
// If the attachment is "oversize text", try the quote as a reply to text, not as
// a reply to an attachment.
if (!hasText && [OWSMimeTypeOversizeTextMessage isEqualToString:attachment.contentType]) {
hasText = YES;
quotedText = @"";
NSData *_Nullable oversizeTextData = [NSData dataWithContentsOfFile:attachmentStream.filePath];
if (oversizeTextData) {
// We don't need to include the entire text body of the message, just
// enough to render a snippet. kOversizeTextMessageSizeThreshold is our
// limit on how long text should be in protos since they'll be stored in
// the database. We apply this constant here for the same reasons.
NSString *_Nullable oversizeText =
[[NSString alloc] initWithData:oversizeTextData encoding:NSUTF8StringEncoding];
// First, truncate to the rough max characters.
NSString *_Nullable truncatedText =
[oversizeText substringToIndex:kOversizeTextMessageSizeThreshold - 1];
// But kOversizeTextMessageSizeThreshold is in _bytes_, not characters,
// so we need to continue to trim the string until it fits.
while (truncatedText && truncatedText.length > 0 &&
[truncatedText dataUsingEncoding:NSUTF8StringEncoding].length
>= kOversizeTextMessageSizeThreshold) {
// A very coarse binary search by halving is acceptable, since
// kOversizeTextMessageSizeThreshold is much longer than our target
// length of "three short lines of text on any device we might
// display this on.
//
// The search will always converge since in the worst case (namely
// a single character which in utf-8 is >= 1024 bytes) the loop will
// exit when the string is empty.
truncatedText = [truncatedText substringToIndex:oversizeText.length / 2];
}
if ([truncatedText dataUsingEncoding:NSUTF8StringEncoding].length
< kOversizeTextMessageSizeThreshold) {
quotedText = truncatedText;
} else {
OWSFail(@"%@ Missing valid text snippet.", self.logTag);
}
} else {
sourceFilename = attachment.sourceFilename;
contentType = attachment.contentType;
// Try to generate a thumbnail, if possible.
thumbnailData = [self thumbnailDataForAttachment:attachment];
hasAttachment = YES;
}
} else {
quotedAttachment = attachmentStream;
hasAttachment = YES;
}
}
@ -206,14 +198,10 @@ NS_ASSUME_NONNULL_BEGIN
return nil;
}
// It's conceivable that the logic above will find neither valid text
// or an attachment to quote.
TSQuotedMessage *quotedMessage = [[TSQuotedMessage alloc] initWithTimestamp:timestamp
authorId:authorId
body:quotedText
sourceFilename:sourceFilename
thumbnailData:thumbnailData
contentType:contentType];
TSQuotedMessage *quotedMessage = [[TSQuotedMessage alloc] initOutgoingWithTimestamp:timestamp
authorId:authorId
body:quotedText
attachment:quotedAttachment];
return quotedMessage;
}

View File

@ -19,7 +19,6 @@ extern NSString *const kAttachmentUploadAttachmentIDKey;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithAttachmentId:(NSString *)attachmentId
message:(TSOutgoingMessage *)outgoingMessage
dbConnection:(YapDatabaseConnection *)dbConnection NS_DESIGNATED_INITIALIZER;
@end

View File

@ -27,7 +27,6 @@ static const CGFloat kAttachmentUploadProgressTheta = 0.001f;
@interface OWSUploadOperation ()
@property (readonly, nonatomic) NSString *attachmentId;
@property (readonly, nonatomic) TSOutgoingMessage *outgoingMessage;
@property (readonly, nonatomic) YapDatabaseConnection *dbConnection;
@end
@ -35,7 +34,6 @@ static const CGFloat kAttachmentUploadProgressTheta = 0.001f;
@implementation OWSUploadOperation
- (instancetype)initWithAttachmentId:(NSString *)attachmentId
message:(TSOutgoingMessage *)outgoingMessage
dbConnection:(YapDatabaseConnection *)dbConnection
{
self = [super init];
@ -45,7 +43,6 @@ static const CGFloat kAttachmentUploadProgressTheta = 0.001f;
self.remainingRetries = 4;
_attachmentId = attachmentId;
_outgoingMessage = outgoingMessage;
_dbConnection = dbConnection;
return self;

View File

@ -1,10 +1,10 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
// A protocol that abstracts away a source of NSData
// A base class that abstracts away a source of NSData
// and allows us to:
//
// * Lazy-load if possible.

View File

@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN
extern NSString *const OWSMimeTypeApplicationOctetStream;
extern NSString *const OWSMimeTypeApplicationZip;
extern NSString *const OWSMimeTypeImagePng;
extern NSString *const OWSMimeTypeImageJpeg;
extern NSString *const OWSMimeTypeOversizeTextMessage;
extern NSString *const OWSMimeTypeUnknownForTests;

View File

@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *const OWSMimeTypeApplicationOctetStream = @"application/octet-stream";
NSString *const OWSMimeTypeImagePng = @"image/png";
NSString *const OWSMimeTypeImageJpeg = @"image/jpeg";
NSString *const OWSMimeTypeOversizeTextMessage = @"text/x-signal-plain";
NSString *const OWSMimeTypeUnknownForTests = @"unknown/mimetype";
NSString *const OWSMimeTypeApplicationZip = @"application/zip";