From 10e6d114a076150bc3c642be3f825edefcb478fe Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 23 Feb 2021 16:01:06 +1100 Subject: [PATCH] Sync profile updates --- Session/Onboarding/LinkDeviceVC.swift | 25 ++------ Session/Onboarding/Onboarding.swift | 10 +++- Session/Settings/SettingsVC.swift | 11 +++- .../MessageReceiver+Handling.swift | 57 +++++++++++++------ SessionMessagingKit/Storage.swift | 1 + .../To Do/ProfileManagerProtocol.h | 2 + .../General/SNUserDefaults.swift | 4 +- .../Database/Storage+Conformances.swift | 4 ++ 8 files changed, 74 insertions(+), 40 deletions(-) diff --git a/Session/Onboarding/LinkDeviceVC.swift b/Session/Onboarding/LinkDeviceVC.swift index 412375b93..585b118c5 100644 --- a/Session/Onboarding/LinkDeviceVC.swift +++ b/Session/Onboarding/LinkDeviceVC.swift @@ -132,28 +132,13 @@ final class LinkDeviceVC : BaseVC, UIPageViewControllerDataSource, UIPageViewCon } @objc private func handleConfigurationMessageReceived(_ notification: Notification) { - guard let profile = notification.object as? [String:Any?], let displayName = profile["displayName"] as? String else { return } - let profilePictureURL = profile["profilePictureURL"] as? String - let profileKeyAsData = profile["profileKey"] as? NSData - let profileKey = given(profileKeyAsData) { OWSAES256Key(data: $0 as Data)! } TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey - let profileManager = OWSProfileManager.shared() - var userProfile: OWSUserProfile! - Storage.write(with: { transaction in - userProfile = profileManager.getLocalUserProfile(with: transaction) - userProfile.profileName = displayName - userProfile.avatarUrlPath = profilePictureURL - userProfile.profileKey = profileKey - userProfile.save(with: transaction) - }, completion: { - profileManager.downloadAvatar(for: userProfile) - DispatchQueue.main.async { - self.navigationController!.dismiss(animated: true) { - let pnModeVC = PNModeVC() - self.navigationController!.setViewControllers([ pnModeVC ], animated: true) - } + DispatchQueue.main.async { + self.navigationController!.dismiss(animated: true) { + let pnModeVC = PNModeVC() + self.navigationController!.setViewControllers([ pnModeVC ], animated: true) } - }) + } } } diff --git a/Session/Onboarding/Onboarding.swift b/Session/Onboarding/Onboarding.swift index 26502930c..1156fdc0f 100644 --- a/Session/Onboarding/Onboarding.swift +++ b/Session/Onboarding/Onboarding.swift @@ -14,11 +14,17 @@ enum Onboarding { case .register: userDefaults[.hasViewedSeed] = false restorationTime = 0 - userDefaults[.hasSyncedConfiguration] = true + userDefaults[.hasSyncedInitialConfiguration] = true case .recover, .link: userDefaults[.hasViewedSeed] = true restorationTime = Date().timeIntervalSince1970 - userDefaults[.hasSyncedConfiguration] = false + userDefaults[.hasSyncedInitialConfiguration] = false + } + switch self { + case .register, .recover: + userDefaults[.lastDisplayNameUpdate] = Date() + userDefaults[.lastProfilePictureUpdate] = Date() + case .link: break } OWSPrimaryStorage.shared().setRestorationTime(restorationTime) } diff --git a/Session/Settings/SettingsVC.swift b/Session/Settings/SettingsVC.swift index 429faa685..9f9eb2647 100644 --- a/Session/Settings/SettingsVC.swift +++ b/Session/Settings/SettingsVC.swift @@ -296,10 +296,19 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { } private func updateProfile(isUpdatingDisplayName: Bool, isUpdatingProfilePicture: Bool) { + let userDefaults = UserDefaults.standard let displayName = displayNameToBeUploaded ?? OWSProfileManager.shared().profileNameForRecipient(withID: getUserHexEncodedPublicKey()) let profilePicture = profilePictureToBeUploaded ?? OWSProfileManager.shared().profileAvatar(forRecipientId: getUserHexEncodedPublicKey()) - ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] modalActivityIndicator in + ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self, displayNameToBeUploaded, profilePictureToBeUploaded] modalActivityIndicator in OWSProfileManager.shared().updateLocalProfileName(displayName, avatarImage: profilePicture, success: { + if displayNameToBeUploaded != nil { + userDefaults[.lastDisplayNameUpdate] = Date() + } + if profilePictureToBeUploaded != nil { + userDefaults[.lastProfilePictureUpdate] = Date() + } + let appDelegate = UIApplication.shared.delegate as! AppDelegate + appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() DispatchQueue.main.async { modalActivityIndicator.dismiss { guard let self = self else { return } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 2bfd7dc60..24b102198 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -143,24 +143,49 @@ extension MessageReceiver { } private static func handleConfigurationMessage(_ message: ConfigurationMessage, using transaction: Any) { - guard message.sender == getUserHexEncodedPublicKey(), !UserDefaults.standard[.hasSyncedConfiguration] else { return } + guard message.sender == getUserHexEncodedPublicKey() else { return } let storage = SNMessagingKitConfiguration.shared.storage - // Notification - UserDefaults.standard[.hasSyncedConfiguration] = true - let profile: [String:Any?] = [ "displayName" : message.displayName, "profilePictureURL" : message.profilePictureURL, "profileKey" : message.profileKey ] - NotificationCenter.default.post(name: .configurationMessageReceived, object: profile) - // Closed groups - let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys() - for closedGroup in message.closedGroups { - guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue } - handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair, - members: [String](closedGroup.members), admins: [String](closedGroup.admins), messageSentTimestamp: message.sentTimestamp!, using: transaction) + let transaction = transaction as! YapDatabaseReadWriteTransaction + let userDefaults = UserDefaults.standard + // Profile + let userProfile = storage.getUserProfile(using: transaction) + if let displayName = message.displayName { + let shouldUpdate = given(userDefaults[.lastDisplayNameUpdate]) { message.sentTimestamp! > UInt64($0.timeIntervalSince1970 * 1000) } ?? true + if shouldUpdate { + userProfile.profileName = displayName + userDefaults[.lastDisplayNameUpdate] = Date() + } } - // Open groups - let allOpenGroups = Set(storage.getAllUserOpenGroups().keys) - for openGroupURL in message.openGroups { - guard !allOpenGroups.contains(openGroupURL) else { continue } - OpenGroupManager.shared.add(with: openGroupURL, using: transaction).retainUntilComplete() + if let profilePictureURL = message.profilePictureURL, let profileKeyAsData = message.profileKey { + let shouldUpdate = given(userDefaults[.lastProfilePictureUpdate]) { message.sentTimestamp! > UInt64($0.timeIntervalSince1970 * 1000) } ?? true + if shouldUpdate { + userProfile.avatarUrlPath = profilePictureURL + userProfile.profileKey = OWSAES256Key(data: profileKeyAsData) + userDefaults[.lastProfilePictureUpdate] = Date() + } + } + userProfile.save(with: transaction) + transaction.addCompletionQueue(DispatchQueue.main) { + SSKEnvironment.shared.profileManager.downloadAvatar(for: userProfile) + } + // Notification + NotificationCenter.default.post(name: .configurationMessageReceived, object: nil) + // Initial configuration sync + if !UserDefaults.standard[.hasSyncedInitialConfiguration] { + UserDefaults.standard[.hasSyncedInitialConfiguration] = true + // Closed groups + let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys() + for closedGroup in message.closedGroups { + guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue } + handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair, + members: [String](closedGroup.members), admins: [String](closedGroup.admins), messageSentTimestamp: message.sentTimestamp!, using: transaction) + } + // Open groups + let allOpenGroups = Set(storage.getAllUserOpenGroups().keys) + for openGroupURL in message.openGroups { + guard !allOpenGroups.contains(openGroupURL) else { continue } + OpenGroupManager.shared.add(with: openGroupURL, using: transaction).retainUntilComplete() + } } } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index b21953e26..0f5c39add 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -19,6 +19,7 @@ public protocol SessionMessagingKitStorageProtocol { func getUserDisplayName() -> String? func getUserProfileKey() -> Data? func getUserProfilePictureURL() -> String? + func getUserProfile(using transaction: Any) -> OWSUserProfile // MARK: - Closed Groups diff --git a/SessionMessagingKit/To Do/ProfileManagerProtocol.h b/SessionMessagingKit/To Do/ProfileManagerProtocol.h index ae4204dac..7120e2df0 100644 --- a/SessionMessagingKit/To Do/ProfileManagerProtocol.h +++ b/SessionMessagingKit/To Do/ProfileManagerProtocol.h @@ -29,6 +29,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)ensureLocalProfileCached; - (void)ensureProfileCachedForContactWithID:(NSString *)contactID with:(YapDatabaseReadWriteTransaction *)transaction; +- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfile; + @end NS_ASSUME_NONNULL_END diff --git a/SessionUtilitiesKit/General/SNUserDefaults.swift b/SessionUtilitiesKit/General/SNUserDefaults.swift index 9c79c4fbf..eaa1929ca 100644 --- a/SessionUtilitiesKit/General/SNUserDefaults.swift +++ b/SessionUtilitiesKit/General/SNUserDefaults.swift @@ -3,7 +3,7 @@ import Foundation public enum SNUserDefaults { public enum Bool : Swift.String { - case hasSyncedConfiguration + case hasSyncedInitialConfiguration = "hasSyncedConfiguration" case hasViewedSeed case hasSeenLinkPreviewSuggestion case isUsingFullAPNs @@ -13,6 +13,8 @@ public enum SNUserDefaults { public enum Date : Swift.String { case lastProfilePictureUpload case lastConfigurationSync + case lastDisplayNameUpdate + case lastProfilePictureUpdate } public enum Double : Swift.String { diff --git a/SignalUtilitiesKit/Database/Storage+Conformances.swift b/SignalUtilitiesKit/Database/Storage+Conformances.swift index 21c74ee43..a9049ee21 100644 --- a/SignalUtilitiesKit/Database/Storage+Conformances.swift +++ b/SignalUtilitiesKit/Database/Storage+Conformances.swift @@ -5,4 +5,8 @@ extension Storage : SessionMessagingKitStorageProtocol, SessionSnodeKitStoragePr let transaction = transaction as! YapDatabaseReadWriteTransaction OWSPrimaryStorage.shared().updateMessageIDCollectionByPruningMessagesWithIDs(messageIDs, in: transaction) } + + public func getUserProfile(using transaction: Any) -> OWSUserProfile { + return OWSProfileManager.shared().getLocalUserProfile(with: transaction as! YapDatabaseReadWriteTransaction) + } }