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
@@ -90,9 +90,7 @@ enum HomeScreenSecurityBannerMode: Equatable {
}
struct HomeScreenViewState: BindableState {
let userID: String
var userDisplayName: String?
var userAvatarURL: URL?
var userProfile: UserProfile
var securityBannerMode = HomeScreenSecurityBannerMode.none
var shouldShowNewSoundBanner = false
@@ -45,7 +45,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
roomSummaryProvider = userSession.clientProxy.roomSummaryProvider
super.init(initialViewState: .init(userID: userSession.clientProxy.userID,
super.init(initialViewState: .init(userProfile: userSession.clientProxy.userProfilePublisher.value,
bindings: .init(filtersState: .init(appSettings: appSettings))),
mediaProvider: userSession.mediaProvider)
@@ -53,14 +53,9 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
state.isRoomListSearchEnabled = false
}
userSession.clientProxy.userAvatarURLPublisher
userSession.clientProxy.userProfilePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.userAvatarURL, on: self)
.store(in: &cancellables)
userSession.clientProxy.userDisplayNamePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.userDisplayName, on: self)
.weakAssign(to: \.state.userProfile, on: self)
.store(in: &cancellables)
userSession.sessionSecurityStatePublisher
@@ -353,8 +348,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
// Delay user profile detail loading until after the initial room list loads
if roomListMode == .rooms {
Task {
await self.userSession.clientProxy.loadUserAvatarURL()
await self.userSession.clientProxy.loadUserDisplayName()
await self.userSession.clientProxy.loadUserProfile()
}
}
}
@@ -85,9 +85,9 @@ struct HomeScreen: View {
Button {
context.send(viewAction: .showSettings)
} label: {
LoadableAvatarImage(url: context.viewState.userAvatarURL,
name: context.viewState.userDisplayName,
contentID: context.viewState.userID,
LoadableAvatarImage(url: context.viewState.userProfile.avatarURL,
name: context.viewState.userProfile.displayName,
contentID: context.viewState.userProfile.id,
avatarSize: .user(on: .chats),
mediaProvider: context.mediaProvider)
.accessibilityIdentifier(A11yIdentifiers.homeScreen.userAvatar)
@@ -34,12 +34,10 @@ enum SettingsScreenSecuritySectionMode {
struct SettingsScreenViewState: BindableState {
var deviceID: String?
var userID: String
var userProfile: UserProfile
var showLinkNewDeviceButton: Bool
var accountProfileURL: URL?
var showAccountDeactivation: Bool
var userAvatarURL: URL?
var userDisplayName: String?
var showDeveloperOptions: Bool
var securitySectionMode = SettingsScreenSecuritySectionMode.none
@@ -24,7 +24,7 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
self.appSettings = appSettings
super.init(initialViewState: .init(deviceID: userSession.clientProxy.deviceID,
userID: userSession.clientProxy.userID,
userProfile: userSession.clientProxy.userProfilePublisher.value,
showLinkNewDeviceButton: appSettings.linkNewDeviceEnabled,
showAccountDeactivation: userSession.clientProxy.canDeactivateAccount,
showDeveloperOptions: appSettings.developerOptionsEnabled,
@@ -41,14 +41,9 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
.weakAssign(to: \.state.showLinkNewDeviceButton, on: self)
.store(in: &cancellables)
userSession.clientProxy.userAvatarURLPublisher
userSession.clientProxy.userProfilePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.userAvatarURL, on: self)
.store(in: &cancellables)
userSession.clientProxy.userDisplayNamePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.userDisplayName, on: self)
.weakAssign(to: \.state.userProfile, on: self)
.store(in: &cancellables)
userSession.sessionSecurityStatePublisher
@@ -86,8 +81,7 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
.store(in: &cancellables)
Task {
await userSession.clientProxy.loadUserAvatarURL()
await userSession.clientProxy.loadUserDisplayName()
await userSession.clientProxy.loadUserProfile()
await state.accountProfileURL = userSession.clientProxy.accountURL(action: .profile)
}
}
@@ -51,18 +51,18 @@ struct SettingsScreen: View {
context.send(viewAction: .userDetails)
} label: {
HStack(spacing: 12) {
LoadableAvatarImage(url: context.viewState.userAvatarURL,
name: context.viewState.userDisplayName,
contentID: context.viewState.userID,
LoadableAvatarImage(url: context.viewState.userProfile.avatarURL,
name: context.viewState.userProfile.displayName,
contentID: context.viewState.userProfile.id,
avatarSize: .user(on: .settings),
mediaProvider: context.mediaProvider)
.accessibilityHidden(true)
VStack(alignment: .leading, spacing: 2) {
Text(context.viewState.userDisplayName ?? "")
Text(context.viewState.userProfile.displayName ?? "")
.font(.compound.headingMD)
.foregroundColor(.compound.textPrimary)
Text(context.viewState.userID)
Text(context.viewState.userProfile.id)
.font(.compound.bodySM)
.foregroundColor(.compound.textSecondary)
}
@@ -16,26 +16,22 @@ enum UserDetailsEditScreenViewModelAction {
}
struct UserDetailsEditScreenViewState: BindableState {
let userID: String
var currentUserProfile: UserProfile
var canEditAvatar = true
var canEditDisplayName = true
var currentAvatarURL: URL?
var selectedAvatarURL: URL?
var currentDisplayName: String?
var localMedia: MediaInfo?
var bindings: UserDetailsEditScreenViewStateBindings
var nameDidChange: Bool {
bindings.name != currentDisplayName
bindings.name != currentUserProfile.displayName
}
var avatarDidChange: Bool {
localMedia != nil || selectedAvatarURL != currentAvatarURL
localMedia != nil || selectedAvatarURL != currentUserProfile.avatarURL
}
var canSave: Bool {
@@ -28,36 +28,22 @@ class UserDetailsEditScreenViewModel: UserDetailsEditScreenViewModelType, UserDe
self.mediaUploadingPreprocessor = mediaUploadingPreprocessor
self.userIndicatorController = userIndicatorController
super.init(initialViewState: UserDetailsEditScreenViewState(userID: clientProxy.userID,
super.init(initialViewState: UserDetailsEditScreenViewState(currentUserProfile: clientProxy.userProfilePublisher.value,
bindings: .init()), mediaProvider: userSession.mediaProvider)
clientProxy.userAvatarURLPublisher
clientProxy.userProfilePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.currentAvatarURL, on: self)
.store(in: &cancellables)
clientProxy.userAvatarURLPublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.selectedAvatarURL, on: self)
.store(in: &cancellables)
clientProxy.userDisplayNamePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.currentDisplayName, on: self)
.store(in: &cancellables)
clientProxy.userDisplayNamePublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] displayName in
.sink { [weak self] profile in
guard let self else { return }
state.bindings.name = displayName ?? ""
state.currentUserProfile = profile
state.selectedAvatarURL = profile.avatarURL
state.bindings.name = profile.displayName ?? ""
}
.store(in: &cancellables)
Task {
await self.clientProxy.loadUserAvatarURL()
await self.clientProxy.loadUserDisplayName()
await self.clientProxy.loadUserProfile()
state.canEditAvatar = await clientProxy.capabilities.canChangeAvatar()
state.canEditDisplayName = await clientProxy.capabilities.canChangeDisplayName()
}
@@ -18,7 +18,7 @@ struct UserDetailsEditScreen: View {
Section {
avatar
} footer: {
Text(context.viewState.userID)
Text(context.viewState.currentUserProfile.id)
.frame(maxWidth: .infinity)
.font(.compound.bodyLG)
.foregroundColor(.compound.textPrimary)
@@ -62,8 +62,8 @@ struct UserDetailsEditScreen: View {
} label: {
OverridableAvatarImage(overrideURL: context.viewState.localMedia?.thumbnailURL,
url: context.viewState.selectedAvatarURL,
name: context.viewState.currentDisplayName,
contentID: context.viewState.userID,
name: context.viewState.currentUserProfile.displayName,
contentID: context.viewState.currentUserProfile.id,
shape: .circle,
avatarSize: .user(on: .editUserDetails),
mediaProvider: context.mediaProvider)
@@ -15,9 +15,7 @@ enum SpacesScreenViewModelAction {
}
struct SpacesScreenViewState: BindableState {
let userID: String
var userDisplayName: String?
var userAvatarURL: URL?
var userProfile: UserProfile
var topLevelSpaces: [SpaceServiceRoom]
var selectedSpaceID: String?
@@ -29,7 +29,7 @@ class SpacesScreenViewModel: SpacesScreenViewModelType, SpacesScreenViewModelPro
self.appSettings = appSettings
self.userIndicatorController = userIndicatorController
super.init(initialViewState: SpacesScreenViewState(userID: userSession.clientProxy.userID,
super.init(initialViewState: SpacesScreenViewState(userProfile: userSession.clientProxy.userProfilePublisher.value,
topLevelSpaces: spaceServiceProxy.topLevelSpacesPublisher.value),
mediaProvider: userSession.mediaProvider)
@@ -42,14 +42,9 @@ class SpacesScreenViewModel: SpacesScreenViewModelType, SpacesScreenViewModelPro
.weakAssign(to: \.state.selectedSpaceID, on: self)
.store(in: &cancellables)
userSession.clientProxy.userAvatarURLPublisher
userSession.clientProxy.userProfilePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.userAvatarURL, on: self)
.store(in: &cancellables)
userSession.clientProxy.userDisplayNamePublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.userDisplayName, on: self)
.weakAssign(to: \.state.userProfile, on: self)
.store(in: &cancellables)
}
@@ -96,9 +96,9 @@ struct SpacesScreen: View {
Button {
context.send(viewAction: .showSettings)
} label: {
LoadableAvatarImage(url: context.viewState.userAvatarURL,
name: context.viewState.userDisplayName,
contentID: context.viewState.userID,
LoadableAvatarImage(url: context.viewState.userProfile.avatarURL,
name: context.viewState.userProfile.displayName,
contentID: context.viewState.userProfile.id,
avatarSize: .user(on: .spaces),
mediaProvider: context.mediaProvider)
.accessibilityIdentifier(A11yIdentifiers.homeScreen.userAvatar)