Add support for homeserver capabilities to disable the UserDetailsEditScreen UI. (#5421)

Add support for homeserver capabilities to disable editing your user profile.

Also updates editable avatar size/formatting to match the latest Figma at the same time.
This commit is contained in:
Doug
2026-04-17 11:52:46 +01:00
committed by GitHub
parent c40454bbd3
commit eef4a2497a
46 changed files with 482 additions and 142 deletions
+20
View File
@@ -905,6 +905,7 @@
9707AF8D41667FA9B35E8953 /* UserToInvite.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED25719E19B205B668FDACFF /* UserToInvite.swift */; }; 9707AF8D41667FA9B35E8953 /* UserToInvite.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED25719E19B205B668FDACFF /* UserToInvite.swift */; };
97189E495F0E47805D1868DB /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; }; 97189E495F0E47805D1868DB /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; };
973C48F9E4EFB808F61BE401 /* LocationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED49073BB1C1FC649DAC2CCD /* LocationRoomTimelineView.swift */; }; 973C48F9E4EFB808F61BE401 /* LocationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED49073BB1C1FC649DAC2CCD /* LocationRoomTimelineView.swift */; };
97550ECE8A1D28FEF74FBACC /* HomeserverCapabilitiesProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E8591F06B2DAA284181308 /* HomeserverCapabilitiesProxyProtocol.swift */; };
978BB24F2A5D31EE59EEC249 /* UserSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */; }; 978BB24F2A5D31EE59EEC249 /* UserSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */; };
97969EF0B9C412CD38E5CA93 /* AppLockScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4005D82E9D27BAF006A8FE1 /* AppLockScreenViewModel.swift */; }; 97969EF0B9C412CD38E5CA93 /* AppLockScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4005D82E9D27BAF006A8FE1 /* AppLockScreenViewModel.swift */; };
97BAEDD9054FB5F233EE928B /* EncryptionResetScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306AB507E1027D6C5C147EB6 /* EncryptionResetScreenModels.swift */; }; 97BAEDD9054FB5F233EE928B /* EncryptionResetScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306AB507E1027D6C5C147EB6 /* EncryptionResetScreenModels.swift */; };
@@ -1132,6 +1133,7 @@
C051475DFF4C8EBDDF4DC8E4 /* StartChatScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99E13633862847D8B7E2815 /* StartChatScreenModels.swift */; }; C051475DFF4C8EBDDF4DC8E4 /* StartChatScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99E13633862847D8B7E2815 /* StartChatScreenModels.swift */; };
C08AAE7563E0722C9383F51C /* RoomMembersListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B8E176484A89BAC389D4076 /* RoomMembersListScreen.swift */; }; C08AAE7563E0722C9383F51C /* RoomMembersListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B8E176484A89BAC389D4076 /* RoomMembersListScreen.swift */; };
C097D5453640E27D397943CB /* TargetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D829FD8958376614504B18 /* TargetConfiguration.swift */; }; C097D5453640E27D397943CB /* TargetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D829FD8958376614504B18 /* TargetConfiguration.swift */; };
C0A845AAFEB7E1BEAE04306E /* HomeserverCapabilitiesProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 751C3DC87817362097287DCC /* HomeserverCapabilitiesProxy.swift */; };
C0B97FFEC0083F3A36609E61 /* TimelineItemMacContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = A243A6E6207297123E60DE48 /* TimelineItemMacContextMenu.swift */; }; C0B97FFEC0083F3A36609E61 /* TimelineItemMacContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = A243A6E6207297123E60DE48 /* TimelineItemMacContextMenu.swift */; };
C11939FDC40716C4387275A4 /* NotificationSettingsEditScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8544F7058D31DBEB8DBFF0F5 /* NotificationSettingsEditScreenViewModelTests.swift */; }; C11939FDC40716C4387275A4 /* NotificationSettingsEditScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8544F7058D31DBEB8DBFF0F5 /* NotificationSettingsEditScreenViewModelTests.swift */; };
C11D4A49DC29D89CE2BB31B8 /* MediaEventsTimelineScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 976ED77B772F50C4BAD757E7 /* MediaEventsTimelineScreenViewModel.swift */; }; C11D4A49DC29D89CE2BB31B8 /* MediaEventsTimelineScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 976ED77B772F50C4BAD757E7 /* MediaEventsTimelineScreenViewModel.swift */; };
@@ -1245,6 +1247,7 @@
D2466C6BC8CAD8FADD7BF89B /* RoomPreviewProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6695C64F066628411EAD21E9 /* RoomPreviewProxyMock.swift */; }; D2466C6BC8CAD8FADD7BF89B /* RoomPreviewProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6695C64F066628411EAD21E9 /* RoomPreviewProxyMock.swift */; };
D26093BB80B69092B0E9AC7C /* PinnedItemsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66763BD54A3A1D9C6E6F2F1 /* PinnedItemsIndicatorView.swift */; }; D26093BB80B69092B0E9AC7C /* PinnedItemsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66763BD54A3A1D9C6E6F2F1 /* PinnedItemsIndicatorView.swift */; };
D2825E013A8ECFB66D9A1DE6 /* RoomChangeRolesScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F841F219ACDFC1D3F42FEFB /* RoomChangeRolesScreenViewModelTests.swift */; }; D2825E013A8ECFB66D9A1DE6 /* RoomChangeRolesScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F841F219ACDFC1D3F42FEFB /* RoomChangeRolesScreenViewModelTests.swift */; };
D293B8277CF50611C284CAB5 /* EditAvatarButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89D7846847BA9D2C5346ED9C /* EditAvatarButtonStyle.swift */; };
D29E999538E5ABC00E1668F8 /* ElementNavigationStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03AEAA2F66E796C365EFD58 /* ElementNavigationStack.swift */; }; D29E999538E5ABC00E1668F8 /* ElementNavigationStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03AEAA2F66E796C365EFD58 /* ElementNavigationStack.swift */; };
D2CBC380FEBCBF29263B8446 /* AudioPlaybackSpeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78B4E56DBFFD4A7A39D10F5 /* AudioPlaybackSpeed.swift */; }; D2CBC380FEBCBF29263B8446 /* AudioPlaybackSpeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78B4E56DBFFD4A7A39D10F5 /* AudioPlaybackSpeed.swift */; };
D2D70B5DB1A5E4AF0CD88330 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 033DB41C51865A2E83174E87 /* target.yml */; }; D2D70B5DB1A5E4AF0CD88330 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 033DB41C51865A2E83174E87 /* target.yml */; };
@@ -2250,6 +2253,7 @@
74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
74FCAA90142DFBFA1E3E4216 /* SpaceAddRoomsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceAddRoomsScreenCoordinator.swift; sourceTree = "<group>"; }; 74FCAA90142DFBFA1E3E4216 /* SpaceAddRoomsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceAddRoomsScreenCoordinator.swift; sourceTree = "<group>"; };
7509AB72755DCC4B4E721B36 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/SAS.strings; sourceTree = "<group>"; }; 7509AB72755DCC4B4E721B36 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/SAS.strings; sourceTree = "<group>"; };
751C3DC87817362097287DCC /* HomeserverCapabilitiesProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeserverCapabilitiesProxy.swift; sourceTree = "<group>"; };
752A0EB49BF5BCEA37EDF7A3 /* Signposter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signposter.swift; sourceTree = "<group>"; }; 752A0EB49BF5BCEA37EDF7A3 /* Signposter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signposter.swift; sourceTree = "<group>"; };
753B4C6C0EDDCBF0708DC384 /* TimelineItemSendInfoLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemSendInfoLabel.swift; sourceTree = "<group>"; }; 753B4C6C0EDDCBF0708DC384 /* TimelineItemSendInfoLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemSendInfoLabel.swift; sourceTree = "<group>"; };
75B3CE05643C7791D46AC54B /* LeaveSpaceHandleProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeaveSpaceHandleProxy.swift; sourceTree = "<group>"; }; 75B3CE05643C7791D46AC54B /* LeaveSpaceHandleProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeaveSpaceHandleProxy.swift; sourceTree = "<group>"; };
@@ -2350,6 +2354,7 @@
858F8D0B0D51CC41BAA18E24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; }; 858F8D0B0D51CC41BAA18E24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
859F51637DA710BBE7B70D6D /* ChatsSpaceFiltersScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsSpaceFiltersScreenViewModel.swift; sourceTree = "<group>"; }; 859F51637DA710BBE7B70D6D /* ChatsSpaceFiltersScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsSpaceFiltersScreenViewModel.swift; sourceTree = "<group>"; };
85A1941B874A3BE9CDDF43EF /* XCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.swift; sourceTree = "<group>"; }; 85A1941B874A3BE9CDDF43EF /* XCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.swift; sourceTree = "<group>"; };
85E8591F06B2DAA284181308 /* HomeserverCapabilitiesProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeserverCapabilitiesProxyProtocol.swift; sourceTree = "<group>"; };
85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; }; 85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; };
8610C1D21565C950BCA6A454 /* AppLockSetupSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 8610C1D21565C950BCA6A454 /* AppLockSetupSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
86376BEE425704AEE197CA54 /* PillContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContext.swift; sourceTree = "<group>"; }; 86376BEE425704AEE197CA54 /* PillContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContext.swift; sourceTree = "<group>"; };
@@ -2372,6 +2377,7 @@
897DF5E9A70CE05A632FC8AF /* UTType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTType.swift; sourceTree = "<group>"; }; 897DF5E9A70CE05A632FC8AF /* UTType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTType.swift; sourceTree = "<group>"; };
89AAEA70CFF3284920811941 /* RoomChangePermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreen.swift; sourceTree = "<group>"; }; 89AAEA70CFF3284920811941 /* RoomChangePermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreen.swift; sourceTree = "<group>"; };
89BB11A792EF6F70B95B467E /* EncryptionResetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetTests.swift; sourceTree = "<group>"; }; 89BB11A792EF6F70B95B467E /* EncryptionResetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetTests.swift; sourceTree = "<group>"; };
89D7846847BA9D2C5346ED9C /* EditAvatarButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAvatarButtonStyle.swift; sourceTree = "<group>"; };
89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormButtonStyles.swift; sourceTree = "<group>"; }; 89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormButtonStyles.swift; sourceTree = "<group>"; };
8A1F2AAA3F0F2B72D2FFE4D0 /* MapTilerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerConfiguration.swift; sourceTree = "<group>"; }; 8A1F2AAA3F0F2B72D2FFE4D0 /* MapTilerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerConfiguration.swift; sourceTree = "<group>"; };
8A8DCBD0ABAADFDE5AF17E1F /* LiveLocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveLocationRoomTimelineItem.swift; sourceTree = "<group>"; }; 8A8DCBD0ABAADFDE5AF17E1F /* LiveLocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveLocationRoomTimelineItem.swift; sourceTree = "<group>"; };
@@ -3244,6 +3250,7 @@
FCE7249621F507F34A8122FB /* Audio */, FCE7249621F507F34A8122FB /* Audio */,
AAFDD509929A0CCF8BCE51EB /* Authentication */, AAFDD509929A0CCF8BCE51EB /* Authentication */,
0ED3F5C21537519389C07644 /* BugReport */, 0ED3F5C21537519389C07644 /* BugReport */,
786C421000CA16305B0FC55C /* Capabilities */,
8039515BAA53B7C3275AC64A /* Client */, 8039515BAA53B7C3275AC64A /* Client */,
8B5E91450E85A9689931B221 /* ComposerDraft */, 8B5E91450E85A9689931B221 /* ComposerDraft */,
92E99C57D7F92ED16F73282C /* ElementCall */, 92E99C57D7F92ED16F73282C /* ElementCall */,
@@ -3807,6 +3814,7 @@
07934EF08BB39353E4A94272 /* BlurEffectView.swift */, 07934EF08BB39353E4A94272 /* BlurEffectView.swift */,
FEC4B431B0117BDEE697DB4A /* ComposerDisabledView.swift */, FEC4B431B0117BDEE697DB4A /* ComposerDisabledView.swift */,
B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */, B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */,
89D7846847BA9D2C5346ED9C /* EditAvatarButtonStyle.swift */,
E2776E63E02719B20758EB78 /* EditRoomAddressListRow.swift */, E2776E63E02719B20758EB78 /* EditRoomAddressListRow.swift */,
8F4F0AB250EFA7B71FB2BDB2 /* HorizontalHighlightGradient.swift */, 8F4F0AB250EFA7B71FB2BDB2 /* HorizontalHighlightGradient.swift */,
98ABC939BC8F08CA3E967D6C /* JoinCallButton.swift */, 98ABC939BC8F08CA3E967D6C /* JoinCallButton.swift */,
@@ -5063,6 +5071,15 @@
path = View; path = View;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
786C421000CA16305B0FC55C /* Capabilities */ = {
isa = PBXGroup;
children = (
751C3DC87817362097287DCC /* HomeserverCapabilitiesProxy.swift */,
85E8591F06B2DAA284181308 /* HomeserverCapabilitiesProxyProtocol.swift */,
);
path = Capabilities;
sourceTree = "<group>";
};
78915D878159D302395D57BF /* SupportingFiles */ = { 78915D878159D302395D57BF /* SupportingFiles */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -8230,6 +8247,7 @@
037006FB6DF1374F94E4058D /* Dictionary.swift in Sources */, 037006FB6DF1374F94E4058D /* Dictionary.swift in Sources */,
EDF8919F15DE0FF00EF99E70 /* DocumentPicker.swift in Sources */, EDF8919F15DE0FF00EF99E70 /* DocumentPicker.swift in Sources */,
4FDC8A9764CFDA90CE035725 /* Duration.swift in Sources */, 4FDC8A9764CFDA90CE035725 /* Duration.swift in Sources */,
D293B8277CF50611C284CAB5 /* EditAvatarButtonStyle.swift in Sources */,
4B25CDB4AA2C2AC0B4577217 /* EditRoomAddressListRow.swift in Sources */, 4B25CDB4AA2C2AC0B4577217 /* EditRoomAddressListRow.swift in Sources */,
4764FC9A843D1F9865EDC29C /* EditRoomAddressScreen.swift in Sources */, 4764FC9A843D1F9865EDC29C /* EditRoomAddressScreen.swift in Sources */,
2BC579CB5CE90CFE07CA0955 /* EditRoomAddressScreenCoordinator.swift in Sources */, 2BC579CB5CE90CFE07CA0955 /* EditRoomAddressScreenCoordinator.swift in Sources */,
@@ -8322,6 +8340,8 @@
A10D6CCDE2010C09EEA1A593 /* HomeScreenRoomList.swift in Sources */, A10D6CCDE2010C09EEA1A593 /* HomeScreenRoomList.swift in Sources */,
DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */, DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */,
56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */, 56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */,
C0A845AAFEB7E1BEAE04306E /* HomeserverCapabilitiesProxy.swift in Sources */,
97550ECE8A1D28FEF74FBACC /* HomeserverCapabilitiesProxyProtocol.swift in Sources */,
277FD4394EAFF323DA34997E /* HorizontalHighlightGradient.swift in Sources */, 277FD4394EAFF323DA34997E /* HorizontalHighlightGradient.swift in Sources */,
2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */, 2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */,
C3BB6887CF13B19182E81F87 /* IdentityConfirmationScreenCoordinator.swift in Sources */, C3BB6887CF13B19182E81F87 /* IdentityConfirmationScreenCoordinator.swift in Sources */,
@@ -29,6 +29,9 @@ struct ClientProxyMockConfiguration {
var timelineMediaVisibility = TimelineMediaVisibility.always var timelineMediaVisibility = TimelineMediaVisibility.always
var hideInviteAvatars = false var hideInviteAvatars = false
var canChangeAvatar = true
var canChangeDisplayName = true
var maxMediaUploadSize: UInt = 100 * 1024 * 1024 var maxMediaUploadSize: UInt = 100 * 1024 * 1024
class Overrides { class Overrides {
@@ -109,6 +112,11 @@ extension ClientProxyMock {
spaceService = SpaceServiceProxyMock(configuration.spaceServiceConfiguration) spaceService = SpaceServiceProxyMock(configuration.spaceServiceConfiguration)
linkNewDeviceServiceReturnValue = LinkNewDeviceServiceMock(.init()) linkNewDeviceServiceReturnValue = LinkNewDeviceServiceMock(.init())
let capabilities = HomeserverCapabilitiesProxyMock()
capabilities.canChangeAvatarReturnValue = configuration.canChangeAvatar
capabilities.canChangeDisplayNameReturnValue = configuration.canChangeDisplayName
self.capabilities = capabilities
roomForIdentifierClosure = { [weak self] identifier in roomForIdentifierClosure = { [weak self] identifier in
if let room = self?.roomSummaryProvider.roomListPublisher.value.first(where: { $0.id == identifier }) { if let room = self?.roomSummaryProvider.roomListPublisher.value.first(where: { $0.id == identifier }) {
let joinedRoomIDs = configuration.overrides.joinedRoomIDs let joinedRoomIDs = configuration.overrides.joinedRoomIDs
@@ -2696,6 +2696,11 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
set(value) { underlyingSpaceService = value } set(value) { underlyingSpaceService = value }
} }
var underlyingSpaceService: SpaceServiceProxyProtocol! var underlyingSpaceService: SpaceServiceProxyProtocol!
var capabilities: HomeserverCapabilitiesProxyProtocol {
get { return underlyingCapabilities }
set(value) { underlyingCapabilities = value }
}
var underlyingCapabilities: HomeserverCapabilitiesProxyProtocol!
var isReportRoomSupportedCallsCount = 0 var isReportRoomSupportedCallsCount = 0
var isReportRoomSupportedCalled: Bool { var isReportRoomSupportedCalled: Bool {
return isReportRoomSupportedCallsCount > 0 return isReportRoomSupportedCallsCount > 0
@@ -6945,6 +6950,172 @@ class ElementCallWidgetDriverMock: ElementCallWidgetDriverProtocol, @unchecked S
} }
} }
} }
class HomeserverCapabilitiesProxyMock: HomeserverCapabilitiesProxyProtocol, @unchecked Sendable {
//MARK: - refresh
var refreshUnderlyingCallsCount = 0
var refreshCallsCount: Int {
get {
if Thread.isMainThread {
return refreshUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = refreshUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
refreshUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
refreshUnderlyingCallsCount = newValue
}
}
}
}
var refreshCalled: Bool {
return refreshCallsCount > 0
}
var refreshClosure: (() async -> Void)?
func refresh() async {
refreshCallsCount += 1
await refreshClosure?()
}
//MARK: - canChangeAvatar
var canChangeAvatarUnderlyingCallsCount = 0
var canChangeAvatarCallsCount: Int {
get {
if Thread.isMainThread {
return canChangeAvatarUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = canChangeAvatarUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
canChangeAvatarUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
canChangeAvatarUnderlyingCallsCount = newValue
}
}
}
}
var canChangeAvatarCalled: Bool {
return canChangeAvatarCallsCount > 0
}
var canChangeAvatarUnderlyingReturnValue: Bool!
var canChangeAvatarReturnValue: Bool! {
get {
if Thread.isMainThread {
return canChangeAvatarUnderlyingReturnValue
} else {
var returnValue: Bool? = nil
DispatchQueue.main.sync {
returnValue = canChangeAvatarUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
canChangeAvatarUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
canChangeAvatarUnderlyingReturnValue = newValue
}
}
}
}
var canChangeAvatarClosure: (() async -> Bool)?
func canChangeAvatar() async -> Bool {
canChangeAvatarCallsCount += 1
if let canChangeAvatarClosure = canChangeAvatarClosure {
return await canChangeAvatarClosure()
} else {
return canChangeAvatarReturnValue
}
}
//MARK: - canChangeDisplayName
var canChangeDisplayNameUnderlyingCallsCount = 0
var canChangeDisplayNameCallsCount: Int {
get {
if Thread.isMainThread {
return canChangeDisplayNameUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = canChangeDisplayNameUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
canChangeDisplayNameUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
canChangeDisplayNameUnderlyingCallsCount = newValue
}
}
}
}
var canChangeDisplayNameCalled: Bool {
return canChangeDisplayNameCallsCount > 0
}
var canChangeDisplayNameUnderlyingReturnValue: Bool!
var canChangeDisplayNameReturnValue: Bool! {
get {
if Thread.isMainThread {
return canChangeDisplayNameUnderlyingReturnValue
} else {
var returnValue: Bool? = nil
DispatchQueue.main.sync {
returnValue = canChangeDisplayNameUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
canChangeDisplayNameUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
canChangeDisplayNameUnderlyingReturnValue = newValue
}
}
}
}
var canChangeDisplayNameClosure: (() async -> Bool)?
func canChangeDisplayName() async -> Bool {
canChangeDisplayNameCallsCount += 1
if let canChangeDisplayNameClosure = canChangeDisplayNameClosure {
return await canChangeDisplayNameClosure()
} else {
return canChangeDisplayNameReturnValue
}
}
}
class InvitedRoomProxyMock: InvitedRoomProxyProtocol, @unchecked Sendable { class InvitedRoomProxyMock: InvitedRoomProxyProtocol, @unchecked Sendable {
var info: BaseRoomInfoProxyProtocol { var info: BaseRoomInfoProxyProtocol {
get { return underlyingInfo } get { return underlyingInfo }
+4 -2
View File
@@ -134,10 +134,12 @@ enum RoomAvatarSizeOnScreen {
case globalSearch case globalSearch
case roomSelection case roomSelection
case details case details
case editRoomDetails
case notificationSettings case notificationSettings
case roomDirectorySearch case roomDirectorySearch
case joinRoom case joinRoom
case spaceHeader case spaceHeader
case editSpaceDetails
case spaceAddRooms case spaceAddRooms
case spaceAddRoomsSelected case spaceAddRoomsSelected
case completionSuggestions case completionSuggestions
@@ -157,9 +159,9 @@ enum RoomAvatarSizeOnScreen {
case .chats, .spaces, .spaceSettings, case .chats, .spaces, .spaceSettings,
.spaceAddRoomsSelected: .spaceAddRoomsSelected:
52 52
case .joinRoom, .spaceHeader: case .joinRoom, .spaceHeader, .editSpaceDetails:
64 64
case .details: case .details, .editRoomDetails:
96 96
} }
} }
@@ -0,0 +1,69 @@
//
// Copyright 2026 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Compound
import SwiftUI
struct EditAvatarButtonStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled
func makeBody(configuration: Configuration) -> some View {
configuration.label
.overlay(alignment: .bottomTrailing) {
if isEnabled {
EditAvatarBadge()
.scaledOffset(x: 8, y: 0, relativeTo: .title)
}
}
}
}
struct EditAvatarBadge: View {
var body: some View {
CompoundIcon(\.edit, size: .small, relativeTo: .body)
.foregroundStyle(.compound.iconPrimary)
.scaledPadding(5, relativeTo: .title)
.background {
Circle()
.fill(Color.compound.bgCanvasDefault)
.overlay {
Circle()
.inset(by: -0.5)
.stroke(.compound.borderInteractiveSecondary, lineWidth: 1)
}
}
.scaledPadding(4, relativeTo: .title)
.background(.compound.bgSubtleSecondaryLevel0, in: Circle())
.scaledPadding(-4)
.accessibilityHidden(true)
}
}
struct EditAvatarButtonStyle_Previews: PreviewProvider {
static var previews: some View {
VStack(spacing: 20) {
Button { } label: {
LoadableAvatarImage(url: nil,
name: "Test", contentID: "test",
avatarSize: .user(on: .editUserDetails),
mediaProvider: MediaProviderMock(configuration: .init()))
}
.buttonStyle(EditAvatarButtonStyle())
Button { } label: {
LoadableAvatarImage(url: nil,
name: "Test", contentID: "test",
avatarSize: .user(on: .editUserDetails),
mediaProvider: MediaProviderMock(configuration: .init()))
}
.buttonStyle(EditAvatarButtonStyle())
.disabled(true)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.compound.bgSubtleSecondaryLevel0)
}
}
@@ -114,11 +114,10 @@ struct CreateRoomScreen: View {
.resizable() .resizable()
.aspectRatio(contentMode: .fill) .aspectRatio(contentMode: .fill)
.scaledFrame(size: 70, relativeTo: .title) .scaledFrame(size: 70, relativeTo: .title)
.clipShape(context.viewState.isSpace ? AnyShape(RoundedRectangle(cornerRadius: 16)) : AnyShape(Circle())) .avatarShape(context.viewState.isSpace ? .roundedRect : .circle, size: 70)
.overlay(alignment: .bottomTrailing) { .overlay(alignment: .bottomTrailing) {
editAvatarBadge EditAvatarBadge()
.scaledOffset(x: 12, y: 4, relativeTo: .title) .scaledOffset(x: 8, y: 0, relativeTo: .title)
.accessibilityHidden(true)
} }
} else { } else {
CompoundIcon(\.takePhoto, size: .medium, relativeTo: .title) CompoundIcon(\.takePhoto, size: .medium, relativeTo: .title)
@@ -153,23 +152,6 @@ struct CreateRoomScreen: View {
} }
} }
private var editAvatarBadge: some View {
CompoundIcon(\.edit, size: .small, relativeTo: .body)
.foregroundStyle(.compound.iconPrimary)
.scaledPadding(5, relativeTo: .title)
.background {
Circle()
.fill(Color.compound.bgCanvasDefault)
.overlay {
Circle()
.inset(by: 0.5)
.stroke(.compound.borderInteractiveSecondary, lineWidth: 1)
}
}
.scaledPadding(3.5, relativeTo: .title)
.background(.compound.bgSubtleSecondaryLevel0, in: Circle())
}
private var topicSection: some View { private var topicSection: some View {
Section { Section {
ListRow(label: .plain(title: L10n.screenCreateRoomTopicPlaceholder), ListRow(label: .plain(title: L10n.screenCreateRoomTopicPlaceholder),
@@ -11,11 +11,12 @@ import SwiftUI
struct RoomDetailsEditScreen: View { struct RoomDetailsEditScreen: View {
@ObservedObject var context: RoomDetailsEditScreenViewModel.Context @ObservedObject var context: RoomDetailsEditScreenViewModel.Context
private enum Focus { case name, topic }
@FocusState private var focus: Focus? @FocusState private var focus: Focus?
private enum Focus { private var isSpace: Bool {
case name context.viewState.isSpace
case topic
} }
var body: some View { var body: some View {
@@ -60,20 +61,15 @@ struct RoomDetailsEditScreen: View {
url: context.viewState.avatarURL, url: context.viewState.avatarURL,
name: context.viewState.initialName, name: context.viewState.initialName,
contentID: context.viewState.roomID, contentID: context.viewState.roomID,
shape: context.viewState.isSpace ? .roundedRect : .circle, shape: isSpace ? .roundedRect : .circle,
avatarSize: .user(on: .memberDetails), avatarSize: .room(on: isSpace ? .editSpaceDetails : .editRoomDetails),
mediaProvider: context.mediaProvider) mediaProvider: context.mediaProvider)
.accessibilityLabel(L10n.a11yEditAvatar) .accessibilityLabel(L10n.a11yEditAvatar)
.overlay(alignment: .bottomTrailing) {
if context.viewState.canEditAvatar {
avatarOverlayIcon
}
}
.confirmationDialog("", isPresented: $context.showMediaSheet) { .confirmationDialog("", isPresented: $context.showMediaSheet) {
mediaActionSheet mediaActionSheet
} }
} }
.buttonStyle(.plain) .buttonStyle(EditAvatarButtonStyle())
.disabled(!context.viewState.canEditAvatar) .disabled(!context.viewState.canEditAvatar)
.frame(maxWidth: .infinity, alignment: .center) .frame(maxWidth: .infinity, alignment: .center)
.listRowBackground(Color.clear) .listRowBackground(Color.clear)
@@ -100,7 +96,7 @@ struct RoomDetailsEditScreen: View {
private var topicSection: some View { private var topicSection: some View {
Section { Section {
if context.viewState.canEditTopic { if context.viewState.canEditTopic {
ListRow(label: .plain(title: context.viewState.isSpace ? L10n.commonSpaceTopicPlaceholder : L10n.commonTopicPlaceholder), ListRow(label: .plain(title: isSpace ? L10n.commonSpaceTopicPlaceholder : L10n.commonTopicPlaceholder),
kind: .textField(text: $context.topic, axis: .vertical)) kind: .textField(text: $context.topic, axis: .vertical))
.focused($focus, equals: .topic) .focused($focus, equals: .topic)
.lineLimit(3...) .lineLimit(3...)
@@ -116,17 +112,6 @@ struct RoomDetailsEditScreen: View {
} }
} }
private var avatarOverlayIcon: some View {
CompoundIcon(\.editSolid, size: .xSmall, relativeTo: .compound.bodyLG)
.foregroundColor(.white)
.padding(4)
.background {
Circle()
.foregroundColor(.black)
}
.accessibilityHidden(true)
}
@ViewBuilder @ViewBuilder
private var mediaActionSheet: some View { private var mediaActionSheet: some View {
Button { Button {
@@ -152,27 +137,9 @@ struct RoomDetailsEditScreen: View {
// MARK: - Previews // MARK: - Previews
struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview { struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview {
static let editableViewModel = { static let editableViewModel = makeViewModel(readOnly: false)
let roomProxy = JoinedRoomProxyMock(.init(id: "test_id", static let readOnlyViewModel = makeViewModel(readOnly: true)
name: "Room", static let editableSpaceViewModel = makeViewModel(readOnly: false, isSpace: true)
members: [.mockMeAdmin]))
return RoomDetailsEditScreenViewModel(roomProxy: roomProxy,
userSession: UserSessionMock(.init()),
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings),
userIndicatorController: UserIndicatorControllerMock.default)
}()
static let readOnlyViewModel = {
let roomProxy = JoinedRoomProxyMock(.init(id: "test_id",
name: "Room",
members: [.mockAlice]))
return RoomDetailsEditScreenViewModel(roomProxy: roomProxy,
userSession: UserSessionMock(.init()),
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings),
userIndicatorController: UserIndicatorControllerMock.default)
}()
static var previews: some View { static var previews: some View {
ElementNavigationStack { ElementNavigationStack {
@@ -183,9 +150,26 @@ struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview {
ElementNavigationStack { ElementNavigationStack {
RoomDetailsEditScreen(context: editableViewModel.context) RoomDetailsEditScreen(context: editableViewModel.context)
} }
.snapshotPreferences(expect: editableViewModel.context.$viewState.map { state in .snapshotPreferences(expect: editableViewModel.context.$viewState.map { $0.canEditTopic == true })
state.canEditTopic == true
})
.previewDisplayName("Editable") .previewDisplayName("Editable")
ElementNavigationStack {
RoomDetailsEditScreen(context: editableSpaceViewModel.context)
}
.snapshotPreferences(expect: editableSpaceViewModel.context.$viewState.map { $0.canEditTopic == true })
.previewDisplayName("Space")
}
static func makeViewModel(readOnly: Bool, isSpace: Bool = false) -> RoomDetailsEditScreenViewModel {
let members: [RoomMemberProxyMock] = readOnly ? [.mockAlice] : [.mockMeAdmin]
let roomProxy = JoinedRoomProxyMock(.init(id: "test_id",
name: isSpace ? "Space" : "Room",
isSpace: isSpace,
members: members))
return RoomDetailsEditScreenViewModel(roomProxy: roomProxy,
userSession: UserSessionMock(.init()),
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings),
userIndicatorController: UserIndicatorControllerMock.default)
} }
} }
@@ -18,6 +18,9 @@ enum UserDetailsEditScreenViewModelAction {
struct UserDetailsEditScreenViewState: BindableState { struct UserDetailsEditScreenViewState: BindableState {
let userID: String let userID: String
var canEditAvatar = true
var canEditDisplayName = true
var currentAvatarURL: URL? var currentAvatarURL: URL?
var selectedAvatarURL: URL? var selectedAvatarURL: URL?
@@ -58,6 +58,8 @@ class UserDetailsEditScreenViewModel: UserDetailsEditScreenViewModelType, UserDe
Task { Task {
await self.clientProxy.loadUserAvatarURL() await self.clientProxy.loadUserAvatarURL()
await self.clientProxy.loadUserDisplayName() await self.clientProxy.loadUserDisplayName()
state.canEditAvatar = await clientProxy.capabilities.canChangeAvatar()
state.canEditDisplayName = await clientProxy.capabilities.canChangeDisplayName()
} }
} }
@@ -67,14 +67,12 @@ struct UserDetailsEditScreen: View {
shape: .circle, shape: .circle,
avatarSize: .user(on: .editUserDetails), avatarSize: .user(on: .editUserDetails),
mediaProvider: context.mediaProvider) mediaProvider: context.mediaProvider)
.overlay(alignment: .bottomTrailing) {
avatarOverlayIcon
}
.confirmationDialog("", isPresented: $context.showMediaSheet) { .confirmationDialog("", isPresented: $context.showMediaSheet) {
mediaActionSheet mediaActionSheet
} }
} }
.buttonStyle(.plain) .buttonStyle(EditAvatarButtonStyle())
.disabled(!context.viewState.canEditAvatar)
.frame(maxWidth: .infinity, alignment: .center) .frame(maxWidth: .infinity, alignment: .center)
.listRowBackground(Color.clear) .listRowBackground(Color.clear)
} }
@@ -84,22 +82,13 @@ struct UserDetailsEditScreen: View {
ListRow(label: .plain(title: L10n.screenEditProfileDisplayNamePlaceholder), ListRow(label: .plain(title: L10n.screenEditProfileDisplayNamePlaceholder),
kind: .textField(text: $context.name, axis: .horizontal)) kind: .textField(text: $context.name, axis: .horizontal))
.focused($focus) .focused($focus)
.disabled(!context.viewState.canEditDisplayName)
} header: { } header: {
Text(L10n.screenEditProfileDisplayName) Text(L10n.screenEditProfileDisplayName)
.compoundListSectionHeader() .compoundListSectionHeader()
} }
} }
private var avatarOverlayIcon: some View {
CompoundIcon(\.editSolid, size: .xSmall, relativeTo: .compound.bodyLG)
.foregroundColor(.white)
.padding(4)
.background {
Circle()
.foregroundColor(.black)
}
}
@ViewBuilder @ViewBuilder
private var mediaActionSheet: some View { private var mediaActionSheet: some View {
Button { Button {
@@ -126,13 +115,26 @@ struct UserDetailsEditScreen: View {
// MARK: - Previews // MARK: - Previews
struct UserDetailsEditScreen_Previews: PreviewProvider, TestablePreview { struct UserDetailsEditScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = UserDetailsEditScreenViewModel(userSession: UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@stefan:matrix.org")))), static let viewModel = makeViewModel()
mediaUploadingPreprocessor: .init(appSettings: ServiceLocator.shared.settings), static let readOnlyViewModel = makeViewModel(canChangeProfile: false)
userIndicatorController: UserIndicatorControllerMock.default)
static var previews: some View { static var previews: some View {
ElementNavigationStack { ElementNavigationStack {
UserDetailsEditScreen(context: viewModel.context) UserDetailsEditScreen(context: viewModel.context)
} }
.previewDisplayName("Default")
ElementNavigationStack {
UserDetailsEditScreen(context: readOnlyViewModel.context)
}
.previewDisplayName("Read Only")
}
static func makeViewModel(canChangeProfile: Bool = true) -> UserDetailsEditScreenViewModel {
UserDetailsEditScreenViewModel(userSession: UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@stefan:matrix.org",
canChangeAvatar: canChangeProfile,
canChangeDisplayName: canChangeProfile)))),
mediaUploadingPreprocessor: .init(appSettings: ServiceLocator.shared.settings),
userIndicatorController: UserIndicatorControllerMock.default)
} }
} }
@@ -0,0 +1,43 @@
//
// Copyright 2026 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Foundation
import MatrixRustSDK
struct HomeserverCapabilitiesProxy: HomeserverCapabilitiesProxyProtocol {
private let underlyingCapabilities: HomeserverCapabilitiesProtocol
init(underlyingCapabilities: HomeserverCapabilitiesProtocol) {
self.underlyingCapabilities = underlyingCapabilities
}
func refresh() async {
do {
try await underlyingCapabilities.refresh()
} catch {
MXLog.error("Failure refreshing homeserver capabilities: \(error)")
}
}
func canChangeAvatar() async -> Bool {
do {
return try await underlyingCapabilities.canChangeAvatar()
} catch {
MXLog.error("Failure checking canChangeAvatar: \(error)")
return true
}
}
func canChangeDisplayName() async -> Bool {
do {
return try await underlyingCapabilities.canChangeDisplayname()
} catch {
MXLog.error("Failure checking canChangeDisplayName: \(error)")
return true
}
}
}
@@ -0,0 +1,15 @@
//
// Copyright 2026 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Foundation
// sourcery: AutoMockable
protocol HomeserverCapabilitiesProxyProtocol {
func refresh() async
func canChangeAvatar() async -> Bool
func canChangeDisplayName() async -> Bool
}
@@ -64,6 +64,9 @@ class ClientProxy: ClientProxyProtocol {
let spaceService: SpaceServiceProxyProtocol let spaceService: SpaceServiceProxyProtocol
let capabilities: HomeserverCapabilitiesProxyProtocol
private var capabilitiesRefreshTask: Task<Void, Never>?
let eventStringBuilder: RoomEventStringBuilder let eventStringBuilder: RoomEventStringBuilder
private static var roomCreationPowerLevelOverrides: PowerLevels { private static var roomCreationPowerLevelOverrides: PowerLevels {
@@ -208,6 +211,8 @@ class ClientProxy: ClientProxyProtocol {
spaceService = await SpaceServiceProxy(spaceService: client.spaceService()) spaceService = await SpaceServiceProxy(spaceService: client.spaceService())
capabilities = HomeserverCapabilitiesProxy(underlyingCapabilities: client.homeserverCapabilities())
let configuredAppService = try await ClientProxyServices(client: client, let configuredAppService = try await ClientProxyServices(client: client,
actionsSubject: actionsSubject, actionsSubject: actionsSubject,
notificationSettings: notificationSettings, notificationSettings: notificationSettings,
@@ -1122,17 +1127,25 @@ class ClientProxy: ClientProxyProtocol {
MXLog.info("Received room list update: \(state)") MXLog.info("Received room list update: \(state)")
guard state != .error, switch state {
state != .terminated else { case .initial, .settingUp, .recovering:
// The sync service is responsible of handling error and termination break // Don't do anything until we're actually running.
return case .running:
} // Hide the sync spinner as soon as we get any update back
actionsSubject.send(.receivedSyncUpdate)
// Hide the sync spinner as soon as we get any update back
actionsSubject.send(.receivedSyncUpdate) if ignoredUsersSubject.value == nil {
updateIgnoredUsers()
if ignoredUsersSubject.value == nil { }
updateIgnoredUsers()
if capabilitiesRefreshTask == nil {
capabilitiesRefreshTask = Task { [weak self] in
await self?.capabilities.refresh()
self?.capabilitiesRefreshTask = nil
}
}
case .error, .terminated:
break // The sync service is responsible for handling error and termination
} }
}) })
} }
@@ -145,6 +145,8 @@ protocol ClientProxyProtocol: AnyObject {
var spaceService: SpaceServiceProxyProtocol { get } var spaceService: SpaceServiceProxyProtocol { get }
var capabilities: HomeserverCapabilitiesProxyProtocol { get }
var isReportRoomSupported: Bool { get async } var isReportRoomSupported: Bool { get async }
var isLiveKitRTCSupported: Bool { get async } var isLiveKitRTCSupported: Bool { get async }
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:7d8badd2dd08312b2e04f4a2ec0980e4d451739e994b2135397cb39d286f6df3 oid sha256:f96b5709f029227211fc38ae9d8f864a379619caca0862fa9ec0d618dcdb2c87
size 164266 size 163998
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c608fd1aa49c2b8889e4e656fca0a2d854a30c24a8028397d340f5bdfadff466 oid sha256:cc2cc853cd1fe04db02544e9fcff375ff16d67f386e4cef54c51b5abe0638f60
size 186219 size 186061
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ba424bba91c740ab31c3b932edbfff630436d78328a068047a8c5bd9a25bf4c8 oid sha256:12f7c5e3b1b53222a4f8cd64fa7bb3b6d0693857900e5fc731cebef4c67c6d43
size 111949 size 111616
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e33c209512f8651725a93d596ade156df2d5f7c97038996de4bbb12b723f4e1e oid sha256:292be3d2424c93b5f075748551d11eb602bd34063394fa2633628c3d010a449a
size 130775 size 130474
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:715a7d4430435115d3a5547cba02cbbc39e53bb6b3ae7cece245c7ff5930eb25 oid sha256:6688f6f768a79e10416739f92728138560757eaa8ebc073a46fd77fe4f88bcf9
size 157890 size 158414
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1082ce0437aebd4f2ef37d1015dc8aecc1c9b00e680d9b51a8dda0973654e475 oid sha256:3c3ef21335a1ba514dee7c40d3fc418f8514584d258319d5809093bffba9dd3e
size 175400 size 176340
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:47f9a963891948d89163fad6621c6bccaccd83c05e727e1029510e41b3aefa3f oid sha256:10a8e9bc5ba5ed5380d99fc4ba9bc4fa75599bc5b2d015e3a3d8910982a1265d
size 106477 size 107405
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:eb08fcd0fa9d0417ce0ccabc59c944a6c93271a4fcb30e522299cd5029f65174 oid sha256:236c2f150e3ec17220a40cfdf0274c2838f4d390a69009c6bdf934d91aec3a03
size 123464 size 124346
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9f82929e08fd6de3bcf0fc6dee6b5d9002cf257dea39154f4c390d271062708a oid sha256:c3c491d9958bdc80618ecdf132bfa3ee8dbc9b196d19325237fb20b88356a159
size 105800 size 107256
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:f7e010aad7b6a32216890867ecfb5ebf27e3874a048550a17ae643dac881b9e8 oid sha256:2cdc317bbadb121afdb1ea2e80f3253cdb8e66b5c6a8eb9b24fc6cd9c6082682
size 114403 size 115846
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:24137b4c05c27b3f187c49751a8661e3fc48584f42c33f0cf11fdff0b27ec36e oid sha256:b91094e03755f7e90aebc3cd5d50d4a32aed4f34fc67db081668ea554a79a4b0
size 58893 size 60105
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a5ba17de537068bca19958113fe13914e40efb1fb988398a660cf0b2c4c52e29 oid sha256:9c8b8d0fd5fb8d850f187b163f3b740f2f0ca031be5d821d31bc44c4d3a956b7
size 65014 size 66260
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fb17df7d4e302d47a6f272c4084fa12ba3b23b72179ae6aed5950ffa751336e3 oid sha256:62b1fc8176a793e990fcf4417c8daecf53323db7ec965c14b68bbf82852a8db8
size 95822 size 95986
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:0cb2e203539d455b4e2c9a2ba3f1323f438e6ee81afbadd53ee3379f7a32231d oid sha256:cd8a44d0825329a7fbaac6d6008d744e4e2b17581f837cc2235eeede385b4e7d
size 100565 size 100749
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8b539bf77e066b1f77b6cc78aa7f4a7ab55ee00ca66dae552768a4af827839f9 oid sha256:ddbbdb9901075b2387f257ac64f2fc3b5b7a66d8358a93bd7499b1247b8bc226
size 44850 size 44952
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6d74b49996c7b5a5e45b08ca8af7452e7db2d1039f6dae30031a6575c77c03f7 oid sha256:0cbf5e0229996d3b8483338350f9fab528e9a9d9a75588bb59c3ea9fe796cc3b
size 45528 size 45637
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5660e7e8e2923dece48caaba208eb7ece4237ad1aaccbca883ed28e3399fcf47
size 109885
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0e9dd3991f0a06afd9668be98204ba73f1e535367f375901e23436d5d971b923
size 117998
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:03fa5dc84f58f5de19be8543a81b468259033534d2179339368f65757f856c67
size 61315
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5e19131dd759b248f4ebd381370ecd28264260aab9bb86885b40dac0ad72a367
size 67916
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5935c47b199d14f01b5f79c8b0a2adb1122fc48b1790366af480516371e55d12
size 104772
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fa21d6018574f3ed5c99e1b5f50d097c2aa3175cb41a46f0d03a4d303f644d14
size 111214
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2be135c4d993374eba85f7c8035dea2d5318fe199627c4b59fc4af1a31daecb9
size 54325
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:947c3a92b8017c04740212ddd7da98138623c6ca0396b235ec4055ac57d24647
size 59340
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5935c47b199d14f01b5f79c8b0a2adb1122fc48b1790366af480516371e55d12
size 104772
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fa21d6018574f3ed5c99e1b5f50d097c2aa3175cb41a46f0d03a4d303f644d14
size 111214
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2be135c4d993374eba85f7c8035dea2d5318fe199627c4b59fc4af1a31daecb9
size 54325
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:947c3a92b8017c04740212ddd7da98138623c6ca0396b235ec4055ac57d24647
size 59340
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:87f751f1906937a5372763b148c3ec2af1f814a9bd9ed35e9df132c4b251d1b4
size 103332
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9ba30cd0d1605c167647bb337f7c52bbbdf0520a7e29ec7923d8e3ecea356d1e
size 109826
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:17f3c9d0c4f04e69378dd5f467cb5b22493af959aef7668f7cab609b0d622362
size 53189
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e3618e299d568d46eed494e6cf079067876e9cd999c02d376117fc90b9da99db
size 58222