mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Fix various bugs in the moderation feature. (#2608)
* Fix search field string. * Show your own user as an Admin when changing roles. * Also show invited users when changing roles. * Don't allow admin's to kick/ban other admins or themselves. * Fix a bug when left members were counted as admins/moderators. * Show when a member is pending. * Add sections to the change role screen.
This commit is contained in:
@@ -379,6 +379,7 @@
|
|||||||
5D2AF8C0DF872E7985F8FE54 /* TimelineDeliveryStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AC06FC11B6638F7BF1670E /* TimelineDeliveryStatusView.swift */; };
|
5D2AF8C0DF872E7985F8FE54 /* TimelineDeliveryStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AC06FC11B6638F7BF1670E /* TimelineDeliveryStatusView.swift */; };
|
||||||
5D4643E485C179B2F485C519 /* MentionSuggestionItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FD0E68C42CA7DDCD4CAD68D /* MentionSuggestionItemView.swift */; };
|
5D4643E485C179B2F485C519 /* MentionSuggestionItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FD0E68C42CA7DDCD4CAD68D /* MentionSuggestionItemView.swift */; };
|
||||||
5D53AE9342A4C06B704247ED /* MediaLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */; };
|
5D53AE9342A4C06B704247ED /* MediaLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */; };
|
||||||
|
5D56CE09743C6B90C21B04C2 /* RoomMembersListScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E9E0929CEFA356090BE5FB8 /* RoomMembersListScreenViewModelTests.swift */; };
|
||||||
5D70FAE4D2BF4553AFFFFE41 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; };
|
5D70FAE4D2BF4553AFFFFE41 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; };
|
||||||
5DD0EF30070DC0A82C5CCD33 /* RoomMembersListManageMemberSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC853F9B4FBE039D2C16EC6B /* RoomMembersListManageMemberSheet.swift */; };
|
5DD0EF30070DC0A82C5CCD33 /* RoomMembersListManageMemberSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC853F9B4FBE039D2C16EC6B /* RoomMembersListManageMemberSheet.swift */; };
|
||||||
5DD85A0FE3D85AEC3C7EFE36 /* DeveloperOptionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7C7CFA6B2A62A685FF6CE3 /* DeveloperOptionsScreenCoordinator.swift */; };
|
5DD85A0FE3D85AEC3C7EFE36 /* DeveloperOptionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7C7CFA6B2A62A685FF6CE3 /* DeveloperOptionsScreenCoordinator.swift */; };
|
||||||
@@ -829,7 +830,6 @@
|
|||||||
C9F5B48D15B9BCAE1F8D564E /* RoomNotificationModeProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1511766C534367700C8DD75 /* RoomNotificationModeProxy.swift */; };
|
C9F5B48D15B9BCAE1F8D564E /* RoomNotificationModeProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1511766C534367700C8DD75 /* RoomNotificationModeProxy.swift */; };
|
||||||
CA12AE0DCD57D49CD96C699A /* WaveformCursorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB9EABCA9348DFA27439A809 /* WaveformCursorView.swift */; };
|
CA12AE0DCD57D49CD96C699A /* WaveformCursorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB9EABCA9348DFA27439A809 /* WaveformCursorView.swift */; };
|
||||||
CA5BFF0C2EF5A8EF40CA2D69 /* VoiceMessageRecordingComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCB6F36CCE44A29A06FCAF1C /* VoiceMessageRecordingComposer.swift */; };
|
CA5BFF0C2EF5A8EF40CA2D69 /* VoiceMessageRecordingComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCB6F36CCE44A29A06FCAF1C /* VoiceMessageRecordingComposer.swift */; };
|
||||||
CAF8755E152204F55F8D6B5B /* RoomMembersListViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69B63F817FE305548DB4B512 /* RoomMembersListViewModelTests.swift */; };
|
|
||||||
CB137BFB3E083C33E398A6CB /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 020597E28A4BC8E1BE8EDF6E /* KeychainAccess */; };
|
CB137BFB3E083C33E398A6CB /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 020597E28A4BC8E1BE8EDF6E /* KeychainAccess */; };
|
||||||
CB498F4E27AA0545DCEF0F6F /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 36B7FC232711031AA2B0D188 /* DTCoreText */; };
|
CB498F4E27AA0545DCEF0F6F /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 36B7FC232711031AA2B0D188 /* DTCoreText */; };
|
||||||
CB6BCBF28E4B76EA08C2926D /* StateRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16048D30F0438731C41F775 /* StateRoomTimelineItem.swift */; };
|
CB6BCBF28E4B76EA08C2926D /* StateRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16048D30F0438731C41F775 /* StateRoomTimelineItem.swift */; };
|
||||||
@@ -843,6 +843,7 @@
|
|||||||
CCBEC2100CAF2EEBE9DB4156 /* TemplateScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */; };
|
CCBEC2100CAF2EEBE9DB4156 /* TemplateScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */; };
|
||||||
CD0088B763CD970CF1CBF8CB /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5E97E9615A158C76B2AB77 /* DateTests.swift */; };
|
CD0088B763CD970CF1CBF8CB /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5E97E9615A158C76B2AB77 /* DateTests.swift */; };
|
||||||
CD6A72B65D3B6076F4045C30 /* PHGPostHogConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */; };
|
CD6A72B65D3B6076F4045C30 /* PHGPostHogConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */; };
|
||||||
|
CDAE3A37D4DF136F9D07DB61 /* RoomChangeRolesScreenSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF710CB1C31F8938EAA3A7D /* RoomChangeRolesScreenSection.swift */; };
|
||||||
CDCA8A559E098503DDE29477 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */; };
|
CDCA8A559E098503DDE29477 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */; };
|
||||||
CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; };
|
CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; };
|
||||||
CE6F237360875D3D573FD0B2 /* RoomNotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */; };
|
CE6F237360875D3D573FD0B2 /* RoomNotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */; };
|
||||||
@@ -1355,6 +1356,7 @@
|
|||||||
3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineItem.swift; sourceTree = "<group>"; };
|
3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
3E6A9B9DFEE964962C179DE3 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = "<group>"; };
|
3E6A9B9DFEE964962C179DE3 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = "<group>"; };
|
||||||
3E93A1BE7D8A2EBCAD51EEB4 /* Array.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = "<group>"; };
|
3E93A1BE7D8A2EBCAD51EEB4 /* Array.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = "<group>"; };
|
||||||
|
3E9E0929CEFA356090BE5FB8 /* RoomMembersListScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
3EF1AC723C2609C7705569CA /* MediaLoaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaLoaderTests.swift; sourceTree = "<group>"; };
|
3EF1AC723C2609C7705569CA /* MediaLoaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaLoaderTests.swift; sourceTree = "<group>"; };
|
||||||
3FFDA99C98BE05F43A92343B /* test_pdf.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test_pdf.pdf; sourceTree = "<group>"; };
|
3FFDA99C98BE05F43A92343B /* test_pdf.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test_pdf.pdf; sourceTree = "<group>"; };
|
||||||
40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageMediaManager.swift; sourceTree = "<group>"; };
|
40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageMediaManager.swift; sourceTree = "<group>"; };
|
||||||
@@ -1503,7 +1505,6 @@
|
|||||||
68010886142843705E342645 /* ProgressMaskModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressMaskModifier.swift; sourceTree = "<group>"; };
|
68010886142843705E342645 /* ProgressMaskModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressMaskModifier.swift; sourceTree = "<group>"; };
|
||||||
6861FE915C7B5466E6962BBA /* StartChatScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreen.swift; sourceTree = "<group>"; };
|
6861FE915C7B5466E6962BBA /* StartChatScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreen.swift; sourceTree = "<group>"; };
|
||||||
693E16574C6F7F9FA1015A8C /* Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Search.swift; sourceTree = "<group>"; };
|
693E16574C6F7F9FA1015A8C /* Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Search.swift; sourceTree = "<group>"; };
|
||||||
69B63F817FE305548DB4B512 /* RoomMembersListViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListViewModelTests.swift; sourceTree = "<group>"; };
|
|
||||||
69CB8242D69B7E4D0B32E18D /* AggregatedReactionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AggregatedReactionMock.swift; sourceTree = "<group>"; };
|
69CB8242D69B7E4D0B32E18D /* AggregatedReactionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AggregatedReactionMock.swift; sourceTree = "<group>"; };
|
||||||
69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModelTests.swift; sourceTree = "<group>"; };
|
69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
6A4C9547BBFEEF30AA11329B /* TimelineItemStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemStatusView.swift; sourceTree = "<group>"; };
|
6A4C9547BBFEEF30AA11329B /* TimelineItemStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemStatusView.swift; sourceTree = "<group>"; };
|
||||||
@@ -2009,6 +2010,7 @@
|
|||||||
E9D059BFE329BE09B6D96A9F /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = ro.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
E9D059BFE329BE09B6D96A9F /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = ro.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
EA4D639E27D5882A6A71AECF /* GlobalSearchScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchScreenViewModelTests.swift; sourceTree = "<group>"; };
|
EA4D639E27D5882A6A71AECF /* GlobalSearchScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
EA880E78AF4BD24E45A7808C /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
EA880E78AF4BD24E45A7808C /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
|
EAF710CB1C31F8938EAA3A7D /* RoomChangeRolesScreenSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenSection.swift; sourceTree = "<group>"; };
|
||||||
EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilderTests.swift; sourceTree = "<group>"; };
|
EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilderTests.swift; sourceTree = "<group>"; };
|
||||||
EB63761D9F9CE8B23CBD6179 /* PollFormScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenModels.swift; sourceTree = "<group>"; };
|
EB63761D9F9CE8B23CBD6179 /* PollFormScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenModels.swift; sourceTree = "<group>"; };
|
||||||
EB76A9AFC6CCAD4998D9B045 /* IdentityConfirmationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenViewModel.swift; sourceTree = "<group>"; };
|
EB76A9AFC6CCAD4998D9B045 /* IdentityConfirmationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
@@ -3217,6 +3219,7 @@
|
|||||||
children = (
|
children = (
|
||||||
6B2A421198FD20AAAED20004 /* RoomChangeRolesScreen.swift */,
|
6B2A421198FD20AAAED20004 /* RoomChangeRolesScreen.swift */,
|
||||||
23E6EB7960BC9D0F7396B3BD /* RoomChangeRolesScreenRow.swift */,
|
23E6EB7960BC9D0F7396B3BD /* RoomChangeRolesScreenRow.swift */,
|
||||||
|
EAF710CB1C31F8938EAA3A7D /* RoomChangeRolesScreenSection.swift */,
|
||||||
3D9B45D584D232CB9E5C7734 /* RoomChangeRolesScreenSelectedItem.swift */,
|
3D9B45D584D232CB9E5C7734 /* RoomChangeRolesScreenSelectedItem.swift */,
|
||||||
);
|
);
|
||||||
path = View;
|
path = View;
|
||||||
@@ -3494,7 +3497,7 @@
|
|||||||
4FCB2126C091EEF2454B4D56 /* RoomFlowCoordinatorTests.swift */,
|
4FCB2126C091EEF2454B4D56 /* RoomFlowCoordinatorTests.swift */,
|
||||||
8AE0C9653870803E4F91F474 /* RoomListFiltersStateTests.swift */,
|
8AE0C9653870803E4F91F474 /* RoomListFiltersStateTests.swift */,
|
||||||
EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */,
|
EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */,
|
||||||
69B63F817FE305548DB4B512 /* RoomMembersListViewModelTests.swift */,
|
3E9E0929CEFA356090BE5FB8 /* RoomMembersListScreenViewModelTests.swift */,
|
||||||
58D295F0081084F38DB20893 /* RoomNotificationSettingsScreenViewModelTests.swift */,
|
58D295F0081084F38DB20893 /* RoomNotificationSettingsScreenViewModelTests.swift */,
|
||||||
F0096BC5DA86AF6B6E5742AC /* RoomPermissionsTests.swift */,
|
F0096BC5DA86AF6B6E5742AC /* RoomPermissionsTests.swift */,
|
||||||
B40233F2989AD49906BB310D /* RoomPollsHistoryScreenViewModelTests.swift */,
|
B40233F2989AD49906BB310D /* RoomPollsHistoryScreenViewModelTests.swift */,
|
||||||
@@ -5632,7 +5635,7 @@
|
|||||||
095D3906CF2F940C2D2D17CC /* RoomFlowCoordinatorTests.swift in Sources */,
|
095D3906CF2F940C2D2D17CC /* RoomFlowCoordinatorTests.swift in Sources */,
|
||||||
4C8C0C9FC10BA73AB7780534 /* RoomListFiltersStateTests.swift in Sources */,
|
4C8C0C9FC10BA73AB7780534 /* RoomListFiltersStateTests.swift in Sources */,
|
||||||
6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */,
|
6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */,
|
||||||
CAF8755E152204F55F8D6B5B /* RoomMembersListViewModelTests.swift in Sources */,
|
5D56CE09743C6B90C21B04C2 /* RoomMembersListScreenViewModelTests.swift in Sources */,
|
||||||
E49F74BD93230BDEFFE5EA51 /* RoomNotificationSettingsScreenViewModelTests.swift in Sources */,
|
E49F74BD93230BDEFFE5EA51 /* RoomNotificationSettingsScreenViewModelTests.swift in Sources */,
|
||||||
2335D1AB954C151FD8779F45 /* RoomPermissionsTests.swift in Sources */,
|
2335D1AB954C151FD8779F45 /* RoomPermissionsTests.swift in Sources */,
|
||||||
7B1605C6FFD4D195F264A684 /* RoomPollsHistoryScreenViewModelTests.swift in Sources */,
|
7B1605C6FFD4D195F264A684 /* RoomPollsHistoryScreenViewModelTests.swift in Sources */,
|
||||||
@@ -6121,6 +6124,7 @@
|
|||||||
244407B18B2F2D6466BA5961 /* RoomChangeRolesScreenCoordinator.swift in Sources */,
|
244407B18B2F2D6466BA5961 /* RoomChangeRolesScreenCoordinator.swift in Sources */,
|
||||||
7FF6E1FBE6E9517FD29A1D8E /* RoomChangeRolesScreenModels.swift in Sources */,
|
7FF6E1FBE6E9517FD29A1D8E /* RoomChangeRolesScreenModels.swift in Sources */,
|
||||||
7F941B063C94E1718DFC2CF3 /* RoomChangeRolesScreenRow.swift in Sources */,
|
7F941B063C94E1718DFC2CF3 /* RoomChangeRolesScreenRow.swift in Sources */,
|
||||||
|
CDAE3A37D4DF136F9D07DB61 /* RoomChangeRolesScreenSection.swift in Sources */,
|
||||||
BD6685592716CA957D7BAAC4 /* RoomChangeRolesScreenSelectedItem.swift in Sources */,
|
BD6685592716CA957D7BAAC4 /* RoomChangeRolesScreenSelectedItem.swift in Sources */,
|
||||||
3EC5A41F9FB7DD63A4DC6144 /* RoomChangeRolesScreenViewModel.swift in Sources */,
|
3EC5A41F9FB7DD63A4DC6144 /* RoomChangeRolesScreenViewModel.swift in Sources */,
|
||||||
4E36A66E0EDA74BF3A036FD0 /* RoomChangeRolesScreenViewModelProtocol.swift in Sources */,
|
4E36A66E0EDA74BF3A036FD0 /* RoomChangeRolesScreenViewModelProtocol.swift in Sources */,
|
||||||
|
|||||||
@@ -519,6 +519,7 @@
|
|||||||
"screen_room_change_role_confirm_demote_self_action" = "Demote";
|
"screen_room_change_role_confirm_demote_self_action" = "Demote";
|
||||||
"screen_room_change_role_confirm_demote_self_description" = "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.";
|
"screen_room_change_role_confirm_demote_self_description" = "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.";
|
||||||
"screen_room_change_role_confirm_demote_self_title" = "Demote yourself?";
|
"screen_room_change_role_confirm_demote_self_title" = "Demote yourself?";
|
||||||
|
"screen_room_change_role_invited_member_name" = "%1$@ (Pending)";
|
||||||
"screen_room_change_role_moderators_title" = "Edit Moderators";
|
"screen_room_change_role_moderators_title" = "Edit Moderators";
|
||||||
"screen_room_change_role_unsaved_changes_description" = "You have unsaved changes.";
|
"screen_room_change_role_unsaved_changes_description" = "You have unsaved changes.";
|
||||||
"screen_room_change_role_unsaved_changes_title" = "Save changes?";
|
"screen_room_change_role_unsaved_changes_title" = "Save changes?";
|
||||||
@@ -793,6 +794,9 @@
|
|||||||
"screen_room_change_permissions_member_moderation" = "Member moderation";
|
"screen_room_change_permissions_member_moderation" = "Member moderation";
|
||||||
"screen_room_change_permissions_messages_and_content" = "Messages and content";
|
"screen_room_change_permissions_messages_and_content" = "Messages and content";
|
||||||
"screen_room_change_permissions_room_details" = "Room details";
|
"screen_room_change_permissions_room_details" = "Room details";
|
||||||
|
"screen_room_change_role_section_administrators" = "Admins";
|
||||||
|
"screen_room_change_role_section_moderators" = "Moderators";
|
||||||
|
"screen_room_change_role_section_users" = "Members";
|
||||||
"screen_room_details_invite_people_title" = "Invite people";
|
"screen_room_details_invite_people_title" = "Invite people";
|
||||||
"screen_room_details_leave_conversation_title" = "Leave conversation";
|
"screen_room_details_leave_conversation_title" = "Leave conversation";
|
||||||
"screen_room_details_leave_room_title" = "Leave room";
|
"screen_room_details_leave_room_title" = "Leave room";
|
||||||
|
|||||||
@@ -1263,8 +1263,18 @@ internal enum L10n {
|
|||||||
internal static var screenRoomChangeRoleConfirmDemoteSelfDescription: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_demote_self_description") }
|
internal static var screenRoomChangeRoleConfirmDemoteSelfDescription: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_demote_self_description") }
|
||||||
/// Demote yourself?
|
/// Demote yourself?
|
||||||
internal static var screenRoomChangeRoleConfirmDemoteSelfTitle: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_demote_self_title") }
|
internal static var screenRoomChangeRoleConfirmDemoteSelfTitle: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_demote_self_title") }
|
||||||
|
/// %1$@ (Pending)
|
||||||
|
internal static func screenRoomChangeRoleInvitedMemberName(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "screen_room_change_role_invited_member_name", String(describing: p1))
|
||||||
|
}
|
||||||
/// Edit Moderators
|
/// Edit Moderators
|
||||||
internal static var screenRoomChangeRoleModeratorsTitle: String { return L10n.tr("Localizable", "screen_room_change_role_moderators_title") }
|
internal static var screenRoomChangeRoleModeratorsTitle: String { return L10n.tr("Localizable", "screen_room_change_role_moderators_title") }
|
||||||
|
/// Admins
|
||||||
|
internal static var screenRoomChangeRoleSectionAdministrators: String { return L10n.tr("Localizable", "screen_room_change_role_section_administrators") }
|
||||||
|
/// Moderators
|
||||||
|
internal static var screenRoomChangeRoleSectionModerators: String { return L10n.tr("Localizable", "screen_room_change_role_section_moderators") }
|
||||||
|
/// Members
|
||||||
|
internal static var screenRoomChangeRoleSectionUsers: String { return L10n.tr("Localizable", "screen_room_change_role_section_users") }
|
||||||
/// You have unsaved changes.
|
/// You have unsaved changes.
|
||||||
internal static var screenRoomChangeRoleUnsavedChangesDescription: String { return L10n.tr("Localizable", "screen_room_change_role_unsaved_changes_description") }
|
internal static var screenRoomChangeRoleUnsavedChangesDescription: String { return L10n.tr("Localizable", "screen_room_change_role_unsaved_changes_description") }
|
||||||
/// Save changes?
|
/// Save changes?
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ extension RoomMemberProxyMock {
|
|||||||
|
|
||||||
static var mockMeAdmin: RoomMemberProxyMock {
|
static var mockMeAdmin: RoomMemberProxyMock {
|
||||||
RoomMemberProxyMock(with: .init(userID: "@me:matrix.org",
|
RoomMemberProxyMock(with: .init(userID: "@me:matrix.org",
|
||||||
displayName: "Me admin",
|
displayName: "Me",
|
||||||
avatarURL: URL.picturesDirectory,
|
avatarURL: URL.picturesDirectory,
|
||||||
membership: .join,
|
membership: .join,
|
||||||
powerLevel: 100,
|
powerLevel: 100,
|
||||||
|
|||||||
@@ -24,8 +24,13 @@ enum RoomChangeRolesScreenViewModelAction {
|
|||||||
struct RoomChangeRolesScreenViewState: BindableState {
|
struct RoomChangeRolesScreenViewState: BindableState {
|
||||||
/// The screen's current mode (which role we are promoting/demoting users to/from.
|
/// The screen's current mode (which role we are promoting/demoting users to/from.
|
||||||
let mode: RoomMemberDetails.Role
|
let mode: RoomMemberDetails.Role
|
||||||
/// All of the room's members.
|
/// All of the room's members who are currently admins.
|
||||||
var members: [RoomMemberDetails]
|
var administrators: [RoomMemberDetails]
|
||||||
|
/// All of the room's members who are currently moderators.
|
||||||
|
var moderators: [RoomMemberDetails]
|
||||||
|
/// All of the room's members who are currently neither an admin or moderator.
|
||||||
|
var users: [RoomMemberDetails]
|
||||||
|
|
||||||
var bindings: RoomChangeRolesScreenViewStateBindings
|
var bindings: RoomChangeRolesScreenViewStateBindings
|
||||||
|
|
||||||
/// The members selected for promotion to the current role.
|
/// The members selected for promotion to the current role.
|
||||||
@@ -48,19 +53,24 @@ struct RoomChangeRolesScreenViewState: BindableState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The visible members in the screen (after searching).
|
/// The visible admins in the screen (after searching).
|
||||||
var visibleMembers: [RoomMemberDetails] {
|
var visibleAdministrators: [RoomMemberDetails] {
|
||||||
guard !bindings.searchQuery.isEmpty else { return members }
|
administrators.filter { $0.matches(searchQuery: bindings.searchQuery) }
|
||||||
|
}
|
||||||
return members.filter { member in
|
|
||||||
member.name?.localizedStandardContains(bindings.searchQuery) == true
|
/// The visible mods in the screen (after searching).
|
||||||
|| member.id.localizedStandardContains(bindings.searchQuery)
|
var visibleModerators: [RoomMemberDetails] {
|
||||||
}
|
moderators.filter { $0.matches(searchQuery: bindings.searchQuery) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The visible regular users in the screen (after searching).
|
||||||
|
var visibleUsers: [RoomMemberDetails] {
|
||||||
|
users.filter { $0.matches(searchQuery: bindings.searchQuery) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All of the members who will gain/keep this screen's role after saving any changes.
|
/// All of the members who will gain/keep this screen's role after saving any changes.
|
||||||
var membersWithRole: [RoomMemberDetails] {
|
var membersWithRole: [RoomMemberDetails] {
|
||||||
members.filter(isMemberSelected)
|
administrators.filter(isMemberSelected) + moderators.filter(isMemberSelected) + users.filter(isMemberSelected)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not any changes have been made to the members.
|
/// Whether or not any changes have been made to the members.
|
||||||
|
|||||||
+23
-4
@@ -40,7 +40,9 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh
|
|||||||
self.analytics = analytics
|
self.analytics = analytics
|
||||||
|
|
||||||
super.init(initialViewState: RoomChangeRolesScreenViewState(mode: mode,
|
super.init(initialViewState: RoomChangeRolesScreenViewState(mode: mode,
|
||||||
members: [],
|
administrators: [],
|
||||||
|
moderators: [],
|
||||||
|
users: [],
|
||||||
bindings: .init()))
|
bindings: .init()))
|
||||||
|
|
||||||
roomProxy.membersPublisher
|
roomProxy.membersPublisher
|
||||||
@@ -82,10 +84,27 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func updateMembers(_ members: [RoomMemberProxyProtocol]) {
|
private func updateMembers(_ members: [RoomMemberProxyProtocol]) {
|
||||||
state.members = members.sorted().compactMap { member in
|
var administrators = [RoomMemberDetails]()
|
||||||
guard member.membership == .join, member.userID != roomProxy.ownUserID else { return nil }
|
var moderators = [RoomMemberDetails]()
|
||||||
return RoomMemberDetails(withProxy: member)
|
var users = [RoomMemberDetails]()
|
||||||
|
|
||||||
|
for member in members.sorted() {
|
||||||
|
guard member.isActive else { continue }
|
||||||
|
let memberDetails = RoomMemberDetails(withProxy: member)
|
||||||
|
|
||||||
|
switch member.role {
|
||||||
|
case .administrator:
|
||||||
|
administrators.append(memberDetails)
|
||||||
|
case .moderator:
|
||||||
|
moderators.append(memberDetails)
|
||||||
|
case .user:
|
||||||
|
users.append(memberDetails)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.administrators = administrators
|
||||||
|
state.moderators = moderators
|
||||||
|
state.users = users
|
||||||
}
|
}
|
||||||
|
|
||||||
private func toggleMember(_ member: RoomMemberDetails) {
|
private func toggleMember(_ member: RoomMemberDetails) {
|
||||||
|
|||||||
@@ -56,34 +56,20 @@ struct RoomChangeRolesScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
membersSection
|
RoomChangeRolesScreenSection(members: context.viewState.administrators,
|
||||||
|
title: L10n.screenRoomChangeRoleSectionAdministrators,
|
||||||
|
context: context)
|
||||||
|
RoomChangeRolesScreenSection(members: context.viewState.moderators,
|
||||||
|
title: L10n.screenRoomChangeRoleSectionModerators,
|
||||||
|
context: context)
|
||||||
|
RoomChangeRolesScreenSection(members: context.viewState.users,
|
||||||
|
title: L10n.screenRoomChangeRoleSectionUsers,
|
||||||
|
context: context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var membersSection: some View {
|
|
||||||
if !context.viewState.visibleMembers.isEmpty {
|
|
||||||
Section {
|
|
||||||
ForEach(context.viewState.visibleMembers, id: \.id) { member in
|
|
||||||
RoomChangeRolesScreenRow(member: member,
|
|
||||||
imageProvider: context.imageProvider,
|
|
||||||
isSelected: context.viewState.isMemberSelected(member)) {
|
|
||||||
context.send(viewAction: .toggleMember(member))
|
|
||||||
}
|
|
||||||
.disabled(member.role == .administrator)
|
|
||||||
}
|
|
||||||
} header: {
|
|
||||||
Text(L10n.screenRoomMemberListRoomMembersHeaderTitle)
|
|
||||||
.compoundListSectionHeader()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Section.empty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ScaledMetric private var cellWidth: CGFloat = 72
|
@ScaledMetric private var cellWidth: CGFloat = 72
|
||||||
|
|
||||||
private var membersWithRoleSection: some View {
|
private var membersWithRoleSection: some View {
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
ScrollViewReader { scrollView in
|
ScrollViewReader { scrollView in
|
||||||
|
|||||||
@@ -28,10 +28,20 @@ struct RoomChangeRolesScreenRow: View {
|
|||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ListRow(label: .avatar(title: member.name ?? member.id,
|
ListRow(label: .avatar(title: memberName,
|
||||||
description: member.name == nil ? nil : member.id,
|
description: member.name == nil ? nil : member.id,
|
||||||
icon: avatar),
|
icon: avatar),
|
||||||
kind: isEnabled ? .multiSelection(isSelected: isSelected, action: action) : .label)
|
kind: .multiSelection(isSelected: isSelected, action: action))
|
||||||
|
}
|
||||||
|
|
||||||
|
var memberName: String {
|
||||||
|
let name = member.name ?? member.id
|
||||||
|
|
||||||
|
return if member.isInvited {
|
||||||
|
L10n.screenRoomChangeRoleInvitedMemberName(name)
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var avatar: LoadableAvatarImage {
|
var avatar: LoadableAvatarImage {
|
||||||
@@ -58,6 +68,11 @@ struct RoomChangeRolesScreenRow_Previews: PreviewProvider, TestablePreview {
|
|||||||
isSelected: false,
|
isSelected: false,
|
||||||
action: action)
|
action: action)
|
||||||
|
|
||||||
|
RoomChangeRolesScreenRow(member: .init(withProxy: RoomMemberProxyMock.mockInvited),
|
||||||
|
imageProvider: MockMediaProvider(),
|
||||||
|
isSelected: false,
|
||||||
|
action: action)
|
||||||
|
|
||||||
RoomChangeRolesScreenRow(member: .init(withProxy: RoomMemberProxyMock.mockCharlie),
|
RoomChangeRolesScreenRow(member: .init(withProxy: RoomMemberProxyMock.mockCharlie),
|
||||||
imageProvider: MockMediaProvider(),
|
imageProvider: MockMediaProvider(),
|
||||||
isSelected: true,
|
isSelected: true,
|
||||||
|
|||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2024 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct RoomChangeRolesScreenSection: View {
|
||||||
|
let members: [RoomMemberDetails]
|
||||||
|
let title: String
|
||||||
|
|
||||||
|
@ObservedObject var context: RoomChangeRolesScreenViewModel.Context
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if !members.isEmpty {
|
||||||
|
Section {
|
||||||
|
ForEach(members, id: \.id) { member in
|
||||||
|
RoomChangeRolesScreenRow(member: member,
|
||||||
|
imageProvider: context.imageProvider,
|
||||||
|
isSelected: context.viewState.isMemberSelected(member)) {
|
||||||
|
context.send(viewAction: .toggleMember(member))
|
||||||
|
}
|
||||||
|
.disabled(member.role == .administrator)
|
||||||
|
}
|
||||||
|
} header: {
|
||||||
|
Text(title)
|
||||||
|
.compoundListSectionHeader()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,15 @@ import Foundation
|
|||||||
enum RoomMembersListScreenViewModelAction {
|
enum RoomMembersListScreenViewModelAction {
|
||||||
case selectMember(_ member: RoomMemberProxyProtocol)
|
case selectMember(_ member: RoomMemberProxyProtocol)
|
||||||
case invite
|
case invite
|
||||||
|
|
||||||
|
var isSelectMember: Bool {
|
||||||
|
switch self {
|
||||||
|
case .selectMember:
|
||||||
|
true
|
||||||
|
default:
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The different modes that the screen can be in.
|
/// The different modes that the screen can be in.
|
||||||
@@ -54,7 +63,7 @@ struct RoomMembersListScreenViewState: BindableState {
|
|||||||
self.bannedMembers = bannedMembers
|
self.bannedMembers = bannedMembers
|
||||||
self.bindings = bindings
|
self.bindings = bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
var visibleJoinedMembers: [RoomMemberDetails] {
|
var visibleJoinedMembers: [RoomMemberDetails] {
|
||||||
joinedMembers
|
joinedMembers
|
||||||
.filter { $0.matches(searchQuery: bindings.searchQuery) }
|
.filter { $0.matches(searchQuery: bindings.searchQuery) }
|
||||||
@@ -76,12 +85,25 @@ struct RoomMembersListScreenViewStateBindings {
|
|||||||
/// The current mode the screen is in.
|
/// The current mode the screen is in.
|
||||||
var mode: RoomMembersListScreenMode = .members
|
var mode: RoomMembersListScreenMode = .members
|
||||||
/// A selected member to kick, ban, promote etc.
|
/// A selected member to kick, ban, promote etc.
|
||||||
var memberToManage: RoomMemberDetails?
|
var memberToManage: RoomMembersListScreenManagementDetails?
|
||||||
|
|
||||||
/// Information describing the currently displayed alert.
|
/// Information describing the currently displayed alert.
|
||||||
var alertInfo: AlertInfo<RoomMembersListScreenAlertType>?
|
var alertInfo: AlertInfo<RoomMembersListScreenAlertType>?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about managing a particular room member.
|
||||||
|
struct RoomMembersListScreenManagementDetails: Identifiable {
|
||||||
|
var id: String { member.id }
|
||||||
|
|
||||||
|
/// The member that is being managed.
|
||||||
|
let member: RoomMemberDetails
|
||||||
|
|
||||||
|
/// A management action that can be performed on the member.
|
||||||
|
enum Action { case kick, ban }
|
||||||
|
/// The management actions available for `member`.
|
||||||
|
let actions: [Action]
|
||||||
|
}
|
||||||
|
|
||||||
enum RoomMembersListScreenViewAction {
|
enum RoomMembersListScreenViewAction {
|
||||||
case selectMember(RoomMemberDetails)
|
case selectMember(RoomMemberDetails)
|
||||||
case showMemberDetails(RoomMemberDetails)
|
case showMemberDetails(RoomMemberDetails)
|
||||||
@@ -94,13 +116,3 @@ enum RoomMembersListScreenViewAction {
|
|||||||
enum RoomMembersListScreenAlertType: Hashable {
|
enum RoomMembersListScreenAlertType: Hashable {
|
||||||
case unbanConfirmation(RoomMemberDetails)
|
case unbanConfirmation(RoomMemberDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension RoomMemberDetails {
|
|
||||||
func matches(searchQuery: String) -> Bool {
|
|
||||||
guard !searchQuery.isEmpty else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return id.localizedCaseInsensitiveContains(searchQuery) || name?.localizedCaseInsensitiveContains(searchQuery) ?? false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+26
-12
@@ -149,18 +149,32 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func selectMember(_ member: RoomMemberDetails) {
|
private func selectMember(_ member: RoomMemberDetails) {
|
||||||
if appSettings.roomModerationEnabled, state.canKickUsers || state.canBanUsers {
|
guard appSettings.roomModerationEnabled else {
|
||||||
if member.isBanned {
|
showMemberDetails(member)
|
||||||
state.bindings.alertInfo = AlertInfo(id: .unbanConfirmation(member),
|
return
|
||||||
title: L10n.screenRoomMemberListManageMemberUnbanTitle,
|
}
|
||||||
message: L10n.screenRoomMemberListManageMemberUnbanMessage,
|
|
||||||
primaryButton: .init(title: L10n.screenRoomMemberListManageMemberUnbanAction) { [weak self] in
|
if member.isBanned { // No need to check canBan here, banned users are only shown when it is true.
|
||||||
self?.context.send(viewAction: .unbanMember(member))
|
state.bindings.alertInfo = AlertInfo(id: .unbanConfirmation(member),
|
||||||
},
|
title: L10n.screenRoomMemberListManageMemberUnbanTitle,
|
||||||
secondaryButton: .init(title: L10n.actionCancel, role: .cancel) { })
|
message: L10n.screenRoomMemberListManageMemberUnbanMessage,
|
||||||
} else {
|
primaryButton: .init(title: L10n.screenRoomMemberListManageMemberUnbanAction) { [weak self] in
|
||||||
state.bindings.memberToManage = member
|
self?.context.send(viewAction: .unbanMember(member))
|
||||||
}
|
},
|
||||||
|
secondaryButton: .init(title: L10n.actionCancel, role: .cancel) { })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var actions = [RoomMembersListScreenManagementDetails.Action]()
|
||||||
|
if state.canKickUsers, member.role != .administrator {
|
||||||
|
actions.append(.kick)
|
||||||
|
}
|
||||||
|
if state.canBanUsers, member.role != .administrator {
|
||||||
|
actions.append(.ban)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !actions.isEmpty {
|
||||||
|
state.bindings.memberToManage = .init(member: member, actions: actions)
|
||||||
} else {
|
} else {
|
||||||
showMemberDetails(member)
|
showMemberDetails(member)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-2
@@ -19,6 +19,8 @@ import SwiftUI
|
|||||||
|
|
||||||
struct RoomMembersListManageMemberSheet: View {
|
struct RoomMembersListManageMemberSheet: View {
|
||||||
let member: RoomMemberDetails
|
let member: RoomMemberDetails
|
||||||
|
let actions: [RoomMembersListScreenManagementDetails.Action]
|
||||||
|
|
||||||
@ObservedObject var context: RoomMembersListScreenViewModel.Context
|
@ObservedObject var context: RoomMembersListScreenViewModel.Context
|
||||||
|
|
||||||
@State private var isPresentingBanConfirmation = false
|
@State private var isPresentingBanConfirmation = false
|
||||||
@@ -38,7 +40,7 @@ struct RoomMembersListManageMemberSheet: View {
|
|||||||
context.send(viewAction: .showMemberDetails(member))
|
context.send(viewAction: .showMemberDetails(member))
|
||||||
})
|
})
|
||||||
|
|
||||||
if context.viewState.canKickUsers, !member.isBanned {
|
if actions.contains(.kick) {
|
||||||
ListRow(label: .default(title: L10n.screenRoomMemberListManageMemberRemove,
|
ListRow(label: .default(title: L10n.screenRoomMemberListManageMemberRemove,
|
||||||
icon: \.close),
|
icon: \.close),
|
||||||
kind: .button {
|
kind: .button {
|
||||||
@@ -46,7 +48,7 @@ struct RoomMembersListManageMemberSheet: View {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if context.viewState.canBanUsers, !member.isBanned {
|
if actions.contains(.ban) {
|
||||||
ListRow(label: .default(title: L10n.screenRoomMemberListManageMemberBan,
|
ListRow(label: .default(title: L10n.screenRoomMemberListManageMemberBan,
|
||||||
icon: \.block,
|
icon: \.block,
|
||||||
role: .destructive),
|
role: .destructive),
|
||||||
@@ -76,11 +78,13 @@ struct RoomMembersListManageMemberSheet_Previews: PreviewProvider, TestablePrevi
|
|||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockDan),
|
RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockDan),
|
||||||
|
actions: [.kick, .ban],
|
||||||
context: viewModel.context)
|
context: viewModel.context)
|
||||||
.previewDisplayName("Joined")
|
.previewDisplayName("Joined")
|
||||||
.snapshot(delay: 0.2)
|
.snapshot(delay: 0.2)
|
||||||
|
|
||||||
RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockBanned[3]),
|
RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockBanned[3]),
|
||||||
|
actions: [],
|
||||||
context: viewModel.context)
|
context: viewModel.context)
|
||||||
.previewDisplayName("Banned")
|
.previewDisplayName("Banned")
|
||||||
.snapshot(delay: 0.2)
|
.snapshot(delay: 0.2)
|
||||||
@@ -94,6 +98,7 @@ struct RoomMembersListManageMemberSheetLive_Previews: PreviewProvider {
|
|||||||
Color.clear
|
Color.clear
|
||||||
.sheet(isPresented: .constant(true)) {
|
.sheet(isPresented: .constant(true)) {
|
||||||
RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockDan),
|
RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockDan),
|
||||||
|
actions: [.kick, .ban],
|
||||||
context: viewModel.context)
|
context: viewModel.context)
|
||||||
}
|
}
|
||||||
.previewDisplayName("Sheet")
|
.previewDisplayName("Sheet")
|
||||||
|
|||||||
@@ -49,13 +49,15 @@ struct RoomMembersListScreen: View {
|
|||||||
.background(.compound.bgCanvasDefault)
|
.background(.compound.bgCanvasDefault)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.searchable(text: $context.searchQuery, placement: .navigationBarDrawer(displayMode: .always))
|
.searchable(text: $context.searchQuery,
|
||||||
|
placement: .navigationBarDrawer(displayMode: .always),
|
||||||
|
prompt: L10n.commonSearchForSomeone)
|
||||||
.compoundSearchField()
|
.compoundSearchField()
|
||||||
.autocorrectionDisabled()
|
.autocorrectionDisabled()
|
||||||
.background(Color.compound.bgCanvasDefault.ignoresSafeArea())
|
.background(Color.compound.bgCanvasDefault.ignoresSafeArea())
|
||||||
.navigationTitle(L10n.commonPeople)
|
.navigationTitle(L10n.commonPeople)
|
||||||
.sheet(item: $context.memberToManage) {
|
.sheet(item: $context.memberToManage) {
|
||||||
RoomMembersListManageMemberSheet(member: $0, context: context)
|
RoomMembersListManageMemberSheet(member: $0.member, actions: $0.actions, context: context)
|
||||||
}
|
}
|
||||||
.alert(item: $context.alertInfo)
|
.alert(item: $context.alertInfo)
|
||||||
.toolbar { toolbar }
|
.toolbar { toolbar }
|
||||||
|
|||||||
+2
-2
@@ -94,8 +94,8 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
// MARK: - Members
|
// MARK: - Members
|
||||||
|
|
||||||
private func updateMembers(_ members: [RoomMemberProxyProtocol]) {
|
private func updateMembers(_ members: [RoomMemberProxyProtocol]) {
|
||||||
state.administratorCount = members.filter { $0.role == .administrator }.count
|
state.administratorCount = members.filter { $0.role == .administrator && $0.isActive }.count
|
||||||
state.moderatorCount = members.filter { $0.role == .moderator }.count
|
state.moderatorCount = members.filter { $0.role == .moderator && $0.isActive }.count
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateOwnRole(_ role: RoomMemberDetails.Role) async {
|
private func updateOwnRole(_ role: RoomMemberDetails.Role) async {
|
||||||
|
|||||||
@@ -23,11 +23,17 @@ struct RoomMemberDetails: Identifiable, Hashable {
|
|||||||
let avatarURL: URL?
|
let avatarURL: URL?
|
||||||
let permalink: URL?
|
let permalink: URL?
|
||||||
|
|
||||||
|
var isInvited: Bool
|
||||||
var isIgnored: Bool
|
var isIgnored: Bool
|
||||||
var isBanned: Bool
|
var isBanned: Bool
|
||||||
|
|
||||||
enum Role { case administrator, moderator, user }
|
enum Role { case administrator, moderator, user }
|
||||||
let role: Role
|
let role: Role
|
||||||
|
|
||||||
|
func matches(searchQuery: String) -> Bool {
|
||||||
|
guard !searchQuery.isEmpty else { return true }
|
||||||
|
return id.localizedStandardContains(searchQuery) || name?.localizedStandardContains(searchQuery) == true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RoomMemberDetails {
|
extension RoomMemberDetails {
|
||||||
@@ -37,6 +43,7 @@ extension RoomMemberDetails {
|
|||||||
avatarURL = proxy.avatarURL
|
avatarURL = proxy.avatarURL
|
||||||
permalink = proxy.permalink
|
permalink = proxy.permalink
|
||||||
|
|
||||||
|
isInvited = proxy.membership == .invite
|
||||||
isIgnored = proxy.isIgnored
|
isIgnored = proxy.isIgnored
|
||||||
isBanned = proxy.membership == .ban
|
isBanned = proxy.membership == .ban
|
||||||
role = .init(proxy.role)
|
role = .init(proxy.role)
|
||||||
@@ -48,6 +55,7 @@ extension RoomMemberDetails {
|
|||||||
avatarURL = nil
|
avatarURL = nil
|
||||||
permalink = nil
|
permalink = nil
|
||||||
|
|
||||||
|
isInvited = false
|
||||||
isIgnored = false
|
isIgnored = false
|
||||||
isBanned = false
|
isBanned = false
|
||||||
role = .user
|
role = .user
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ protocol RoomMemberProxyProtocol: AnyObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension RoomMemberProxyProtocol {
|
extension RoomMemberProxyProtocol {
|
||||||
|
/// The member is active in the room (joined or invited).
|
||||||
|
var isActive: Bool {
|
||||||
|
membership == .join || membership == .invite
|
||||||
|
}
|
||||||
|
|
||||||
var permalink: URL? {
|
var permalink: URL? {
|
||||||
try? PermalinkBuilder.permalinkTo(userIdentifier: userID,
|
try? PermalinkBuilder.permalinkTo(userIdentifier: userID,
|
||||||
baseURL: ServiceLocator.shared.settings.permalinkBaseURL)
|
baseURL: ServiceLocator.shared.settings.permalinkBaseURL)
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0c7d3ddb84e8a174c27229f31bf494b120974b261344fef7b5450d42cc2803e9
|
oid sha256:8f8a5ad7a853f08fa0624ca707c41b56f7fbc2075ac66631c32e0e3118ea9b9a
|
||||||
size 209697
|
size 207428
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:100cb0d5858afe432962fac47fc2d7c7fba630906641c62a966594aed7d2bd73
|
oid sha256:6c2bfebcfb57baa6582ca914e3380ca382b4017c758b7c7b2af90a9680e7ddbb
|
||||||
size 214948
|
size 206724
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:237abad46072702cfac2c1e6b4f02acb17d8aa7eb65a227646864bf6a5d2fa5a
|
oid sha256:89d3928a5ae405e6f1b695044b54f94aedb3ddfce583b6ba2e2b667c4eeba157
|
||||||
size 229595
|
size 233785
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d4ff8f0b3b8f3829d2c986d81c2074ecaf5737e7bc12373f6fc5378ef4f3625a
|
oid sha256:2dd12a574b0287d8f3d4342fb207c76321fa2e8cf9b8f9773463ee1686f13211
|
||||||
size 236011
|
size 234107
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:7d46021802ef0edebab273fe747f567e2637b36e0e2637f596747d989256a388
|
oid sha256:143c3399a49fd85bedeee78a0f739189208a2500b339afc07cc5bc6cc99ed686
|
||||||
size 148810
|
size 156940
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:facb67a406d2932c70baf4873ff217d1267e29100bd9dcd11235f8d097b4291a
|
oid sha256:92fe524e9a4fb9115fadc5e43f5f89d950573d6a0750fb83e87f61a729781a06
|
||||||
size 152563
|
size 156764
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:fa33656ad1cad730ed07709c2529a70931b9e8d8b26f43d947e4143e7034b6bc
|
oid sha256:dc861092e7490dbd5fe06a541dbcd1dd46aa378dd41015e6e6619f0158f88843
|
||||||
size 166950
|
size 180421
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:56767f44df9037d6d089761ad9a1424e6859fc4095b5479c4726fda566871134
|
oid sha256:274993576e92cd103dced5b43595d4ae234811a49a0d20cf4fffc58fbf0bed7b
|
||||||
size 169884
|
size 179459
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:7fe77092cf19d88dd1e8da9aca24e6cfab3e9abacfa19574a6cdcd51b29a5f5c
|
oid sha256:9d015139ff3d614fe612060872d9214c5215255f11363152232ffe75a5ed9a79
|
||||||
size 149249
|
size 171955
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:7fe77092cf19d88dd1e8da9aca24e6cfab3e9abacfa19574a6cdcd51b29a5f5c
|
oid sha256:bf8bd2bedda7e59353aaf9bcd52fdd3c9cd247e530ceec7e629fcc1f930f23bc
|
||||||
size 149249
|
size 179850
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:caa5c7bd6c8781e700ba2ac1eafe1ecd12776892ad3a3f956e923085be35ce80
|
oid sha256:a5f00e0da1089b66c6cf8c256bec3adf8ccd11b51569cb19258c97eec3f7b5ba
|
||||||
size 94285
|
size 112584
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:caa5c7bd6c8781e700ba2ac1eafe1ecd12776892ad3a3f956e923085be35ce80
|
oid sha256:b9cd8c744acbd7733f3099ec865aa0d3205136f3f2bef09399a53d798af4409b
|
||||||
size 94285
|
size 116515
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:3b86cce3ab068ea93f4647ec5efb8762e2b92edb78c2d647d9621486c3afa7f5
|
oid sha256:f74610196ad9da46013aa7dcfd0f0a64051b3552872993a9bb54f64419eccdb7
|
||||||
size 136479
|
size 141774
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:20046627aca878cee89c1d1fb6d2370c9841312d909b5db3cb8f8d85866e4cc3
|
oid sha256:68034d3beee6bbd4089c9f19c19485356ff9e5bf23ade9e7838a57ae287b35ac
|
||||||
size 101950
|
size 107276
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e0104abccb916e6004eadbf6020f66ce504c168b9d03abb91e618a50b0c8b6a3
|
oid sha256:bf414829dcf5f6885632b608f2cceccc15ab8418f7fc93d0d56e1b488834e804
|
||||||
size 163769
|
size 169215
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4fc85d0fcfecb4de8b49c6dff26c8baaf8371c6c7e467199c1749aff308184c1
|
oid sha256:d2f1d162b91fbf5f764e57bb79f843c21c65c5be2e488448011cf1d21921f219
|
||||||
size 172433
|
size 177644
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:2f957ed20a375c6f117c41efa9267b31b0a0ea35942dc6206b09641024e8df0b
|
oid sha256:54c647dd14050cab70988eb4e3802ce23d2e04427a4144a441f82cf806291acb
|
||||||
size 155295
|
size 160550
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b52ddbd7ffc13e7a519448fa478f61d8cea0bfc5e2852266d6e4c2352ff92122
|
oid sha256:3b2eb891016995b39e23cfc777fe531f3927039465983468ccaad42726a85f49
|
||||||
size 148556
|
size 159267
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a527ddb8a3db4b7e4fa0b89a05b4f2a67ce6ecb65498eb21f828f2cffdc283ba
|
oid sha256:357301e28ea588a5d38fc63d4eb781c580d96e629cbdde675dd35d788452183d
|
||||||
size 126125
|
size 136693
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:25bf9187d0523df76dff77b6b4d4a42d660a7c920a7cdf2df5681be8e811549f
|
oid sha256:11cb56e13df8abe892264775ee64a89f389e022db0376899b24bd6fb42856a54
|
||||||
size 192470
|
size 203181
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:2eaef305bab6997df7f1d953d7a1d1a440c720fa4c53988012183d6fae52b708
|
oid sha256:bf75b5dac24845f7461e2ea5de0d2818470cfd5e779331129975204365e0ad6d
|
||||||
size 200534
|
size 211131
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ea48a2079bd5adb7eda03aea9d1c5ccd2be39ae22ad93cf383495938cf27da5c
|
oid sha256:bebf9d38ab727bfc5d206ebaef2e75c8ab6ad6d7546c22be7b0a0a19dbd4c160
|
||||||
size 179530
|
size 190293
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:dde8c1b0aac2644af48ab8d9a5c2eef5119580c79e7b1a7d8c3228c79c3a04d7
|
oid sha256:66ed2cdca4cc96d6aa3ed59081c1c42349f057fb30db951c0fff123db97e8f90
|
||||||
size 83855
|
size 87673
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0798e87d35e3fc0610017b6829345f4e3446a6c6fa038f8c38919c4e4aee3cbc
|
oid sha256:0129b9f9f9c770c9d78d73b0ec73ac65aaa2cce9cb30ef86e737b21a6ce40ca2
|
||||||
size 57564
|
size 60783
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:03f41bbbdefb7b6e58c79545a1bf718a8834f51c08589df5d779fb1bdd9814ec
|
oid sha256:3b39de84f6fb238b7b959c78185c02c7c9e77f67eaf0ccad8918da10687da0f4
|
||||||
size 112153
|
size 115880
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:6e0761e72763b69108207802bd930f8fdbf0188d58de7c7617dab9ea095430b2
|
oid sha256:ea9be731b726d1ca46b07b7e45fed591471f4ebb69213e64008227aa65a7e45e
|
||||||
size 120230
|
size 124143
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ced785329bc86c7c25e0f3d4e77be7cdf686a7334f0577c577aa76fbd8a01e16
|
oid sha256:a8c29737d601d4b70d46783fb28668fd80e1e3e4aeafa10b84b13708d2b4f003
|
||||||
size 106031
|
size 110383
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ec65f2a73c8cd5ad03afc7bf189679044459d84e4aaecfed39e2a555f2b060e7
|
oid sha256:dc386629fb566cc3aa1e35af1d9001cceb9aab298077cc12625d1eadb729c5bb
|
||||||
size 95750
|
size 103518
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1ae66cafa25f4b6bfc0bdca91d5ddaf2b6bec6ffbd2b7015c2f1cceed8dd3035
|
oid sha256:f37e99938197b30df7787756b70a8d4a927a922db3915dfb3f1f64cc91ba1365
|
||||||
size 79294
|
size 87405
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:83a65b1e1d6881fcdfdcc485e3ce4a986114789219f313b88702b0ce495808e9
|
oid sha256:8f0f9906b81e1ab0a278271f1a03985ec2b5cc357b7e55175fbf50b199d17e6a
|
||||||
size 136571
|
size 144193
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0227511fe99e1b9bed944bb8a3d995de7bf9da25d5c2d194cc65eb3b0d2bf732
|
oid sha256:f7f31147866db8ee3903500b7f2d15e03052721a2adbbfbe0800ccea77cd7344
|
||||||
size 144931
|
size 152549
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:78e794288debdba5b8e6abaaf7ac3f6c482342d4f07e87c50bd1999582f85be0
|
oid sha256:d9e9a7f574bb4036e36a9a6e808e3da606924e62c879392c394d85fd1017d4a9
|
||||||
size 127540
|
size 136611
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase {
|
|||||||
setupViewModel(mode: .administrator)
|
setupViewModel(mode: .administrator)
|
||||||
XCTAssertEqual(context.viewState.membersToPromote, [])
|
XCTAssertEqual(context.viewState.membersToPromote, [])
|
||||||
XCTAssertEqual(context.viewState.membersToDemote, [])
|
XCTAssertEqual(context.viewState.membersToDemote, [])
|
||||||
XCTAssertEqual(context.viewState.members, context.viewState.visibleMembers)
|
XCTAssertEqual(context.viewState.administrators, context.viewState.visibleAdministrators)
|
||||||
XCTAssertEqual(context.viewState.membersWithRole.count, 1)
|
XCTAssertEqual(context.viewState.moderators, context.viewState.visibleModerators)
|
||||||
|
XCTAssertEqual(context.viewState.users, context.viewState.visibleUsers)
|
||||||
|
XCTAssertEqual(context.viewState.membersWithRole.count, 2)
|
||||||
XCTAssertEqual(context.viewState.membersWithRole.first?.id, RoomMemberProxyMock.mockAdmin.userID)
|
XCTAssertEqual(context.viewState.membersWithRole.first?.id, RoomMemberProxyMock.mockAdmin.userID)
|
||||||
XCTAssertFalse(context.viewState.hasChanges)
|
XCTAssertFalse(context.viewState.hasChanges)
|
||||||
XCTAssertFalse(context.viewState.isSearching)
|
XCTAssertFalse(context.viewState.isSearching)
|
||||||
@@ -42,7 +44,9 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase {
|
|||||||
setupViewModel(mode: .moderator)
|
setupViewModel(mode: .moderator)
|
||||||
XCTAssertEqual(context.viewState.membersToPromote, [])
|
XCTAssertEqual(context.viewState.membersToPromote, [])
|
||||||
XCTAssertEqual(context.viewState.membersToDemote, [])
|
XCTAssertEqual(context.viewState.membersToDemote, [])
|
||||||
XCTAssertEqual(context.viewState.members, context.viewState.visibleMembers)
|
XCTAssertEqual(context.viewState.administrators, context.viewState.visibleAdministrators)
|
||||||
|
XCTAssertEqual(context.viewState.moderators, context.viewState.visibleModerators)
|
||||||
|
XCTAssertEqual(context.viewState.users, context.viewState.visibleUsers)
|
||||||
XCTAssertEqual(context.viewState.membersWithRole.count, 1)
|
XCTAssertEqual(context.viewState.membersWithRole.count, 1)
|
||||||
XCTAssertEqual(context.viewState.membersWithRole.first?.id, RoomMemberProxyMock.mockModerator.userID)
|
XCTAssertEqual(context.viewState.membersWithRole.first?.id, RoomMemberProxyMock.mockModerator.userID)
|
||||||
XCTAssertFalse(context.viewState.hasChanges)
|
XCTAssertFalse(context.viewState.hasChanges)
|
||||||
@@ -51,7 +55,7 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
func testToggleUserOn() {
|
func testToggleUserOn() {
|
||||||
testInitialStateModerators()
|
testInitialStateModerators()
|
||||||
guard let firstUser = context.viewState.members.first(where: { !context.viewState.isMemberSelected($0) }) else {
|
guard let firstUser = context.viewState.users.first(where: { !context.viewState.isMemberSelected($0) }) else {
|
||||||
XCTFail("There should be a regular user available to promote.")
|
XCTFail("There should be a regular user available to promote.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -150,7 +154,7 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase {
|
|||||||
// Given the change roles view model for moderators.
|
// Given the change roles view model for moderators.
|
||||||
setupViewModel(mode: .moderator)
|
setupViewModel(mode: .moderator)
|
||||||
|
|
||||||
guard let firstUser = context.viewState.members.first(where: { !context.viewState.isMemberSelected($0) }),
|
guard let firstUser = context.viewState.users.first(where: { !context.viewState.isMemberSelected($0) }),
|
||||||
let existingModerator = context.viewState.membersWithRole.first else {
|
let existingModerator = context.viewState.membersWithRole.first else {
|
||||||
XCTFail("There should be a regular user and a moderator to begin with.")
|
XCTFail("There should be a regular user and a moderator to begin with.")
|
||||||
return
|
return
|
||||||
@@ -175,7 +179,7 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase {
|
|||||||
setupViewModel(mode: .administrator)
|
setupViewModel(mode: .administrator)
|
||||||
XCTAssertNil(context.alertInfo)
|
XCTAssertNil(context.alertInfo)
|
||||||
|
|
||||||
guard let firstUser = context.viewState.members.first(where: { !context.viewState.isMemberSelected($0) }) else {
|
guard let firstUser = context.viewState.users.first(where: { !context.viewState.isMemberSelected($0) }) else {
|
||||||
XCTFail("There should be a regular user to begin with.")
|
XCTFail("There should be a regular user to begin with.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+126
-3
@@ -126,8 +126,128 @@ class RoomMembersListScreenViewModelTests: XCTestCase {
|
|||||||
XCTAssertEqual(viewModel.state.visibleJoinedMembers.count, 0)
|
XCTAssertEqual(viewModel.state.visibleJoinedMembers.count, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testKickMember() async throws {
|
func testSelectUserAsUser() async throws {
|
||||||
|
// Given the room list viewed as a regular user.
|
||||||
setup(with: .allMembers)
|
setup(with: .allMembers)
|
||||||
|
let deferred = deferFulfillment(context.$viewState) { !$0.visibleInvitedMembers.isEmpty }
|
||||||
|
try await deferred.fulfill()
|
||||||
|
|
||||||
|
// When tapping on another user in the list.
|
||||||
|
let memberDetailsAction = deferFulfillment(viewModel.actions) { $0.isSelectMember }
|
||||||
|
guard let user = viewModel.state.visibleJoinedMembers.first(where: { $0.role == .user && $0.id != RoomMemberProxyMock.mockMe.userID }) else {
|
||||||
|
XCTFail("Expected to find a regular user.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.send(viewAction: .selectMember(user))
|
||||||
|
|
||||||
|
// Then the member's details should be shown.
|
||||||
|
try await memberDetailsAction.fulfill()
|
||||||
|
XCTAssertNil(context.memberToManage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSelectUserAsAdmin() async throws {
|
||||||
|
// Given the room list viewed as an admin.
|
||||||
|
setup(with: .allMembersAsAdmin)
|
||||||
|
var deferred = deferFulfillment(context.$viewState) { !$0.visibleInvitedMembers.isEmpty }
|
||||||
|
try await deferred.fulfill()
|
||||||
|
XCTAssertNil(context.memberToManage)
|
||||||
|
|
||||||
|
// When tapping on a user in the list.
|
||||||
|
deferred = deferFulfillment(context.$viewState) { $0.bindings.memberToManage != nil }
|
||||||
|
guard let user = viewModel.state.visibleJoinedMembers.first(where: { $0.role == .user && $0.id != RoomMemberProxyMock.mockMe.userID }) else {
|
||||||
|
XCTFail("Expected to find a regular user.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.send(viewAction: .selectMember(user))
|
||||||
|
try await deferred.fulfill()
|
||||||
|
|
||||||
|
// Then member management should be shown for that user.
|
||||||
|
XCTAssertEqual(context.memberToManage?.member, user)
|
||||||
|
XCTAssertEqual(context.memberToManage?.actions, [.kick, .ban])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSelectModeratorAsAdmin() async throws {
|
||||||
|
// Given the room list viewed as an admin.
|
||||||
|
setup(with: .allMembersAsAdmin)
|
||||||
|
var deferred = deferFulfillment(context.$viewState) { !$0.visibleInvitedMembers.isEmpty }
|
||||||
|
try await deferred.fulfill()
|
||||||
|
XCTAssertNil(context.memberToManage)
|
||||||
|
|
||||||
|
// When tapping on a moderator in the list.
|
||||||
|
deferred = deferFulfillment(context.$viewState) { $0.bindings.memberToManage != nil }
|
||||||
|
guard let moderator = viewModel.state.visibleJoinedMembers.first(where: { $0.role == .moderator }) else {
|
||||||
|
XCTFail("Expected to find a moderator.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.send(viewAction: .selectMember(moderator))
|
||||||
|
try await deferred.fulfill()
|
||||||
|
|
||||||
|
// Then member management should be shown for the moderator.
|
||||||
|
XCTAssertEqual(context.memberToManage?.member, moderator)
|
||||||
|
XCTAssertEqual(context.memberToManage?.actions, [.kick, .ban])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSelectAdminAsAdmin() async throws {
|
||||||
|
// Given the room list viewed as an admin.
|
||||||
|
setup(with: .allMembersAsAdmin)
|
||||||
|
let deferred = deferFulfillment(context.$viewState) { !$0.visibleInvitedMembers.isEmpty }
|
||||||
|
try await deferred.fulfill()
|
||||||
|
|
||||||
|
// When tapping on another administrator in the list.
|
||||||
|
let memberDetailsAction = deferFulfillment(viewModel.actions) { $0.isSelectMember }
|
||||||
|
guard let admin = viewModel.state.visibleJoinedMembers.first(where: { $0.role == .administrator && $0.id != RoomMemberProxyMock.mockMe.userID }) else {
|
||||||
|
XCTFail("Expected to find another admin.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.send(viewAction: .selectMember(admin))
|
||||||
|
|
||||||
|
// Then the administrator's details should be shown.
|
||||||
|
try await memberDetailsAction.fulfill()
|
||||||
|
XCTAssertNil(context.memberToManage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSelectOwnMemberAsAdmin() async throws {
|
||||||
|
// Given the room list viewed as an admin.
|
||||||
|
setup(with: .allMembersAsAdmin)
|
||||||
|
let deferred = deferFulfillment(context.$viewState) { !$0.visibleInvitedMembers.isEmpty }
|
||||||
|
try await deferred.fulfill()
|
||||||
|
|
||||||
|
// When tapping on yourself in the list.
|
||||||
|
let memberDetailsAction = deferFulfillment(viewModel.actions) { $0.isSelectMember }
|
||||||
|
guard let ownMember = viewModel.state.visibleJoinedMembers.first(where: { $0.id == RoomMemberProxyMock.mockMe.userID }) else {
|
||||||
|
XCTFail("Expected to find own user admin.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.send(viewAction: .selectMember(ownMember))
|
||||||
|
|
||||||
|
// Then your member's details should be shown.
|
||||||
|
try await memberDetailsAction.fulfill()
|
||||||
|
XCTAssertNil(context.memberToManage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSelectBannedMember() async throws {
|
||||||
|
// Given the room list viewed as an admin.
|
||||||
|
setup(with: .allMembersAsAdmin + RoomMemberProxyMock.mockBanned)
|
||||||
|
var deferred = deferFulfillment(context.$viewState) { !$0.visibleInvitedMembers.isEmpty }
|
||||||
|
try await deferred.fulfill()
|
||||||
|
XCTAssertNil(context.alertInfo)
|
||||||
|
|
||||||
|
// When tapping on a banned member in the list.
|
||||||
|
deferred = deferFulfillment(context.$viewState) { $0.bindings.alertInfo != nil }
|
||||||
|
guard let bannedMember = viewModel.state.visibleBannedMembers.first else {
|
||||||
|
XCTFail("Expected to find a banned user.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.send(viewAction: .selectMember(bannedMember))
|
||||||
|
|
||||||
|
// Then an alert should be shown to unban the user.
|
||||||
|
try await deferred.fulfill()
|
||||||
|
XCTAssertNil(context.memberToManage)
|
||||||
|
XCTAssertNotNil(context.alertInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testKickMember() async throws {
|
||||||
|
setup(with: .allMembersAsAdmin)
|
||||||
let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty }
|
let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty }
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
|
|
||||||
@@ -140,7 +260,7 @@ class RoomMembersListScreenViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testBanMember() async throws {
|
func testBanMember() async throws {
|
||||||
setup(with: .allMembers)
|
setup(with: .allMembersAsAdmin)
|
||||||
let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty }
|
let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty }
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
|
|
||||||
@@ -153,7 +273,7 @@ class RoomMembersListScreenViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testUnbanMember() async throws {
|
func testUnbanMember() async throws {
|
||||||
setup(with: .allMembers)
|
setup(with: .allMembersAsAdmin)
|
||||||
let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty }
|
let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty }
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
|
|
||||||
@@ -166,6 +286,9 @@ class RoomMembersListScreenViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setup(with members: [RoomMemberProxyMock]) {
|
private func setup(with members: [RoomMemberProxyMock]) {
|
||||||
|
AppSettings.resetAllSettings()
|
||||||
|
ServiceLocator.shared.settings.roomModerationEnabled = true
|
||||||
|
|
||||||
roomProxy = RoomProxyMock(with: .init(name: "test", members: members))
|
roomProxy = RoomProxyMock(with: .init(name: "test", members: members))
|
||||||
viewModel = .init(roomProxy: roomProxy,
|
viewModel = .init(roomProxy: roomProxy,
|
||||||
mediaProvider: MockMediaProvider(),
|
mediaProvider: MockMediaProvider(),
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Bug fixes on the moderation feature.
|
||||||
Reference in New Issue
Block a user