diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 5303d771c..cbe55ccb3 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -379,6 +379,7 @@ 5D2AF8C0DF872E7985F8FE54 /* TimelineDeliveryStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AC06FC11B6638F7BF1670E /* TimelineDeliveryStatusView.swift */; }; 5D4643E485C179B2F485C519 /* MentionSuggestionItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FD0E68C42CA7DDCD4CAD68D /* MentionSuggestionItemView.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 */; }; 5DD0EF30070DC0A82C5CCD33 /* RoomMembersListManageMemberSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC853F9B4FBE039D2C16EC6B /* RoomMembersListManageMemberSheet.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 */; }; CA12AE0DCD57D49CD96C699A /* WaveformCursorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB9EABCA9348DFA27439A809 /* WaveformCursorView.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 */; }; CB498F4E27AA0545DCEF0F6F /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 36B7FC232711031AA2B0D188 /* DTCoreText */; }; 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 */; }; CD0088B763CD970CF1CBF8CB /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5E97E9615A158C76B2AB77 /* DateTests.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 */; }; CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; }; 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 = ""; }; 3E6A9B9DFEE964962C179DE3 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = ""; }; 3E93A1BE7D8A2EBCAD51EEB4 /* Array.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = ""; }; + 3E9E0929CEFA356090BE5FB8 /* RoomMembersListScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModelTests.swift; sourceTree = ""; }; 3EF1AC723C2609C7705569CA /* MediaLoaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaLoaderTests.swift; sourceTree = ""; }; 3FFDA99C98BE05F43A92343B /* test_pdf.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test_pdf.pdf; sourceTree = ""; }; 40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageMediaManager.swift; sourceTree = ""; }; @@ -1503,7 +1505,6 @@ 68010886142843705E342645 /* ProgressMaskModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressMaskModifier.swift; sourceTree = ""; }; 6861FE915C7B5466E6962BBA /* StartChatScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreen.swift; sourceTree = ""; }; 693E16574C6F7F9FA1015A8C /* Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Search.swift; sourceTree = ""; }; - 69B63F817FE305548DB4B512 /* RoomMembersListViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListViewModelTests.swift; sourceTree = ""; }; 69CB8242D69B7E4D0B32E18D /* AggregatedReactionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AggregatedReactionMock.swift; sourceTree = ""; }; 69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModelTests.swift; sourceTree = ""; }; 6A4C9547BBFEEF30AA11329B /* TimelineItemStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemStatusView.swift; sourceTree = ""; }; @@ -2009,6 +2010,7 @@ E9D059BFE329BE09B6D96A9F /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = ro.lproj/Localizable.stringsdict; sourceTree = ""; }; EA4D639E27D5882A6A71AECF /* GlobalSearchScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchScreenViewModelTests.swift; sourceTree = ""; }; EA880E78AF4BD24E45A7808C /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/InfoPlist.strings; sourceTree = ""; }; + EAF710CB1C31F8938EAA3A7D /* RoomChangeRolesScreenSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenSection.swift; sourceTree = ""; }; EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilderTests.swift; sourceTree = ""; }; EB63761D9F9CE8B23CBD6179 /* PollFormScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenModels.swift; sourceTree = ""; }; EB76A9AFC6CCAD4998D9B045 /* IdentityConfirmationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenViewModel.swift; sourceTree = ""; }; @@ -3217,6 +3219,7 @@ children = ( 6B2A421198FD20AAAED20004 /* RoomChangeRolesScreen.swift */, 23E6EB7960BC9D0F7396B3BD /* RoomChangeRolesScreenRow.swift */, + EAF710CB1C31F8938EAA3A7D /* RoomChangeRolesScreenSection.swift */, 3D9B45D584D232CB9E5C7734 /* RoomChangeRolesScreenSelectedItem.swift */, ); path = View; @@ -3494,7 +3497,7 @@ 4FCB2126C091EEF2454B4D56 /* RoomFlowCoordinatorTests.swift */, 8AE0C9653870803E4F91F474 /* RoomListFiltersStateTests.swift */, EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */, - 69B63F817FE305548DB4B512 /* RoomMembersListViewModelTests.swift */, + 3E9E0929CEFA356090BE5FB8 /* RoomMembersListScreenViewModelTests.swift */, 58D295F0081084F38DB20893 /* RoomNotificationSettingsScreenViewModelTests.swift */, F0096BC5DA86AF6B6E5742AC /* RoomPermissionsTests.swift */, B40233F2989AD49906BB310D /* RoomPollsHistoryScreenViewModelTests.swift */, @@ -5632,7 +5635,7 @@ 095D3906CF2F940C2D2D17CC /* RoomFlowCoordinatorTests.swift in Sources */, 4C8C0C9FC10BA73AB7780534 /* RoomListFiltersStateTests.swift in Sources */, 6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */, - CAF8755E152204F55F8D6B5B /* RoomMembersListViewModelTests.swift in Sources */, + 5D56CE09743C6B90C21B04C2 /* RoomMembersListScreenViewModelTests.swift in Sources */, E49F74BD93230BDEFFE5EA51 /* RoomNotificationSettingsScreenViewModelTests.swift in Sources */, 2335D1AB954C151FD8779F45 /* RoomPermissionsTests.swift in Sources */, 7B1605C6FFD4D195F264A684 /* RoomPollsHistoryScreenViewModelTests.swift in Sources */, @@ -6121,6 +6124,7 @@ 244407B18B2F2D6466BA5961 /* RoomChangeRolesScreenCoordinator.swift in Sources */, 7FF6E1FBE6E9517FD29A1D8E /* RoomChangeRolesScreenModels.swift in Sources */, 7F941B063C94E1718DFC2CF3 /* RoomChangeRolesScreenRow.swift in Sources */, + CDAE3A37D4DF136F9D07DB61 /* RoomChangeRolesScreenSection.swift in Sources */, BD6685592716CA957D7BAAC4 /* RoomChangeRolesScreenSelectedItem.swift in Sources */, 3EC5A41F9FB7DD63A4DC6144 /* RoomChangeRolesScreenViewModel.swift in Sources */, 4E36A66E0EDA74BF3A036FD0 /* RoomChangeRolesScreenViewModelProtocol.swift in Sources */, diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index c96a98aff..e9cfc2d40 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -519,6 +519,7 @@ "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_title" = "Demote yourself?"; +"screen_room_change_role_invited_member_name" = "%1$@ (Pending)"; "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_title" = "Save changes?"; @@ -793,6 +794,9 @@ "screen_room_change_permissions_member_moderation" = "Member moderation"; "screen_room_change_permissions_messages_and_content" = "Messages and content"; "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_leave_conversation_title" = "Leave conversation"; "screen_room_details_leave_room_title" = "Leave room"; diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index c7dfef952..102be4fc9 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -1263,8 +1263,18 @@ internal enum L10n { internal static var screenRoomChangeRoleConfirmDemoteSelfDescription: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_demote_self_description") } /// Demote yourself? 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 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. internal static var screenRoomChangeRoleUnsavedChangesDescription: String { return L10n.tr("Localizable", "screen_room_change_role_unsaved_changes_description") } /// Save changes? diff --git a/ElementX/Sources/Mocks/RoomMemberProxyMock.swift b/ElementX/Sources/Mocks/RoomMemberProxyMock.swift index 4cd472f2a..2523ee0fd 100644 --- a/ElementX/Sources/Mocks/RoomMemberProxyMock.swift +++ b/ElementX/Sources/Mocks/RoomMemberProxyMock.swift @@ -53,7 +53,7 @@ extension RoomMemberProxyMock { static var mockMeAdmin: RoomMemberProxyMock { RoomMemberProxyMock(with: .init(userID: "@me:matrix.org", - displayName: "Me admin", + displayName: "Me", avatarURL: URL.picturesDirectory, membership: .join, powerLevel: 100, diff --git a/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenModels.swift b/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenModels.swift index 54327bacb..53b851fdb 100644 --- a/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenModels.swift +++ b/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenModels.swift @@ -24,8 +24,13 @@ enum RoomChangeRolesScreenViewModelAction { struct RoomChangeRolesScreenViewState: BindableState { /// The screen's current mode (which role we are promoting/demoting users to/from. let mode: RoomMemberDetails.Role - /// All of the room's members. - var members: [RoomMemberDetails] + /// All of the room's members who are currently admins. + 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 /// The members selected for promotion to the current role. @@ -48,19 +53,24 @@ struct RoomChangeRolesScreenViewState: BindableState { } } - /// The visible members in the screen (after searching). - var visibleMembers: [RoomMemberDetails] { - guard !bindings.searchQuery.isEmpty else { return members } - - return members.filter { member in - member.name?.localizedStandardContains(bindings.searchQuery) == true - || member.id.localizedStandardContains(bindings.searchQuery) - } + /// The visible admins in the screen (after searching). + var visibleAdministrators: [RoomMemberDetails] { + administrators.filter { $0.matches(searchQuery: bindings.searchQuery) } + } + + /// The visible mods in the screen (after searching). + 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. 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. diff --git a/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift b/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift index 9c169aade..ace913f6b 100644 --- a/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift @@ -40,7 +40,9 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh self.analytics = analytics super.init(initialViewState: RoomChangeRolesScreenViewState(mode: mode, - members: [], + administrators: [], + moderators: [], + users: [], bindings: .init())) roomProxy.membersPublisher @@ -82,10 +84,27 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh // MARK: - Private private func updateMembers(_ members: [RoomMemberProxyProtocol]) { - state.members = members.sorted().compactMap { member in - guard member.membership == .join, member.userID != roomProxy.ownUserID else { return nil } - return RoomMemberDetails(withProxy: member) + var administrators = [RoomMemberDetails]() + var moderators = [RoomMemberDetails]() + 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) { diff --git a/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift index 017a60ff1..9ced774d3 100644 --- a/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift +++ b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreen.swift @@ -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 - private var membersWithRoleSection: some View { ScrollView(.horizontal, showsIndicators: false) { ScrollViewReader { scrollView in diff --git a/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreenRow.swift b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreenRow.swift index 3f57443fb..0dc926dc8 100644 --- a/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreenRow.swift +++ b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreenRow.swift @@ -28,10 +28,20 @@ struct RoomChangeRolesScreenRow: View { let action: () -> Void var body: some View { - ListRow(label: .avatar(title: member.name ?? member.id, + ListRow(label: .avatar(title: memberName, description: member.name == nil ? nil : member.id, 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 { @@ -58,6 +68,11 @@ struct RoomChangeRolesScreenRow_Previews: PreviewProvider, TestablePreview { isSelected: false, action: action) + RoomChangeRolesScreenRow(member: .init(withProxy: RoomMemberProxyMock.mockInvited), + imageProvider: MockMediaProvider(), + isSelected: false, + action: action) + RoomChangeRolesScreenRow(member: .init(withProxy: RoomMemberProxyMock.mockCharlie), imageProvider: MockMediaProvider(), isSelected: true, diff --git a/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreenSection.swift b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreenSection.swift new file mode 100644 index 000000000..fe55c93d3 --- /dev/null +++ b/ElementX/Sources/Screens/RoomChangeRolesScreen/View/RoomChangeRolesScreenSection.swift @@ -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() + } + } + } +} diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenModels.swift b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenModels.swift index 1dd56bf77..e589a17f9 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenModels.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenModels.swift @@ -19,6 +19,15 @@ import Foundation enum RoomMembersListScreenViewModelAction { case selectMember(_ member: RoomMemberProxyProtocol) case invite + + var isSelectMember: Bool { + switch self { + case .selectMember: + true + default: + false + } + } } /// The different modes that the screen can be in. @@ -54,7 +63,7 @@ struct RoomMembersListScreenViewState: BindableState { self.bannedMembers = bannedMembers self.bindings = bindings } - + var visibleJoinedMembers: [RoomMemberDetails] { joinedMembers .filter { $0.matches(searchQuery: bindings.searchQuery) } @@ -76,12 +85,25 @@ struct RoomMembersListScreenViewStateBindings { /// The current mode the screen is in. var mode: RoomMembersListScreenMode = .members /// A selected member to kick, ban, promote etc. - var memberToManage: RoomMemberDetails? + var memberToManage: RoomMembersListScreenManagementDetails? /// Information describing the currently displayed alert. var alertInfo: AlertInfo? } +/// 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 { case selectMember(RoomMemberDetails) case showMemberDetails(RoomMemberDetails) @@ -94,13 +116,3 @@ enum RoomMembersListScreenViewAction { enum RoomMembersListScreenAlertType: Hashable { 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 - } -} diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift index ef8409944..ca168c546 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift @@ -149,18 +149,32 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe } private func selectMember(_ member: RoomMemberDetails) { - if appSettings.roomModerationEnabled, state.canKickUsers || state.canBanUsers { - if member.isBanned { - state.bindings.alertInfo = AlertInfo(id: .unbanConfirmation(member), - title: L10n.screenRoomMemberListManageMemberUnbanTitle, - message: L10n.screenRoomMemberListManageMemberUnbanMessage, - primaryButton: .init(title: L10n.screenRoomMemberListManageMemberUnbanAction) { [weak self] in - self?.context.send(viewAction: .unbanMember(member)) - }, - secondaryButton: .init(title: L10n.actionCancel, role: .cancel) { }) - } else { - state.bindings.memberToManage = member - } + guard appSettings.roomModerationEnabled else { + showMemberDetails(member) + return + } + + if member.isBanned { // No need to check canBan here, banned users are only shown when it is true. + state.bindings.alertInfo = AlertInfo(id: .unbanConfirmation(member), + title: L10n.screenRoomMemberListManageMemberUnbanTitle, + message: L10n.screenRoomMemberListManageMemberUnbanMessage, + primaryButton: .init(title: L10n.screenRoomMemberListManageMemberUnbanAction) { [weak self] in + 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 { showMemberDetails(member) } diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListManageMemberSheet.swift b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListManageMemberSheet.swift index 154dd2e17..2510227f7 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListManageMemberSheet.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListManageMemberSheet.swift @@ -19,6 +19,8 @@ import SwiftUI struct RoomMembersListManageMemberSheet: View { let member: RoomMemberDetails + let actions: [RoomMembersListScreenManagementDetails.Action] + @ObservedObject var context: RoomMembersListScreenViewModel.Context @State private var isPresentingBanConfirmation = false @@ -38,7 +40,7 @@ struct RoomMembersListManageMemberSheet: View { context.send(viewAction: .showMemberDetails(member)) }) - if context.viewState.canKickUsers, !member.isBanned { + if actions.contains(.kick) { ListRow(label: .default(title: L10n.screenRoomMemberListManageMemberRemove, icon: \.close), 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, icon: \.block, role: .destructive), @@ -76,11 +78,13 @@ struct RoomMembersListManageMemberSheet_Previews: PreviewProvider, TestablePrevi static var previews: some View { RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockDan), + actions: [.kick, .ban], context: viewModel.context) .previewDisplayName("Joined") .snapshot(delay: 0.2) RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockBanned[3]), + actions: [], context: viewModel.context) .previewDisplayName("Banned") .snapshot(delay: 0.2) @@ -94,6 +98,7 @@ struct RoomMembersListManageMemberSheetLive_Previews: PreviewProvider { Color.clear .sheet(isPresented: .constant(true)) { RoomMembersListManageMemberSheet(member: .init(withProxy: RoomMemberProxyMock.mockDan), + actions: [.kick, .ban], context: viewModel.context) } .previewDisplayName("Sheet") diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift index 8256a2c19..b95c354fc 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/View/RoomMembersListScreen.swift @@ -49,13 +49,15 @@ struct RoomMembersListScreen: View { .background(.compound.bgCanvasDefault) } } - .searchable(text: $context.searchQuery, placement: .navigationBarDrawer(displayMode: .always)) + .searchable(text: $context.searchQuery, + placement: .navigationBarDrawer(displayMode: .always), + prompt: L10n.commonSearchForSomeone) .compoundSearchField() .autocorrectionDisabled() .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) .navigationTitle(L10n.commonPeople) .sheet(item: $context.memberToManage) { - RoomMembersListManageMemberSheet(member: $0, context: context) + RoomMembersListManageMemberSheet(member: $0.member, actions: $0.actions, context: context) } .alert(item: $context.alertInfo) .toolbar { toolbar } diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift index 88d78cf3b..2bd720f28 100644 --- a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift @@ -94,8 +94,8 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM // MARK: - Members private func updateMembers(_ members: [RoomMemberProxyProtocol]) { - state.administratorCount = members.filter { $0.role == .administrator }.count - state.moderatorCount = members.filter { $0.role == .moderator }.count + state.administratorCount = members.filter { $0.role == .administrator && $0.isActive }.count + state.moderatorCount = members.filter { $0.role == .moderator && $0.isActive }.count } private func updateOwnRole(_ role: RoomMemberDetails.Role) async { diff --git a/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift b/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift index bb97c63ef..4c643ba8c 100644 --- a/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift +++ b/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift @@ -23,11 +23,17 @@ struct RoomMemberDetails: Identifiable, Hashable { let avatarURL: URL? let permalink: URL? + var isInvited: Bool var isIgnored: Bool var isBanned: Bool enum Role { case administrator, moderator, user } let role: Role + + func matches(searchQuery: String) -> Bool { + guard !searchQuery.isEmpty else { return true } + return id.localizedStandardContains(searchQuery) || name?.localizedStandardContains(searchQuery) == true + } } extension RoomMemberDetails { @@ -37,6 +43,7 @@ extension RoomMemberDetails { avatarURL = proxy.avatarURL permalink = proxy.permalink + isInvited = proxy.membership == .invite isIgnored = proxy.isIgnored isBanned = proxy.membership == .ban role = .init(proxy.role) @@ -48,6 +55,7 @@ extension RoomMemberDetails { avatarURL = nil permalink = nil + isInvited = false isIgnored = false isBanned = false role = .user diff --git a/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift index a57792b97..e9785525a 100644 --- a/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift @@ -31,6 +31,11 @@ protocol RoomMemberProxyProtocol: AnyObject { } extension RoomMemberProxyProtocol { + /// The member is active in the room (joined or invited). + var isActive: Bool { + membership == .join || membership == .invite + } + var permalink: URL? { try? PermalinkBuilder.permalinkTo(userIdentifier: userID, baseURL: ServiceLocator.shared.settings.permalinkBaseURL) diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Administrators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Administrators.png index f4822f115..f51fe4bc5 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Administrators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Administrators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c7d3ddb84e8a174c27229f31bf494b120974b261344fef7b5450d42cc2803e9 -size 209697 +oid sha256:8f8a5ad7a853f08fa0624ca707c41b56f7fbc2075ac66631c32e0e3118ea9b9a +size 207428 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Moderators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Moderators.png index 371f6e66a..47ab33e40 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Moderators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-en-GB.Moderators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:100cb0d5858afe432962fac47fc2d7c7fba630906641c62a966594aed7d2bd73 -size 214948 +oid sha256:6c2bfebcfb57baa6582ca914e3380ca382b4017c758b7c7b2af90a9680e7ddbb +size 206724 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Administrators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Administrators.png index f90c69c08..b425f8bc8 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Administrators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Administrators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:237abad46072702cfac2c1e6b4f02acb17d8aa7eb65a227646864bf6a5d2fa5a -size 229595 +oid sha256:89d3928a5ae405e6f1b695044b54f94aedb3ddfce583b6ba2e2b667c4eeba157 +size 233785 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Moderators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Moderators.png index c527cc7ab..823be3e2c 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Moderators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPad-pseudo.Moderators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4ff8f0b3b8f3829d2c986d81c2074ecaf5737e7bc12373f6fc5378ef4f3625a -size 236011 +oid sha256:2dd12a574b0287d8f3d4342fb207c76321fa2e8cf9b8f9773463ee1686f13211 +size 234107 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Administrators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Administrators.png index 069e84b54..26932c9a9 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Administrators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Administrators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d46021802ef0edebab273fe747f567e2637b36e0e2637f596747d989256a388 -size 148810 +oid sha256:143c3399a49fd85bedeee78a0f739189208a2500b339afc07cc5bc6cc99ed686 +size 156940 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Moderators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Moderators.png index 639618a2a..64eaa64eb 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Moderators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-en-GB.Moderators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:facb67a406d2932c70baf4873ff217d1267e29100bd9dcd11235f8d097b4291a -size 152563 +oid sha256:92fe524e9a4fb9115fadc5e43f5f89d950573d6a0750fb83e87f61a729781a06 +size 156764 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Administrators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Administrators.png index 2429805ec..4d6dc01fe 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Administrators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Administrators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa33656ad1cad730ed07709c2529a70931b9e8d8b26f43d947e4143e7034b6bc -size 166950 +oid sha256:dc861092e7490dbd5fe06a541dbcd1dd46aa378dd41015e6e6619f0158f88843 +size 180421 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Moderators.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Moderators.png index acf6c613b..6512421cc 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Moderators.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreen-iPhone-15-pseudo.Moderators.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56767f44df9037d6d089761ad9a1424e6859fc4095b5479c4726fda566871134 -size 169884 +oid sha256:274993576e92cd103dced5b43595d4ae234811a49a0d20cf4fffc58fbf0bed7b +size 179459 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-en-GB.1.png index 42c4cd8de..db8c9fabb 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7fe77092cf19d88dd1e8da9aca24e6cfab3e9abacfa19574a6cdcd51b29a5f5c -size 149249 +oid sha256:9d015139ff3d614fe612060872d9214c5215255f11363152232ffe75a5ed9a79 +size 171955 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-pseudo.1.png index 42c4cd8de..9dc466c82 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPad-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7fe77092cf19d88dd1e8da9aca24e6cfab3e9abacfa19574a6cdcd51b29a5f5c -size 149249 +oid sha256:bf8bd2bedda7e59353aaf9bcd52fdd3c9cd247e530ceec7e629fcc1f930f23bc +size 179850 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-en-GB.1.png index 3dc65efcd..09dd6efcc 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:caa5c7bd6c8781e700ba2ac1eafe1ecd12776892ad3a3f956e923085be35ce80 -size 94285 +oid sha256:a5f00e0da1089b66c6cf8c256bec3adf8ccd11b51569cb19258c97eec3f7b5ba +size 112584 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-pseudo.1.png index 3dc65efcd..47c3ddfd0 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomChangeRolesScreenRow-iPhone-15-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:caa5c7bd6c8781e700ba2ac1eafe1ecd12776892ad3a3f956e923085be35ce80 -size 94285 +oid sha256:b9cd8c744acbd7733f3099ec865aa0d3205136f3f2bef09399a53d798af4409b +size 116515 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Banned.png index 767cd3da0..3ca7d8cb6 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b86cce3ab068ea93f4647ec5efb8762e2b92edb78c2d647d9621486c3afa7f5 -size 136479 +oid sha256:f74610196ad9da46013aa7dcfd0f0a64051b3552872993a9bb54f64419eccdb7 +size 141774 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Empty-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Empty-Banned.png index 44b63e9e5..8d50d9c73 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Empty-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Empty-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20046627aca878cee89c1d1fb6d2370c9841312d909b5db3cb8f8d85866e4cc3 -size 101950 +oid sha256:68034d3beee6bbd4089c9f19c19485356ff9e5bf23ade9e7838a57ae287b35ac +size 107276 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Members.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Members.png index 2a800734b..a658ceca8 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Members.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Admin-Members.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0104abccb916e6004eadbf6020f66ce504c168b9d03abb91e618a50b0c8b6a3 -size 163769 +oid sha256:bf414829dcf5f6885632b608f2cceccc15ab8418f7fc93d0d56e1b488834e804 +size 169215 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Invites.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Invites.png index 28d80a064..ff2a20c61 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Invites.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Invites.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4fc85d0fcfecb4de8b49c6dff26c8baaf8371c6c7e467199c1749aff308184c1 -size 172433 +oid sha256:d2f1d162b91fbf5f764e57bb79f843c21c65c5be2e488448011cf1d21921f219 +size 177644 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Member.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Member.png index 5a1c5b1aa..40b5ca808 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Member.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-en-GB.Member.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f957ed20a375c6f117c41efa9267b31b0a0ea35942dc6206b09641024e8df0b -size 155295 +oid sha256:54c647dd14050cab70988eb4e3802ce23d2e04427a4144a441f82cf806291acb +size 160550 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Banned.png index 4c0e42e82..e593269eb 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b52ddbd7ffc13e7a519448fa478f61d8cea0bfc5e2852266d6e4c2352ff92122 -size 148556 +oid sha256:3b2eb891016995b39e23cfc777fe531f3927039465983468ccaad42726a85f49 +size 159267 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Empty-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Empty-Banned.png index 92b55c592..0690335e2 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Empty-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Empty-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a527ddb8a3db4b7e4fa0b89a05b4f2a67ce6ecb65498eb21f828f2cffdc283ba -size 126125 +oid sha256:357301e28ea588a5d38fc63d4eb781c580d96e629cbdde675dd35d788452183d +size 136693 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Members.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Members.png index 7f1fb4134..d6b04b686 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Members.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Admin-Members.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25bf9187d0523df76dff77b6b4d4a42d660a7c920a7cdf2df5681be8e811549f -size 192470 +oid sha256:11cb56e13df8abe892264775ee64a89f389e022db0376899b24bd6fb42856a54 +size 203181 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Invites.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Invites.png index 12e14a2ba..ae45b1292 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Invites.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Invites.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2eaef305bab6997df7f1d953d7a1d1a440c720fa4c53988012183d6fae52b708 -size 200534 +oid sha256:bf75b5dac24845f7461e2ea5de0d2818470cfd5e779331129975204365e0ad6d +size 211131 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Member.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Member.png index 4ca660fb7..4d58776a6 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Member.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPad-pseudo.Member.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea48a2079bd5adb7eda03aea9d1c5ccd2be39ae22ad93cf383495938cf27da5c -size 179530 +oid sha256:bebf9d38ab727bfc5d206ebaef2e75c8ab6ad6d7546c22be7b0a0a19dbd4c160 +size 190293 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Banned.png index 241699108..735285602 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dde8c1b0aac2644af48ab8d9a5c2eef5119580c79e7b1a7d8c3228c79c3a04d7 -size 83855 +oid sha256:66ed2cdca4cc96d6aa3ed59081c1c42349f057fb30db951c0fff123db97e8f90 +size 87673 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Empty-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Empty-Banned.png index dcfb50a11..0a5d25756 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Empty-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Empty-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0798e87d35e3fc0610017b6829345f4e3446a6c6fa038f8c38919c4e4aee3cbc -size 57564 +oid sha256:0129b9f9f9c770c9d78d73b0ec73ac65aaa2cce9cb30ef86e737b21a6ce40ca2 +size 60783 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Members.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Members.png index af5f4f0b8..9e8697bf1 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Members.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Admin-Members.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03f41bbbdefb7b6e58c79545a1bf718a8834f51c08589df5d779fb1bdd9814ec -size 112153 +oid sha256:3b39de84f6fb238b7b959c78185c02c7c9e77f67eaf0ccad8918da10687da0f4 +size 115880 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Invites.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Invites.png index 1baa09123..a2be2ecfe 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Invites.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Invites.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e0761e72763b69108207802bd930f8fdbf0188d58de7c7617dab9ea095430b2 -size 120230 +oid sha256:ea9be731b726d1ca46b07b7e45fed591471f4ebb69213e64008227aa65a7e45e +size 124143 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Member.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Member.png index e1ae585bd..18bf34de4 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Member.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-en-GB.Member.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ced785329bc86c7c25e0f3d4e77be7cdf686a7334f0577c577aa76fbd8a01e16 -size 106031 +oid sha256:a8c29737d601d4b70d46783fb28668fd80e1e3e4aeafa10b84b13708d2b4f003 +size 110383 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Banned.png index 85dbfae1e..93b0329a9 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec65f2a73c8cd5ad03afc7bf189679044459d84e4aaecfed39e2a555f2b060e7 -size 95750 +oid sha256:dc386629fb566cc3aa1e35af1d9001cceb9aab298077cc12625d1eadb729c5bb +size 103518 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Empty-Banned.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Empty-Banned.png index df7c51da9..662d2ab74 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Empty-Banned.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Empty-Banned.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ae66cafa25f4b6bfc0bdca91d5ddaf2b6bec6ffbd2b7015c2f1cceed8dd3035 -size 79294 +oid sha256:f37e99938197b30df7787756b70a8d4a927a922db3915dfb3f1f64cc91ba1365 +size 87405 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Members.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Members.png index a6134dfce..63e64b646 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Members.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Admin-Members.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:83a65b1e1d6881fcdfdcc485e3ce4a986114789219f313b88702b0ce495808e9 -size 136571 +oid sha256:8f0f9906b81e1ab0a278271f1a03985ec2b5cc357b7e55175fbf50b199d17e6a +size 144193 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Invites.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Invites.png index e0e8b5205..266eb9f63 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Invites.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Invites.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0227511fe99e1b9bed944bb8a3d995de7bf9da25d5c2d194cc65eb3b0d2bf732 -size 144931 +oid sha256:f7f31147866db8ee3903500b7f2d15e03052721a2adbbfbe0800ccea77cd7344 +size 152549 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Member.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Member.png index 5b56c11d1..2205b3a02 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Member.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomMembersListScreen-iPhone-15-pseudo.Member.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78e794288debdba5b8e6abaaf7ac3f6c482342d4f07e87c50bd1999582f85be0 -size 127540 +oid sha256:d9e9a7f574bb4036e36a9a6e808e3da606924e62c879392c394d85fd1017d4a9 +size 136611 diff --git a/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift b/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift index a1cf3d58e..535a6943f 100644 --- a/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomChangeRolesScreenViewModelTests.swift @@ -31,8 +31,10 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase { setupViewModel(mode: .administrator) XCTAssertEqual(context.viewState.membersToPromote, []) XCTAssertEqual(context.viewState.membersToDemote, []) - XCTAssertEqual(context.viewState.members, context.viewState.visibleMembers) - XCTAssertEqual(context.viewState.membersWithRole.count, 1) + 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, 2) XCTAssertEqual(context.viewState.membersWithRole.first?.id, RoomMemberProxyMock.mockAdmin.userID) XCTAssertFalse(context.viewState.hasChanges) XCTAssertFalse(context.viewState.isSearching) @@ -42,7 +44,9 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase { setupViewModel(mode: .moderator) XCTAssertEqual(context.viewState.membersToPromote, []) 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.first?.id, RoomMemberProxyMock.mockModerator.userID) XCTAssertFalse(context.viewState.hasChanges) @@ -51,7 +55,7 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase { func testToggleUserOn() { 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.") return } @@ -150,7 +154,7 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase { // Given the change roles view model for moderators. 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 { XCTFail("There should be a regular user and a moderator to begin with.") return @@ -175,7 +179,7 @@ class RoomChangeRolesScreenViewModelTests: XCTestCase { setupViewModel(mode: .administrator) 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.") return } diff --git a/UnitTests/Sources/RoomMembersListViewModelTests.swift b/UnitTests/Sources/RoomMembersListScreenViewModelTests.swift similarity index 51% rename from UnitTests/Sources/RoomMembersListViewModelTests.swift rename to UnitTests/Sources/RoomMembersListScreenViewModelTests.swift index cc91de610..6a3537aab 100644 --- a/UnitTests/Sources/RoomMembersListViewModelTests.swift +++ b/UnitTests/Sources/RoomMembersListScreenViewModelTests.swift @@ -126,8 +126,128 @@ class RoomMembersListScreenViewModelTests: XCTestCase { 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) + 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 } try await deferred.fulfill() @@ -140,7 +260,7 @@ class RoomMembersListScreenViewModelTests: XCTestCase { } func testBanMember() async throws { - setup(with: .allMembers) + setup(with: .allMembersAsAdmin) let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty } try await deferred.fulfill() @@ -153,7 +273,7 @@ class RoomMembersListScreenViewModelTests: XCTestCase { } func testUnbanMember() async throws { - setup(with: .allMembers) + setup(with: .allMembersAsAdmin) let deferred = deferFulfillment(context.$viewState) { !$0.visibleJoinedMembers.isEmpty } try await deferred.fulfill() @@ -166,6 +286,9 @@ class RoomMembersListScreenViewModelTests: XCTestCase { } private func setup(with members: [RoomMemberProxyMock]) { + AppSettings.resetAllSettings() + ServiceLocator.shared.settings.roomModerationEnabled = true + roomProxy = RoomProxyMock(with: .init(name: "test", members: members)) viewModel = .init(roomProxy: roomProxy, mediaProvider: MockMediaProvider(), diff --git a/changelog.d/pr-2608.wip b/changelog.d/pr-2608.wip new file mode 100644 index 000000000..1e5349517 --- /dev/null +++ b/changelog.d/pr-2608.wip @@ -0,0 +1 @@ +Bug fixes on the moderation feature. \ No newline at end of file