Combine the user's own display name/avatar into a single profile.

This is in preparation for adding the user status fields into the profile.
This commit is contained in:
Doug
2026-07-01 16:45:42 +01:00
committed by Doug
parent b8860baf49
commit ace05b97d0
17 changed files with 88 additions and 175 deletions
@@ -130,14 +130,9 @@ class ClientProxy: ClientProxyProtocol {
}
private var loadCachedAvatarURLTask: Task<Void, Never>?
private let userAvatarURLSubject = CurrentValueSubject<URL?, Never>(nil)
var userAvatarURLPublisher: CurrentValuePublisher<URL?, Never> {
userAvatarURLSubject.asCurrentValuePublisher()
}
private let userDisplayNameSubject = CurrentValueSubject<String?, Never>(nil)
var userDisplayNamePublisher: CurrentValuePublisher<String?, Never> {
userDisplayNameSubject.asCurrentValuePublisher()
private let userProfileSubject: CurrentValueSubject<UserProfile, Never>
var userProfilePublisher: CurrentValuePublisher<UserProfile, Never> {
userProfileSubject.asCurrentValuePublisher()
}
private let ignoredUsersSubject = CurrentValueSubject<[String]?, Never>(nil)
@@ -213,6 +208,8 @@ class ClientProxy: ClientProxyProtocol {
self.appSettings = appSettings
self.analyticsService = analyticsService
userProfileSubject = .init(UserProfile(userID: (try? client.userId()) ?? ""))
if appSettings.automaticBackPaginationEnabled {
// Must be called before creating the sync service, timelines etc.
client.enableAutomaticBackpagination()
@@ -677,13 +674,19 @@ class ClientProxy: ClientProxyProtocol {
}
}
func loadUserDisplayName() async -> Result<Void, ClientProxyError> {
func loadUserProfile() async -> Result<Void, ClientProxyError> {
do {
let displayName = try await client.displayName()
userDisplayNameSubject.send(displayName)
async let displayName = client.displayName()
async let avatarURLString = client.avatarUrl()
let profile = try await UserProfile(userID: userID,
displayName: displayName,
avatarURL: avatarURLString.flatMap(URL.init))
loadCachedAvatarURLTask?.cancel()
userProfileSubject.send(profile)
return .success(())
} catch {
MXLog.error("Failed loading user display name with error: \(error)")
MXLog.error("Failed loading user profile with error: \(error)")
return .failure(.sdkError(error))
}
}
@@ -692,7 +695,7 @@ class ClientProxy: ClientProxyProtocol {
do {
try await client.setDisplayName(name: name)
Task {
await self.loadUserDisplayName()
await self.loadUserProfile()
}
return .success(())
} catch {
@@ -701,18 +704,6 @@ class ClientProxy: ClientProxyProtocol {
}
}
func loadUserAvatarURL() async -> Result<Void, ClientProxyError> {
do {
let urlString = try await client.avatarUrl()
loadCachedAvatarURLTask?.cancel()
userAvatarURLSubject.send(urlString.flatMap(URL.init))
return .success(())
} catch {
MXLog.error("Failed loading user avatar URL with error: \(error)")
return .failure(.sdkError(error))
}
}
func setUserAvatar(media: MediaInfo) async -> Result<Void, ClientProxyError> {
guard case let .image(imageURL, _, _) = media, let mimeType = media.mimeType else {
MXLog.error("Failed uploading, invalid media: \(media)")
@@ -723,7 +714,7 @@ class ClientProxy: ClientProxyProtocol {
let data = try Data(contentsOf: imageURL)
try await client.uploadAvatar(mimeType: mimeType, data: data)
Task {
await self.loadUserAvatarURL()
await self.loadUserProfile()
}
return .success(())
} catch {
@@ -736,7 +727,7 @@ class ClientProxy: ClientProxyProtocol {
do {
try await client.removeAvatar()
Task {
await self.loadUserAvatarURL()
await self.loadUserProfile()
}
return .success(())
} catch {
@@ -1172,7 +1163,10 @@ class ClientProxy: ClientProxyProtocol {
do {
let urlString = try await self.client.cachedAvatarUrl()
guard !Task.isCancelled else { return }
self.userAvatarURLSubject.value = urlString.flatMap(URL.init)
let profile = self.userProfileSubject.value
self.userProfileSubject.value = UserProfile(userID: profile.id,
displayName: profile.displayName,
avatarURL: urlString.flatMap(URL.init))
} catch {
MXLog.error("Failed to look for the avatar url in the cache: \(error)")
}
@@ -120,9 +120,7 @@ protocol ClientProxyProtocol: AnyObject {
var userIDServerName: String? { get }
var userDisplayNamePublisher: CurrentValuePublisher<String?, Never> { get }
var userAvatarURLPublisher: CurrentValuePublisher<URL?, Never> { get }
var userProfilePublisher: CurrentValuePublisher<UserProfile, Never> { get }
/// We delay fetching this until after the first sync. Nil until then
var ignoredUsersPublisher: CurrentValuePublisher<[String]?, Never> { get }
@@ -212,12 +210,10 @@ protocol ClientProxyProtocol: AnyObject {
/// Will only work for rooms that are in our room list/local store
func reportRoomForIdentifier(_ identifier: String, reason: String) async -> Result<Void, ClientProxyError>
@discardableResult func loadUserDisplayName() async -> Result<Void, ClientProxyError>
@discardableResult func loadUserProfile() async -> Result<Void, ClientProxyError>
func setUserDisplayName(_ name: String) async -> Result<Void, ClientProxyError>
@discardableResult func loadUserAvatarURL() async -> Result<Void, ClientProxyError>
func setUserAvatar(media: MediaInfo) async -> Result<Void, ClientProxyError>
func removeUserAvatar() async -> Result<Void, ClientProxyError>