merge avatar with existing

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
parent 95b93115f9
commit c15fea4eca

@ -144,7 +144,7 @@ public class ContactShareViewHelper: NSObject, CNContactViewControllerDelegate {
return return
} }
guard let systemContact = OWSContacts.systemContact(for: contactShare.dbRecord) else { guard let systemContact = OWSContacts.systemContact(for: contactShare.dbRecord, imageData: contactShare.avatarImageData) else {
owsFail("\(logTag) Could not derive system contact.") owsFail("\(logTag) Could not derive system contact.")
return return
} }

@ -5004,20 +5004,20 @@ interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransiti
} }
BOOL isProfileAvatar = NO; BOOL isProfileAvatar = NO;
UIImage *_Nullable avatarImage = contact.image; NSData *_Nullable avatarImageData = contact.imageData;
for (NSString *recipientId in contact.textSecureIdentifiers) { for (NSString *recipientId in contact.textSecureIdentifiers) {
if (avatarImage) { if (avatarImageData) {
break; break;
} }
avatarImage = [self.contactsManager profileImageForPhoneIdentifier:recipientId]; avatarImageData = [self.contactsManager profileImageDataForPhoneIdentifier:recipientId];
if (avatarImage) { if (avatarImageData) {
isProfileAvatar = YES; isProfileAvatar = YES;
} }
} }
contactShareRecord.isProfileAvatar = isProfileAvatar; contactShareRecord.isProfileAvatar = isProfileAvatar;
ContactShareViewModel *contactShare = ContactShareViewModel *contactShare =
[[ContactShareViewModel alloc] initWithContactShareRecord:contactShareRecord avatarImage:avatarImage]; [[ContactShareViewModel alloc] initWithContactShareRecord:contactShareRecord avatarImageData:avatarImageData];
// TODO: We should probably show this in the same navigation view controller. // TODO: We should probably show this in the same navigation view controller.
ApproveContactShareViewController *approveContactShare = ApproveContactShareViewController *approveContactShare =

@ -8,18 +8,26 @@ import Foundation
public class ContactShareViewModel: NSObject { public class ContactShareViewModel: NSObject {
public let dbRecord: OWSContact public let dbRecord: OWSContact
public let avatarImage: UIImage?
public required init(contactShareRecord: OWSContact, avatarImage: UIImage?) { public let avatarImageData: Data?
lazy var avatarImage: UIImage? = {
guard let avatarImageData = self.avatarImageData else {
return nil
}
return UIImage(data: avatarImageData)
}()
public required init(contactShareRecord: OWSContact, avatarImageData: Data?) {
self.dbRecord = contactShareRecord self.dbRecord = contactShareRecord
self.avatarImage = avatarImage self.avatarImageData = avatarImageData
} }
public convenience init(contactShareRecord: OWSContact, transaction: YapDatabaseReadTransaction) { public convenience init(contactShareRecord: OWSContact, transaction: YapDatabaseReadTransaction) {
if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction) as? TSAttachmentStream { if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction) as? TSAttachmentStream {
self.init(contactShareRecord: contactShareRecord, avatarImage: avatarAttachment.image()) self.init(contactShareRecord: contactShareRecord, avatarImageData: avatarAttachment.validStillImageData())
} else { } else {
self.init(contactShareRecord: contactShareRecord, avatarImage: nil) self.init(contactShareRecord: contactShareRecord, avatarImageData: nil)
} }
} }
@ -111,7 +119,7 @@ public class ContactShareViewModel: NSObject {
public func cnContact(mergedWithExistingContact existingContact: Contact) -> CNContact? { public func cnContact(mergedWithExistingContact existingContact: Contact) -> CNContact? {
guard let newCNContact = OWSContacts.systemContact(for: self.dbRecord) else { guard let newCNContact = OWSContacts.systemContact(for: self.dbRecord, imageData: self.avatarImageData) else {
owsFail("\(logTag) in \(#function) newCNContact was unexpectedly nil") owsFail("\(logTag) in \(#function) newCNContact was unexpectedly nil")
return nil return nil
} }
@ -128,7 +136,7 @@ public class ContactShareViewModel: NSObject {
// TODO move the `copy` logic into the view model? // TODO move the `copy` logic into the view model?
let newDbRecord = dbRecord.copy(withNamePrefix: namePrefix, givenName: givenName, middleName: middleName, familyName: familyName, nameSuffix: nameSuffix) let newDbRecord = dbRecord.copy(withNamePrefix: namePrefix, givenName: givenName, middleName: middleName, familyName: familyName, nameSuffix: nameSuffix)
return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImage: self.avatarImage) return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: self.avatarImageData)
} }
public func newContact(withNamePrefix namePrefix: String?, public func newContact(withNamePrefix namePrefix: String?,
@ -144,7 +152,7 @@ public class ContactShareViewModel: NSObject {
familyName: familyName, familyName: familyName,
nameSuffix: nameSuffix) nameSuffix: nameSuffix)
return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImage: self.avatarImage) return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: self.avatarImageData)
} }
} }

@ -159,11 +159,11 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
// TODO: Populate avatar image. // TODO: Populate avatar image.
BOOL isProfileAvatar = NO; BOOL isProfileAvatar = NO;
UIImage *_Nullable avatarImage = nil; NSData *_Nullable avatarImageData = nil;
contact.isProfileAvatar = isProfileAvatar; contact.isProfileAvatar = isProfileAvatar;
ContactShareViewModel *contactShare = ContactShareViewModel *contactShare =
[[ContactShareViewModel alloc] initWithContactShareRecord:contact avatarImage:avatarImage]; [[ContactShareViewModel alloc] initWithContactShareRecord:contact avatarImageData:avatarImageData];
ApproveContactShareViewController *approvalVC = ApproveContactShareViewController *approvalVC =
[[ApproveContactShareViewController alloc] initWithContactShare:contactShare [[ApproveContactShareViewController alloc] initWithContactShare:contactShare

@ -81,6 +81,7 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
- (nullable UIImage *)systemContactImageForPhoneIdentifier:(nullable NSString *)identifier; - (nullable UIImage *)systemContactImageForPhoneIdentifier:(nullable NSString *)identifier;
- (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier; - (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier;
- (nullable NSData *)profileImageDataForPhoneIdentifier:(nullable NSString *)identifier;
- (nullable UIImage *)imageForPhoneIdentifier:(nullable NSString *)identifier; - (nullable UIImage *)imageForPhoneIdentifier:(nullable NSString *)identifier;
- (NSAttributedString *)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *_Nonnull)font; - (NSAttributedString *)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *_Nonnull)font;

@ -739,6 +739,11 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
return [self.profileManager profileAvatarForRecipientId:identifier]; return [self.profileManager profileAvatarForRecipientId:identifier];
} }
- (nullable NSData *)profileImageDataForPhoneIdentifier:(nullable NSString *)identifier
{
return [self.profileManager profileAvatarDataForRecipientId:identifier];
}
- (UIImage *_Nullable)imageForPhoneIdentifier:(NSString *_Nullable)identifier - (UIImage *_Nullable)imageForPhoneIdentifier:(NSString *_Nullable)identifier
{ {
// Prefer the contact image from the local address book if available // Prefer the contact image from the local address book if available

@ -75,6 +75,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
- (nullable NSString *)profileNameForRecipientId:(NSString *)recipientId; - (nullable NSString *)profileNameForRecipientId:(NSString *)recipientId;
- (nullable UIImage *)profileAvatarForRecipientId:(NSString *)recipientId; - (nullable UIImage *)profileAvatarForRecipientId:(NSString *)recipientId;
- (nullable NSData *)profileAvatarDataForRecipientId:(NSString *)recipientId;
- (void)updateProfileForRecipientId:(NSString *)recipientId - (void)updateProfileForRecipientId:(NSString *)recipientId
profileNameEncrypted:(nullable NSData *)profileNameEncrypted profileNameEncrypted:(nullable NSData *)profileNameEncrypted

@ -783,6 +783,20 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
return nil; return nil;
} }
- (nullable NSData *)profileAvatarDataForRecipientId:(NSString *)recipientId
{
OWSAssert(recipientId.length > 0);
OWSUserProfile *userProfile =
[OWSUserProfile getOrBuildUserProfileForRecipientId:recipientId dbConnection:self.dbConnection];
if (userProfile.avatarFileName.length > 0) {
return [self loadProfileDataWithFilename:userProfile.avatarFileName];
}
return nil;
}
- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfile - (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfile
{ {
OWSAssert(userProfile); OWSAssert(userProfile);

@ -30,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) BOOL isSignalContact; @property (nonatomic, readonly) BOOL isSignalContact;
#if TARGET_OS_IOS #if TARGET_OS_IOS
@property (nullable, readonly, nonatomic) UIImage *image; @property (nullable, readonly, nonatomic) UIImage *image;
@property (nullable, readonly, nonatomic) NSData *imageData;
@property (nullable, nonatomic, readonly) CNContact *cnContact; @property (nullable, nonatomic, readonly) CNContact *cnContact;
#endif // TARGET_OS_IOS #endif // TARGET_OS_IOS

@ -17,7 +17,6 @@ NS_ASSUME_NONNULL_BEGIN
@interface Contact () @interface Contact ()
@property (readonly, nonatomic) NSMutableDictionary<NSString *, NSString *> *phoneNumberNameMap; @property (readonly, nonatomic) NSMutableDictionary<NSString *, NSString *> *phoneNumberNameMap;
@property (readonly, nonatomic) NSData *imageData;
@end @end
@ -336,14 +335,15 @@ NS_ASSUME_NONNULL_BEGIN
// Address // Address
// merged all or nothing - do not try to piece-meal merge. // merged all or nothing - do not try to piece-meal merge.
BOOL hasExistingAddress = NO; if (mergedCNContact.postalAddresses.count == 0) {
for (CNLabeledValue<CNPostalAddress *> *labeledPostalAddress in mergedCNContact.postalAddresses) {
hasExistingAddress = YES;
}
if (!hasExistingAddress) {
mergedCNContact.postalAddresses = newCNContact.postalAddresses; mergedCNContact.postalAddresses = newCNContact.postalAddresses;
} }
// Avatar
if (!mergedCNContact.imageData) {
mergedCNContact.imageData = newCNContact.imageData;
}
return [mergedCNContact copy]; return [mergedCNContact copy];
} }

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

@ -331,6 +331,30 @@ NS_ASSUME_NONNULL_BEGIN
} }
} }
- (nullable NSData *)validStillImageData
{
if ([self isVideo]) {
OWSFail(@"%@ in %s isVideo was unexpectedly true", self.logTag, __PRETTY_FUNCTION__);
return nil;
}
if ([self isAnimated]) {
OWSFail(@"%@ in %s isAnimated was unexpectedly true", self.logTag, __PRETTY_FUNCTION__);
return nil;
}
NSURL *_Nullable mediaUrl = [self mediaURL];
if (!mediaUrl) {
return nil;
}
NSData *data = [NSData dataWithContentsOfURL:mediaUrl];
if (![data ows_isValidImage]) {
return nil;
}
return data;
}
+ (BOOL)hasThumbnailForMimeType:(NSString *)contentType + (BOOL)hasThumbnailForMimeType:(NSString *)contentType
{ {
return ([MIMETypeUtil isVideo:contentType] || [MIMETypeUtil isImage:contentType] || return ([MIMETypeUtil isVideo:contentType] || [MIMETypeUtil isImage:contentType] ||

@ -166,7 +166,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value);
#pragma mark - System Contact Conversion #pragma mark - System Contact Conversion
+ (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact; + (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact;
+ (nullable CNContact *)systemContactForContact:(OWSContact *)contact; + (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData;
#pragma mark - #pragma mark -

@ -372,7 +372,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
- (void)ensureDisplayName - (void)ensureDisplayName
{ {
if (_displayName.length < 1) { if (_displayName.length < 1) {
CNContact *_Nullable cnContact = [OWSContacts systemContactForContact:self]; CNContact *_Nullable cnContact = [OWSContacts systemContactForContact:self imageData:nil];
_displayName = [Contact formattedFullNameWithCNContact:cnContact]; _displayName = [Contact formattedFullNameWithCNContact:cnContact];
} }
if (_displayName.length < 1) { if (_displayName.length < 1) {
@ -693,7 +693,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
return contact; return contact;
} }
+ (nullable CNContact *)systemContactForContact:(OWSContact *)contact + (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData
{ {
if (!contact) { if (!contact) {
OWSProdLogAndFail(@"%@ Missing contact.", self.logTag); OWSProdLogAndFail(@"%@ Missing contact.", self.logTag);
@ -790,11 +790,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
} }
} }
systemContact.postalAddresses = systemAddresses; systemContact.postalAddresses = systemAddresses;
systemContact.imageData = imageData;
// TODO: Avatar
// @property (readonly, copy, nullable, NS_NONATOMIC_IOSONLY) NSData *imageData;
// @property (readonly, copy, nullable, NS_NONATOMIC_IOSONLY) NSData *thumbnailImageData;
return systemContact; return systemContact;
} }
@ -816,7 +812,8 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
{ {
OWSAssert(contact); OWSAssert(contact);
CNContact *_Nullable systemContact = [self systemContactForContact:contact]; // TODO pass in image for vcard
CNContact *_Nullable systemContact = [self systemContactForContact:contact imageData:nil];
if (!systemContact) { if (!systemContact) {
return nil; return nil;
} }

Loading…
Cancel
Save