From aa7cc4633a2278744af22ac788822ce729ccc5c3 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 10 May 2018 11:09:35 -0400 Subject: [PATCH] Rework contact names. --- .../ViewControllers/DebugUI/DebugUIMessages.m | 89 +++--- .../translations/en.lproj/Localizable.strings | 3 + .../ViewModels/ContactShareViewModel.swift | 51 +--- .../ApproveContactShareViewController.swift | 19 +- .../EditContactShareNameViewController.swift | 52 ++-- .../contacts/SystemContactsFetcher.swift | 3 +- .../Interactions/OWSContact+Private.h | 8 - .../src/Messages/Interactions/OWSContact.h | 36 +-- .../src/Messages/Interactions/OWSContact.m | 272 +++++++++--------- .../src/Messages/Interactions/TSMessage.m | 4 +- 10 files changed, 277 insertions(+), 260 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index c36986438..2076f574a 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -13,7 +13,6 @@ #import #import #import -#import #import #import #import @@ -33,6 +32,8 @@ NS_ASSUME_NONNULL_BEGIN @end +#pragma mark - + @interface TSOutgoingMessage (PostDatingDebug) - (void)setReceivedAtTimestamp:(uint64_t)value; @@ -2953,9 +2954,11 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac [actions addObject:[self fakeContactShareMessageAction:thread label:@"Name & Number" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Alice"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Alice"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; phoneNumber.phoneType = OWSContactPhoneType_Home; phoneNumber.phoneNumber = @"+13213214321"; @@ -2966,9 +2969,11 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"Name & Email" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Bob"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Bob"; OWSContactEmail *email = [OWSContactEmail new]; email.emailType = OWSContactEmailType_Home; email.email = @"a@b.com"; @@ -2979,14 +2984,16 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"Complicated" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Alice"; - contact.familyName = @"Carol"; - contact.middleName = @"Bob"; - contact.namePrefix = @"Ms."; - contact.nameSuffix = @"Esq."; - contact.organizationName = @"Falafel Hut"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Alice"; + name.familyName = @"Carol"; + name.middleName = @"Bob"; + name.namePrefix = @"Ms."; + name.nameSuffix = @"Esq."; + name.organizationName = @"Falafel Hut"; OWSContactPhoneNumber *phoneNumber1 = [OWSContactPhoneNumber new]; phoneNumber1.phoneType = OWSContactPhoneType_Home; @@ -3039,10 +3046,12 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"Long values" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Bobasdjasdlkjasldkjas"; - contact.familyName = @"Bobasdjasdlkjasldkjas"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Bobasdjasdlkjasldkjas"; + name.familyName = @"Bobasdjasdlkjasldkjas"; OWSContactEmail *email = [OWSContactEmail new]; email.emailType = OWSContactEmailType_Mobile; email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; @@ -3053,9 +3062,11 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"System Contact w/o Signal" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Add Me To Your Contacts"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Add Me To Your Contacts"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; phoneNumber.phoneType = OWSContactPhoneType_Work; phoneNumber.phoneNumber = @"+324602053911"; @@ -3066,9 +3077,11 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac }]]; [actions addObject:[self fakeContactShareMessageAction:thread label:@"System Contact w. Signal" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Add Me To Your Contacts"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Add Me To Your Contacts"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; phoneNumber.phoneType = OWSContactPhoneType_Work; phoneNumber.phoneNumber = @"+32460205392"; @@ -3128,7 +3141,9 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac label:@"Name & Number" contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Alice"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Alice"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; phoneNumber.phoneType = OWSContactPhoneType_Home; phoneNumber.phoneNumber = @"+13213214321"; @@ -3141,7 +3156,9 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac label:@"Name & Email" contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Bob"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Bob"; OWSContactEmail *email = [OWSContactEmail new]; email.emailType = OWSContactEmailType_Home; email.email = @"a@b.com"; @@ -3152,14 +3169,16 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac }]]; [actions addObject:[self sendContactShareMessageAction:thread label:@"Complicated" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction){ + contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Alice"; - contact.familyName = @"Carol"; - contact.middleName = @"Bob"; - contact.namePrefix = @"Ms."; - contact.nameSuffix = @"Esq."; - contact.organizationName = @"Falafel Hut"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Alice"; + name.familyName = @"Carol"; + name.middleName = @"Bob"; + name.namePrefix = @"Ms."; + name.nameSuffix = @"Esq."; + name.organizationName = @"Falafel Hut"; OWSContactPhoneNumber *phoneNumber1 = [OWSContactPhoneNumber new]; phoneNumber1.phoneType = OWSContactPhoneType_Home; @@ -3214,8 +3233,10 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac label:@"Long values" contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Bobasdjasdlkjasldkjas"; - contact.familyName = @"Bobasdjasdlkjasldkjas"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Bobasdjasdlkjasldkjas"; + name.familyName = @"Bobasdjasdlkjasldkjas"; OWSContactEmail *email = [OWSContactEmail new]; email.emailType = OWSContactEmailType_Mobile; email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; @@ -3228,7 +3249,9 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac label:@"System Contact w/o Signal" contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Add Me To Your Contacts"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Add Me To Your Contacts"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; phoneNumber.phoneType = OWSContactPhoneType_Work; phoneNumber.phoneNumber = @"+324602053911"; @@ -3241,7 +3264,9 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac label:@"System Contact w. Signal" contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { OWSContact *contact = [OWSContact new]; - contact.givenName = @"Add Me To Your Contacts"; + OWSContactName *name = [OWSContactName new]; + contact.name = name; + name.givenName = @"Add Me To Your Contacts"; OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; phoneNumber.phoneType = OWSContactPhoneType_Work; phoneNumber.phoneNumber = @"+32460205392"; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 3a41f46ec..077d194b2 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -460,6 +460,9 @@ /* Label for the 'name suffix' field of a contact. */ "CONTACT_FIELD_NAME_SUFFIX" = "Suffix"; +/* Label for the 'organization' field of a contact. */ +"CONTACT_FIELD_ORGANIZATION" = "Organization"; + /* Label for a contact's phone number. */ "CONTACT_PHONE" = "Phone"; diff --git a/SignalMessaging/ViewModels/ContactShareViewModel.swift b/SignalMessaging/ViewModels/ContactShareViewModel.swift index be887edf9..bb80ceaae 100644 --- a/SignalMessaging/ViewModels/ContactShareViewModel.swift +++ b/SignalMessaging/ViewModels/ContactShareViewModel.swift @@ -46,6 +46,15 @@ public class ContactShareViewModel: NSObject { // MARK: Delegated -> dbRecord + public var name: OWSContactName { + get { + return dbRecord.name + } + set { + return dbRecord.name = newValue + } + } + public var addresses: [OWSContactAddress] { get { return dbRecord.addresses @@ -86,33 +95,13 @@ public class ContactShareViewModel: NSObject { } public var displayName: String { - return dbRecord.displayName + return dbRecord.name.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 } @@ -127,30 +116,18 @@ public class ContactShareViewModel: NSObject { return existingContact.buildCNContact(mergedWithNewContact: newCNContact) } - public func copy(withNamePrefix namePrefix: String?, - givenName: String?, - middleName: String?, - familyName: String?, - nameSuffix: String?) -> ContactShareViewModel { + public func copy(withName name: OWSContactName) -> ContactShareViewModel { // 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(with: name) return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: self.avatarImageData) } - public func newContact(withNamePrefix namePrefix: String?, - givenName: String?, - middleName: String?, - familyName: String?, - nameSuffix: String?) -> ContactShareViewModel { + public func newContact(withName name: OWSContactName) -> ContactShareViewModel { // TODO move the `newContact` logic into the view model? - let newDbRecord = dbRecord.newContact(withNamePrefix: namePrefix, - givenName: givenName, - middleName: middleName, - familyName: familyName, - nameSuffix: nameSuffix) + let newDbRecord = dbRecord.newContact(with: name) return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: self.avatarImageData) } diff --git a/SignalMessaging/attachments/ApproveContactShareViewController.swift b/SignalMessaging/attachments/ApproveContactShareViewController.swift index c3ef9d746..f992d3fd8 100644 --- a/SignalMessaging/attachments/ApproveContactShareViewController.swift +++ b/SignalMessaging/attachments/ApproveContactShareViewController.swift @@ -7,8 +7,10 @@ import SignalServiceKit @objc public protocol ApproveContactShareViewControllerDelegate: class { - func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didApproveContactShare contactShare: ContactShareViewModel) - func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didCancelContactShare contactShare: ContactShareViewModel) + func approveContactShare(_ approveContactShare: ApproveContactShareViewController, + didApproveContactShare contactShare: ContactShareViewModel) + func approveContactShare(_ approveContactShare: ApproveContactShareViewController, + didCancelContactShare contactShare: ContactShareViewModel) } protocol ContactShareField: class { @@ -361,7 +363,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh let nameLabel = UILabel() self.nameLabel = nameLabel - nameLabel.text = contactShare.displayName + nameLabel.text = contactShare.name.displayName nameLabel.font = UIFont.ows_dynamicTypeBody.ows_mediumWeight() nameLabel.textColor = UIColor.black nameLabel.lineBreakMode = .byTruncatingTail @@ -381,11 +383,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh // MARK: - func filteredContactShare() -> ContactShareViewModel { - let result = self.contactShare.newContact(withNamePrefix: self.contactShare.namePrefix, - givenName: self.contactShare.givenName, - middleName: self.contactShare.middleName, - familyName: self.contactShare.familyName, - nameSuffix: self.contactShare.nameSuffix) + let result = self.contactShare.newContact(withName: self.contactShare.name) for fieldView in fieldViews { if fieldView.field.isIncluded() { @@ -445,10 +443,11 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh // MARK: - EditContactShareNameViewControllerDelegate - public func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: ContactShareViewModel) { + public func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, + didEditContactShare contactShare: ContactShareViewModel) { self.contactShare = contactShare - nameLabel.text = contactShare.displayName + nameLabel.text = contactShare.name.displayName self.updateNavigationBar() } diff --git a/SignalMessaging/attachments/EditContactShareNameViewController.swift b/SignalMessaging/attachments/EditContactShareNameViewController.swift index 732ca6068..7c43ca22e 100644 --- a/SignalMessaging/attachments/EditContactShareNameViewController.swift +++ b/SignalMessaging/attachments/EditContactShareNameViewController.swift @@ -111,7 +111,8 @@ class ContactNameFieldView: UIView { @objc public protocol EditContactShareNameViewControllerDelegate: class { - func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: ContactShareViewModel) + func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, + didEditContactShare contactShare: ContactShareViewModel) } // MARK: - @@ -127,6 +128,7 @@ public class EditContactShareNameViewController: OWSViewController, ContactNameF var middleNameView: ContactNameFieldView! var familyNameView: ContactNameFieldView! var nameSuffixView: ContactNameFieldView! + var organizationNameView: ContactNameFieldView! var fieldViews = [ContactNameFieldView]() @@ -148,22 +150,31 @@ public class EditContactShareNameViewController: OWSViewController, ContactNameF } func buildFields() { - namePrefixView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_NAME_PREFIX", comment: "Label for the 'name prefix' field of a contact."), - value: contactShare.namePrefix, delegate: self) - givenNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_GIVEN_NAME", comment: "Label for the 'given name' field of a contact."), - value: contactShare.givenName, delegate: self) - middleNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_MIDDLE_NAME", comment: "Label for the 'middle name' field of a contact."), - value: contactShare.middleName, delegate: self) - familyNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_FAMILY_NAME", comment: "Label for the 'family name' field of a contact."), - value: contactShare.familyName, delegate: self) - nameSuffixView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_NAME_SUFFIX", comment: "Label for the 'name suffix' field of a contact."), - value: contactShare.nameSuffix, delegate: self) + namePrefixView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_NAME_PREFIX", + comment: "Label for the 'name prefix' field of a contact."), + value: contactShare.name.namePrefix, delegate: self) + givenNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_GIVEN_NAME", + comment: "Label for the 'given name' field of a contact."), + value: contactShare.name.givenName, delegate: self) + middleNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_MIDDLE_NAME", + comment: "Label for the 'middle name' field of a contact."), + value: contactShare.name.middleName, delegate: self) + familyNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_FAMILY_NAME", + comment: "Label for the 'family name' field of a contact."), + value: contactShare.name.familyName, delegate: self) + nameSuffixView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_NAME_SUFFIX", + comment: "Label for the 'name suffix' field of a contact."), + value: contactShare.name.nameSuffix, delegate: self) + organizationNameView = ContactNameFieldView(name: NSLocalizedString("CONTACT_FIELD_ORGANIZATION", + comment: "Label for the 'organization' field of a contact."), + value: contactShare.name.organizationName, delegate: self) fieldViews = [ namePrefixView , givenNameView , middleNameView , familyNameView , - nameSuffixView + nameSuffixView, + organizationNameView ] } @@ -277,11 +288,18 @@ public class EditContactShareNameViewController: OWSViewController, ContactNameF func didPressSave() { Logger.info("\(logTag) \(#function)") - let modifiedContactShare = contactShare.copy(withNamePrefix: namePrefixView.value(), - givenName: givenNameView.value(), - middleName: middleNameView.value(), - familyName: familyNameView.value(), - nameSuffix: nameSuffixView.value()) + guard let newName = OWSContactName() else { + owsFail("\(logTag) could not create a new name.") + return + } + newName.namePrefix = namePrefixView.value().ows_stripped() + newName.givenName = givenNameView.value().ows_stripped() + newName.middleName = middleNameView.value().ows_stripped() + newName.familyName = familyNameView.value().ows_stripped() + newName.nameSuffix = nameSuffixView.value().ows_stripped() + newName.organizationName = organizationNameView.value().ows_stripped() + + let modifiedContactShare = contactShare.copy(withName: newName) guard let delegate = self.delegate else { owsFail("\(logTag) missing delegate.") diff --git a/SignalMessaging/contacts/SystemContactsFetcher.swift b/SignalMessaging/contacts/SystemContactsFetcher.swift index 33a3900f6..1e82fe352 100644 --- a/SignalMessaging/contacts/SystemContactsFetcher.swift +++ b/SignalMessaging/contacts/SystemContactsFetcher.swift @@ -36,7 +36,8 @@ class ContactsFrameworkContactStoreAdaptee: ContactStoreAdaptee { CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactEmailAddressesKey as CNKeyDescriptor, CNContactPostalAddressesKey as CNKeyDescriptor, - CNContactViewController.descriptorForRequiredKeys() + CNContactViewController.descriptorForRequiredKeys(), + CNContactVCardSerialization.descriptorForRequiredKeys() ] var authorizationStatus: ContactStoreAuthorizationStatus { diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h b/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h index 913100f2f..8ccdbdd8b 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact+Private.h @@ -49,14 +49,6 @@ NS_ASSUME_NONNULL_BEGIN @interface OWSContact (Private) -@property (nonatomic, nullable) NSString *givenName; -@property (nonatomic, nullable) NSString *familyName; -@property (nonatomic, nullable) NSString *nameSuffix; -@property (nonatomic, nullable) NSString *namePrefix; -@property (nonatomic, nullable) NSString *middleName; -@property (nonatomic, nullable) NSString *organizationName; -@property (nonatomic) NSString *displayName; - @property (nonatomic) NSArray *phoneNumbers; @property (nonatomic) NSArray *emails; @property (nonatomic) NSArray *addresses; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.h b/SignalServiceKit/src/Messages/Interactions/OWSContact.h index eeb4d3304..98621b341 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.h @@ -101,15 +101,23 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value); #pragma mark - +@interface OWSContactName : MTLModel + +@property (nonatomic, nullable) NSString *givenName; +@property (nonatomic, nullable) NSString *familyName; +@property (nonatomic, nullable) NSString *nameSuffix; +@property (nonatomic, nullable) NSString *namePrefix; +@property (nonatomic, nullable) NSString *middleName; +@property (nonatomic, nullable) NSString *organizationName; +@property (nonatomic) NSString *displayName; + +@end + +#pragma mark - + @interface OWSContact : MTLModel -@property (nonatomic, readonly, nullable) NSString *givenName; -@property (nonatomic, readonly, nullable) NSString *familyName; -@property (nonatomic, readonly, nullable) NSString *nameSuffix; -@property (nonatomic, readonly, nullable) NSString *namePrefix; -@property (nonatomic, readonly, nullable) NSString *middleName; -@property (nonatomic, readonly, nullable) NSString *organizationName; -@property (nonatomic, readonly) NSString *displayName; +@property (nonatomic) OWSContactName *name; @property (nonatomic, readonly) NSArray *phoneNumbers; @property (nonatomic, readonly) NSArray *emails; @@ -133,17 +141,9 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value); #pragma mark - Creation and Derivation -- (OWSContact *)newContactWithNamePrefix:(nullable NSString *)namePrefix - givenName:(nullable NSString *)givenName - middleName:(nullable NSString *)middleName - familyName:(nullable NSString *)familyName - nameSuffix:(nullable NSString *)nameSuffix; - -- (OWSContact *)copyContactWithNamePrefix:(nullable NSString *)namePrefix - givenName:(nullable NSString *)givenName - middleName:(nullable NSString *)middleName - familyName:(nullable NSString *)familyName - nameSuffix:(nullable NSString *)nameSuffix; +- (OWSContact *)newContactWithName:(OWSContactName *)name; + +- (OWSContact *)copyContactWithName:(OWSContactName *)name; #pragma mark - Phone Numbers and Recipient IDs diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index 6828f640a..874b0cf7f 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -276,15 +276,84 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) #pragma mark - -@interface OWSContact () +@implementation OWSContactName + +- (NSString *)logDescription +{ + NSMutableString *result = [NSMutableString new]; + [result appendString:@"["]; + + if (self.givenName.length > 0) { + [result appendFormat:@"givenName: %@, ", self.givenName]; + } + if (self.familyName.length > 0) { + [result appendFormat:@"familyName: %@, ", self.familyName]; + } + if (self.middleName.length > 0) { + [result appendFormat:@"middleName: %@, ", self.middleName]; + } + if (self.namePrefix.length > 0) { + [result appendFormat:@"namePrefix: %@, ", self.namePrefix]; + } + if (self.nameSuffix.length > 0) { + [result appendFormat:@"nameSuffix: %@, ", self.nameSuffix]; + } + if (self.displayName.length > 0) { + [result appendFormat:@"displayName: %@, ", self.displayName]; + } -@property (nonatomic, nullable) NSString *givenName; -@property (nonatomic, nullable) NSString *familyName; -@property (nonatomic, nullable) NSString *nameSuffix; -@property (nonatomic, nullable) NSString *namePrefix; -@property (nonatomic, nullable) NSString *middleName; -@property (nonatomic, nullable) NSString *organizationName; -@property (nonatomic) NSString *displayName; + [result appendString:@"]"]; + return result; +} + +- (NSString *)displayName +{ + [self ensureDisplayName]; + + if (_displayName.length < 1) { + OWSProdLogAndFail(@"%@ could not derive a valid display name.", self.logTag); + return NSLocalizedString(@"CONTACT_WITHOUT_NAME", @"Indicates that a contact has no name."); + } + return _displayName; +} + +- (void)ensureDisplayName +{ + if (_displayName.length < 1) { + CNContact *_Nullable cnContact = [self systemContactForName]; + _displayName = [CNContactFormatter stringFromContact:cnContact style:CNContactFormatterStyleFullName]; + } + if (_displayName.length < 1) { + // Fall back to using the organization name. + _displayName = self.organizationName; + } +} + +- (void)updateDisplayName +{ + _displayName = nil; + + [self ensureDisplayName]; +} + +- (nullable CNContact *)systemContactForName +{ + CNMutableContact *systemContact = [CNMutableContact new]; + systemContact.givenName = self.givenName; + systemContact.middleName = self.middleName; + systemContact.familyName = self.familyName; + systemContact.namePrefix = self.namePrefix; + systemContact.nameSuffix = self.nameSuffix; + // We don't need to set display name, it's implicit for system contacts. + systemContact.organizationName = self.organizationName; + return systemContact; +} + +@end + +#pragma mark - + +@interface OWSContact () @property (nonatomic) NSArray *phoneNumbers; @property (nonatomic) NSArray *emails; @@ -304,6 +373,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) - (instancetype)init { if (self = [super init]) { + _name = [OWSContactName new]; _phoneNumbers = @[]; _emails = @[]; _addresses = @[]; @@ -332,7 +402,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) - (BOOL)ows_isValid { - if (self.displayName.ows_stripped.length < 1) { + if (self.name.displayName.ows_stripped.length < 1) { DDLogWarn(@"%@ invalid contact; no display name.", self.logTag); return NO; } @@ -358,59 +428,12 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) return hasValue; } -- (NSString *)displayName -{ - [self ensureDisplayName]; - - if (_displayName.length < 1) { - OWSProdLogAndFail(@"%@ could not derive a valid display name.", self.logTag); - return NSLocalizedString(@"CONTACT_WITHOUT_NAME", @"Indicates that a contact has no name."); - } - return _displayName; -} - -- (void)ensureDisplayName -{ - if (_displayName.length < 1) { - CNContact *_Nullable cnContact = [OWSContacts systemContactForContact:self imageData:nil]; - _displayName = [Contact formattedFullNameWithCNContact:cnContact]; - } - if (_displayName.length < 1) { - // Fall back to using the organization name. - _displayName = self.organizationName; - } -} - -- (void)updateDisplayName -{ - _displayName = nil; - - [self ensureDisplayName]; -} - - (NSString *)debugDescription { NSMutableString *result = [NSMutableString new]; [result appendString:@"["]; - if (self.givenName.length > 0) { - [result appendFormat:@"givenName: %@, ", self.givenName]; - } - if (self.familyName.length > 0) { - [result appendFormat:@"familyName: %@, ", self.familyName]; - } - if (self.middleName.length > 0) { - [result appendFormat:@"middleName: %@, ", self.middleName]; - } - if (self.namePrefix.length > 0) { - [result appendFormat:@"namePrefix: %@, ", self.namePrefix]; - } - if (self.nameSuffix.length > 0) { - [result appendFormat:@"nameSuffix: %@, ", self.nameSuffix]; - } - if (self.displayName.length > 0) { - [result appendFormat:@"displayName: %@, ", self.displayName]; - } + [result appendFormat:@"%@, ", self.name.logDescription]; for (OWSContactPhoneNumber *phoneNumber in self.phoneNumbers) { [result appendFormat:@"%@, ", phoneNumber.debugDescription]; @@ -426,53 +449,30 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) return result; } -- (OWSContact *)newContactWithNamePrefix:(nullable NSString *)namePrefix - givenName:(nullable NSString *)givenName - middleName:(nullable NSString *)middleName - familyName:(nullable NSString *)familyName - nameSuffix:(nullable NSString *)nameSuffix +- (OWSContact *)newContactWithName:(OWSContactName *)name { + OWSAssert(name); + OWSContact *newContact = [OWSContact new]; - [newContact setNamePrefix:namePrefix - givenName:givenName - middleName:middleName - familyName:familyName - nameSuffix:nameSuffix]; + newContact.name = name; + + [name updateDisplayName]; return newContact; } -- (OWSContact *)copyContactWithNamePrefix:(nullable NSString *)namePrefix - givenName:(nullable NSString *)givenName - middleName:(nullable NSString *)middleName - familyName:(nullable NSString *)familyName - nameSuffix:(nullable NSString *)nameSuffix +- (OWSContact *)copyContactWithName:(OWSContactName *)name { + OWSAssert(name); + OWSContact *contactCopy = [self copy]; - [contactCopy setNamePrefix:namePrefix - givenName:givenName - middleName:middleName - familyName:familyName - nameSuffix:nameSuffix]; + contactCopy.name = name; - return contactCopy; -} + [name updateDisplayName]; -- (void)setNamePrefix:(nullable NSString *)namePrefix - givenName:(nullable NSString *)givenName - middleName:(nullable NSString *)middleName - familyName:(nullable NSString *)familyName - nameSuffix:(nullable NSString *)nameSuffix -{ - self.namePrefix = namePrefix.ows_stripped; - self.givenName = givenName.ows_stripped; - self.middleName = middleName.ows_stripped; - self.familyName = familyName.ows_stripped; - self.nameSuffix = nameSuffix.ows_stripped; - - [self updateDisplayName]; + return contactCopy; } #pragma mark - Avatar @@ -567,14 +567,16 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) } OWSContact *contact = [OWSContact new]; - contact.givenName = systemContact.givenName.ows_stripped; - contact.middleName = systemContact.middleName.ows_stripped; - contact.familyName = systemContact.familyName.ows_stripped; - contact.namePrefix = systemContact.namePrefix.ows_stripped; - contact.nameSuffix = systemContact.nameSuffix.ows_stripped; - // TODO: Verify. - contact.displayName = [CNContactFormatter stringFromContact:systemContact style:CNContactFormatterStyleFullName]; - contact.organizationName = systemContact.organizationName.ows_stripped; + + OWSContactName *contactName = [OWSContactName new]; + contactName.givenName = systemContact.givenName.ows_stripped; + contactName.middleName = systemContact.middleName.ows_stripped; + contactName.familyName = systemContact.familyName.ows_stripped; + contactName.namePrefix = systemContact.namePrefix.ows_stripped; + contactName.nameSuffix = systemContact.nameSuffix.ows_stripped; + contactName.organizationName = systemContact.organizationName.ows_stripped; + [contactName ensureDisplayName]; + contact.name = contactName; NSMutableArray *phoneNumbers = [NSMutableArray new]; for (CNLabeledValue *phoneNumberField in systemContact.phoneNumbers) { @@ -649,8 +651,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) } contact.addresses = addresses; - [contact ensureDisplayName]; - return contact; } @@ -662,13 +662,14 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) } CNMutableContact *systemContact = [CNMutableContact new]; - systemContact.givenName = contact.givenName; - systemContact.middleName = contact.middleName; - systemContact.familyName = contact.familyName; - systemContact.namePrefix = contact.namePrefix; - systemContact.nameSuffix = contact.nameSuffix; + + systemContact.givenName = contact.name.givenName; + systemContact.middleName = contact.name.middleName; + systemContact.familyName = contact.name.familyName; + systemContact.namePrefix = contact.name.namePrefix; + systemContact.nameSuffix = contact.name.nameSuffix; // We don't need to set display name, it's implicit for system contacts. - systemContact.organizationName = contact.organizationName; + systemContact.organizationName = contact.name.organizationName; NSMutableArray *> *systemPhoneNumbers = [NSMutableArray new]; for (OWSContactPhoneNumber *phoneNumber in contact.phoneNumbers) { @@ -767,27 +768,28 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) OWSSignalServiceProtosDataMessageContactNameBuilder *nameBuilder = [OWSSignalServiceProtosDataMessageContactNameBuilder new]; - if (contact.givenName.ows_stripped.length > 0) { - nameBuilder.givenName = contact.givenName.ows_stripped; + + OWSContactName *contactName = contact.name; + if (contactName.givenName.ows_stripped.length > 0) { + nameBuilder.givenName = contactName.givenName.ows_stripped; } - if (contact.familyName.ows_stripped.length > 0) { - nameBuilder.familyName = contact.familyName.ows_stripped; + if (contactName.familyName.ows_stripped.length > 0) { + nameBuilder.familyName = contactName.familyName.ows_stripped; } - if (contact.middleName.ows_stripped.length > 0) { - nameBuilder.middleName = contact.middleName.ows_stripped; + if (contactName.middleName.ows_stripped.length > 0) { + nameBuilder.middleName = contactName.middleName.ows_stripped; } - if (contact.namePrefix.ows_stripped.length > 0) { - nameBuilder.prefix = contact.namePrefix.ows_stripped; + if (contactName.namePrefix.ows_stripped.length > 0) { + nameBuilder.prefix = contactName.namePrefix.ows_stripped; } - if (contact.nameSuffix.ows_stripped.length > 0) { - nameBuilder.suffix = contact.nameSuffix.ows_stripped; + if (contactName.nameSuffix.ows_stripped.length > 0) { + nameBuilder.suffix = contactName.nameSuffix.ows_stripped; } - nameBuilder.displayName = contact.displayName; - [contactBuilder setNameBuilder:nameBuilder]; - - if (contact.organizationName.ows_stripped.length > 0) { - contactBuilder.organization = contact.organizationName.ows_stripped; + if (contactName.organizationName.ows_stripped.length > 0) { + contactBuilder.organization = contactName.organizationName.ows_stripped; } + nameBuilder.displayName = contactName.displayName; + [contactBuilder setNameBuilder:nameBuilder]; for (OWSContactPhoneNumber *phoneNumber in contact.phoneNumbers) { OWSSignalServiceProtosDataMessageContactPhoneBuilder *phoneBuilder = @@ -897,32 +899,34 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) OWSContact *contact = [OWSContact new]; - if (contactProto.hasOrganization) { - contact.organizationName = contactProto.organization.ows_stripped; - } - + OWSContactName *contactName = [OWSContactName new]; if (contactProto.hasName) { OWSSignalServiceProtosDataMessageContactName *nameProto = contactProto.name; if (nameProto.hasGivenName) { - contact.givenName = nameProto.givenName.ows_stripped; + contactName.givenName = nameProto.givenName.ows_stripped; } if (nameProto.hasFamilyName) { - contact.familyName = nameProto.familyName.ows_stripped; + contactName.familyName = nameProto.familyName.ows_stripped; } if (nameProto.hasPrefix) { - contact.namePrefix = nameProto.prefix.ows_stripped; + contactName.namePrefix = nameProto.prefix.ows_stripped; } if (nameProto.hasSuffix) { - contact.nameSuffix = nameProto.suffix.ows_stripped; + contactName.nameSuffix = nameProto.suffix.ows_stripped; } if (nameProto.hasMiddleName) { - contact.middleName = nameProto.middleName.ows_stripped; + contactName.middleName = nameProto.middleName.ows_stripped; } if (nameProto.hasDisplayName) { - contact.displayName = nameProto.displayName.ows_stripped; + contactName.displayName = nameProto.displayName.ows_stripped; } } + if (contactProto.hasOrganization) { + contactName.organizationName = contactProto.organization.ows_stripped; + } + [contactName ensureDisplayName]; + contact.name = contactName; NSMutableArray *phoneNumbers = [NSMutableArray new]; for (OWSSignalServiceProtosDataMessageContactPhone *phoneNumberProto in contactProto.number) { @@ -951,8 +955,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) } contact.addresses = [addresses copy]; - [contact ensureDisplayName]; - if (contactProto.hasAvatar) { OWSSignalServiceProtosDataMessageContactAvatar *avatarInfo = contactProto.avatar; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index 4368822fc..94a774e86 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -263,9 +263,9 @@ static const NSUInteger OWSMessageSchemaVersion = 4; return attachmentDescription; } else if (self.contactShare) { if (CurrentAppContext().isRTL) { - return [self.contactShare.displayName stringByAppendingString:@" 👤"]; + return [self.contactShare.name.displayName stringByAppendingString:@" 👤"]; } else { - return [@"👤 " stringByAppendingString:self.contactShare.displayName]; + return [@"👤 " stringByAppendingString:self.contactShare.name.displayName]; } } else { OWSFail(@"%@ message has neither body nor attachment.", self.logTag);