diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 1b4f31e50..45fd3174e 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -302,7 +302,7 @@ static NSTimeInterval launchStartedAt; error = [OWSPrimaryStorage migrateToSharedData]; } if (!error) { - error = [OWSProfileManager migrateToSharedData]; + error = [OWSUserProfile migrateToSharedData]; } if (!error) { error = [TSAttachmentStream migrateToSharedData]; diff --git a/Signal/src/environment/SignalApp.m b/Signal/src/environment/SignalApp.m index 4d95b7d8d..f33802f2b 100644 --- a/Signal/src/environment/SignalApp.m +++ b/Signal/src/environment/SignalApp.m @@ -234,7 +234,7 @@ NS_ASSUME_NONNULL_BEGIN [DDLog flushLog]; [OWSStorage resetAllStorage]; - [[OWSProfileManager sharedManager] resetProfileStorage]; + [OWSUserProfile resetProfileStorage]; [Environment.preferences clear]; [self clearAllNotifications]; diff --git a/SignalMessaging/profiles/OWSProfileManager.h b/SignalMessaging/profiles/OWSProfileManager.h index d1b228d98..18a23b8b5 100644 --- a/SignalMessaging/profiles/OWSProfileManager.h +++ b/SignalMessaging/profiles/OWSProfileManager.h @@ -22,10 +22,6 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; + (instancetype)sharedManager; -- (void)resetProfileStorage; - -+ (nullable NSError *)migrateToSharedData; - #pragma mark - Local Profile // These two methods should only be called from the main thread. diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 3f006061d..7d106790c 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -304,7 +304,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSAssert(data); if (data) { NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingPathExtension:@"jpg"]; - NSString *filePath = [self.profileAvatarsDirPath stringByAppendingPathComponent:fileName]; + NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:fileName]; BOOL success = [data writeToFile:filePath atomically:YES]; OWSAssert(success); if (success) { @@ -817,7 +817,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSAES256Key *profileKeyAtStart = userProfile.profileKey; NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingPathExtension:@"jpg"]; - NSString *filePath = [self.profileAvatarsDirPath stringByAppendingPathComponent:fileName]; + NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:fileName]; @synchronized(self.currentAvatarDownloads) { @@ -883,6 +883,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; if (localNumber && [localNumber isEqualToString:userProfile.recipientId]) { OWSUserProfile *localUserProfile = self.localUserProfile; OWSAssert(localUserProfile); + [localUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil]; [self updateProfileAvatarCache:image filename:fileName]; } @@ -1074,7 +1075,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; { OWSAssert(filename.length > 0); - NSString *filePath = [self.profileAvatarsDirPath stringByAppendingPathComponent:filename]; + NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:filename]; return [NSData dataWithContentsOfFile:filePath]; } @@ -1117,49 +1118,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; } } -+ (NSString *)legacyProfileAvatarsDirPath -{ - return [[OWSFileSystem appDocumentDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; -} - -+ (NSString *)sharedDataProfileAvatarsDirPath -{ - return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; -} - -+ (nullable NSError *)migrateToSharedData -{ - DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); - - return [OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath - sharedDataFilePath:self.sharedDataProfileAvatarsDirPath]; -} - -- (NSString *)profileAvatarsDirPath -{ - static NSString *profileAvatarsDirPath = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - profileAvatarsDirPath = OWSProfileManager.sharedDataProfileAvatarsDirPath; - - [OWSFileSystem ensureDirectoryExists:profileAvatarsDirPath]; - }); - return profileAvatarsDirPath; -} - -// TODO: We may want to clean up this directory in the "orphan cleanup" logic. - -- (void)resetProfileStorage -{ - OWSAssertIsOnMainThread(); - - NSError *error; - [[NSFileManager defaultManager] removeItemAtPath:[self profileAvatarsDirPath] error:&error]; - if (error) { - DDLogError(@"Failed to delete database: %@", error.description); - } -} - #pragma mark - User Interface - (void)presentAddThreadToProfileWhitelist:(TSThread *)thread diff --git a/SignalMessaging/profiles/OWSUserProfile.h b/SignalMessaging/profiles/OWSUserProfile.h index 35402fff1..1d68916aa 100644 --- a/SignalMessaging/profiles/OWSUserProfile.h +++ b/SignalMessaging/profiles/OWSUserProfile.h @@ -65,6 +65,13 @@ extern NSString *const kLocalProfileUniqueId; dbConnection:(YapDatabaseConnection *)dbConnection completion:(nullable OWSUserProfileCompletion)completion; +#pragma mark - Profile Avatars Directory + ++ (NSString *)profileAvatarFilepathWithFilename:(NSString *)filename; ++ (nullable NSError *)migrateToSharedData; ++ (NSString *)profileAvatarsDirPath; ++ (void)resetProfileStorage; + @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/profiles/OWSUserProfile.m b/SignalMessaging/profiles/OWSUserProfile.m index 760573c4b..180ab4925 100644 --- a/SignalMessaging/profiles/OWSUserProfile.m +++ b/SignalMessaging/profiles/OWSUserProfile.m @@ -8,6 +8,7 @@ #import #import #import +#import #import #import #import @@ -37,6 +38,7 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; @implementation OWSUserProfile @synthesize avatarUrlPath = _avatarUrlPath; +@synthesize avatarFileName = _avatarFileName; @synthesize profileName = _profileName; + (NSString *)collection @@ -113,11 +115,38 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; if (didChange) { // If the avatarURL changed, the avatarFileName can't be valid. // Clear it. + self.avatarFileName = nil; } } } +- (nullable NSString *)avatarFileName +{ + @synchronized(self) { + return _avatarFileName; + } +} + +- (void)setAvatarFileName:(nullable NSString *)avatarFileName +{ + @synchronized(self) { + BOOL didChange = ![NSObject isNullableObject:_avatarFileName equalTo:avatarFileName]; + if (!didChange) { + return; + } + + if (_avatarFileName) { + NSString *oldAvatarFilePath = [OWSUserProfile profileAvatarFilepathWithFilename:_avatarFileName]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; + }); + } + + _avatarFileName = avatarFileName; + } +} + #pragma mark - Update With... Methods // Similar in spirit to [TSYapDatabaseObject applyChangeToSelfAndLatestCopy], @@ -356,6 +385,58 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; } } +#pragma mark - Profile Avatars Directory + ++ (NSString *)profileAvatarFilepathWithFilename:(NSString *)filename +{ + OWSAssert(filename.length > 0); + + return [self.profileAvatarsDirPath stringByAppendingPathComponent:filename]; +} + ++ (NSString *)legacyProfileAvatarsDirPath +{ + return [[OWSFileSystem appDocumentDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; +} + ++ (NSString *)sharedDataProfileAvatarsDirPath +{ + return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; +} + ++ (nullable NSError *)migrateToSharedData +{ + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + return [OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath + sharedDataFilePath:self.sharedDataProfileAvatarsDirPath]; +} + ++ (NSString *)profileAvatarsDirPath +{ + static NSString *profileAvatarsDirPath = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + profileAvatarsDirPath = self.sharedDataProfileAvatarsDirPath; + + [OWSFileSystem ensureDirectoryExists:profileAvatarsDirPath]; + }); + return profileAvatarsDirPath; +} + +// TODO: We may want to clean up this directory in the "orphan cleanup" logic. + ++ (void)resetProfileStorage +{ + OWSAssertIsOnMainThread(); + + NSError *error; + [[NSFileManager defaultManager] removeItemAtPath:[self profileAvatarsDirPath] error:&error]; + if (error) { + DDLogError(@"Failed to delete database: %@", error.description); + } +} + @end NS_ASSUME_NONNULL_END