diff --git a/SignalMessaging/profiles/OWSProfileManager.h b/SignalMessaging/profiles/OWSProfileManager.h index 0f1122220..225db23f6 100644 --- a/SignalMessaging/profiles/OWSProfileManager.h +++ b/SignalMessaging/profiles/OWSProfileManager.h @@ -17,6 +17,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; @class OWSPrimaryStorage; @class TSNetworkManager; @class TSThread; +@class YapDatabaseReadWriteTransaction; // This class can be safely accessed and used from any thread. @interface OWSProfileManager : NSObject @@ -81,6 +82,8 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; profileNameEncrypted:(nullable NSData *)profileNameEncrypted avatarUrlPath:(nullable NSString *)avatarUrlPath; +- (void)setDisplayNameForContactWithID:(NSString *)contactID to:(NSString *)displayName with:(YapDatabaseReadWriteTransaction *)transaction; + #pragma mark - User Interface - (void)presentAddThreadToProfileWhitelist:(TSThread *)thread diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 408150212..8e344f414 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -1325,6 +1325,12 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); }); } +- (void)setDisplayNameForContactWithID:(NSString *)contactID to:(NSString *)displayName with:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSUserProfile *userProfile = [OWSUserProfile getOrBuildUserProfileForRecipientId:contactID transaction:transaction]; + [userProfile updateWithProfileName:displayName avatarUrlPath:@"" avatarFileName:@"" transaction:transaction completion:nil]; +} + - (BOOL)isNullableDataEqual:(NSData *_Nullable)left toData:(NSData *_Nullable)right { if (left == nil && right == nil) { diff --git a/SignalMessaging/profiles/OWSUserProfile.h b/SignalMessaging/profiles/OWSUserProfile.h index e0e298180..5061fb96a 100644 --- a/SignalMessaging/profiles/OWSUserProfile.h +++ b/SignalMessaging/profiles/OWSUserProfile.h @@ -37,10 +37,18 @@ extern NSString *const kLocalProfileUniqueId; + (OWSUserProfile *)getOrBuildUserProfileForRecipientId:(NSString *)recipientId dbConnection:(YapDatabaseConnection *)dbConnection; ++ (OWSUserProfile *)getOrBuildUserProfileForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; + + (BOOL)localUserProfileExists:(YapDatabaseConnection *)dbConnection; #pragma mark - Update With... Methods +- (void)updateWithProfileName:(nullable NSString *)profileName + avatarUrlPath:(nullable NSString *)avatarUrlPath + avatarFileName:(nullable NSString *)avatarFileName + transaction:(YapDatabaseReadWriteTransaction *)transaction + completion:(nullable OWSUserProfileCompletion)completion; + - (void)updateWithProfileName:(nullable NSString *)profileName avatarUrlPath:(nullable NSString *)avatarUrlPath avatarFileName:(nullable NSString *)avatarFileName diff --git a/SignalMessaging/profiles/OWSUserProfile.m b/SignalMessaging/profiles/OWSUserProfile.m index 484197e46..887fb9c3b 100644 --- a/SignalMessaging/profiles/OWSUserProfile.m +++ b/SignalMessaging/profiles/OWSUserProfile.m @@ -54,19 +54,25 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; + (OWSUserProfile *)getOrBuildUserProfileForRecipientId:(NSString *)recipientId dbConnection:(YapDatabaseConnection *)dbConnection { - OWSAssertDebug(recipientId.length > 0); - __block OWSUserProfile *userProfile; [dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - userProfile = [OWSUserProfile fetchObjectWithUniqueID:recipientId transaction:transaction]; + userProfile = [OWSUserProfile getOrBuildUserProfileForRecipientId:recipientId transaction:transaction]; }]; + return userProfile; +} + ++ (OWSUserProfile *)getOrBuildUserProfileForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction +{ + OWSAssertDebug(recipientId.length > 0); + + OWSUserProfile *userProfile = [OWSUserProfile fetchObjectWithUniqueID:recipientId transaction:transaction]; if (!userProfile) { userProfile = [[OWSUserProfile alloc] initWithRecipientId:recipientId]; if ([recipientId isEqualToString:kLocalProfileUniqueId]) { [userProfile updateWithProfileKey:[OWSAES256Key generateRandomKey] - dbConnection:dbConnection + dbConnection:transaction.connection completion:nil]; } } @@ -180,38 +186,46 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; functionName:(const char *)functionName dbConnection:(YapDatabaseConnection *)dbConnection completion:(nullable OWSUserProfileCompletion)completion -{ + { + [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [self applyChanges:changeBlock functionName:functionName transaction:transaction completion:completion]; + }]; +} + +- (void)applyChanges:(void (^)(id))changeBlock + functionName:(const char *)functionName + transaction:(YapDatabaseReadWriteTransaction *)transaction + completion:(nullable OWSUserProfileCompletion)completion + { // self might be the latest instance, so take a "before" snapshot // before any changes have been made. __block NSDictionary *beforeSnapshot = [self.dictionaryValue copy]; changeBlock(self); - __block BOOL didChange = YES; - [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - NSString *collection = [[self class] collection]; - OWSUserProfile *_Nullable latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection]; - if (latestInstance) { - // If self is NOT the latest instance, take a new "before" snapshot - // before updating. - if (self != latestInstance) { - beforeSnapshot = [latestInstance.dictionaryValue copy]; - } - - changeBlock(latestInstance); - - NSDictionary *afterSnapshot = [latestInstance.dictionaryValue copy]; - - if ([beforeSnapshot isEqual:afterSnapshot]) { - OWSLogVerbose(@"Ignoring redundant update in %s: %@", functionName, self.debugDescription); - didChange = NO; - } else { - [latestInstance saveWithTransaction:transaction]; - } - } else { - [self saveWithTransaction:transaction]; + BOOL didChange = YES; + NSString *collection = [[self class] collection]; + OWSUserProfile *_Nullable latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection]; + if (latestInstance) { + // If self is NOT the latest instance, take a new "before" snapshot + // before updating. + if (self != latestInstance) { + beforeSnapshot = [latestInstance.dictionaryValue copy]; } - }]; + + changeBlock(latestInstance); + + NSDictionary *afterSnapshot = [latestInstance.dictionaryValue copy]; + + if ([beforeSnapshot isEqual:afterSnapshot]) { + OWSLogVerbose(@"Ignoring redundant update in %s: %@", functionName, self.debugDescription); + didChange = NO; + } else { + [latestInstance saveWithTransaction:transaction]; + } + } else { + [self saveWithTransaction:transaction]; + } if (completion) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), completion); @@ -252,12 +266,30 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; }); } +- (void)updateWithProfileName:(nullable NSString *)profileName + avatarUrlPath:(nullable NSString *)avatarUrlPath + avatarFileName:(nullable NSString *)avatarFileName + transaction:(YapDatabaseReadWriteTransaction *)transaction + completion:(nullable OWSUserProfileCompletion)completion + { + [self applyChanges:^(OWSUserProfile *userProfile) { + [userProfile setProfileName:[profileName ows_stripped]]; + // Always setAvatarUrlPath: before you setAvatarFileName: since + // setAvatarUrlPath: may clear the avatar filename. + [userProfile setAvatarUrlPath:avatarUrlPath]; + [userProfile setAvatarFileName:avatarFileName]; + } + functionName:__PRETTY_FUNCTION__ + transaction:transaction + completion:completion]; +} + - (void)updateWithProfileName:(nullable NSString *)profileName avatarUrlPath:(nullable NSString *)avatarUrlPath avatarFileName:(nullable NSString *)avatarFileName dbConnection:(YapDatabaseConnection *)dbConnection completion:(nullable OWSUserProfileCompletion)completion -{ + { [self applyChanges:^(OWSUserProfile *userProfile) { [userProfile setProfileName:[profileName ows_stripped]]; // Always setAvatarUrlPath: before you setAvatarFileName: since diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 0b22edee9..ab4b9dbb2 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -8,6 +8,7 @@ #import "OWSMessageSender.h" #import "OWSOutgoingSyncMessage.h" #import "OWSPrimaryStorage.h" +#import "ProfileManagerProtocol.h" #import "ProtoUtils.h" #import "SSKEnvironment.h" #import "SignalRecipient.h" @@ -1102,13 +1103,17 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt [ProtoUtils addLocalProfileKeyIfNecessary:self.thread recipientId:recipientId dataMessageBuilder:builder]; - SSKProtoDataMessageContactBuilder *profileBuilder = [SSKProtoDataMessageContact builder]; - SSKProtoDataMessageContactNameBuilder *nameBuilder = [SSKProtoDataMessageContactName builder]; - [nameBuilder setDisplayName:@"Test"]; // TODO: Use actual name - SSKProtoDataMessageContactName *name = [nameBuilder buildIgnoringErrors]; - [profileBuilder setName:name]; - SSKProtoDataMessageContact *profile = [profileBuilder buildIgnoringErrors]; - [builder setProfile:profile]; + id profileManager = SSKEnvironment.shared.profileManager; + NSString *displayName = [profileManager localProfileName]; + if (displayName != nil) { + SSKProtoDataMessageContactBuilder *profileBuilder = [SSKProtoDataMessageContact builder]; + SSKProtoDataMessageContactNameBuilder *nameBuilder = [SSKProtoDataMessageContactName builder]; + [nameBuilder setDisplayName:displayName]; + SSKProtoDataMessageContactName *name = [nameBuilder buildIgnoringErrors]; + [profileBuilder setName:name]; + SSKProtoDataMessageContact *profile = [profileBuilder buildIgnoringErrors]; + [builder setProfile:profile]; + } NSError *error; SSKProtoDataMessage *_Nullable dataProto = [builder buildAndReturnError:&error]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 9ee23d67b..2e7f18d0c 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1445,6 +1445,9 @@ NS_ASSUME_NONNULL_BEGIN serverTimestamp:serverTimestamp wasReceivedByUD:wasReceivedByUD]; + NSString *displayName = dataMessage.profile.name.displayName; + [self.profileManager setDisplayNameForContactWithID:thread.contactIdentifier to:displayName with:transaction]; + if (envelope.isPtpMessage) { incomingMessage.isP2P = YES; } NSArray *attachmentPointers = @@ -1478,6 +1481,7 @@ NS_ASSUME_NONNULL_BEGIN thread:thread envelope:envelope transaction:transaction]; + return incomingMessage; } } diff --git a/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h b/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h index be08179ac..18946ce22 100644 --- a/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h +++ b/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h @@ -4,6 +4,7 @@ @class OWSAES256Key; @class TSThread; +@class YapDatabaseReadWriteTransaction; NS_ASSUME_NONNULL_BEGIN @@ -11,6 +12,8 @@ NS_ASSUME_NONNULL_BEGIN - (OWSAES256Key *)localProfileKey; +- (nullable NSString *)localProfileName; + - (nullable NSData *)profileKeyDataForRecipientId:(NSString *)recipientId; - (void)setProfileKeyData:(NSData *)profileKeyData forRecipientId:(NSString *)recipientId; @@ -25,6 +28,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)fetchProfileForRecipientId:(NSString *)recipientId; +- (void)setDisplayNameForContactWithID:(NSString *)contactID to:(NSString *)displayName with:(YapDatabaseReadWriteTransaction *)transaction; + @end NS_ASSUME_NONNULL_END