From adabf0273276dae805244fb4b22b54f23e5f9804 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 10 May 2018 10:56:48 -0400 Subject: [PATCH 1/4] Fix contact sharing (Avatar TODO) // FREEBIE --- .../SharingThreadPickerViewController.m | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/SignalMessaging/attachments/SharingThreadPickerViewController.m b/SignalMessaging/attachments/SharingThreadPickerViewController.m index 15e47f0a6..d82985f60 100644 --- a/SignalMessaging/attachments/SharingThreadPickerViewController.m +++ b/SignalMessaging/attachments/SharingThreadPickerViewController.m @@ -31,6 +31,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); @property (nonatomic) TSThread *thread; @property (nonatomic, readonly, weak) id shareViewDelegate; @property (nonatomic, readonly) UIProgressView *progressView; +@property (nonatomic, readonly) YapDatabaseConnection *editingDBConnection; @property (atomic, nullable) TSOutgoingMessage *outgoingMessage; @end @@ -46,6 +47,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); return self; } + _editingDBConnection = [OWSPrimaryStorage.sharedManager newDatabaseConnection]; _shareViewDelegate = shareViewDelegate; self.selectThreadViewDelegate = self; @@ -282,29 +284,37 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); #pragma mark - ApproveContactShareViewControllerDelegate - (void)approveContactShare:(ApproveContactShareViewController *)approvalViewController - didApproveContactShare:(OWSContact *)contactShare + didApproveContactShare:(ContactShareViewModel *)contactShare { DDLogInfo(@"%@ in %s", self.logTag, __PRETTY_FUNCTION__); [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; [self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) { OWSAssertIsOnMainThread(); - - __block TSOutgoingMessage *outgoingMessage = nil; - outgoingMessage = [ThreadUtil sendMessageWithContactShare:contactShare - inThread:self.thread - messageSender:self.messageSender - completion:^(NSError *_Nullable error) { - sendCompletion(error, outgoingMessage); - }]; - // This is necessary to show progress. - self.outgoingMessage = outgoingMessage; + [self.editingDBConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + if (contactShare.avatarImage) { + [contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction]; + } + } + completionBlock:^{ + __block TSOutgoingMessage *outgoingMessage = nil; + outgoingMessage = [ThreadUtil sendMessageWithContactShare:contactShare.dbRecord + inThread:self.thread + messageSender:self.messageSender + completion:^(NSError *_Nullable error) { + sendCompletion(error, outgoingMessage); + }]; + // This is necessary to show progress. + self.outgoingMessage = outgoingMessage; + }]; + + } fromViewController:approvalViewController]; } - (void)approveContactShare:(ApproveContactShareViewController *)approvalViewController - didCancelContactShare:(OWSContact *)contactShare + didCancelContactShare:(ContactShareViewModel *)contactShare { DDLogInfo(@"%@ in %s", self.logTag, __PRETTY_FUNCTION__); From a16040f19f10841e2967aa83dd37a72dedae4a30 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 10 May 2018 11:27:15 -0400 Subject: [PATCH 2/4] Fix avatar sending in SAE // FREEBIE --- .../SharingThreadPickerViewController.m | 26 +++++++++----- SignalServiceKit/src/Contacts/Contact.h | 1 + SignalServiceKit/src/Contacts/Contact.m | 36 +++++++++++++++++++ .../src/Messages/Interactions/OWSContact.m | 5 --- .../ShareViewController.swift | 2 +- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/SignalMessaging/attachments/SharingThreadPickerViewController.m b/SignalMessaging/attachments/SharingThreadPickerViewController.m index d82985f60..51daca53a 100644 --- a/SignalMessaging/attachments/SharingThreadPickerViewController.m +++ b/SignalMessaging/attachments/SharingThreadPickerViewController.m @@ -150,22 +150,30 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); if (self.attachment.isConvertibleToContactShare) { NSData *data = self.attachment.data; - OWSContact *_Nullable contact = [OWSContacts contactForVCardData:data]; - if (!contact) { - // This should never happen since we verify that the contact can be parsed when building the attachment. - OWSFail(@"%@ could not parse contact share.", self.logTag); - [self.shareViewDelegate shareViewWasCancelled]; + Contact *_Nullable contact = [Contact contactWithVCardData:data]; + OWSContact *_Nullable contactShareRecord = [OWSContacts contactForSystemContact:contact.cnContact]; + if (!contactShareRecord) { + DDLogError(@"%@ Could not convert system contact.", self.logTag); return; } - // TODO: Populate avatar image. BOOL isProfileAvatar = NO; - NSData *_Nullable avatarImageData = nil; - contact.isProfileAvatar = isProfileAvatar; + NSData *_Nullable avatarImageData = contact.imageData; + for (NSString *recipientId in contact.textSecureIdentifiers) { + if (avatarImageData) { + break; + } + avatarImageData = [self.contactsManager profileImageDataForPhoneIdentifier:recipientId]; + if (avatarImageData) { + isProfileAvatar = YES; + } + } + contactShareRecord.isProfileAvatar = isProfileAvatar; ContactShareViewModel *contactShare = - [[ContactShareViewModel alloc] initWithContactShareRecord:contact avatarImageData:avatarImageData]; + [[ContactShareViewModel alloc] initWithContactShareRecord:contactShareRecord + avatarImageData:avatarImageData]; ApproveContactShareViewController *approvalVC = [[ApproveContactShareViewController alloc] initWithContactShare:contactShare diff --git a/SignalServiceKit/src/Contacts/Contact.h b/SignalServiceKit/src/Contacts/Contact.h index aec8c014b..72b5a31f8 100644 --- a/SignalServiceKit/src/Contacts/Contact.h +++ b/SignalServiceKit/src/Contacts/Contact.h @@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN #if TARGET_OS_IOS - (instancetype)initWithSystemContact:(CNContact *)contact NS_AVAILABLE_IOS(9_0); ++ (nullable Contact *)contactWithVCardData:(NSData *)data; - (NSString *)nameForPhoneNumber:(NSString *)recipientId; diff --git a/SignalServiceKit/src/Contacts/Contact.m b/SignalServiceKit/src/Contacts/Contact.m index 84d82b9a8..49d4d6f33 100644 --- a/SignalServiceKit/src/Contacts/Contact.m +++ b/SignalServiceKit/src/Contacts/Contact.m @@ -106,11 +106,25 @@ NS_ASSUME_NONNULL_BEGIN if (contact.thumbnailImageData) { _imageData = [contact.thumbnailImageData copy]; + } else if (contact.imageData) { + // This only occurs when sharing a contact via the share extension + _imageData = [contact.imageData copy]; } return self; } ++ (nullable Contact *)contactWithVCardData:(NSData *)data +{ + CNContact *_Nullable cnContact = [self cnContactWithVCardData:data]; + + if (!cnContact) { + return nil; + } + + return [[self alloc] initWithSystemContact:cnContact]; +} + - (nullable UIImage *)image { if (_image) { @@ -290,6 +304,28 @@ NS_ASSUME_NONNULL_BEGIN return hash; } +#pragma mark - CNContactConverters + ++ (nullable CNContact *)cnContactWithVCardData:(NSData *)data +{ + OWSAssert(data); + + NSError *error; + NSArray *_Nullable contacts = [CNContactVCardSerialization contactsWithData:data error:&error]; + if (!contacts || error) { + OWSProdLogAndFail(@"%@ could not parse vcard: %@", self.logTag, error); + return nil; + } + if (contacts.count < 1) { + OWSProdLogAndFail(@"%@ empty vcard: %@", self.logTag, error); + return nil; + } + if (contacts.count > 1) { + OWSProdLogAndFail(@"%@ more than one contact in vcard: %@", self.logTag, error); + } + return contacts.firstObject; +} + - (CNContact *)buildCNContactMergedWithNewContact:(CNContact *)newCNContact { CNMutableContact *_Nullable mergedCNContact = [self.cnContact mutableCopy]; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index b4fa3815e..940f00508 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -690,11 +690,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) } contact.addresses = addresses; - // TODO: Avatar - - // @property (readonly, copy, nullable, NS_NONATOMIC_IOSONLY) NSData *imageData; - // @property (readonly, copy, nullable, NS_NONATOMIC_IOSONLY) NSData *thumbnailImageData; - [contact ensureDisplayName]; return contact; diff --git a/SignalShareExtension/ShareViewController.swift b/SignalShareExtension/ShareViewController.swift index 0ee30616a..81891c543 100644 --- a/SignalShareExtension/ShareViewController.swift +++ b/SignalShareExtension/ShareViewController.swift @@ -721,7 +721,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed utiType: kUTTypeVCard as String) { customFileName = "Contact.vcf" - if let contactShare = OWSContacts.contact(forVCardData: data) { + if Contact(vCardData: data) != nil { isConvertibleToContactShare = true } else { Logger.error("\(strongSelf.logTag) could not parse vcard.") From 76313152271706a6ba65ad0f1565774801a195c1 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 10 May 2018 11:30:32 -0400 Subject: [PATCH 3/4] Remove unused code // FREEBIE --- .../src/Messages/Interactions/OWSContact.h | 10 --- .../src/Messages/Interactions/OWSContact.m | 67 ------------------- 2 files changed, 77 deletions(-) diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.h b/SignalServiceKit/src/Messages/Interactions/OWSContact.h index 13937b23b..586ffb6a3 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.h @@ -160,21 +160,11 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value); // TODO: Move to separate source file, rename to OWSContactConversion. @interface OWSContacts : NSObject -#pragma mark - VCard Serialization - -+ (nullable CNContact *)systemContactForVCardData:(NSData *)data; -+ (nullable NSData *)vCardDataForSystemContact:(CNContact *)systemContact; - #pragma mark - System Contact Conversion + (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact; + (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData; -#pragma mark - - -+ (nullable OWSContact *)contactForVCardData:(NSData *)data; -+ (nullable NSData *)vCardDataContact:(OWSContact *)contact; - #pragma mark - Proto Serialization + (nullable OWSSignalServiceProtosDataMessageContact *)protoForContact:(OWSContact *)contact; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index 940f00508..70e9b40fa 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -556,48 +556,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) @implementation OWSContacts -#pragma mark - VCard Serialization - -+ (nullable CNContact *)systemContactForVCardData:(NSData *)data -{ - OWSAssert(data); - - NSError *error; - NSArray *_Nullable contacts = [CNContactVCardSerialization contactsWithData:data error:&error]; - if (!contacts || error) { - OWSProdLogAndFail(@"%@ could not parse vcard: %@", self.logTag, error); - return nil; - } - if (contacts.count < 1) { - OWSProdLogAndFail(@"%@ empty vcard: %@", self.logTag, error); - return nil; - } - if (contacts.count > 1) { - OWSProdLogAndFail(@"%@ more than one contact in vcard: %@", self.logTag, error); - } - return contacts.firstObject; -} - -+ (nullable NSData *)vCardDataForSystemContact:(CNContact *)systemContact -{ - OWSAssert(systemContact); - - NSError *error; - NSData *_Nullable data = [CNContactVCardSerialization dataWithContacts:@[ - systemContact, - ] - error:&error]; - if (!data || error) { - OWSProdLogAndFail(@"%@ could not serialize to vcard: %@", self.logTag, error); - return nil; - } - if (data.length < 1) { - OWSProdLogAndFail(@"%@ empty vcard data: %@", self.logTag, error); - return nil; - } - return data; -} - #pragma mark - System Contact Conversion + (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact @@ -797,31 +755,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) return systemContact; } -#pragma mark - - -+ (nullable OWSContact *)contactForVCardData:(NSData *)data -{ - OWSAssert(data); - - CNContact *_Nullable systemContact = [self systemContactForVCardData:data]; - if (!systemContact) { - return nil; - } - return [self contactForSystemContact:systemContact]; -} - -+ (nullable NSData *)vCardDataContact:(OWSContact *)contact -{ - OWSAssert(contact); - - // TODO pass in image for vcard - CNContact *_Nullable systemContact = [self systemContactForContact:contact imageData:nil]; - if (!systemContact) { - return nil; - } - return [self vCardDataForSystemContact:systemContact]; -} - #pragma mark - Proto Serialization + (nullable OWSSignalServiceProtosDataMessageContact *)protoForContact:(OWSContact *)contact From 407ec997ab022d6e4e4c07b3714a73e926b0d793 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 10 May 2018 11:57:30 -0400 Subject: [PATCH 4/4] Add comment per CR // FREEBIE --- SignalServiceKit/src/Messages/Interactions/OWSContact.h | 2 ++ SignalServiceKit/src/Messages/Interactions/OWSContact.m | 1 + 2 files changed, 3 insertions(+) diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.h b/SignalServiceKit/src/Messages/Interactions/OWSContact.h index 586ffb6a3..eeb4d3304 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.h @@ -162,7 +162,9 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value); #pragma mark - System Contact Conversion +// `contactForSystemContact` does *not* handle avatars. That must be delt with by the caller + (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact; + + (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData; #pragma mark - Proto Serialization diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index 70e9b40fa..6828f640a 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -558,6 +558,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) #pragma mark - System Contact Conversion +// `contactForSystemContact` does *not* handle avatars. That must be delt with by the caller + (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact { if (!systemContact) {