From 48b4791b138410628e7336623107fe54e45f67f9 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 3 May 2018 11:31:06 -0400 Subject: [PATCH 1/6] Download avatar attachment stream // FREEBIE --- .../ViewControllers/DebugUI/DebugUIMessages.m | 230 ++++++++++-------- SignalMessaging/Models/OWSQuotedReplyModel.m | 5 +- .../Messages/Attachments/TSAttachmentStream.h | 9 + .../Messages/Attachments/TSAttachmentStream.m | 69 ++++++ .../OWSIncomingSentMessageTranscript.m | 2 +- .../Interactions/OWSContact+Private.h | 3 +- .../src/Messages/Interactions/OWSContact.h | 14 +- .../src/Messages/Interactions/OWSContact.m | 54 +++- .../src/Messages/Interactions/TSMessage.h | 2 + .../src/Messages/Interactions/TSMessage.m | 7 + .../Messages/Interactions/TSOutgoingMessage.m | 61 +---- .../Messages/Interactions/TSQuotedMessage.h | 4 +- .../Messages/Interactions/TSQuotedMessage.m | 17 +- .../src/Messages/OWSMessageManager.m | 32 ++- .../src/Messages/OWSMessageSender.m | 31 +++ 15 files changed, 361 insertions(+), 179 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index c9f3c85fbf..3ca97aa878 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -84,8 +84,13 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ [DebugUIMessages deleteAllMessagesInThread:thread]; }]]; + [items addObject:[OWSTableItem itemWithTitle:@"Send All Contact Shares" + actionBlock:^{ + [DebugUIMessages sendAllContacts:thread]; + }]]; [items addObjectsFromArray:[self itemsForActions:@[ + [DebugUIMessages sendMessageVariationsAction:thread], // Send Media [DebugUIMessages sendAllMediaAction:thread], @@ -130,10 +135,7 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ [DebugUIMessages selectBackDatedAction:thread]; }], - [OWSTableItem itemWithTitle:@"Send All Contact Shares" - actionBlock:^{ - [DebugUIMessages sendAllContacts:thread]; - }], + #pragma mark - Misc. @@ -2914,7 +2916,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Contact Shares -typedef OWSContact * (^OWSContactBlock)(void); +typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transaction); + (DebugUIMessagesAction *)fakeContactShareMessageAction:(TSThread *)thread label:(NSString *)label @@ -2925,7 +2927,7 @@ typedef OWSContact * (^OWSContactBlock)(void); return [DebugUIMessagesSingleAction actionWithLabel:[NSString stringWithFormat:@"Fake Contact Share (%@)", label] unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = contactBlock(); + OWSContact *contact = contactBlock(transaction); TSOutgoingMessage *message = [self createFakeOutgoingMessage:thread messageBody:nil fakeAssetLoader:nil @@ -2953,7 +2955,7 @@ typedef OWSContact * (^OWSContactBlock)(void); [actions addObject:[self fakeContactShareMessageAction:thread label:@"Name & Number" - contactBlock:^{ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ OWSContact *contact = [OWSContact new]; contact.givenName = @"Alice"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; @@ -2966,7 +2968,7 @@ typedef OWSContact * (^OWSContactBlock)(void); }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"Name & Email" - contactBlock:^{ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ OWSContact *contact = [OWSContact new]; contact.givenName = @"Bob"; OWSContactEmail *email = [OWSContactEmail new]; @@ -2979,7 +2981,7 @@ typedef OWSContact * (^OWSContactBlock)(void); }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"Complicated" - contactBlock:^{ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ OWSContact *contact = [OWSContact new]; contact.givenName = @"Alice"; contact.familyName = @"Carol"; @@ -3031,12 +3033,30 @@ typedef OWSContact * (^OWSContactBlock)(void); address2, ]; - // TODO: Avatar + // MJK + UIImage *avatarImage = + [OWSAvatarBuilder buildRandomAvatarWithDiameter:200]; + NSData *avatarImageData + = UIImageJPEGRepresentation(avatarImage, (CGFloat)0.9); + TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] + initWithContentType:@"image/jpg" + byteCount:avatarImageData.length + sourceFilename:nil]; + + + NSError *error; + BOOL success = + [attachmentStream writeData:avatarImageData error:&error]; + OWSAssert(success && !error); + [attachmentStream saveWithTransaction:transaction]; + + contact.avatarAttachmentInfo = [[OWSAttachmentInfo alloc] + initWithAttachmentStream:attachmentStream]; return contact; }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"Long values" - contactBlock:^{ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ OWSContact *contact = [OWSContact new]; contact.givenName = @"Bobasdjasdlkjasldkjas"; contact.familyName = @"Bobasdjasdlkjasldkjas"; @@ -3050,7 +3070,7 @@ typedef OWSContact * (^OWSContactBlock)(void); }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"System Contact w/o Signal" - contactBlock:^{ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ OWSContact *contact = [OWSContact new]; contact.givenName = @"Add Me To Your Contacts"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; @@ -3063,7 +3083,7 @@ typedef OWSContact * (^OWSContactBlock)(void); }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"System Contact w. Signal" - contactBlock:^{ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ OWSContact *contact = [OWSContact new]; contact.givenName = @"Add Me To Your Contacts"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; @@ -3094,24 +3114,21 @@ typedef OWSContact * (^OWSContactBlock)(void); { OWSAssert(thread); - return - [DebugUIMessagesSingleAction actionWithLabel:[NSString stringWithFormat:@"Send Contact Share (%@)", label] - staggeredActionBlock:^(NSUInteger index, - YapDatabaseReadWriteTransaction *transaction, - ActionSuccessBlock success, - ActionFailureBlock failure) { - dispatch_async(dispatch_get_main_queue(), ^{ - OWSContact *contact = contactBlock(); - DDLogVerbose(@"%@ sending contact: %@", self.logTag, contact.debugDescription); - OWSMessageSender *messageSender = [Environment current].messageSender; - [ThreadUtil sendMessageWithContactShare:contact - inThread:thread - messageSender:messageSender - completion:nil]; + return [DebugUIMessagesSingleAction + actionWithLabel:[NSString stringWithFormat:@"Send Contact Share (%@)", label] + staggeredActionBlock:^(NSUInteger index, + YapDatabaseReadWriteTransaction *transaction, + ActionSuccessBlock success, + ActionFailureBlock failure) { + // dispatch_async(dispatch_get_main_queue(), ^{ + OWSContact *contact = contactBlock(transaction); + DDLogVerbose(@"%@ sending contact: %@", self.logTag, contact.debugDescription); + OWSMessageSender *messageSender = [Environment current].messageSender; + [ThreadUtil sendMessageWithContactShare:contact inThread:thread messageSender:messageSender completion:nil]; - success(); - }); - }]; + success(); + // }); + }]; } + (NSArray *)allSendContactShareActions:(TSThread *)thread includeLabels:(BOOL)includeLabels @@ -3126,35 +3143,35 @@ typedef OWSContact * (^OWSContactBlock)(void); text:@"⚠️ Send Share Contact ⚠️"]]; } - [actions addObject:[self sendContactShareMessageAction:thread - label:@"Name & Number" - contactBlock:^{ - OWSContact *contact = [OWSContact new]; - contact.givenName = @"Alice"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Home; - phoneNumber.phoneNumber = @"+13213214321"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"Name & Email" - contactBlock:^{ - OWSContact *contact = [OWSContact new]; - contact.givenName = @"Bob"; - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Home; - email.email = @"a@b.com"; - contact.emails = @[ - email, - ]; - return contact; - }]]; + // [actions addObject:[self sendContactShareMessageAction:thread + // label:@"Name & Number" + // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + // OWSContact *contact = [OWSContact new]; + // contact.givenName = @"Alice"; + // OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber + // new]; phoneNumber.phoneType = OWSContactPhoneType_Home; + // phoneNumber.phoneNumber = @"+13213214321"; + // contact.phoneNumbers = @[ + // phoneNumber, + // ]; + // return contact; + // }]]; + // [actions addObject:[self sendContactShareMessageAction:thread + // label:@"Name & Email" + // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + // OWSContact *contact = [OWSContact new]; + // contact.givenName = @"Bob"; + // OWSContactEmail *email = [OWSContactEmail new]; + // email.emailType = OWSContactEmailType_Home; + // email.email = @"a@b.com"; + // contact.emails = @[ + // email, + // ]; + // return contact; + // }]]; [actions addObject:[self sendContactShareMessageAction:thread label:@"Complicated" - contactBlock:^{ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ OWSContact *contact = [OWSContact new]; contact.givenName = @"Alice"; contact.familyName = @"Carol"; @@ -3206,49 +3223,66 @@ typedef OWSContact * (^OWSContactBlock)(void); address2, ]; - // TODO: Avatar - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"Long values" - contactBlock:^{ - OWSContact *contact = [OWSContact new]; - contact.givenName = @"Bobasdjasdlkjasldkjas"; - contact.familyName = @"Bobasdjasdlkjasldkjas"; - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Mobile; - email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; - contact.emails = @[ - email, - ]; - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"System Contact w/o Signal" - contactBlock:^{ - OWSContact *contact = [OWSContact new]; - contact.givenName = @"Add Me To Your Contacts"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Work; - phoneNumber.phoneNumber = @"+324602053911"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"System Contact w. Signal" - contactBlock:^{ - OWSContact *contact = [OWSContact new]; - contact.givenName = @"Add Me To Your Contacts"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Work; - phoneNumber.phoneNumber = @"+32460205392"; - contact.phoneNumbers = @[ - phoneNumber, - ]; + // MJK + UIImage *avatarImage = + [OWSAvatarBuilder buildRandomAvatarWithDiameter:200]; + NSData *avatarImageData + = UIImageJPEGRepresentation(avatarImage, (CGFloat)0.9); + TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] + initWithContentType:@"image/jpg" + byteCount:avatarImageData.length + sourceFilename:nil]; + + + NSError *error; + BOOL success = + [attachmentStream writeData:avatarImageData error:&error]; + OWSAssert(success && !error); + [attachmentStream saveWithTransaction:transaction]; + [contact setAvatarAttachmentStream:attachmentStream]; + return contact; }]]; + // [actions addObject:[self sendContactShareMessageAction:thread + // label:@"Long values" + // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + // OWSContact *contact = [OWSContact new]; + // contact.givenName = @"Bobasdjasdlkjasldkjas"; + // contact.familyName = @"Bobasdjasdlkjasldkjas"; + // OWSContactEmail *email = [OWSContactEmail new]; + // email.emailType = OWSContactEmailType_Mobile; + // email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; + // contact.emails = @[ + // email, + // ]; + // return contact; + // }]]; + // [actions addObject:[self sendContactShareMessageAction:thread + // label:@"System Contact w/o Signal" + // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + // OWSContact *contact = [OWSContact new]; + // contact.givenName = @"Add Me To Your Contacts"; + // OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber + // new]; phoneNumber.phoneType = OWSContactPhoneType_Work; + // phoneNumber.phoneNumber = @"+324602053911"; + // contact.phoneNumbers = @[ + // phoneNumber, + // ]; + // return contact; + // }]]; + // [actions addObject:[self sendContactShareMessageAction:thread + // label:@"System Contact w. Signal" + // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + // OWSContact *contact = [OWSContact new]; + // contact.givenName = @"Add Me To Your Contacts"; + // OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber + // new]; phoneNumber.phoneType = OWSContactPhoneType_Work; + // phoneNumber.phoneNumber = @"+32460205392"; + // contact.phoneNumbers = @[ + // phoneNumber, + // ]; + // return contact; + // }]]; return actions; } diff --git a/SignalMessaging/Models/OWSQuotedReplyModel.m b/SignalMessaging/Models/OWSQuotedReplyModel.m index 82ba9f59f9..57ed325c0a 100644 --- a/SignalMessaging/Models/OWSQuotedReplyModel.m +++ b/SignalMessaging/Models/OWSQuotedReplyModel.m @@ -53,8 +53,9 @@ } } else if (attachmentInfo.thumbnailAttachmentPointerId) { // download failed, or hasn't completed yet. - TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:attachmentInfo.thumbnailAttachmentPointerId transaction:transaction]; - + TSAttachment *attachment = + [TSAttachment fetchObjectWithUniqueID:attachmentInfo.thumbnailAttachmentPointerId transaction:transaction]; + if ([attachment isKindOfClass:[TSAttachmentPointer class]]) { attachmentPointer = (TSAttachmentPointer *)attachment; if (attachmentPointer.state == TSAttachmentPointerStateFailed) { diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h index 9bf4304e95..161058545f 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN +@class OWSSignalServiceProtosAttachmentPointer; @class TSAttachmentPointer; @class YapDatabaseReadWriteTransaction; @@ -79,6 +80,14 @@ NS_ASSUME_NONNULL_BEGIN - (nullable TSAttachmentStream *)cloneAsThumbnail; +#pragma mark - Protobuf + ++ (nullable OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentId:(nullable NSString *)filename + isVoiceMessage:(BOOL)isVoiceMessage; + +- (OWSSignalServiceProtosAttachmentPointer *)buildProtoWithFilename:(nullable NSString *)filename + isVoiceMessage:(BOOL)isVoiceMessage; + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index 432189565f..c85e6eb47f 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -703,6 +703,75 @@ NS_ASSUME_NONNULL_BEGIN return thumbnailAttachment; } +// MARK: Protobuf serialization + ++ (nullable OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentId:(nullable NSString *)attachmentId + isVoiceMessage:(BOOL)isVoiceMessage +{ + OWSAssert(attachmentId.length > 0); + + // TODO we should hoist this transaction to make sure we're getting a consistent view in the message sending process + // A brief glance shows it touches quite a bit of code, but should be straight forward. + TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; + if (![attachment isKindOfClass:[TSAttachmentStream class]]) { + DDLogError(@"Unexpected type for attachment builder: %@", attachment); + return nil; + } + + TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; + return [attachmentStream buildProtoWithFilename:attachmentStream.sourceFilename isVoiceMessage:isVoiceMessage]; +} + +// MJK can we get rid of the filename / isVoiceMessage pararms? +// They seem to live (redundantly) on attachmentStream... ++ (nullable OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentId:(NSString *)attachmentId + filename:(nullable NSString *)filename + isVoiceMessage:(BOOL)isVoiceMessage +{ + OWSAssert(attachmentId.length > 0); + + TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; + if (![attachment isKindOfClass:[TSAttachmentStream class]]) { + DDLogError(@"Unexpected type for attachment builder: %@", attachment); + return nil; + } + TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; + return [attachmentStream buildProtoWithFilename:filename isVoiceMessage:isVoiceMessage]; +} + +- (OWSSignalServiceProtosAttachmentPointer *)buildProtoWithFilename:(nullable NSString *)filename + isVoiceMessage:(BOOL)isVoiceMessage +{ + OWSSignalServiceProtosAttachmentPointerBuilder *builder = [OWSSignalServiceProtosAttachmentPointerBuilder new]; + + builder.id = self.serverId; + + OWSAssert(self.contentType.length > 0); + builder.contentType = self.contentType; + + DDLogVerbose(@"%@ Sending attachment with filename: '%@'", self.logTag, filename); + builder.fileName = filename; + + builder.size = self.byteCount; + builder.key = self.encryptionKey; + builder.digest = self.digest; + builder.flags = isVoiceMessage ? OWSSignalServiceProtosAttachmentPointerFlagsVoiceMessage : 0; + + if (self.shouldHaveImageSize) { + CGSize imageSize = self.imageSize; + if (imageSize.width < NSIntegerMax && imageSize.height < NSIntegerMax) { + NSInteger imageWidth = (NSInteger)round(imageSize.width); + NSInteger imageHeight = (NSInteger)round(imageSize.height); + if (imageWidth > 0 && imageHeight > 0) { + builder.width = (UInt32)imageWidth; + builder.height = (UInt32)imageHeight; + } + } + } + + return [builder build]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m index 0d99dcf14b..01490fc492 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m @@ -47,7 +47,7 @@ NS_ASSUME_NONNULL_BEGIN _quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:_dataMessage thread:_thread relay:relay transaction:transaction]; - _contact = [OWSContacts contactForDataMessage:_dataMessage]; + _contact = [OWSContacts contactForDataMessage:_dataMessage relay:relay transaction:transaction]; return self; } diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h b/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h index e8f37c6cb5..70d3391557 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h @@ -61,7 +61,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) NSArray *emails; @property (nonatomic) NSArray *addresses; -@property (nonatomic, nullable) TSAttachment *avatar; +@property (nonatomic, nullable) OWSAttachmentInfo *avatarAttachmentInfo; + @property (nonatomic) BOOL isProfileAvatar; @end diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.h b/SignalServiceKit/src/Messages/Interactions/OWSContact.h index 91f4176347..3eef6a437c 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.h @@ -7,10 +7,13 @@ NS_ASSUME_NONNULL_BEGIN @class CNContact; +@class OWSAttachmentInfo; @class OWSSignalServiceProtosDataMessage; @class OWSSignalServiceProtosDataMessage; @class OWSSignalServiceProtosDataMessageContact; @class TSAttachment; +@class TSAttachmentStream; +@class YapDatabaseReadTransaction; @class YapDatabaseReadWriteTransaction; extern BOOL kIsSendingContactSharesEnabled; @@ -109,8 +112,10 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value); @property (nonatomic, readonly) NSArray *emails; @property (nonatomic, readonly) NSArray *addresses; -// TODO: This is provisional. -@property (nonatomic, readonly, nullable) TSAttachment *avatar; +// MJK +@property (nonatomic, readonly, nullable) NSString *avatarAttachmentId; +- (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction; +- (void)setAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream; // "Profile" avatars should _not_ be saved to device contacts. @property (nonatomic, readonly) BOOL isProfileAvatar; @@ -160,7 +165,10 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value); #pragma mark - Proto Serialization + (nullable OWSSignalServiceProtosDataMessageContact *)protoForContact:(OWSContact *)contact; -+ (OWSContact *_Nullable)contactForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage; + ++ (nullable OWSContact *)contactForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage + relay:(nullable NSString *)relay + transaction:(YapDatabaseReadWriteTransaction *)transaction; @end diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index 5e1130e550..0a55f7e49f 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -3,13 +3,15 @@ // #import "OWSContact.h" -#import "NSString+SSK.h" +#import "NSString+SSK.h" OWSAttachmentInfo.h #import "OWSContact+Private.h" #import "OWSSignalServiceProtos.pb.h" #import "PhoneNumber.h" //#import "Contact.h" #import "TSAttachment.h" +#import "TSAttachmentPointer.h" +#import "TSAttachmentStream.h" #import @import Contacts; @@ -273,7 +275,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) @property (nonatomic) NSArray *emails; @property (nonatomic) NSArray *addresses; -@property (nonatomic, nullable) TSAttachment *avatar; +@property (nonatomic, nullable) NSString *avatarAttachmentId; @property (nonatomic) BOOL isProfileAvatar; @end @@ -456,6 +458,22 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) [self updateDisplayName]; } +#pragma mark - Avatar +// MJK + +- (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + return [TSAttachment fetchObjectWithUniqueID:self.avatarAttachmentId transaction:transaction]; +} + +- (void)setAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream +{ + OWSAssert([attachmentStream isKindOfClass:[TSAttachmentStream class]]); + OWSAssert(self.avatarAttachmentId == nil); + + self.avatarAttachmentId = attachmentStream.uniqueId; +} + @end #pragma mark - @@ -829,7 +847,13 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) [contactBuilder addAddress:addressBuilder.build]; } - // TODO: avatar + if (contact.avatarAttachmentId != nil) { + OWSSignalServiceProtosDataMessageContactAvatarBuilder *avatarBuilder = + [OWSSignalServiceProtosDataMessageContactAvatarBuilder new]; + avatarBuilder.avatar = + [TSAttachmentStream buildProtoForAttachmentId:contact.avatarAttachmentId isVoiceMessage:NO]; + contactBuilder.avatar = [avatarBuilder build]; + } OWSSignalServiceProtosDataMessageContact *contactProto = [contactBuilder build]; if (contactProto.number.count < 1 && contactProto.email.count < 1 && contactProto.address.count < 1) { @@ -839,7 +863,9 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) return contactProto; } -+ (OWSContact *_Nullable)contactForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage ++ (nullable OWSContact *)contactForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage + relay:(nullable NSString *)relay + transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(dataMessage); @@ -905,10 +931,26 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) } contact.addresses = [addresses copy]; - // TODO: Avatar - [contact ensureDisplayName]; + if (contactProto.hasAvatar) { + OWSSignalServiceProtosDataMessageContactAvatar *avatarInfo = contactProto.avatar; + + if (avatarInfo.hasAvatar) { + OWSSignalServiceProtosAttachmentPointer *avatarAttachment = avatarInfo.avatar; + + TSAttachmentPointer *attachmentPointer = + [TSAttachmentPointer attachmentPointerFromProto:avatarAttachment relay:relay]; + [attachmentPointer saveWithTransaction:transaction]; + + contact.avatarAttachmentId = attachmentPointer.uniqueId; + contact.isProfileAvatar = avatarInfo.isProfile; + } else { + OWSFail(@"%@ in %s avatarInfo.hasAvatar was unexpectedly false", self.logTag, __PRETTY_FUNCTION__); + } + } + + return contact; } diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.h b/SignalServiceKit/src/Messages/Interactions/TSMessage.h index 9d2fc81d44..ce8677e4f0 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.h @@ -42,7 +42,9 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)hasAttachments; - (nullable TSAttachment *)attachmentWithTransaction:(YapDatabaseReadTransaction *)transaction; + - (void)setQuotedMessageThumbnailAttachmentStream:(TSAttachmentStream *)attachmentStream; +- (void)setContactShareAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream; - (BOOL)shouldStartExpireTimer; - (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index 68572ada4e..636bb7aa45 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -332,6 +332,13 @@ static const NSUInteger OWSMessageSchemaVersion = 4; [self.quotedMessage setThumbnailAttachmentStream:attachmentStream]; } +- (void)setContactShareAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream +{ + OWSAssert(self.contactShare); + + [self.contactShare setAvatarAttachmentStream:attachmentStream]; +} + #pragma mark - Update With... Methods - (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 46dc5539ca..76f95054a1 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -799,6 +799,8 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt [OWSContacts protoForContact:self.contactShare]; if (contactProto) { [builder addContact:contactProto]; + } else { + OWSFail(@"%@ in %s <# thing #> was unexpectedly nil", self.logTag, __PRETTY_FUNCTION__); } } @@ -834,7 +836,8 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt quotedAttachmentBuilder.fileName = attachment.sourceFilename; if (attachment.thumbnailAttachmentStreamId) { quotedAttachmentBuilder.thumbnail = - [self buildProtoForAttachmentId:attachment.thumbnailAttachmentStreamId]; + [TSAttachmentStream buildProtoForAttachmentId:attachment.thumbnailAttachmentStreamId + isVoiceMessage:NO]; } [quoteBuilder addAttachments:[quotedAttachmentBuilder build]]; @@ -871,62 +874,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt return !self.hasSyncedTranscript; } -- (OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentId:(NSString *)attachmentId -{ - OWSAssert(attachmentId.length > 0); - - TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; - if (![attachment isKindOfClass:[TSAttachmentStream class]]) { - DDLogError(@"Unexpected type for attachment builder: %@", attachment); - return nil; - } - TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; - return [self buildProtoForAttachmentStream:attachmentStream filename:attachmentStream.sourceFilename]; -} - -- (OWSSignalServiceProtosAttachmentPointer *)buildProtoForAttachmentId:(NSString *)attachmentId - filename:(nullable NSString *)filename -{ - OWSAssert(attachmentId.length > 0); - - TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; - if (![attachment isKindOfClass:[TSAttachmentStream class]]) { - DDLogError(@"Unexpected type for attachment builder: %@", attachment); - 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); - [builder setContentType:attachmentStream.contentType]; - DDLogVerbose(@"%@ Sending attachment with filename: '%@'", self.logTag, filename); - [builder setFileName:filename]; - [builder setSize:attachmentStream.byteCount]; - [builder setKey:attachmentStream.encryptionKey]; - [builder setDigest:attachmentStream.digest]; - [builder setFlags:(self.isVoiceMessage ? OWSSignalServiceProtosAttachmentPointerFlagsVoiceMessage : 0)]; - - if ([attachmentStream shouldHaveImageSize]) { - CGSize imageSize = [attachmentStream imageSize]; - if (imageSize.width < NSIntegerMax && imageSize.height < NSIntegerMax) { - NSInteger imageWidth = (NSInteger)round(imageSize.width); - NSInteger imageHeight = (NSInteger)round(imageSize.height); - if (imageWidth > 0 && imageHeight > 0) { - [builder setWidth:(UInt32)imageWidth]; - [builder setHeight:(UInt32)imageHeight]; - } - } - } - - return [builder build]; -} - - (NSString *)statusDescription { NSMutableString *result = [NSMutableString new]; diff --git a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h index e8505df2b5..202f8f1ec5 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h @@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN @class TSThread; @class YapDatabaseReadWriteTransaction; -@interface OWSAttachmentInfo: MTLModel +@interface OWSAttachmentInfo : MTLModel @property (nonatomic, readonly, nullable) NSString *contentType; @property (nonatomic, readonly, nullable) NSString *sourceFilename; @@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN contentType:(NSString *)contentType sourceFilename:(NSString *)sourceFilename NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithAttachment:(TSAttachment *)attachment; +- (instancetype)initWithAttachmentStream:(TSAttachmentStream *)attachmentStream; @end diff --git a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m index 5e9544bacf..8f6e33e7a6 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m @@ -18,14 +18,15 @@ NS_ASSUME_NONNULL_BEGIN @implementation OWSAttachmentInfo -- (instancetype)initWithAttachment:(TSAttachment *)attachment +- (instancetype)initWithAttachmentStream:(TSAttachmentStream *)attachmentStream; { - OWSAssert(attachment.uniqueId); - OWSAssert(attachment.contentType); + OWSAssert([attachmentStream isKindOfClass:[TSAttachmentStream class]]); + OWSAssert(attachmentStream.uniqueId); + OWSAssert(attachmentStream.contentType); - return [self initWithAttachmentId:attachment.uniqueId - contentType:attachment.contentType - sourceFilename:attachment.sourceFilename]; + return [self initWithAttachmentId:attachmentStream.uniqueId + contentType:attachmentStream.contentType + sourceFilename:attachmentStream.sourceFilename]; } - (instancetype)initWithAttachmentId:(nullable NSString *)attachmentId @@ -94,8 +95,8 @@ NS_ASSUME_NONNULL_BEGIN _body = body; NSMutableArray *attachmentInfos = [NSMutableArray new]; - for (TSAttachment *attachment in attachments) { - [attachmentInfos addObject:[[OWSAttachmentInfo alloc] initWithAttachment:attachment]]; + for (TSAttachmentStream *attachmentStream in attachments) { + [attachmentInfos addObject:[[OWSAttachmentInfo alloc] initWithAttachmentStream:attachmentStream]]; } _quotedAttachments = [attachmentInfos copy]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 27b4fccfa9..590b98b8e0 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -909,7 +909,8 @@ NS_ASSUME_NONNULL_BEGIN uint64_t timestamp = envelope.timestamp; NSString *body = dataMessage.body; NSData *groupId = dataMessage.hasGroup ? dataMessage.group.id : nil; - OWSContact *_Nullable contact = [OWSContacts contactForDataMessage:dataMessage]; + OWSContact *_Nullable contact = + [OWSContacts contactForDataMessage:dataMessage relay:envelope.relay transaction:transaction]; if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeRequestInfo) { [self handleGroupInfoRequest:envelope dataMessage:dataMessage transaction:transaction]; @@ -1127,6 +1128,35 @@ NS_ASSUME_NONNULL_BEGIN } } + OWSContact *_Nullable contact = incomingMessage.contactShare; + if (contact && contact.avatarAttachmentId) { + TSAttachmentPointer *attachmentPointer = + [TSAttachmentPointer fetchObjectWithUniqueID:contact.avatarAttachmentId transaction:transaction]; + + if (![attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) { + OWSFail(@"%@ in %s avatar attachmentPointer was unexpectedly nil", self.logTag, __PRETTY_FUNCTION__); + } else { + OWSAttachmentsProcessor *attachmentProcessor = + [[OWSAttachmentsProcessor alloc] initWithAttachmentPointer:attachmentPointer + networkManager:self.networkManager]; + + DDLogDebug(@"%@ downloading contact avatar for message: %tu", self.logTag, incomingMessage.timestamp); + [attachmentProcessor fetchAttachmentsForMessage:incomingMessage + transaction:transaction + success:^(TSAttachmentStream *_Nonnull attachmentStream) { + [self.dbConnection + asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [incomingMessage touchWithTransaction:transaction]; + }]; + } + failure:^(NSError *_Nonnull error) { + DDLogWarn(@"%@ failed to fetch contact avatar for message: %tu with error: %@", + self.logTag, + incomingMessage.timestamp, + error); + }]; + } + } // In case we already have a read receipt for this new message (this happens sometimes). [OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage transaction:transaction]; diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 4e0ec2275b..63da9f41c0 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -11,6 +11,7 @@ #import "NSError+MessageSending.h" #import "OWSBackgroundTask.h" #import "OWSBlockingManager.h" +#import "OWSContact.h" #import "OWSDevice.h" #import "OWSDisappearingMessagesJob.h" #import "OWSError.h" @@ -293,6 +294,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ __block NSArray *quotedThumbnailAttachments = @[]; + __block TSAttachmentStream *_Nullable contactShareAvatarAttachment; // This method will use a read/write transaction. This transaction // will block until any open read/write transactions are complete. @@ -312,6 +314,22 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction]; } + // MJK TODO - don't generate the avatar attachment until here, when we've committed to sending it. + if (message.contactShare.avatarAttachmentId != nil) { + // contactShareAvatarAttachment = [message.contactShare + // createAvatarForUploadWithTransaction:transaction]; + // TODO generate and save the attachment for upload here. + TSAttachment *avatarAttachment = [message.contactShare avatarAttachmentWithTransaction:transaction]; + if ([avatarAttachment isKindOfClass:[TSAttachmentStream class]]) { + contactShareAvatarAttachment = (TSAttachmentStream *)avatarAttachment; + } else { + OWSFail(@"%@ in %s unexpected avatarAttachment: %@", + self.logTag, + __PRETTY_FUNCTION__, + avatarAttachment); + } + } + // All outgoing messages should be saved at the time they are enqueued. [message saveWithTransaction:transaction]; // When we start a message send, all "failed" recipients should be marked as "sending". @@ -325,6 +343,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; dbConnection:self.dbConnection success:successHandler failure:failureHandler]; + + // TODO de-dupe attachment enque logic. if (message.hasAttachments) { OWSUploadOperation *uploadAttachmentOperation = [[OWSUploadOperation alloc] initWithAttachmentId:message.attachmentIds.firstObject @@ -349,6 +369,17 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [sendingQueue addOperation:uploadQuoteThumbnailOperation]; } + if (contactShareAvatarAttachment != nil) { + OWSAssert(message.contactShare); + OWSUploadOperation *uploadAvatarOperation = + [[OWSUploadOperation alloc] initWithAttachmentId:contactShareAvatarAttachment.uniqueId + dbConnection:self.dbConnection]; + + // TODO put attachment uploads on a (lowly) concurrent queue + [sendMessageOperation addDependency:uploadAvatarOperation]; + [sendingQueue addOperation:uploadAvatarOperation]; + } + [sendingQueue addOperation:sendMessageOperation]; }); } From 5ba5e98260aa8698fae395d352006f4cabe92232 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 4 May 2018 20:46:00 -0400 Subject: [PATCH 2/6] Show downloaded contact avatar in thread // FREEBIE --- Signal.xcodeproj/project.pbxproj | 20 ++++++++-- Signal/src/Models/ThreadModel.swift | 40 ------------------- .../ContactViewController.swift | 9 +++-- .../Cells/OWSContactShareView.h | 4 +- .../Cells/OWSContactShareView.m | 22 ++++++---- .../ConversationViewController.m | 2 +- .../ConversationView/ConversationViewItem.h | 4 +- .../ConversationView/ConversationViewItem.m | 5 ++- .../ViewControllers/DebugUI/DebugUIMessages.m | 8 ++-- .../MessageDetailViewController.swift | 4 +- .../src/Storage/OWSOrphanedDataCleaner.m | 30 +++++++++----- 11 files changed, 69 insertions(+), 79 deletions(-) delete mode 100644 Signal/src/Models/ThreadModel.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 624e464424..c216af5387 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -310,7 +310,8 @@ 45360B901F9527DA00FA666C /* SearcherTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45360B8F1F9527DA00FA666C /* SearcherTest.swift */; }; 45360B911F952AA900FA666C /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; }; 4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4539B5851F79348F007141FF /* PushRegistrationManager.swift */; }; - 4542DF52208B82E9007B4E76 /* ThreadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadModel.swift */; }; + 4541B71B209D2DAE0008608F /* ContactShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */; }; + 4542DF52208B82E9007B4E76 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; }; 4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */; }; 45464DBC1DFA041F001D3FD6 /* DataChannelMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45464DBB1DFA041F001D3FD6 /* DataChannelMessage.swift */; }; 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 454A84032059C787008B8C75 /* MediaTileViewController.swift */; }; @@ -939,7 +940,8 @@ 45360B8F1F9527DA00FA666C /* SearcherTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearcherTest.swift; sourceTree = ""; }; 4539B5851F79348F007141FF /* PushRegistrationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushRegistrationManager.swift; sourceTree = ""; }; 453CC0361D08E1A60040EBA3 /* sn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sn; path = translations/sn.lproj/Localizable.strings; sourceTree = ""; }; - 4542DF51208B82E9007B4E76 /* ThreadModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadModel.swift; sourceTree = ""; }; + 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactShareViewModel.swift; sourceTree = ""; }; + 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadViewModel.swift; sourceTree = ""; }; 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = ""; }; 45464DBB1DFA041F001D3FD6 /* DataChannelMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataChannelMessage.swift; sourceTree = ""; }; 454A84032059C787008B8C75 /* MediaTileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaTileViewController.swift; sourceTree = ""; }; @@ -1806,6 +1808,7 @@ 450DF2061E0DD28D003D14BE /* UserInterface */ = { isa = PBXGroup; children = ( + 4541B719209D2D860008608F /* ViewModels */, 450DF2071E0DD29E003D14BE /* Notifications */, 34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */, 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */, @@ -1886,6 +1889,15 @@ path = SignalMessaging; sourceTree = ""; }; + 4541B719209D2D860008608F /* ViewModels */ = { + isa = PBXGroup; + children = ( + 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */, + 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; 45464DB81DFA03D8001D3FD6 /* Signaling */ = { isa = PBXGroup; children = ( @@ -1931,7 +1943,6 @@ 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */, 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */, 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */, - 4542DF51208B82E9007B4E76 /* ThreadModel.swift */, ); path = Models; sourceTree = ""; @@ -3147,7 +3158,7 @@ 34D1F0501F7D45A60066283D /* GifPickerCell.swift in Sources */, 34D99C931F2937CC00D284D6 /* OWSAnalytics.swift in Sources */, 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */, - 4542DF52208B82E9007B4E76 /* ThreadModel.swift in Sources */, + 4542DF52208B82E9007B4E76 /* ThreadViewModel.swift in Sources */, 341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */, 340FC8AF204DAC8D007AEB0F /* OWSLinkDeviceViewController.m in Sources */, 34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */, @@ -3181,6 +3192,7 @@ 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */, 340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, + 4541B71B209D2DAE0008608F /* ContactShareViewModel.swift in Sources */, 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */, 34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */, 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, diff --git a/Signal/src/Models/ThreadModel.swift b/Signal/src/Models/ThreadModel.swift deleted file mode 100644 index 33d73e657d..0000000000 --- a/Signal/src/Models/ThreadModel.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -public class ThreadViewModel: NSObject { - let hasUnreadMessages: Bool - let lastMessageDate: Date - let isGroupThread: Bool - let threadRecord: TSThread - let unreadCount: UInt - let contactIdentifier: String? - let name: String - let isMuted: Bool - var isContactThread: Bool { - return !isGroupThread - } - - let lastMessageText: String? - - init(thread: TSThread, transaction: YapDatabaseReadTransaction) { - self.threadRecord = thread - self.lastMessageDate = thread.lastMessageDate() - self.isGroupThread = thread.isGroupThread() - self.name = thread.name() - self.isMuted = thread.isMuted - self.lastMessageText = thread.lastMessageText(transaction: transaction) - - if let contactThread = thread as? TSContactThread { - self.contactIdentifier = contactThread.contactIdentifier() - } else { - self.contactIdentifier = nil - } - - self.unreadCount = thread.unreadMessageCount(transaction: transaction) - self.hasUnreadMessages = unreadCount > 0 - } -} diff --git a/Signal/src/ViewControllers/ContactViewController.swift b/Signal/src/ViewControllers/ContactViewController.swift index 8c03decff0..cf429db847 100644 --- a/Signal/src/ViewControllers/ContactViewController.swift +++ b/Signal/src/ViewControllers/ContactViewController.swift @@ -65,7 +65,8 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate var reachability: Reachability? - private let contact: OWSContact + // TODO rename this property to contactShare + private let contact: ContactShareViewModel // MARK: - Initializers @@ -74,9 +75,9 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate fatalError("Unimplemented") } - required init(contact: OWSContact) { + required init(contactShare: ContactShareViewModel) { contactsManager = Environment.current().contactsManager - self.contact = contact + self.contact = contactShare super.init(nibName: nil, bundle: nil) @@ -639,7 +640,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate return } - guard let systemContact = OWSContacts.systemContact(for: contact) else { + guard let systemContact = OWSContacts.systemContact(for: contact.dbRecord) else { owsFail("\(logTag) Could not derive system contact.") return } diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.h b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.h index 3a62a08135..c374c9fcfc 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.h +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.h @@ -4,11 +4,11 @@ NS_ASSUME_NONNULL_BEGIN -@class OWSContact; +@class ContactShareViewModel; @interface OWSContactShareView : UIView -- (instancetype)initWithContactShare:(OWSContact *)contactShare isIncoming:(BOOL)isIncoming; +- (instancetype)initWithContactShare:(ContactShareViewModel *)contactShare isIncoming:(BOOL)isIncoming; - (void)createContents; diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m index f56f63bb58..73f2a9a990 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN @interface OWSContactShareView () -@property (nonatomic) OWSContact *contactShare; +@property (nonatomic) ContactShareViewModel *contactShare; @property (nonatomic) BOOL isIncoming; @end @@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN @implementation OWSContactShareView -- (instancetype)initWithContactShare:(OWSContact *)contactShare isIncoming:(BOOL)isIncoming +- (instancetype)initWithContactShare:(ContactShareViewModel *)contactShare isIncoming:(BOOL)isIncoming { self = [super init]; @@ -108,12 +108,18 @@ NS_ASSUME_NONNULL_BEGIN // TODO: Use the contact's avatar if present and downloaded. AvatarImageView *avatarView = [AvatarImageView new]; // TODO: What's the best colorSeed value to use? - OWSAvatarBuilder *avatarBuilder = - [[OWSContactAvatarBuilder alloc] initWithNonSignalName:self.contactShare.displayName - colorSeed:self.contactShare.displayName - diameter:(NSUInteger)self.iconSize - contactsManager:[Environment current].contactsManager]; - avatarView.image = [avatarBuilder build]; + + UIImage *_Nullable avatarImage = self.contactShare.avatarImage; + if (!avatarImage) { + OWSAvatarBuilder *avatarBuilder = + [[OWSContactAvatarBuilder alloc] initWithNonSignalName:self.contactShare.displayName + colorSeed:self.contactShare.displayName + diameter:(NSUInteger)self.iconSize + contactsManager:[Environment current].contactsManager]; + avatarImage = [avatarBuilder build]; + } + avatarView.image = avatarImage; + [avatarView autoSetDimension:ALDimensionWidth toSize:self.iconSize]; [avatarView autoSetDimension:ALDimensionHeight toSize:self.iconSize]; [avatarView setCompressionResistanceHigh]; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index b1357f4773..0d252c8153 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2087,7 +2087,7 @@ typedef enum : NSUInteger { OWSAssert(conversationItem.contactShare); OWSAssert([conversationItem.interaction isKindOfClass:[TSMessage class]]); - ContactViewController *view = [[ContactViewController alloc] initWithContact:conversationItem.contactShare]; + ContactViewController *view = [[ContactViewController alloc] initWithContactShare:conversationItem.contactShare]; [self.navigationController pushViewController:view animated:YES]; } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h index 32bfdb4abd..fc9fc1cf27 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h @@ -24,10 +24,10 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType); #pragma mark - +@class ContactShareViewModel; @class ConversationViewCell; @class DisplayableText; @class OWSAudioMessageView; -@class OWSContact; @class OWSQuotedReplyModel; @class TSAttachmentPointer; @class TSAttachmentStream; @@ -103,7 +103,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType); // if a load has previously failed. @property (nonatomic) BOOL didCellMediaFailToLoad; -- (nullable OWSContact *)contactShare; +@property (nonatomic, readonly, nullable) ContactShareViewModel *contactShare; #pragma mark - UIMenuController diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m index 909cff9093..c2ceae6a37 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m @@ -65,7 +65,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) @property (nonatomic, readonly, nullable) NSString *quotedRecipientId; @property (nonatomic, nullable) TSAttachmentStream *attachmentStream; @property (nonatomic, nullable) TSAttachmentPointer *attachmentPointer; -@property (nonatomic, nullable) OWSContact *contactShare; +@property (nonatomic, nullable) ContactShareViewModel *contactShare; @property (nonatomic) CGSize mediaSize; @end @@ -406,7 +406,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) TSMessage *message = (TSMessage *)self.interaction; if (message.contactShare) { - self.contactShare = message.contactShare; + self.contactShare = + [[ContactShareViewModel alloc] initWithContactShareRecord:message.contactShare transaction:transaction]; self.messageCellType = OWSMessageCellType_ContactShare; return; } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index 3ca97aa878..da6e0da0f5 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -3039,11 +3039,11 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac NSData *avatarImageData = UIImageJPEGRepresentation(avatarImage, (CGFloat)0.9); TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] - initWithContentType:@"image/jpg" + initWithContentType:OWSMimeTypeImageJpeg byteCount:avatarImageData.length sourceFilename:nil]; - - + + NSError *error; BOOL success = [attachmentStream writeData:avatarImageData error:&error]; @@ -3229,7 +3229,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac NSData *avatarImageData = UIImageJPEGRepresentation(avatarImage, (CGFloat)0.9); TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] - initWithContentType:@"image/jpg" + initWithContentType:OWSMimeTypeImageJpeg byteCount:avatarImageData.length sourceFilename:nil]; diff --git a/Signal/src/ViewControllers/MessageDetailViewController.swift b/Signal/src/ViewControllers/MessageDetailViewController.swift index f9c42ba7c4..9c479ca231 100644 --- a/Signal/src/ViewControllers/MessageDetailViewController.swift +++ b/Signal/src/ViewControllers/MessageDetailViewController.swift @@ -613,11 +613,11 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele } func didTapContactShare(_ viewItem: ConversationViewItem) { - guard let contact = viewItem.contactShare() else { + guard let contactShare = viewItem.contactShare else { owsFail("\(logTag) missing contact.") return } - let contactViewController = ContactViewController(contact: contact) + let contactViewController = ContactViewController(contactShare: contactShare) self.navigationController?.pushViewController(contactViewController, animated: true) } diff --git a/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m b/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m index 2d0b79539d..fa0e3f15cf 100644 --- a/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m +++ b/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m @@ -4,6 +4,7 @@ #import "OWSOrphanedDataCleaner.h" #import "NSDate+OWS.h" +#import "OWSContact.h" #import "OWSPrimaryStorage.h" #import "TSAttachmentStream.h" #import "TSInteraction.h" @@ -82,18 +83,18 @@ NS_ASSUME_NONNULL_BEGIN }]; }]; - CleanupLogDebug(@"%@ fileCount: %zd", self.logTag, fileCount); + CleanupLogDebug(@"%@ fileCount: %tu", self.logTag, fileCount); CleanupLogDebug(@"%@ totalFileSize: %lld", self.logTag, totalFileSize); CleanupLogDebug(@"%@ attachmentStreams: %d", self.logTag, attachmentStreamCount); - CleanupLogDebug(@"%@ attachmentStreams with file paths: %zd", self.logTag, attachmentFilePaths.count); + CleanupLogDebug(@"%@ attachmentStreams with file paths: %tu", self.logTag, attachmentFilePaths.count); NSMutableSet *orphanDiskFilePaths = [diskFilePaths mutableCopy]; [orphanDiskFilePaths minusSet:attachmentFilePaths]; NSMutableSet *missingAttachmentFilePaths = [attachmentFilePaths mutableCopy]; [missingAttachmentFilePaths minusSet:diskFilePaths]; - CleanupLogDebug(@"%@ orphan disk file paths: %zd", self.logTag, orphanDiskFilePaths.count); - CleanupLogDebug(@"%@ missing attachment file paths: %zd", self.logTag, missingAttachmentFilePaths.count); + CleanupLogDebug(@"%@ orphan disk file paths: %tu", self.logTag, orphanDiskFilePaths.count); + CleanupLogDebug(@"%@ missing attachment file paths: %tu", self.logTag, missingAttachmentFilePaths.count); [self printPaths:orphanDiskFilePaths.allObjects label:@"orphan disk file paths"]; [self printPaths:missingAttachmentFilePaths.allObjects label:@"missing attachment file paths"]; @@ -106,6 +107,7 @@ NS_ASSUME_NONNULL_BEGIN NSMutableSet *orphanInteractionIds = [NSMutableSet new]; NSMutableSet *messageAttachmentIds = [NSMutableSet new]; NSMutableSet *quotedReplyThumbnailAttachmentIds = [NSMutableSet new]; + NSMutableSet *contactShareAvatarAttachmentIds = [NSMutableSet new]; [databaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { [transaction enumerateKeysAndObjectsInCollection:TSMessage.collection @@ -129,22 +131,30 @@ NS_ASSUME_NONNULL_BEGIN addObjectsFromArray:quotedMessage .thumbnailAttachmentStreamIds]; } + + OWSContact *_Nullable contactShare = message.contactShare; + if (contactShare && contactShare.avatarAttachmentId) { + [contactShareAvatarAttachmentIds + addObject:contactShare.avatarAttachmentId]; + } }]; }]; - CleanupLogDebug(@"%@ attachmentIds: %zd", self.logTag, attachmentIds.count); - CleanupLogDebug(@"%@ messageAttachmentIds: %zd", self.logTag, messageAttachmentIds.count); - CleanupLogDebug(@"%@ quotedReplyThumbnailAttachmentIds: %zd", self.logTag, quotedReplyThumbnailAttachmentIds.count); + CleanupLogDebug(@"%@ attachmentIds: %tu", self.logTag, attachmentIds.count); + CleanupLogDebug(@"%@ messageAttachmentIds: %tu", self.logTag, messageAttachmentIds.count); + CleanupLogDebug(@"%@ quotedReplyThumbnailAttachmentIds: %tu", self.logTag, quotedReplyThumbnailAttachmentIds.count); + CleanupLogDebug(@"%@ contactShareAvatarAttachmentIds: %tu", self.logTag, contactShareAvatarAttachmentIds.count); NSMutableSet *orphanAttachmentIds = [attachmentIds mutableCopy]; [orphanAttachmentIds minusSet:messageAttachmentIds]; [orphanAttachmentIds minusSet:quotedReplyThumbnailAttachmentIds]; + [orphanAttachmentIds minusSet:contactShareAvatarAttachmentIds]; NSMutableSet *missingAttachmentIds = [messageAttachmentIds mutableCopy]; [missingAttachmentIds minusSet:attachmentIds]; - CleanupLogDebug(@"%@ orphan attachmentIds: %zd", self.logTag, orphanAttachmentIds.count); - CleanupLogDebug(@"%@ missing attachmentIds: %zd", self.logTag, missingAttachmentIds.count); - CleanupLogDebug(@"%@ orphan interactions: %zd", self.logTag, orphanInteractionIds.count); + CleanupLogDebug(@"%@ orphan attachmentIds: %tu", self.logTag, orphanAttachmentIds.count); + CleanupLogDebug(@"%@ missing attachmentIds: %tu", self.logTag, missingAttachmentIds.count); + CleanupLogDebug(@"%@ orphan interactions: %tu", self.logTag, orphanInteractionIds.count); // We need to avoid cleaning up new attachments and files that are still in the process of // being created/written, so we don't clean up anything recent. From eb97e82d196507dc2750cb6f72734182aa1cf6d2 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 4 May 2018 21:01:50 -0400 Subject: [PATCH 3/6] fixup debug UI --- .../ViewControllers/DebugUI/DebugUIMessages.m | 151 ++++++++---------- .../Interactions/OWSContact+Private.h | 2 - 2 files changed, 71 insertions(+), 82 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index da6e0da0f5..b11b513cf5 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -84,13 +84,12 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ [DebugUIMessages deleteAllMessagesInThread:thread]; }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send All Contact Shares" + [items addObject:[OWSTableItem itemWithTitle:@"👷 Send All Contact Shares" actionBlock:^{ [DebugUIMessages sendAllContacts:thread]; }]]; - [items addObjectsFromArray:[self itemsForActions:@[ - + [DebugUIMessages fakeAllContactShareAction:thread], [DebugUIMessages sendMessageVariationsAction:thread], // Send Media [DebugUIMessages sendAllMediaAction:thread], @@ -108,7 +107,6 @@ NS_ASSUME_NONNULL_BEGIN // Exemplary [DebugUIMessages allFakeAction:thread], [DebugUIMessages allFakeBackDatedAction:thread], - [DebugUIMessages allContactShareAction:thread], ]]]; [items addObjectsFromArray:@[ @@ -3033,7 +3031,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac address2, ]; - // MJK UIImage *avatarImage = [OWSAvatarBuilder buildRandomAvatarWithDiameter:200]; NSData *avatarImageData @@ -3043,15 +3040,13 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac byteCount:avatarImageData.length sourceFilename:nil]; - NSError *error; BOOL success = [attachmentStream writeData:avatarImageData error:&error]; OWSAssert(success && !error); [attachmentStream saveWithTransaction:transaction]; + [contact setAvatarAttachmentStream:attachmentStream]; - contact.avatarAttachmentInfo = [[OWSAttachmentInfo alloc] - initWithAttachmentStream:attachmentStream]; return contact; }]]; [actions addObject:[self fakeContactShareMessageAction:thread @@ -3098,12 +3093,12 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac return actions; } -+ (DebugUIMessagesAction *)allContactShareAction:(TSThread *)thread ++ (DebugUIMessagesAction *)fakeAllContactShareAction:(TSThread *)thread { OWSAssert(thread); return - [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake Contact Shares" + [DebugUIMessagesGroupAction allGroupActionWithLabel:@"👷 All Fake Contact Shares" subactions:[self allFakeContactShareActions:thread includeLabels:YES]]; } @@ -3120,14 +3115,12 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac YapDatabaseReadWriteTransaction *transaction, ActionSuccessBlock success, ActionFailureBlock failure) { - // dispatch_async(dispatch_get_main_queue(), ^{ OWSContact *contact = contactBlock(transaction); DDLogVerbose(@"%@ sending contact: %@", self.logTag, contact.debugDescription); OWSMessageSender *messageSender = [Environment current].messageSender; [ThreadUtil sendMessageWithContactShare:contact inThread:thread messageSender:messageSender completion:nil]; success(); - // }); }]; } @@ -3143,32 +3136,32 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac text:@"⚠️ Send Share Contact ⚠️"]]; } - // [actions addObject:[self sendContactShareMessageAction:thread - // label:@"Name & Number" - // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ - // OWSContact *contact = [OWSContact new]; - // contact.givenName = @"Alice"; - // OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber - // new]; phoneNumber.phoneType = OWSContactPhoneType_Home; - // phoneNumber.phoneNumber = @"+13213214321"; - // contact.phoneNumbers = @[ - // phoneNumber, - // ]; - // return contact; - // }]]; - // [actions addObject:[self sendContactShareMessageAction:thread - // label:@"Name & Email" - // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ - // OWSContact *contact = [OWSContact new]; - // contact.givenName = @"Bob"; - // OWSContactEmail *email = [OWSContactEmail new]; - // email.emailType = OWSContactEmailType_Home; - // email.email = @"a@b.com"; - // contact.emails = @[ - // email, - // ]; - // return contact; - // }]]; + [actions addObject:[self sendContactShareMessageAction:thread + label:@"Name & Number" + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { + OWSContact *contact = [OWSContact new]; + contact.givenName = @"Alice"; + OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; + phoneNumber.phoneType = OWSContactPhoneType_Home; + phoneNumber.phoneNumber = @"+13213214321"; + contact.phoneNumbers = @[ + phoneNumber, + ]; + return contact; + }]]; + [actions addObject:[self sendContactShareMessageAction:thread + label:@"Name & Email" + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { + OWSContact *contact = [OWSContact new]; + contact.givenName = @"Bob"; + OWSContactEmail *email = [OWSContactEmail new]; + email.emailType = OWSContactEmailType_Home; + email.email = @"a@b.com"; + contact.emails = @[ + email, + ]; + return contact; + }]]; [actions addObject:[self sendContactShareMessageAction:thread label:@"Complicated" contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ @@ -3223,7 +3216,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac address2, ]; - // MJK UIImage *avatarImage = [OWSAvatarBuilder buildRandomAvatarWithDiameter:200]; NSData *avatarImageData @@ -3233,7 +3225,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac byteCount:avatarImageData.length sourceFilename:nil]; - NSError *error; BOOL success = [attachmentStream writeData:avatarImageData error:&error]; @@ -3243,46 +3234,46 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac return contact; }]]; - // [actions addObject:[self sendContactShareMessageAction:thread - // label:@"Long values" - // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ - // OWSContact *contact = [OWSContact new]; - // contact.givenName = @"Bobasdjasdlkjasldkjas"; - // contact.familyName = @"Bobasdjasdlkjasldkjas"; - // OWSContactEmail *email = [OWSContactEmail new]; - // email.emailType = OWSContactEmailType_Mobile; - // email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; - // contact.emails = @[ - // email, - // ]; - // return contact; - // }]]; - // [actions addObject:[self sendContactShareMessageAction:thread - // label:@"System Contact w/o Signal" - // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ - // OWSContact *contact = [OWSContact new]; - // contact.givenName = @"Add Me To Your Contacts"; - // OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber - // new]; phoneNumber.phoneType = OWSContactPhoneType_Work; - // phoneNumber.phoneNumber = @"+324602053911"; - // contact.phoneNumbers = @[ - // phoneNumber, - // ]; - // return contact; - // }]]; - // [actions addObject:[self sendContactShareMessageAction:thread - // label:@"System Contact w. Signal" - // contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ - // OWSContact *contact = [OWSContact new]; - // contact.givenName = @"Add Me To Your Contacts"; - // OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber - // new]; phoneNumber.phoneType = OWSContactPhoneType_Work; - // phoneNumber.phoneNumber = @"+32460205392"; - // contact.phoneNumbers = @[ - // phoneNumber, - // ]; - // return contact; - // }]]; + [actions addObject:[self sendContactShareMessageAction:thread + label:@"Long values" + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { + OWSContact *contact = [OWSContact new]; + contact.givenName = @"Bobasdjasdlkjasldkjas"; + contact.familyName = @"Bobasdjasdlkjasldkjas"; + OWSContactEmail *email = [OWSContactEmail new]; + email.emailType = OWSContactEmailType_Mobile; + email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; + contact.emails = @[ + email, + ]; + return contact; + }]]; + [actions addObject:[self sendContactShareMessageAction:thread + label:@"System Contact w/o Signal" + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { + OWSContact *contact = [OWSContact new]; + contact.givenName = @"Add Me To Your Contacts"; + OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; + phoneNumber.phoneType = OWSContactPhoneType_Work; + phoneNumber.phoneNumber = @"+324602053911"; + contact.phoneNumbers = @[ + phoneNumber, + ]; + return contact; + }]]; + [actions addObject:[self sendContactShareMessageAction:thread + label:@"System Contact w. Signal" + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { + OWSContact *contact = [OWSContact new]; + contact.givenName = @"Add Me To Your Contacts"; + OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; + phoneNumber.phoneType = OWSContactPhoneType_Work; + phoneNumber.phoneNumber = @"+32460205392"; + contact.phoneNumbers = @[ + phoneNumber, + ]; + return contact; + }]]; return actions; } diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h b/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h index 70d3391557..913100f2f3 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h @@ -61,8 +61,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) NSArray *emails; @property (nonatomic) NSArray *addresses; -@property (nonatomic, nullable) OWSAttachmentInfo *avatarAttachmentInfo; - @property (nonatomic) BOOL isProfileAvatar; @end From 77fc5571fb2cc94f6f630ac8d46463d75ee0f687 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 4 May 2018 22:32:29 -0400 Subject: [PATCH 4/6] Implement avatar sending // FREEBIE --- Signal.xcodeproj/project.pbxproj | 16 ++- .../ContactViewController.swift | 41 +++--- .../ConversationViewController.m | 45 +++++-- .../ViewControllers/DebugUI/DebugUIMessages.m | 28 +---- Signal/src/ViewModels/ThreadViewModel.swift | 40 ++++++ .../ViewModels/ContactShareViewModel.swift | 119 ++++++++++++++++++ .../OWSQuotedReplyModel.h | 0 .../OWSQuotedReplyModel.m | 0 .../ApproveContactShareViewController.swift | 24 ++-- .../EditContactShareNameViewController.swift | 6 +- SignalMessaging/contacts/OWSContactsManager.h | 5 +- SignalMessaging/contacts/OWSContactsManager.m | 19 ++- SignalServiceKit/src/Contacts/TSThread.h | 10 -- .../src/Contacts/Threads/TSContactThread.m | 9 -- .../src/Messages/Interactions/OWSContact.h | 3 +- .../src/Messages/Interactions/OWSContact.m | 23 ++-- .../src/Messages/Interactions/TSMessage.h | 1 - .../src/Messages/Interactions/TSMessage.m | 7 -- .../src/Messages/OWSMessageSender.m | 4 - .../src/Protocols/ContactsManagerProtocol.h | 6 +- 20 files changed, 275 insertions(+), 131 deletions(-) create mode 100644 Signal/src/ViewModels/ThreadViewModel.swift create mode 100644 SignalMessaging/ViewModels/ContactShareViewModel.swift rename SignalMessaging/{Models => ViewModels}/OWSQuotedReplyModel.h (100%) rename SignalMessaging/{Models => ViewModels}/OWSQuotedReplyModel.m (100%) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index c216af5387..6941e6a985 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -310,7 +310,7 @@ 45360B901F9527DA00FA666C /* SearcherTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45360B8F1F9527DA00FA666C /* SearcherTest.swift */; }; 45360B911F952AA900FA666C /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; }; 4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4539B5851F79348F007141FF /* PushRegistrationManager.swift */; }; - 4541B71B209D2DAE0008608F /* ContactShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */; }; + 4541B71D209D3B7A0008608F /* ContactShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */; }; 4542DF52208B82E9007B4E76 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; }; 4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */; }; 45464DBC1DFA041F001D3FD6 /* DataChannelMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45464DBB1DFA041F001D3FD6 /* DataChannelMessage.swift */; }; @@ -1830,8 +1830,6 @@ 45194F911FD7214600333B2C /* Models */ = { isa = PBXGroup; children = ( - 459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */, - 459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */, 34C42D621F4734ED0072EC04 /* OWSContactOffersInteraction.h */, 34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */, 34C42D641F4734ED0072EC04 /* TSUnreadIndicatorInteraction.h */, @@ -1872,6 +1870,7 @@ 453518931FC63DBF00210559 /* SignalMessaging */ = { isa = PBXGroup; children = ( + 4541B71C209D3B4F0008608F /* ViewModels */, 45194F911FD7214600333B2C /* Models */, 451F8A361FD7115D005CB9DA /* ViewControllers */, 454A96571FD600B4008D2A0E /* attachments */, @@ -1893,7 +1892,16 @@ isa = PBXGroup; children = ( 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + 4541B71C209D3B4F0008608F /* ViewModels */ = { + isa = PBXGroup; + children = ( 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */, + 459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */, + 459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */, ); path = ViewModels; sourceTree = ""; @@ -3118,6 +3126,7 @@ 4503F1C3204711D300CEE724 /* OWS107LegacySounds.m in Sources */, 3438226A209B63500094FEB7 /* EditContactShareNameViewController.swift in Sources */, 346129A61FD1F09100532771 /* OWSContactsManager.m in Sources */, + 4541B71D209D3B7A0008608F /* ContactShareViewModel.swift in Sources */, 4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */, 346129D21FD2085A00532771 /* CommonStrings.swift in Sources */, 45F59A082028E4FB00E8D2B0 /* OWSAudioSession.swift in Sources */, @@ -3192,7 +3201,6 @@ 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */, 340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, - 4541B71B209D2DAE0008608F /* ContactShareViewModel.swift in Sources */, 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */, 34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */, 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, diff --git a/Signal/src/ViewControllers/ContactViewController.swift b/Signal/src/ViewControllers/ContactViewController.swift index cf429db847..4c8765f0e7 100644 --- a/Signal/src/ViewControllers/ContactViewController.swift +++ b/Signal/src/ViewControllers/ContactViewController.swift @@ -65,8 +65,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate var reachability: Reachability? - // TODO rename this property to contactShare - private let contact: ContactShareViewModel + private let contactShare: ContactShareViewModel // MARK: - Initializers @@ -77,7 +76,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate required init(contactShare: ContactShareViewModel) { contactsManager = Environment.current().contactsManager - self.contact = contactShare + self.contactShare = contactShare super.init(nibName: nil, bundle: nil) @@ -141,7 +140,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate private func updateMode() { SwiftAssertIsOnMainThread(#function) - guard phoneNumbersForContact().count > 0 else { + guard contactShare.phoneNumberStrings.count > 0 else { viewMode = .noPhoneNumber return } @@ -160,7 +159,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate private func systemContactsWithSignalAccountsForContact() -> [String] { SwiftAssertIsOnMainThread(#function) - return phoneNumbersForContact().filter({ (phoneNumber) -> Bool in + return contactShare.phoneNumberStrings.filter({ (phoneNumber) -> Bool in return contactsManager.hasSignalAccount(forRecipientId: phoneNumber) }) } @@ -168,21 +167,11 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate private func systemContactsForContact() -> [String] { SwiftAssertIsOnMainThread(#function) - return phoneNumbersForContact().filter({ (phoneNumber) -> Bool in + return contactShare.phoneNumberStrings.filter({ (phoneNumber) -> Bool in return contactsManager.allContactsMap[phoneNumber] != nil }) } - private func phoneNumbersForContact() -> [String] { - SwiftAssertIsOnMainThread(#function) - - var result = [String]() - for phoneNumber in contact.phoneNumbers { - result.append(phoneNumber.phoneNumber) - } - return result - } - private func updateContent() { SwiftAssertIsOnMainThread(#function) @@ -265,8 +254,8 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate let avatarView = AvatarImageView() // TODO: What's the best colorSeed value to use? - let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contact.displayName, - colorSeed: contact.displayName, + let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contactShare.displayName, + colorSeed: contactShare.displayName, diameter: UInt(avatarSize), contactsManager: contactsManager) avatarView.image = avatarBuilder.build() @@ -277,7 +266,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate avatarView.autoSetDimension(.height, toSize: avatarSize) let nameLabel = UILabel() - nameLabel.text = contact.displayName + nameLabel.text = contactShare.displayName nameLabel.font = UIFont.ows_dynamicTypeTitle2.ows_bold() nameLabel.textColor = UIColor.black nameLabel.lineBreakMode = .byTruncatingTail @@ -289,7 +278,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate var lastView: UIView = nameLabel - if let firstPhoneNumber = contact.phoneNumbers.first { + if let firstPhoneNumber = contactShare.phoneNumbers.first { let phoneNumberLabel = UILabel() phoneNumberLabel.text = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: firstPhoneNumber.phoneNumber) phoneNumberLabel.font = UIFont.ows_dynamicTypeCaption2 @@ -388,7 +377,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate // action:#selector(didPressShareContact))) // } - for phoneNumber in contact.phoneNumbers { + for phoneNumber in contactShare.phoneNumbers { let formattedPhoneNumber = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber.phoneNumber) rows.append(createNameValueRow(name: phoneNumber.localizedLabel(), @@ -402,7 +391,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate })) } - for email in contact.emails { + for email in contactShare.emails { rows.append(createNameValueRow(name: email.localizedLabel(), value: email.email, actionBlock: { @@ -600,7 +589,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate OWSAlerts.showErrorAlert(message: NSLocalizedString("UNSUPPORTED_FEATURE_ERROR", comment: "")) return } - let phoneNumbers = phoneNumbersForContact() + let phoneNumbers = contactShare.phoneNumberStrings guard phoneNumbers.count > 0 else { owsFail("\(logTag) no phone numbers.") return @@ -640,8 +629,8 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate return } - guard let systemContact = OWSContacts.systemContact(for: contact.dbRecord) else { - owsFail("\(logTag) Could not derive system contact.") + guard let systemContact = OWSContacts.systemContact(for: contactShare.dbRecord) else { + owsFail("\(logTag) Could not derive system contactShare.") return } @@ -679,7 +668,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate return } - guard let firstPhoneNumber = contact.phoneNumbers.first else { + guard let firstPhoneNumber = contactShare.phoneNumbers.first else { owsFail("\(logTag) Missing phone number.") return } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 0d252c8153..ce3fe62caa 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -65,6 +65,7 @@ #import #import #import +#import #import #import #import @@ -2948,7 +2949,7 @@ typedef enum : NSUInteger { } } -- (void)sendContactShare:(OWSContact *)contactShare +- (void)sendContactShare:(ContactShareViewModel *)contactShare { OWSAssertIsOnMainThread(); OWSAssert(contactShare); @@ -2956,12 +2957,20 @@ typedef enum : NSUInteger { DDLogVerbose(@"%@ Sending contact share.", self.logTag); BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - TSOutgoingMessage *message = [ThreadUtil sendMessageWithContactShare:contactShare - inThread:self.thread - messageSender:self.messageSender - completion:nil]; - [self messageWasSent:message]; + [self.editingDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + if (contactShare.avatarImage) { + [contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction]; + } + } + completionBlock:^{ + TSOutgoingMessage *message = [ThreadUtil sendMessageWithContactShare:contactShare.dbRecord + inThread:self.thread + messageSender:self.messageSender + completion:nil]; + [self messageWasSent:message]; + }]; + if (didAddToProfileWhitelist) { [self ensureDynamicInteractions]; @@ -4942,12 +4951,28 @@ interactionControllerForAnimationController:(id 0 + } +} diff --git a/SignalMessaging/ViewModels/ContactShareViewModel.swift b/SignalMessaging/ViewModels/ContactShareViewModel.swift new file mode 100644 index 0000000000..5cd0235d15 --- /dev/null +++ b/SignalMessaging/ViewModels/ContactShareViewModel.swift @@ -0,0 +1,119 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import Foundation + +@objc +public class ContactShareViewModel: NSObject { + + public let dbRecord: OWSContact + public let avatarImage: UIImage? + + public required init(contactShareRecord: OWSContact, avatarImage: UIImage?) { + self.dbRecord = contactShareRecord + self.avatarImage = avatarImage + } + + public convenience init(contactShareRecord: OWSContact, transaction: YapDatabaseReadTransaction) { + if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction) as? TSAttachmentStream { + self.init(contactShareRecord: contactShareRecord, avatarImage: avatarAttachment.image()) + } else { + self.init(contactShareRecord: contactShareRecord, avatarImage: nil) + } + } + + // MARK: Delegated -> dbRecord + + public var addresses: [OWSContactAddress] { + get { + return dbRecord.addresses + } + set { + return dbRecord.addresses = newValue + } + } + + public var emails: [OWSContactEmail] { + get { + return dbRecord.emails + } + set { + dbRecord.emails = newValue + } + } + + public var phoneNumbers: [OWSContactPhoneNumber] { + get { + return dbRecord.phoneNumbers + } + set { + dbRecord.phoneNumbers = newValue + } + } + + public var phoneNumberStrings: [String] { + return phoneNumbers.map { $0.phoneNumber } + } + + public var displayName: String { + return dbRecord.displayName + } + + public var ows_isValid: Bool { + return dbRecord.ows_isValid() + } + + public var namePrefix: String? { + return dbRecord.namePrefix + } + + public var givenName: String? { + return dbRecord.givenName + } + + public var middleName: String? { + return dbRecord.middleName + } + + public var familyName: String? { + return dbRecord.familyName + } + + public var nameSuffix: String? { + return dbRecord.nameSuffix + } + + public var isProfileAvatar: Bool { + return dbRecord.isProfileAvatar + } + + public func copy(withNamePrefix namePrefix: String?, + givenName: String?, + middleName: String?, + familyName: String?, + nameSuffix: String?) -> ContactShareViewModel { + + // TODO move the `copy` logic into the view model? + let newDbRecord = dbRecord.copy(withNamePrefix: namePrefix, givenName: givenName, middleName: middleName, familyName: familyName, nameSuffix: nameSuffix) + + return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImage: self.avatarImage) + } + + public func newContact(withNamePrefix namePrefix: String?, + givenName: String?, + middleName: String?, + familyName: String?, + nameSuffix: String?) -> ContactShareViewModel { + + // TODO move the `newContact` logic into the view model? + let newDbRecord = dbRecord.newContact(withNamePrefix: namePrefix, + givenName: givenName, + middleName: middleName, + familyName: familyName, + nameSuffix: nameSuffix) + + return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImage: self.avatarImage) + } + +} diff --git a/SignalMessaging/Models/OWSQuotedReplyModel.h b/SignalMessaging/ViewModels/OWSQuotedReplyModel.h similarity index 100% rename from SignalMessaging/Models/OWSQuotedReplyModel.h rename to SignalMessaging/ViewModels/OWSQuotedReplyModel.h diff --git a/SignalMessaging/Models/OWSQuotedReplyModel.m b/SignalMessaging/ViewModels/OWSQuotedReplyModel.m similarity index 100% rename from SignalMessaging/Models/OWSQuotedReplyModel.m rename to SignalMessaging/ViewModels/OWSQuotedReplyModel.m diff --git a/SignalMessaging/attachments/ApproveContactShareViewController.swift b/SignalMessaging/attachments/ApproveContactShareViewController.swift index 5bddec249c..71078ef298 100644 --- a/SignalMessaging/attachments/ApproveContactShareViewController.swift +++ b/SignalMessaging/attachments/ApproveContactShareViewController.swift @@ -7,8 +7,8 @@ import SignalServiceKit @objc public protocol ApproveContactShareViewControllerDelegate: class { - func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didApproveContactShare contactShare: OWSContact) - func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didCancelContactShare contactShare: OWSContact) + func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didApproveContactShare contactShare: ContactShareViewModel) + func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didCancelContactShare contactShare: ContactShareViewModel) } protocol ContactShareField: class { @@ -48,7 +48,7 @@ class ContactShareFieldBase: NSObject, Contac isIncludedFlag = isIncluded } - func applyToContact(contact: OWSContact) { + func applyToContact(contact: ContactShareViewModel) { preconditionFailure("This method must be overridden") } } @@ -57,7 +57,7 @@ class ContactShareFieldBase: NSObject, Contac class ContactSharePhoneNumber: ContactShareFieldBase { - override func applyToContact(contact: OWSContact) { + override func applyToContact(contact: ContactShareViewModel) { assert(isIncluded()) var values = [OWSContactPhoneNumber]() @@ -71,7 +71,7 @@ class ContactSharePhoneNumber: ContactShareFieldBase { class ContactShareEmail: ContactShareFieldBase { - override func applyToContact(contact: OWSContact) { + override func applyToContact(contact: ContactShareViewModel) { assert(isIncluded()) var values = [OWSContactEmail]() @@ -85,7 +85,7 @@ class ContactShareEmail: ContactShareFieldBase { class ContactShareAddress: ContactShareFieldBase { - override func applyToContact(contact: OWSContact) { + override func applyToContact(contact: ContactShareViewModel) { assert(isIncluded()) var values = [OWSContactAddress]() @@ -185,7 +185,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh let contactsManager: OWSContactsManager - var contactShare: OWSContact + var contactShare: ContactShareViewModel var fieldViews = [ContactShareFieldView]() @@ -199,7 +199,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh } @objc - required public init(contactShare: OWSContact, contactsManager: OWSContactsManager, delegate: ApproveContactShareViewControllerDelegate) { + required public init(contactShare: ContactShareViewModel, contactsManager: OWSContactsManager, delegate: ApproveContactShareViewControllerDelegate) { self.contactsManager = contactsManager self.contactShare = contactShare self.delegate = delegate @@ -277,7 +277,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh // TODO: Surface error with resolution to user if not. func canShareContact() -> Bool { - return contactShare.ows_isValid() + return contactShare.ows_isValid } func updateNavigationBar() { @@ -471,7 +471,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh // MARK: - - func filteredContactShare() -> OWSContact { + func filteredContactShare() -> ContactShareViewModel { let result = self.contactShare.newContact(withNamePrefix: self.contactShare.namePrefix, givenName: self.contactShare.givenName, middleName: self.contactShare.middleName, @@ -498,7 +498,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh } let filteredContactShare = self.filteredContactShare() - assert(filteredContactShare.ows_isValid()) + assert(filteredContactShare.ows_isValid) delegate.approveContactShare(self, didApproveContactShare: filteredContactShare) } @@ -523,7 +523,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh // MARK: - EditContactShareNameViewControllerDelegate - public func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: OWSContact) { + public func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: ContactShareViewModel) { self.contactShare = contactShare nameLabel.text = contactShare.displayName diff --git a/SignalMessaging/attachments/EditContactShareNameViewController.swift b/SignalMessaging/attachments/EditContactShareNameViewController.swift index b943b60c99..edf6db9fe0 100644 --- a/SignalMessaging/attachments/EditContactShareNameViewController.swift +++ b/SignalMessaging/attachments/EditContactShareNameViewController.swift @@ -109,7 +109,7 @@ class ContactNameFieldView: UIView { @objc public protocol EditContactShareNameViewControllerDelegate: class { - func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: OWSContact) + func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: ContactShareViewModel) } // MARK: - @@ -118,7 +118,7 @@ public protocol EditContactShareNameViewControllerDelegate: class { public class EditContactShareNameViewController: OWSViewController, ContactNameFieldViewDelegate { weak var delegate: EditContactShareNameViewControllerDelegate? - let contactShare: OWSContact + let contactShare: ContactShareViewModel var namePrefixView: ContactNameFieldView! var givenNameView: ContactNameFieldView! @@ -136,7 +136,7 @@ public class EditContactShareNameViewController: OWSViewController, ContactNameF } @objc - required public init(contactShare: OWSContact, delegate: EditContactShareNameViewControllerDelegate) { + required public init(contactShare: ContactShareViewModel, delegate: EditContactShareNameViewControllerDelegate) { self.contactShare = contactShare self.delegate = delegate diff --git a/SignalMessaging/contacts/OWSContactsManager.h b/SignalMessaging/contacts/OWSContactsManager.h index 53c3c34b52..a26ca8b3df 100644 --- a/SignalMessaging/contacts/OWSContactsManager.h +++ b/SignalMessaging/contacts/OWSContactsManager.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import @@ -77,6 +77,9 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification; - (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId; - (NSString *)stringForConversationTitleWithPhoneIdentifier:(NSString *)recipientId; +- (nullable UIImage *)systemContactImageForPhoneIdentifier:(nullable NSString *)identifier; +- (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier; + - (nullable UIImage *)imageForPhoneIdentifier:(nullable NSString *)identifier; - (NSAttributedString *)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *_Nonnull)font; - (NSAttributedString *)formattedFullNameForRecipientId:(NSString *)recipientId font:(UIFont *)font; diff --git a/SignalMessaging/contacts/OWSContactsManager.m b/SignalMessaging/contacts/OWSContactsManager.m index 7cda1c4faa..27b998592f 100644 --- a/SignalMessaging/contacts/OWSContactsManager.m +++ b/SignalMessaging/contacts/OWSContactsManager.m @@ -707,19 +707,32 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification return [self signalAccountForRecipientId:recipientId] != nil; } -- (UIImage *_Nullable)imageForPhoneIdentifier:(NSString *_Nullable)identifier + +- (UIImage *_Nullable)systemContactImageForPhoneIdentifier:(NSString *_Nullable)identifier { Contact *contact = self.allContactsMap[identifier]; if (!contact) { + // If we haven't loaded system contacts yet, we may have a cached + // copy in the db contact = [self signalAccountForRecipientId:identifier].contact; } + return contact.image; +} + +- (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier +{ + return [self.profileManager profileAvatarForRecipientId:identifier]; +} + +- (UIImage *_Nullable)imageForPhoneIdentifier:(NSString *_Nullable)identifier +{ // Prefer the contact image from the local address book if available - UIImage *_Nullable image = contact.image; + UIImage *_Nullable image = [self systemContactImageForPhoneIdentifier:identifier]; // Else try to use the image from their profile if (image == nil) { - image = [self.profileManager profileAvatarForRecipientId:identifier]; + image = [self profileImageForPhoneIdentifier:identifier]; } return image; diff --git a/SignalServiceKit/src/Contacts/TSThread.h b/SignalServiceKit/src/Contacts/TSThread.h index 07b795bd98..fa616048e1 100644 --- a/SignalServiceKit/src/Contacts/TSThread.h +++ b/SignalServiceKit/src/Contacts/TSThread.h @@ -43,16 +43,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, readonly) NSArray *recipientIdentifiers; -#if TARGET_OS_IOS - -/** - * Returns the image representing the thread. Nil if not available. - * - * @return UIImage of the thread, or nil. - */ -- (nullable UIImage *)image; -#endif - #pragma mark Interactions /** diff --git a/SignalServiceKit/src/Contacts/Threads/TSContactThread.m b/SignalServiceKit/src/Contacts/Threads/TSContactThread.m index 9b4de20ed2..2570a0c4ef 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSContactThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSContactThread.m @@ -120,15 +120,6 @@ NS_ASSUME_NONNULL_BEGIN return [[TextSecureKitEnv sharedEnv].contactsManager displayNameForPhoneIdentifier:self.contactIdentifier]; } -#if TARGET_OS_IPHONE - -- (nullable UIImage *)image -{ - UIImage *image = [[TextSecureKitEnv sharedEnv].contactsManager imageForPhoneIdentifier:self.contactIdentifier]; - return image; -} - -#endif + (NSString *)threadIdFromContactId:(NSString *)contactId { return [TSContactThreadPrefix stringByAppendingString:contactId]; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.h b/SignalServiceKit/src/Messages/Interactions/OWSContact.h index 3eef6a437c..0d4109f7d5 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.h @@ -112,10 +112,9 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value); @property (nonatomic, readonly) NSArray *emails; @property (nonatomic, readonly) NSArray *addresses; -// MJK @property (nonatomic, readonly, nullable) NSString *avatarAttachmentId; - (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction; -- (void)setAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream; +- (void)saveAvatarImage:(UIImage *)image transaction:(YapDatabaseReadWriteTransaction *)transaction; // "Profile" avatars should _not_ be saved to device contacts. @property (nonatomic, readonly) BOOL isProfileAvatar; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index 0a55f7e49f..fe979a0080 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -3,12 +3,11 @@ // #import "OWSContact.h" -#import "NSString+SSK.h" OWSAttachmentInfo.h +#import "MimeTypeUtil.h" +#import "NSString+SSK.h" #import "OWSContact+Private.h" #import "OWSSignalServiceProtos.pb.h" #import "PhoneNumber.h" - -//#import "Contact.h" #import "TSAttachment.h" #import "TSAttachmentPointer.h" #import "TSAttachmentStream.h" @@ -459,18 +458,26 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) } #pragma mark - Avatar -// MJK - (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction { return [TSAttachment fetchObjectWithUniqueID:self.avatarAttachmentId transaction:transaction]; } -- (void)setAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream -{ - OWSAssert([attachmentStream isKindOfClass:[TSAttachmentStream class]]); - OWSAssert(self.avatarAttachmentId == nil); +- (void)saveAvatarImage:(UIImage *)image transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + NSData *imageData = UIImageJPEGRepresentation(image, (CGFloat)0.9); + + TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:OWSMimeTypeImageJpeg + byteCount:imageData.length + sourceFilename:nil]; + + NSError *error; + BOOL success = [attachmentStream writeData:imageData error:&error]; + OWSAssert(success && !error); + + [attachmentStream saveWithTransaction:transaction]; self.avatarAttachmentId = attachmentStream.uniqueId; } diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.h b/SignalServiceKit/src/Messages/Interactions/TSMessage.h index ce8677e4f0..4c672c7e21 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.h @@ -44,7 +44,6 @@ NS_ASSUME_NONNULL_BEGIN - (nullable TSAttachment *)attachmentWithTransaction:(YapDatabaseReadTransaction *)transaction; - (void)setQuotedMessageThumbnailAttachmentStream:(TSAttachmentStream *)attachmentStream; -- (void)setContactShareAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream; - (BOOL)shouldStartExpireTimer; - (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index 636bb7aa45..68572ada4e 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -332,13 +332,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4; [self.quotedMessage setThumbnailAttachmentStream:attachmentStream]; } -- (void)setContactShareAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream -{ - OWSAssert(self.contactShare); - - [self.contactShare setAvatarAttachmentStream:attachmentStream]; -} - #pragma mark - Update With... Methods - (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 63da9f41c0..5fc1d82309 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -314,11 +314,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction]; } - // MJK TODO - don't generate the avatar attachment until here, when we've committed to sending it. if (message.contactShare.avatarAttachmentId != nil) { - // contactShareAvatarAttachment = [message.contactShare - // createAvatarForUploadWithTransaction:transaction]; - // TODO generate and save the attachment for upload here. TSAttachment *avatarAttachment = [message.contactShare avatarAttachmentWithTransaction:transaction]; if ([avatarAttachment isKindOfClass:[TSAttachmentStream class]]) { contactShareAvatarAttachment = (TSAttachmentStream *)avatarAttachment; diff --git a/SignalServiceKit/src/Protocols/ContactsManagerProtocol.h b/SignalServiceKit/src/Protocols/ContactsManagerProtocol.h index 26af046da5..c20015d9f7 100644 --- a/SignalServiceKit/src/Protocols/ContactsManagerProtocol.h +++ b/SignalServiceKit/src/Protocols/ContactsManagerProtocol.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // @class Contact; @@ -12,8 +12,4 @@ - (NSString * _Nonnull)displayNameForPhoneIdentifier:(NSString * _Nullable)phoneNumber; - (NSArray * _Nonnull)signalAccounts; -#if TARGET_OS_IPHONE -- (UIImage * _Nullable)imageForPhoneIdentifier:(NSString * _Nullable)phoneNumber; -#endif - @end From 45f91ead44af25e317858f7768350efc75699bc2 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 4 May 2018 22:52:43 -0400 Subject: [PATCH 5/6] Use actual avatar in ContactViewController // FREEBIE --- .../ContactViewController.swift | 11 ++--------- .../Cells/OWSContactShareView.m | 19 +++++++------------ .../ViewModels/ContactShareViewModel.swift | 13 +++++++++++++ 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Signal/src/ViewControllers/ContactViewController.swift b/Signal/src/ViewControllers/ContactViewController.swift index 4c8765f0e7..b8d51e1a88 100644 --- a/Signal/src/ViewControllers/ContactViewController.swift +++ b/Signal/src/ViewControllers/ContactViewController.swift @@ -249,16 +249,9 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate backButton.addSubview(backIconView) backIconView.autoCenterInSuperview() - // TODO: Use actual avatar. - let avatarSize = CGFloat(100) - + let avatarSize: CGFloat = 100 let avatarView = AvatarImageView() - // TODO: What's the best colorSeed value to use? - let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contactShare.displayName, - colorSeed: contactShare.displayName, - diameter: UInt(avatarSize), - contactsManager: contactsManager) - avatarView.image = avatarBuilder.build() + avatarView.image = contactShare.getAvatarImage(diameter: avatarSize, contactsManager: contactsManager) topView.addSubview(avatarView) avatarView.autoPin(toTopLayoutGuideOf: self, withInset: 20) avatarView.autoHCenterInSuperview() diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m index 73f2a9a990..3170054b90 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m @@ -38,6 +38,11 @@ NS_ASSUME_NONNULL_BEGIN return self; } +- (OWSContactsManager *)contactsManager +{ + return [Environment current].contactsManager; +} + #pragma mark - - (CGFloat)iconHMargin @@ -107,18 +112,8 @@ NS_ASSUME_NONNULL_BEGIN // TODO: Use the contact's avatar if present and downloaded. AvatarImageView *avatarView = [AvatarImageView new]; - // TODO: What's the best colorSeed value to use? - - UIImage *_Nullable avatarImage = self.contactShare.avatarImage; - if (!avatarImage) { - OWSAvatarBuilder *avatarBuilder = - [[OWSContactAvatarBuilder alloc] initWithNonSignalName:self.contactShare.displayName - colorSeed:self.contactShare.displayName - diameter:(NSUInteger)self.iconSize - contactsManager:[Environment current].contactsManager]; - avatarImage = [avatarBuilder build]; - } - avatarView.image = avatarImage; + avatarView.image = + [self.contactShare getAvatarImageWithDiameter:self.iconSize contactsManager:self.contactsManager]; [avatarView autoSetDimension:ALDimensionWidth toSize:self.iconSize]; [avatarView autoSetDimension:ALDimensionHeight toSize:self.iconSize]; diff --git a/SignalMessaging/ViewModels/ContactShareViewModel.swift b/SignalMessaging/ViewModels/ContactShareViewModel.swift index 5cd0235d15..5ba8471483 100644 --- a/SignalMessaging/ViewModels/ContactShareViewModel.swift +++ b/SignalMessaging/ViewModels/ContactShareViewModel.swift @@ -23,6 +23,19 @@ public class ContactShareViewModel: NSObject { } } + public func getAvatarImage(diameter: CGFloat, contactsManager: OWSContactsManager) -> UIImage { + if let avatarImage = avatarImage { + return avatarImage + } + + // TODO: What's the best colorSeed value to use? + let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: displayName, + colorSeed: displayName, + diameter: UInt(diameter), + contactsManager: contactsManager) + return avatarBuilder.build() + } + // MARK: Delegated -> dbRecord public var addresses: [OWSContactAddress] { From a10ae1835e6f5df2fdc9e06724c48ca5b7115489 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 7 May 2018 12:32:31 -0400 Subject: [PATCH 6/6] respond to code review // FREEBIE --- .../Cells/OWSContactShareView.m | 1 - .../ConversationViewController.m | 9 +++---- .../ViewControllers/DebugUI/DebugUIMessages.m | 16 ++++++----- .../ApproveContactShareViewController.swift | 2 +- SignalMessaging/utils/OWSAvatarBuilder.m | 8 +++--- SignalServiceKit/src/Contacts/TSThread.m | 9 +++---- .../src/Devices/OWSRecordTranscriptJob.m | 7 ++--- .../Messages/Attachments/TSAttachmentStream.m | 5 ++-- .../src/Messages/Interactions/TSInteraction.m | 6 +++-- .../Messages/Interactions/TSOutgoingMessage.m | 6 ++--- .../Messages/Interactions/TSQuotedMessage.m | 11 ++++---- .../src/Messages/OWSBatchMessageProcessor.m | 6 ++--- .../src/Messages/OWSDisappearingMessagesJob.m | 4 +-- .../src/Messages/OWSMessageManager.m | 15 ++++++----- .../src/Messages/OWSReadReceiptManager.m | 4 +-- .../src/Storage/OWSOrphanedDataCleaner.m | 27 +++++++++++-------- 16 files changed, 74 insertions(+), 62 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m index 3170054b90..cfd9a4c473 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m @@ -110,7 +110,6 @@ NS_ASSUME_NONNULL_BEGIN [contentView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.vMargin]; [contentView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.vMargin]; - // TODO: Use the contact's avatar if present and downloaded. AvatarImageView *avatarView = [AvatarImageView new]; avatarView.image = [self.contactShare getAvatarImageWithDiameter:self.iconSize contactsManager:self.contactsManager]; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index ce3fe62caa..619acde572 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2969,12 +2969,11 @@ typedef enum : NSUInteger { messageSender:self.messageSender completion:nil]; [self messageWasSent:message]; + + if (didAddToProfileWhitelist) { + [self ensureDynamicInteractions]; + } }]; - - - if (didAddToProfileWhitelist) { - [self ensureDynamicInteractions]; - } } - (NSURL *)videoTempFolder diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index 1e581c78fb..c369864383 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -3584,9 +3584,9 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:phoneNumber.toE164]; [self sendFakeMessages:messageCount thread:contactThread]; - DDLogError(@"Create fake thread: %@, interactions: %tu", + DDLogError(@"Create fake thread: %@, interactions: %lu", phoneNumber.toE164, - contactThread.numberOfInteractions); + (unsigned long)contactThread.numberOfInteractions); }]; } @@ -3612,7 +3612,10 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac [self sendFakeMessages:batchSize thread:thread isTextOnly:isTextOnly transaction:transaction]; }]; remainder -= batchSize; - DDLogInfo(@"%@ sendFakeMessages %td / %tu", self.logTag, counter - remainder, counter); + DDLogInfo(@"%@ sendFakeMessages %lu / %lu", + self.logTag, + (unsigned long)(counter - remainder), + (unsigned long)counter); } }); } @@ -3624,7 +3627,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac isTextOnly:(BOOL)isTextOnly transaction:(YapDatabaseReadWriteTransaction *)transaction { - DDLogInfo(@"%@ sendFakeMessages: %tu", self.logTag, counter); + DDLogInfo(@"%@ sendFakeMessages: %lu", self.logTag, (unsigned long)counter); for (NSUInteger i = 0; i < counter; i++) { NSString *randomText = [self randomText]; @@ -3776,7 +3779,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac { OWSAssert(thread); - DDLogInfo(@"%@ injectIncomingMessageInThread: %tu", self.logTag, counter); + DDLogInfo(@"%@ injectIncomingMessageInThread: %lu", self.logTag, (unsigned long)counter); NSString *randomText = [self randomText]; NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText]; @@ -4168,7 +4171,8 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac inThread:thread authorId:thread.recipientIdentifiers.firstObject sourceDeviceId:0 - messageBody:[NSString stringWithFormat:@"Should disappear 60s after %tu", now] + messageBody:[NSString + stringWithFormat:@"Should disappear 60s after %lu", (unsigned long)now] attachmentIds:[NSMutableArray new] expiresInSeconds:60 quotedMessage:nil diff --git a/SignalMessaging/attachments/ApproveContactShareViewController.swift b/SignalMessaging/attachments/ApproveContactShareViewController.swift index 71078ef298..2b79a29f2e 100644 --- a/SignalMessaging/attachments/ApproveContactShareViewController.swift +++ b/SignalMessaging/attachments/ApproveContactShareViewController.swift @@ -19,7 +19,7 @@ protocol ContactShareField: class { func setIsIncluded(_ isIncluded: Bool) - func applyToContact(contact: OWSContact) + func applyToContact(contact: ContactShareViewModel) } // MARK: - diff --git a/SignalMessaging/utils/OWSAvatarBuilder.m b/SignalMessaging/utils/OWSAvatarBuilder.m index 55987acd74..49433c15c7 100644 --- a/SignalMessaging/utils/OWSAvatarBuilder.m +++ b/SignalMessaging/utils/OWSAvatarBuilder.m @@ -89,14 +89,14 @@ NS_ASSUME_NONNULL_BEGIN - (nullable UIImage *)buildSavedImage { - OWSRaiseException( - NSInternalInconsistencyException, @"You must override %@ in a subclass", NSStringFromSelector(_cmd)); + OWS_ABSTRACT_METHOD(); + return nil; } - (UIImage *)buildDefaultImage { - OWSRaiseException( - NSInternalInconsistencyException, @"You must override %@ in a subclass", NSStringFromSelector(_cmd)); + OWS_ABSTRACT_METHOD(); + return [UIImage new]; } @end diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index 074dc7c0d1..7b4f17e733 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -112,11 +112,6 @@ NS_ASSUME_NONNULL_BEGIN return @[]; } -- (nullable UIImage *)image -{ - return nil; -} - - (BOOL)hasSafetyNumbers { return NO; @@ -256,7 +251,9 @@ NS_ASSUME_NONNULL_BEGIN // who's test devices are constantly reinstalled. We could add a purpose-built DB view, // but I think in the real world this is rare to be a hotspot. if (missedCount > 50) { - DDLogWarn(@"%@ found last interaction for inbox after skipping %tu items", self.logTag, missedCount); + DDLogWarn(@"%@ found last interaction for inbox after skipping %lu items", + self.logTag, + (unsigned long)missedCount); } *stop = YES; } diff --git a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m index 586993d714..22f338c2d8 100644 --- a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m +++ b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m @@ -110,7 +110,8 @@ NS_ASSUME_NONNULL_BEGIN [[OWSAttachmentsProcessor alloc] initWithAttachmentPointer:attachmentPointer networkManager:self.networkManager]; - DDLogDebug(@"%@ downloading thumbnail for transcript: %tu", self.logTag, transcript.timestamp); + DDLogDebug( + @"%@ downloading thumbnail for transcript: %lu", self.logTag, (unsigned long)transcript.timestamp); [attachmentProcessor fetchAttachmentsForMessage:outgoingMessage transaction:transaction success:^(TSAttachmentStream *_Nonnull attachmentStream) { @@ -121,9 +122,9 @@ NS_ASSUME_NONNULL_BEGIN }]; } failure:^(NSError *_Nonnull error) { - DDLogWarn(@"%@ failed to fetch thumbnail for transcript: %tu with error: %@", + DDLogWarn(@"%@ failed to fetch thumbnail for transcript: %lu with error: %@", self.logTag, - transcript.timestamp, + (unsigned long)transcript.timestamp, error); }]; } diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index c85e6eb47f..e1036cc439 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -710,8 +710,9 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert(attachmentId.length > 0); - // TODO we should hoist this transaction to make sure we're getting a consistent view in the message sending process - // A brief glance shows it touches quite a bit of code, but should be straight forward. + // TODO we should past in a transaction, rather than sneakily generate one in `fetch...` to make sure we're + // getting a consistent view in the message sending process. A brief glance shows it touches quite a bit of code, + // but should be straight forward. TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; if (![attachment isKindOfClass:[TSAttachmentStream class]]) { DDLogError(@"Unexpected type for attachment builder: %@", attachment); diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m index bd6a53662e..babff7e05c 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m @@ -129,8 +129,10 @@ NS_ASSUME_NONNULL_BEGIN - (NSString *)description { - return [NSString - stringWithFormat:@"%@ in thread: %@ timestamp: %tu", [super description], self.uniqueThreadId, self.timestamp]; + return [NSString stringWithFormat:@"%@ in thread: %@ timestamp: %lu", + [super description], + self.uniqueThreadId, + (unsigned long)self.timestamp]; } - (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 76f95054a1..1e2c0d96f1 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -738,9 +738,9 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt OWSFail(@"%@ message body length too long.", self.logTag); NSString *truncatedBody = [self.body copy]; while ([truncatedBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > kOversizeTextMessageSizeThreshold) { - DDLogError(@"%@ truncating body which is too long: %tu", + DDLogError(@"%@ truncating body which is too long: %lu", self.logTag, - [truncatedBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + (unsigned long)[truncatedBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); truncatedBody = [truncatedBody substringToIndex:truncatedBody.length / 2]; } [builder setBody:truncatedBody]; @@ -800,7 +800,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt if (contactProto) { [builder addContact:contactProto]; } else { - OWSFail(@"%@ in %s <# thing #> was unexpectedly nil", self.logTag, __PRETTY_FUNCTION__); + OWSFail(@"%@ in %s contactProto was unexpectedly nil", self.logTag, __PRETTY_FUNCTION__); } } diff --git a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m index 8f6e33e7a6..a846b5e6a6 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m @@ -153,19 +153,19 @@ NS_ASSUME_NONNULL_BEGIN transaction:transaction]; if (thumbnailStream) { - DDLogDebug(@"%@ Generated local thumbnail for quoted quoted message: %@:%tu", + DDLogDebug(@"%@ Generated local thumbnail for quoted quoted message: %@:%lu", self.logTag, thread.uniqueId, - timestamp); + (unsigned long)timestamp); [thumbnailStream saveWithTransaction:transaction]; attachmentInfo.thumbnailAttachmentStreamId = thumbnailStream.uniqueId; } else if (quotedAttachment.hasThumbnail) { - DDLogDebug(@"%@ Saving reference for fetching remote thumbnail for quoted message: %@:%tu", + DDLogDebug(@"%@ Saving reference for fetching remote thumbnail for quoted message: %@:%lu", self.logTag, thread.uniqueId, - timestamp); + (unsigned long)timestamp); OWSSignalServiceProtosAttachmentPointer *thumbnailAttachmentProto = quotedAttachment.thumbnail; TSAttachmentPointer *thumbnailPointer = @@ -174,7 +174,8 @@ NS_ASSUME_NONNULL_BEGIN attachmentInfo.thumbnailAttachmentPointerId = thumbnailPointer.uniqueId; } else { - DDLogDebug(@"%@ No thumbnail for quoted message: %@:%tu", self.logTag, thread.uniqueId, timestamp); + DDLogDebug( + @"%@ No thumbnail for quoted message: %@:%lu", self.logTag, thread.uniqueId, (unsigned long)timestamp); } [attachmentInfos addObject:attachmentInfo]; diff --git a/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m b/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m index 5b5c96b0fa..d33fc96070 100644 --- a/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m +++ b/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m @@ -356,10 +356,10 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo backgroundTask = nil; - DDLogVerbose(@"%@ completed %zu/%zu jobs. %zd jobs left.", + DDLogVerbose(@"%@ completed %lu/%lu jobs. %zd jobs left.", self.logTag, - processedJobs.count, - batchJobs.count, + (unsigned long)processedJobs.count, + (unsigned long)batchJobs.count, [OWSMessageContentJob numberOfKeysInCollection]); // Wait a bit in hopes of increasing the batch size. diff --git a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m index e5215e286d..e173e15dfd 100644 --- a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m +++ b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m @@ -135,7 +135,7 @@ void AssertIsOnDisappearingMessagesQueue() transaction:transaction]; }]; - DDLogDebug(@"%@ Removed %tu expired messages", self.logTag, expirationCount); + DDLogDebug(@"%@ Removed %lu expired messages", self.logTag, (unsigned long)expirationCount); backgroundTask = nil; return expirationCount; @@ -398,7 +398,7 @@ void AssertIsOnDisappearingMessagesQueue() { [self.disappearingMessagesFinder enumerateMessagesWhichFailedToStartExpiringWithBlock:^( TSMessage *_Nonnull message) { - DDLogWarn(@"%@ starting old timer for message timestamp: %tu", self.logTag, message.timestamp); + DDLogWarn(@"%@ starting old timer for message timestamp: %lu", self.logTag, (unsigned long)message.timestamp); [self setExpirationForMessage:message expirationStartedAt:message.timestampForSorting transaction:transaction]; } transaction:transaction]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 590b98b8e0..67097cfc12 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1109,7 +1109,8 @@ NS_ASSUME_NONNULL_BEGIN [[OWSAttachmentsProcessor alloc] initWithAttachmentPointer:attachmentPointer networkManager:self.networkManager]; - DDLogDebug(@"%@ downloading thumbnail for message: %tu", self.logTag, incomingMessage.timestamp); + DDLogDebug( + @"%@ downloading thumbnail for message: %lu", self.logTag, (unsigned long)incomingMessage.timestamp); [attachmentProcessor fetchAttachmentsForMessage:incomingMessage transaction:transaction success:^(TSAttachmentStream *_Nonnull attachmentStream) { @@ -1120,9 +1121,9 @@ NS_ASSUME_NONNULL_BEGIN }]; } failure:^(NSError *_Nonnull error) { - DDLogWarn(@"%@ failed to fetch thumbnail for message: %tu with error: %@", + DDLogWarn(@"%@ failed to fetch thumbnail for message: %lu with error: %@", self.logTag, - incomingMessage.timestamp, + (unsigned long)incomingMessage.timestamp, error); }]; } @@ -1140,7 +1141,9 @@ NS_ASSUME_NONNULL_BEGIN [[OWSAttachmentsProcessor alloc] initWithAttachmentPointer:attachmentPointer networkManager:self.networkManager]; - DDLogDebug(@"%@ downloading contact avatar for message: %tu", self.logTag, incomingMessage.timestamp); + DDLogDebug(@"%@ downloading contact avatar for message: %lu", + self.logTag, + (unsigned long)incomingMessage.timestamp); [attachmentProcessor fetchAttachmentsForMessage:incomingMessage transaction:transaction success:^(TSAttachmentStream *_Nonnull attachmentStream) { @@ -1150,9 +1153,9 @@ NS_ASSUME_NONNULL_BEGIN }]; } failure:^(NSError *_Nonnull error) { - DDLogWarn(@"%@ failed to fetch contact avatar for message: %tu with error: %@", + DDLogWarn(@"%@ failed to fetch contact avatar for message: %lu with error: %@", self.logTag, - incomingMessage.timestamp, + (unsigned long)incomingMessage.timestamp, error); }]; } diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m index ca54eae1db..8c5b1c2cb5 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m @@ -559,9 +559,9 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE } if (wasLocal) { - DDLogError(@"Marking %zu messages as read locally.", newlyReadList.count); + DDLogError(@"Marking %lu messages as read locally.", (unsigned long)newlyReadList.count); } else { - DDLogError(@"Marking %zu messages as read by linked device.", newlyReadList.count); + DDLogError(@"Marking %lu messages as read by linked device.", (unsigned long)newlyReadList.count); } for (id readItem in newlyReadList) { [readItem markAsReadAtTimestamp:readTimestamp sendReadReceipt:wasLocal transaction:transaction]; diff --git a/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m b/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m index fa0e3f15cf..de92950e49 100644 --- a/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m +++ b/SignalServiceKit/src/Storage/OWSOrphanedDataCleaner.m @@ -83,18 +83,20 @@ NS_ASSUME_NONNULL_BEGIN }]; }]; - CleanupLogDebug(@"%@ fileCount: %tu", self.logTag, fileCount); + CleanupLogDebug(@"%@ fileCount: %lu", self.logTag, (unsigned long)fileCount); CleanupLogDebug(@"%@ totalFileSize: %lld", self.logTag, totalFileSize); CleanupLogDebug(@"%@ attachmentStreams: %d", self.logTag, attachmentStreamCount); - CleanupLogDebug(@"%@ attachmentStreams with file paths: %tu", self.logTag, attachmentFilePaths.count); + CleanupLogDebug( + @"%@ attachmentStreams with file paths: %lu", self.logTag, (unsigned long)attachmentFilePaths.count); NSMutableSet *orphanDiskFilePaths = [diskFilePaths mutableCopy]; [orphanDiskFilePaths minusSet:attachmentFilePaths]; NSMutableSet *missingAttachmentFilePaths = [attachmentFilePaths mutableCopy]; [missingAttachmentFilePaths minusSet:diskFilePaths]; - CleanupLogDebug(@"%@ orphan disk file paths: %tu", self.logTag, orphanDiskFilePaths.count); - CleanupLogDebug(@"%@ missing attachment file paths: %tu", self.logTag, missingAttachmentFilePaths.count); + CleanupLogDebug(@"%@ orphan disk file paths: %lu", self.logTag, (unsigned long)orphanDiskFilePaths.count); + CleanupLogDebug( + @"%@ missing attachment file paths: %lu", self.logTag, (unsigned long)missingAttachmentFilePaths.count); [self printPaths:orphanDiskFilePaths.allObjects label:@"orphan disk file paths"]; [self printPaths:missingAttachmentFilePaths.allObjects label:@"missing attachment file paths"]; @@ -140,10 +142,13 @@ NS_ASSUME_NONNULL_BEGIN }]; }]; - CleanupLogDebug(@"%@ attachmentIds: %tu", self.logTag, attachmentIds.count); - CleanupLogDebug(@"%@ messageAttachmentIds: %tu", self.logTag, messageAttachmentIds.count); - CleanupLogDebug(@"%@ quotedReplyThumbnailAttachmentIds: %tu", self.logTag, quotedReplyThumbnailAttachmentIds.count); - CleanupLogDebug(@"%@ contactShareAvatarAttachmentIds: %tu", self.logTag, contactShareAvatarAttachmentIds.count); + CleanupLogDebug(@"%@ attachmentIds: %lu", self.logTag, (unsigned long)attachmentIds.count); + CleanupLogDebug(@"%@ messageAttachmentIds: %lu", self.logTag, (unsigned long)messageAttachmentIds.count); + CleanupLogDebug(@"%@ quotedReplyThumbnailAttachmentIds: %lu", + self.logTag, + (unsigned long)quotedReplyThumbnailAttachmentIds.count); + CleanupLogDebug( + @"%@ contactShareAvatarAttachmentIds: %lu", self.logTag, (unsigned long)contactShareAvatarAttachmentIds.count); NSMutableSet *orphanAttachmentIds = [attachmentIds mutableCopy]; [orphanAttachmentIds minusSet:messageAttachmentIds]; @@ -152,9 +157,9 @@ NS_ASSUME_NONNULL_BEGIN NSMutableSet *missingAttachmentIds = [messageAttachmentIds mutableCopy]; [missingAttachmentIds minusSet:attachmentIds]; - CleanupLogDebug(@"%@ orphan attachmentIds: %tu", self.logTag, orphanAttachmentIds.count); - CleanupLogDebug(@"%@ missing attachmentIds: %tu", self.logTag, missingAttachmentIds.count); - CleanupLogDebug(@"%@ orphan interactions: %tu", self.logTag, orphanInteractionIds.count); + CleanupLogDebug(@"%@ orphan attachmentIds: %lu", self.logTag, (unsigned long)orphanAttachmentIds.count); + CleanupLogDebug(@"%@ missing attachmentIds: %lu", self.logTag, (unsigned long)missingAttachmentIds.count); + CleanupLogDebug(@"%@ orphan interactions: %lu", self.logTag, (unsigned long)orphanInteractionIds.count); // We need to avoid cleaning up new attachments and files that are still in the process of // being created/written, so we don't clean up anything recent.