Fix profile avatar flicker
- We were clobbering our saved avatar filepath. - Our "should notify" check was too aggressive. - Only fetch profiles when entering a conversation. - Only fetch profiles in main app Also added (a little) debounce time to debug profile fetching. // FREEBIE
This commit is contained in:
parent
34d2df8d67
commit
14723f3e7f
|
@ -76,8 +76,6 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
|
|||
|
||||
- (nullable UIImage *)profileAvatarForRecipientId:(NSString *)recipientId;
|
||||
|
||||
- (void)refreshProfileForRecipientId:(NSString *)recipientId;
|
||||
|
||||
- (void)updateProfileForRecipientId:(NSString *)recipientId
|
||||
profileNameEncrypted:(nullable NSData *)profileNameEncrypted
|
||||
avatarUrlPath:(nullable NSString *)avatarUrlPath;
|
||||
|
|
|
@ -722,6 +722,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
|
||||
OWSUserProfile *userProfile =
|
||||
[OWSUserProfile getOrBuildUserProfileForRecipientId:recipientId dbConnection:self.dbConnection];
|
||||
|
||||
OWSAssert(userProfile);
|
||||
if (userProfile.profileKey && [userProfile.profileKey.keyData isEqual:profileKey.keyData]) {
|
||||
// Ignore redundant update.
|
||||
|
@ -734,7 +735,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
avatarFileName:nil
|
||||
dbConnection:self.dbConnection
|
||||
completion:^{
|
||||
[self refreshProfileForRecipientId:recipientId ignoreThrottling:YES];
|
||||
[ProfileFetcherJob runWithRecipientId:recipientId
|
||||
networkManager:self.networkManager
|
||||
ignoreThrottling:YES];
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
@ -751,6 +754,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
OWSUserProfile *userProfile =
|
||||
[OWSUserProfile getOrBuildUserProfileForRecipientId:recipientId dbConnection:self.dbConnection];
|
||||
OWSAssert(userProfile);
|
||||
|
||||
return userProfile.profileKey;
|
||||
}
|
||||
|
||||
|
@ -758,25 +762,24 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
[self refreshProfileForRecipientId:recipientId];
|
||||
|
||||
OWSUserProfile *userProfile =
|
||||
[OWSUserProfile getOrBuildUserProfileForRecipientId:recipientId dbConnection:self.dbConnection];
|
||||
|
||||
return userProfile.profileName;
|
||||
return self.localUserProfile.profileName;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)profileAvatarForRecipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
[self refreshProfileForRecipientId:recipientId];
|
||||
|
||||
OWSUserProfile *userProfile =
|
||||
[OWSUserProfile getOrBuildUserProfileForRecipientId:recipientId dbConnection:self.dbConnection];
|
||||
|
||||
if (userProfile.avatarFileName.length > 0) {
|
||||
return [self loadProfileAvatarWithFilename:userProfile.avatarFileName];
|
||||
} else if (userProfile.avatarUrlPath.length > 0) {
|
||||
}
|
||||
|
||||
if (userProfile.avatarUrlPath.length > 0) {
|
||||
[self downloadAvatarForUserProfile:userProfile];
|
||||
}
|
||||
|
||||
|
@ -892,46 +895,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
});
|
||||
}
|
||||
|
||||
- (void)refreshProfileForRecipientId:(NSString *)recipientId
|
||||
{
|
||||
[self refreshProfileForRecipientId:recipientId ignoreThrottling:NO];
|
||||
}
|
||||
|
||||
- (void)refreshProfileForRecipientId:(NSString *)recipientId ignoreThrottling:(BOOL)ignoreThrottling
|
||||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
OWSUserProfile *userProfile =
|
||||
[OWSUserProfile getOrBuildUserProfileForRecipientId:recipientId dbConnection:self.dbConnection];
|
||||
|
||||
if (!userProfile.profileKey) {
|
||||
// There's no point in fetching the profile for a user
|
||||
// if we don't have their profile key; we won't be able
|
||||
// to decrypt it.
|
||||
return;
|
||||
}
|
||||
|
||||
// Throttle and debounce the updates.
|
||||
const NSTimeInterval kMaxRefreshFrequency = 5 * kMinuteInterval;
|
||||
if (userProfile.lastUpdateDate
|
||||
&& fabs([userProfile.lastUpdateDate timeIntervalSinceNow]) < kMaxRefreshFrequency) {
|
||||
// This profile was updated recently or already has an update in flight.
|
||||
return;
|
||||
}
|
||||
|
||||
[userProfile updateWithLastUpdateDate:[NSDate new]
|
||||
dbConnection:self.dbConnection
|
||||
completion:^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[ProfileFetcherJob runWithRecipientId:recipientId
|
||||
networkManager:self.networkManager
|
||||
ignoreThrottling:ignoreThrottling];
|
||||
});
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)updateProfileForRecipientId:(NSString *)recipientId
|
||||
profileNameEncrypted:(nullable NSData *)profileNameEncrypted
|
||||
avatarUrlPath:(nullable NSString *)avatarUrlPath;
|
||||
|
@ -959,8 +922,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
|
||||
[userProfile updateWithProfileName:profileName
|
||||
avatarUrlPath:avatarUrlPath
|
||||
avatarFileName:nil
|
||||
lastUpdateDate:[NSDate new]
|
||||
avatarFileName:userProfile.avatarFileName // use existing file name if already downloaded
|
||||
dbConnection:self.dbConnection
|
||||
completion:nil];
|
||||
|
||||
|
@ -978,7 +940,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
// downloaded the latest avatar by downloadAvatarForUserProfile.
|
||||
[localUserProfile updateWithProfileName:profileName
|
||||
avatarUrlPath:avatarUrlPath
|
||||
lastUpdateDate:[NSDate new]
|
||||
dbConnection:self.dbConnection
|
||||
completion:nil];
|
||||
}
|
||||
|
|
|
@ -32,12 +32,6 @@ extern NSString *const kLocalProfileUniqueId;
|
|||
// This filename is relative to OWSProfileManager.profileAvatarsDirPath.
|
||||
@property (atomic, readonly, nullable) NSString *avatarFileName;
|
||||
|
||||
// This should reflect when either:
|
||||
//
|
||||
// * The last successful update finished.
|
||||
// * The current in-flight update began.
|
||||
@property (atomic, readonly, nullable) NSDate *lastUpdateDate;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (OWSUserProfile *)getOrBuildUserProfileForRecipientId:(NSString *)recipientId
|
||||
|
@ -62,14 +56,6 @@ extern NSString *const kLocalProfileUniqueId;
|
|||
|
||||
- (void)updateWithProfileName:(nullable NSString *)profileName
|
||||
avatarUrlPath:(nullable NSString *)avatarUrlPath
|
||||
avatarFileName:(nullable NSString *)avatarFileName
|
||||
lastUpdateDate:(nullable NSDate *)lastUpdateDate
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion;
|
||||
|
||||
- (void)updateWithProfileName:(nullable NSString *)profileName
|
||||
avatarUrlPath:(nullable NSString *)avatarUrlPath
|
||||
lastUpdateDate:(nullable NSDate *)lastUpdateDate
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion;
|
||||
|
||||
|
@ -82,10 +68,6 @@ extern NSString *const kLocalProfileUniqueId;
|
|||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion;
|
||||
|
||||
- (void)updateWithLastUpdateDate:(nullable NSDate *)lastUpdateDate
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion;
|
||||
|
||||
- (void)clearWithProfileKey:(OWSAES256Key *)profileKey
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion;
|
||||
|
|
|
@ -29,7 +29,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
|||
@property (atomic, nullable) NSString *profileName;
|
||||
@property (atomic, nullable) NSString *avatarUrlPath;
|
||||
@property (atomic, nullable) NSString *avatarFileName;
|
||||
@property (atomic, nullable) NSDate *lastUpdateDate;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -187,32 +186,12 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
|||
|
||||
- (void)updateWithProfileName:(nullable NSString *)profileName
|
||||
avatarUrlPath:(nullable NSString *)avatarUrlPath
|
||||
avatarFileName:(nullable NSString *)avatarFileName
|
||||
lastUpdateDate:(nullable NSDate *)lastUpdateDate
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion
|
||||
{
|
||||
[self applyChanges:^(OWSUserProfile *userProfile) {
|
||||
[userProfile setProfileName:[profileName ows_stripped]];
|
||||
[userProfile setAvatarUrlPath:avatarUrlPath];
|
||||
[userProfile setAvatarFileName:avatarFileName];
|
||||
[userProfile setLastUpdateDate:lastUpdateDate];
|
||||
}
|
||||
functionName:__PRETTY_FUNCTION__
|
||||
dbConnection:dbConnection
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
- (void)updateWithProfileName:(nullable NSString *)profileName
|
||||
avatarUrlPath:(nullable NSString *)avatarUrlPath
|
||||
lastUpdateDate:(nullable NSDate *)lastUpdateDate
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion
|
||||
{
|
||||
[self applyChanges:^(OWSUserProfile *userProfile) {
|
||||
[userProfile setProfileName:[profileName ows_stripped]];
|
||||
[userProfile setAvatarUrlPath:avatarUrlPath];
|
||||
[userProfile setLastUpdateDate:lastUpdateDate];
|
||||
}
|
||||
functionName:__PRETTY_FUNCTION__
|
||||
dbConnection:dbConnection
|
||||
|
@ -263,18 +242,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
|||
completion:completion];
|
||||
}
|
||||
|
||||
- (void)updateWithLastUpdateDate:(nullable NSDate *)lastUpdateDate
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion
|
||||
{
|
||||
[self applyChanges:^(OWSUserProfile *userProfile) {
|
||||
[userProfile setLastUpdateDate:lastUpdateDate];
|
||||
}
|
||||
functionName:__PRETTY_FUNCTION__
|
||||
dbConnection:dbConnection
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
- (void)clearWithProfileKey:(OWSAES256Key *)profileKey
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
completion:(nullable OWSUserProfileCompletion)completion;
|
||||
|
@ -284,7 +251,6 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
|||
[userProfile setProfileName:nil];
|
||||
[userProfile setAvatarUrlPath:nil];
|
||||
[userProfile setAvatarFileName:nil];
|
||||
[userProfile setLastUpdateDate:nil];
|
||||
}
|
||||
functionName:__PRETTY_FUNCTION__
|
||||
dbConnection:dbConnection
|
||||
|
@ -338,15 +304,14 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
|||
// This should only be used in verbose, developer-only logs.
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ %p %@ %zd %@ %@ %@ %f",
|
||||
return [NSString stringWithFormat:@"%@ %p %@ %zd %@ %@ %@",
|
||||
self.logTag,
|
||||
self,
|
||||
self.recipientId,
|
||||
self.profileKey.keyData.length,
|
||||
self.profileName,
|
||||
self.avatarUrlPath,
|
||||
self.avatarFileName,
|
||||
self.lastUpdateDate.timeIntervalSinceNow];
|
||||
self.avatarFileName];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -38,6 +38,13 @@ public class ProfileFetcherJob: NSObject {
|
|||
public func run(recipientIds: [String]) {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
if (!CurrentAppContext().isMainApp) {
|
||||
// Only refresh profiles in the MainApp to decrease the chance of missed SN notifications
|
||||
// in the AppExtension for our users who choose not to verify contacts.
|
||||
owsFail("Should only fetch profiles in the main app")
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
for recipientId in recipientIds {
|
||||
self.updateProfile(recipientId: recipientId)
|
||||
|
@ -74,11 +81,11 @@ public class ProfileFetcherJob: NSObject {
|
|||
if !ignoreThrottling {
|
||||
if let lastDate = ProfileFetcherJob.fetchDateMap[recipientId] {
|
||||
let lastTimeInterval = fabs(lastDate.timeIntervalSinceNow)
|
||||
// Don't check a profile more often than every N minutes.
|
||||
// Don't check a profile more often than every N seconds.
|
||||
//
|
||||
// Only throttle profile fetch in production builds in order to
|
||||
// facilitate debugging.
|
||||
let kGetProfileMaxFrequencySeconds = _isDebugAssertConfiguration() ? 0 : 60.0 * 5.0
|
||||
// Throttle less in debug to make it easier to test problems
|
||||
// with our fetching logic.
|
||||
let kGetProfileMaxFrequencySeconds = _isDebugAssertConfiguration() ? 60 : 60.0 * 5.0
|
||||
guard lastTimeInterval > kGetProfileMaxFrequencySeconds else {
|
||||
return Promise(error: ProfileFetcherJobError.throttled(lastTimeInterval: lastTimeInterval))
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ public class ShareViewController: UINavigationController, ShareViewDelegate, SAE
|
|||
|
||||
// We don't need to use OWSOrphanedDataCleaner in the SAE.
|
||||
|
||||
OWSProfileManager.shared().fetchLocalUsersProfile()
|
||||
// We don't need to fetch the local profile in the SAE
|
||||
|
||||
OWSReadReceiptManager.shared().prepareCachedValues()
|
||||
|
||||
|
|
Loading…
Reference in New Issue