Merge branch 'mkirk/contact-sharing-via-sae'
This commit is contained in:
commit
6ecaf01b95
@ -31,6 +31,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
|
||||
@property (nonatomic) TSThread *thread;
|
||||
@property (nonatomic, readonly, weak) id<ShareViewDelegate> 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;
|
||||
|
||||
@ -148,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
|
||||
@ -282,29 +292,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__);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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<CNContact *> *_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];
|
||||
|
||||
@ -160,21 +160,13 @@ 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
|
||||
|
||||
// `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 -
|
||||
|
||||
+ (nullable OWSContact *)contactForVCardData:(NSData *)data;
|
||||
+ (nullable NSData *)vCardDataContact:(OWSContact *)contact;
|
||||
|
||||
#pragma mark - Proto Serialization
|
||||
|
||||
+ (nullable OWSSignalServiceProtosDataMessageContact *)protoForContact:(OWSContact *)contact;
|
||||
|
||||
@ -556,50 +556,9 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
|
||||
|
||||
@implementation OWSContacts
|
||||
|
||||
#pragma mark - VCard Serialization
|
||||
|
||||
+ (nullable CNContact *)systemContactForVCardData:(NSData *)data
|
||||
{
|
||||
OWSAssert(data);
|
||||
|
||||
NSError *error;
|
||||
NSArray<CNContact *> *_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
|
||||
|
||||
// `contactForSystemContact` does *not* handle avatars. That must be delt with by the caller
|
||||
+ (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact
|
||||
{
|
||||
if (!systemContact) {
|
||||
@ -690,11 +649,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;
|
||||
@ -802,31 +756,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
|
||||
|
||||
@ -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.")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user