mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
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:
@@ -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 }
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -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?
|
||||||
|
|
||||||
|
|||||||
+2
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-17
@@ -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 }
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5660e7e8e2923dece48caaba208eb7ece4237ad1aaccbca883ed28e3399fcf47
|
||||||
|
size 109885
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:0e9dd3991f0a06afd9668be98204ba73f1e535367f375901e23436d5d971b923
|
||||||
|
size 117998
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:03fa5dc84f58f5de19be8543a81b468259033534d2179339368f65757f856c67
|
||||||
|
size 61315
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5e19131dd759b248f4ebd381370ecd28264260aab9bb86885b40dac0ad72a367
|
||||||
|
size 67916
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5935c47b199d14f01b5f79c8b0a2adb1122fc48b1790366af480516371e55d12
|
||||||
|
size 104772
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:fa21d6018574f3ed5c99e1b5f50d097c2aa3175cb41a46f0d03a4d303f644d14
|
||||||
|
size 111214
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:2be135c4d993374eba85f7c8035dea2d5318fe199627c4b59fc4af1a31daecb9
|
||||||
|
size 54325
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:947c3a92b8017c04740212ddd7da98138623c6ca0396b235ec4055ac57d24647
|
||||||
|
size 59340
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5935c47b199d14f01b5f79c8b0a2adb1122fc48b1790366af480516371e55d12
|
||||||
|
size 104772
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:fa21d6018574f3ed5c99e1b5f50d097c2aa3175cb41a46f0d03a4d303f644d14
|
||||||
|
size 111214
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:2be135c4d993374eba85f7c8035dea2d5318fe199627c4b59fc4af1a31daecb9
|
||||||
|
size 54325
|
||||||
+3
@@ -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
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9ba30cd0d1605c167647bb337f7c52bbbdf0520a7e29ec7923d8e3ecea356d1e
|
|
||||||
size 109826
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:17f3c9d0c4f04e69378dd5f467cb5b22493af959aef7668f7cab609b0d622362
|
|
||||||
size 53189
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:e3618e299d568d46eed494e6cf079067876e9cd999c02d376117fc90b9da99db
|
|
||||||
size 58222
|
|
||||||
Reference in New Issue
Block a user