diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 00c99e0bf..a17008a70 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -413,6 +413,7 @@ 6860721DB3091BE08164C132 /* MapAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B48B7AD4908C5C374517B892 /* MapAssets.xcassets */; }; 68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */; }; 695825D20A761C678809345D /* MessageForwardingScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52135BD9E0E7A091688F627A /* MessageForwardingScreenModels.swift */; }; + 69B3C6010B42010F591FC3CB /* RoomRolesAndPermissionsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C1AF829F12FDC99717082D9 /* RoomRolesAndPermissionsScreenViewModel.swift */; }; 69BCBB4FB2DC3D61A28D3FD8 /* TimelineStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */; }; 69C7B956B74BEC3DB88224EA /* NavigationSplitCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78913D6E120D46138E97C107 /* NavigationSplitCoordinatorTests.swift */; }; 69DE29C3E3180BB17D840690 /* ProgressCursorModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C8E13A1FBA717B0C277ECC /* ProgressCursorModifier.swift */; }; @@ -513,11 +514,13 @@ 828EA5009557C2B9DCD4CA0F /* UserDiscoverySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */; }; 829062DD3C3F7016FE1A6476 /* RoomDetailsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BFDAF6918BB096C44788FC9 /* RoomDetailsScreenUITests.swift */; }; 8317E1314C00DCCC99D30DA8 /* TextBasedRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9227F7495DA43324050A863 /* TextBasedRoomTimelineItem.swift */; }; + 8358D145F9BF94F412BEDCA8 /* RoomRolesAndPermissionsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE7969EBCAF078813E18EA1 /* RoomRolesAndPermissionsScreenModels.swift */; }; 835B7AD20407F766C747BEC5 /* RoomPollsHistoryScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D147EB979902DBBE452EADC /* RoomPollsHistoryScreenUITests.swift */; }; 83A4DAB181C56987C3E804FF /* MapTilerStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B9F5BC4C80543DE7228B9D /* MapTilerStyle.swift */; }; 84226AD2E1F1FBC965F3B09E /* UnitTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A8E19C4645D3F5F9FB02355 /* UnitTestsAppCoordinator.swift */; }; 8478992479B296C45150208F /* AppLockScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */; }; 847DE3A7EB9FCA2C429C6E85 /* PINTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D1D4A6D451F43A03CACD01D /* PINTextField.swift */; }; + 84C631E734FD2555B39B681C /* RoomRolesAndPermissionsScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48FEFF746DB341CDB18D7AAA /* RoomRolesAndPermissionsScreenViewModelTests.swift */; }; 84CAE3E96D93194DA06B9194 /* CallScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD9AD6AE5FC868962F090740 /* CallScreenViewModelProtocol.swift */; }; 84EFCB95F9DA2979C8042B26 /* UITestsSignalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */; }; 8544657DEEE717ED2E22E382 /* RoomNotificationSettingsProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D1BAA90F3A073D91B4F16B /* RoomNotificationSettingsProxyMock.swift */; }; @@ -706,6 +709,7 @@ B09DC6E3D0EE87C4D4ABFAB3 /* EncryptedHistoryRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0140615D2232612C813FD6C /* EncryptedHistoryRoomTimelineItem.swift */; }; B0CB16349B96262AA65A04AF /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = A05AF81DDD14AD58CB0E1B9B /* Version */; }; B1069F361E604D5436AE9FFD /* StaticLocationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B06663F7858E45882E63471 /* StaticLocationScreen.swift */; }; + B13774779EA19FDD7A35A4A8 /* RoomRolesAndPermissionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C28B70BEFD3676F11D5D51F /* RoomRolesAndPermissionsScreenCoordinator.swift */; }; B1387648C6F71F1B98244803 /* SecureBackupRecoveryKeyScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596AA8843AC1A234F3387767 /* SecureBackupRecoveryKeyScreenCoordinator.swift */; }; B14BC354E56616B6B7D9A3D7 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27A1AD6389A4659AF0CEAE62 /* NotificationServiceExtension.swift */; }; B188D0907A4D38AAAF6FEFA8 /* AppLockSetupFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DBB08A95EFA668F2CF27211 /* AppLockSetupFlowCoordinator.swift */; }; @@ -836,6 +840,7 @@ D050D7756E92CA061ED0ABF0 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */; }; D0550B8E0AE2C0CDBE52C88F /* MediaPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */; }; D0A965852D6C04138FA55181 /* SecureBackupLogoutConfirmationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */; }; + D10BA4F041DC58580A440A32 /* RoomRolesAndPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B1DC3B3FB40A7F4AE9B7BF /* RoomRolesAndPermissionsScreen.swift */; }; D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */; }; D181AC8FF236B7F91C0A8C28 /* MapTiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23AA3F4B285570805CB0CCDD /* MapTiler.swift */; }; D19A748E95E2FAB2940570F0 /* CallScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4103AB4340F2974D690A12A /* CallScreen.swift */; }; @@ -991,6 +996,7 @@ F833D5B5BE6707F961FA88DB /* SecureBackupController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1119E9C63AE530252640D2 /* SecureBackupController.swift */; }; F86102DC2C68BBBB0521BAAE /* SoftLogoutScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BB385E148DE55C85C0A02D6 /* SoftLogoutScreenModels.swift */; }; F8E725D42023ECA091349245 /* AudioRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57EAAF82432B0B53881CF826 /* AudioRoomTimelineItem.swift */; }; + F8F47CE757EE656905F01F2C /* RoomRolesAndPermissionsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90DFF217B3D9D0941283278C /* RoomRolesAndPermissionsScreenViewModelProtocol.swift */; }; F9842667B68DC6FA1F9ECCBB /* NSItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72EFC8C634469F9262659C7 /* NSItemProvider.swift */; }; F99FB21EFC6D99D247FE7CBE /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DE8DC9B3FBA402117DC4C49F /* Kingfisher */; }; F9EA79092C18A8CFE4922DD2 /* PollFormScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F64A8582F65567AC38C2976A /* PollFormScreenViewModel.swift */; }; @@ -1195,6 +1201,7 @@ 1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenUITests.swift; sourceTree = ""; }; 1D8C38663020DF2EB2D13F5E /* AppLockSetupSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenViewModel.swift; sourceTree = ""; }; 1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenUITests.swift; sourceTree = ""; }; + 1DE7969EBCAF078813E18EA1 /* RoomRolesAndPermissionsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenModels.swift; sourceTree = ""; }; 1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelProtocol.swift; sourceTree = ""; }; 1DFE0E493FB55E5A62E7852A /* ProposedViewSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProposedViewSize.swift; sourceTree = ""; }; 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DTHTMLElement+AttributedStringBuilder.swift"; sourceTree = ""; }; @@ -1355,6 +1362,7 @@ 47873756E45B46683D97DC32 /* LegalInformationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenModels.swift; sourceTree = ""; }; 47EBB5D698CE9A25BB553A2D /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; 47F29139BC2A804CE5E0757E /* MediaUploadPreviewScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenViewModel.swift; sourceTree = ""; }; + 48FEFF746DB341CDB18D7AAA /* RoomRolesAndPermissionsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenViewModelTests.swift; sourceTree = ""; }; 490BEADEFB2D6B7C9F618AE8 /* AppLockTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockTimer.swift; sourceTree = ""; }; 49193CB0C248D621A96FB2AA /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; 4959CECEC984B3995616F427 /* DataProtectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataProtectionManager.swift; sourceTree = ""; }; @@ -1534,6 +1542,8 @@ 7B3D16709ADD4F4BCC710B1E /* SecureBackupScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenModels.swift; sourceTree = ""; }; 7B849D2FF2CC12BA411A1651 /* CreateRoomModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomModels.swift; sourceTree = ""; }; 7B9FCA1CFD07B8CF9BD21266 /* FlowCoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowCoordinatorProtocol.swift; sourceTree = ""; }; + 7C1AF829F12FDC99717082D9 /* RoomRolesAndPermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenViewModel.swift; sourceTree = ""; }; + 7C28B70BEFD3676F11D5D51F /* RoomRolesAndPermissionsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenCoordinator.swift; sourceTree = ""; }; 7CA3F8E905DF50BF22ECC18F /* ThreadDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDecorator.swift; sourceTree = ""; }; 7D0CBC76C80E04345E11F2DB /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactoryProtocol.swift; sourceTree = ""; }; @@ -1607,6 +1617,7 @@ 90791B9C739C716A40E1B230 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; 907FA4DE17DEA1A3738EFB83 /* AudioRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorder.swift; sourceTree = ""; }; 90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItem.swift; sourceTree = ""; }; + 90DFF217B3D9D0941283278C /* RoomRolesAndPermissionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenViewModelProtocol.swift; sourceTree = ""; }; 90F2F8998E5632668B0AD848 /* RoomTimelineItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemView.swift; sourceTree = ""; }; 913C8E13B8B602C7B6C0C4AE /* PillTextAttachmentData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillTextAttachmentData.swift; sourceTree = ""; }; 91831D7042EADD0CC2B5EC36 /* SecureBackupScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenUITests.swift; sourceTree = ""; }; @@ -1727,6 +1738,7 @@ B172057567E049007A5C4D92 /* Strings+SAS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+SAS.swift"; sourceTree = ""; }; B1E227F34BE43B08E098796E /* TestablePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestablePreview.swift; sourceTree = ""; }; B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = ""; }; + B2B1DC3B3FB40A7F4AE9B7BF /* RoomRolesAndPermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreen.swift; sourceTree = ""; }; B2B5EDCD05D50BA9B815C66C /* ImageRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineItemContent.swift; sourceTree = ""; }; B2E7C987AE5DC9087BB19F7D /* MediaUploadPreviewScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenModels.swift; sourceTree = ""; }; B3005886F00029F058DB62BE /* StartChatScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenCoordinator.swift; sourceTree = ""; }; @@ -3386,6 +3398,7 @@ 69B63F817FE305548DB4B512 /* RoomMembersListViewModelTests.swift */, 58D295F0081084F38DB20893 /* RoomNotificationSettingsScreenViewModelTests.swift */, B40233F2989AD49906BB310D /* RoomPollsHistoryScreenViewModelTests.swift */, + 48FEFF746DB341CDB18D7AAA /* RoomRolesAndPermissionsScreenViewModelTests.swift */, 93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */, AEEAFB646E583655652C3D04 /* RoomStateEventStringBuilderTests.swift */, 2E88534A39781D76487D59DF /* SecureBackupKeyBackupScreenViewModelTests.swift */, @@ -3585,6 +3598,18 @@ path = View; sourceTree = ""; }; + 7B890CCD20B037760BFDF957 /* RoomRolesAndPermissionsScreen */ = { + isa = PBXGroup; + children = ( + 7C28B70BEFD3676F11D5D51F /* RoomRolesAndPermissionsScreenCoordinator.swift */, + 1DE7969EBCAF078813E18EA1 /* RoomRolesAndPermissionsScreenModels.swift */, + 7C1AF829F12FDC99717082D9 /* RoomRolesAndPermissionsScreenViewModel.swift */, + 90DFF217B3D9D0941283278C /* RoomRolesAndPermissionsScreenViewModelProtocol.swift */, + 81D5D206BCA482C324144FBA /* View */, + ); + path = RoomRolesAndPermissionsScreen; + sourceTree = ""; + }; 7B91CB64534AD870924CCFEF /* NotificationSettingsScreen */ = { isa = PBXGroup; children = ( @@ -3637,6 +3662,14 @@ path = NetworkMonitor; sourceTree = ""; }; + 81D5D206BCA482C324144FBA /* View */ = { + isa = PBXGroup; + children = ( + B2B1DC3B3FB40A7F4AE9B7BF /* RoomRolesAndPermissionsScreen.swift */, + ); + path = View; + sourceTree = ""; + }; 823ED0EC3F1B6CF47D284011 /* Tools */ = { isa = PBXGroup; children = ( @@ -4615,6 +4648,7 @@ D4DB8163C10389C069458252 /* RoomMemberListScreen */, 0210F4932B59277E2EEEF7BC /* RoomNotificationSettingsScreen */, D57B3BC211BB74420C9138D7 /* RoomPollsHistoryScreen */, + 7B890CCD20B037760BFDF957 /* RoomRolesAndPermissionsScreen */, 679E9837ECA8D6776079D16E /* RoomScreen */, 2565414373E6F68005966B8E /* SecureBackup */, 3153FCA3F4B0E88B16D99D12 /* SessionVerificationScreen */, @@ -5417,6 +5451,7 @@ CAF8755E152204F55F8D6B5B /* RoomMembersListViewModelTests.swift in Sources */, E49F74BD93230BDEFFE5EA51 /* RoomNotificationSettingsScreenViewModelTests.swift in Sources */, 7B1605C6FFD4D195F264A684 /* RoomPollsHistoryScreenViewModelTests.swift in Sources */, + 84C631E734FD2555B39B681C /* RoomRolesAndPermissionsScreenViewModelTests.swift in Sources */, 46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */, CC0D088F505F33A20DC5590F /* RoomStateEventStringBuilderTests.swift in Sources */, 7691233E3572A9173FD96CB3 /* SecureBackupKeyBackupScreenViewModelTests.swift in Sources */, @@ -5926,6 +5961,11 @@ 4FC1EFE4968A259CBBACFAFB /* RoomProxy.swift in Sources */, BD203FC6A7AE7637EA003643 /* RoomProxyMock.swift in Sources */, FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */, + D10BA4F041DC58580A440A32 /* RoomRolesAndPermissionsScreen.swift in Sources */, + B13774779EA19FDD7A35A4A8 /* RoomRolesAndPermissionsScreenCoordinator.swift in Sources */, + 8358D145F9BF94F412BEDCA8 /* RoomRolesAndPermissionsScreenModels.swift in Sources */, + 69B3C6010B42010F591FC3CB /* RoomRolesAndPermissionsScreenViewModel.swift in Sources */, + F8F47CE757EE656905F01F2C /* RoomRolesAndPermissionsScreenViewModelProtocol.swift in Sources */, C55A44C99F64A479ABA85B46 /* RoomScreen.swift in Sources */, A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */, 47FF70C051A991FB65CDBCF3 /* RoomScreenInteractionHandler.swift in Sources */, diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index 046e5bd64..00b13b500 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -564,7 +564,7 @@ "screen_room_roles_and_permissions_messages_and_content" = "Messages and content"; "screen_room_roles_and_permissions_moderators" = "Moderators"; "screen_room_roles_and_permissions_permissions_header" = "Permissions"; -"screen_room_roles_and_permissions_reset" = "Reset roles and permissions"; +"screen_room_roles_and_permissions_reset" = "Reset permissions"; "screen_room_roles_and_permissions_roles_header" = "Roles"; "screen_room_roles_and_permissions_room_details" = "Room details"; "screen_room_roles_and_permissions_title" = "Roles and permissions"; diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index 977f6a469..403cc415c 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -1385,7 +1385,7 @@ internal enum L10n { internal static var screenRoomRolesAndPermissionsModerators: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_moderators") } /// Permissions internal static var screenRoomRolesAndPermissionsPermissionsHeader: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_permissions_header") } - /// Reset roles and permissions + /// Reset permissions internal static var screenRoomRolesAndPermissionsReset: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_reset") } /// Roles internal static var screenRoomRolesAndPermissionsRolesHeader: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_roles_header") } diff --git a/ElementX/Sources/Mocks/RoomMemberProxyMock.swift b/ElementX/Sources/Mocks/RoomMemberProxyMock.swift index 5dcbbd491..ba7d6b3c6 100644 --- a/ElementX/Sources/Mocks/RoomMemberProxyMock.swift +++ b/ElementX/Sources/Mocks/RoomMemberProxyMock.swift @@ -59,6 +59,19 @@ extension RoomMemberProxyMock { canInviteUsers: true)) } + static var mockMeAdmin: RoomMemberProxyMock { + RoomMemberProxyMock(with: .init(userID: "@me:matrix.org", + displayName: "Me admin", + avatarURL: URL.picturesDirectory, + membership: .join, + isAccountOwner: true, + powerLevel: 100, + role: .administrator, + canInviteUsers: true, + canKickUsers: true, + canBanUsers: true)) + } + static var mockAlice: RoomMemberProxyMock { RoomMemberProxyMock(with: .init(userID: "@alice:matrix.org", displayName: "Alice", @@ -154,4 +167,16 @@ extension Array where Element == RoomMemberProxyMock { .mockInvited, .mockIgnored ] + + static let allMembersAsAdmin: [RoomMemberProxyMock] = [ + .mockMeAdmin, + .mockAlice, + .mockBob, + .mockCharlie, + .mockDan, + .mockInvited, + .mockIgnored, + .mockAdmin, + .mockModerator + ] } diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenCoordinator.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenCoordinator.swift new file mode 100644 index 000000000..d4b338239 --- /dev/null +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenCoordinator.swift @@ -0,0 +1,62 @@ +// +// Copyright 2022 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. +// + +// periphery:ignore:all - this is just a roomRolesAndPermissions remove this comment once generating the final file + +import Combine +import SwiftUI + +struct RoomRolesAndPermissionsScreenCoordinatorParameters { + let roomProxy: RoomProxyProtocol +} + +enum RoomRolesAndPermissionsScreenCoordinatorAction { + case editRoles(RoomRolesAndPermissionsScreenRole) + case editPermissions(RoomRolesAndPermissionsScreenPermissionsGroup) +} + +final class RoomRolesAndPermissionsScreenCoordinator: CoordinatorProtocol { + private var viewModel: RoomRolesAndPermissionsScreenViewModelProtocol + private let actionsSubject: PassthroughSubject = .init() + private var cancellables = Set() + + var actions: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(parameters: RoomRolesAndPermissionsScreenCoordinatorParameters) { + viewModel = RoomRolesAndPermissionsScreenViewModel(roomProxy: parameters.roomProxy) + } + + func start() { + viewModel.actions.sink { [weak self] action in + MXLog.info("Coordinator: received view model action: \(action)") + + guard let self else { return } + switch action { + case .editRoles(let role): + actionsSubject.send(.editRoles(role)) + case .editPermissions(let permissionsGroup): + actionsSubject.send(.editPermissions(permissionsGroup)) + } + } + .store(in: &cancellables) + } + + func toPresentable() -> AnyView { + AnyView(RoomRolesAndPermissionsScreen(context: viewModel.context)) + } +} diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenModels.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenModels.swift new file mode 100644 index 000000000..ab94bc926 --- /dev/null +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenModels.swift @@ -0,0 +1,44 @@ +// +// Copyright 2022 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 Foundation + +enum RoomRolesAndPermissionsScreenViewModelAction { + case editRoles(RoomRolesAndPermissionsScreenRole) + case editPermissions(RoomRolesAndPermissionsScreenPermissionsGroup) +} + +struct RoomRolesAndPermissionsScreenViewState: BindableState { + var administratorCount: Int? + var moderatorCount: Int? +} + +enum RoomRolesAndPermissionsScreenViewAction { + case editRoles(RoomRolesAndPermissionsScreenRole) + case editPermissions(RoomRolesAndPermissionsScreenPermissionsGroup) + case reset +} + +enum RoomRolesAndPermissionsScreenRole { + case administrators + case moderators +} + +enum RoomRolesAndPermissionsScreenPermissionsGroup { + case roomDetails + case messagesAndContent + case memberModeration +} diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift new file mode 100644 index 000000000..150a398e7 --- /dev/null +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift @@ -0,0 +1,63 @@ +// +// Copyright 2022 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 Combine +import SwiftUI + +typealias RoomRolesAndPermissionsScreenViewModelType = StateStoreViewModel + +class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewModelType, RoomRolesAndPermissionsScreenViewModelProtocol { + private let roomProxy: RoomProxyProtocol + private var actionsSubject: PassthroughSubject = .init() + + var actions: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(roomProxy: RoomProxyProtocol) { + self.roomProxy = roomProxy + super.init(initialViewState: RoomRolesAndPermissionsScreenViewState()) + + roomProxy.members.sink { [weak self] members in + self?.updateMembers(members) + } + .store(in: &cancellables) + + updateMembers(roomProxy.members.value) + } + + // MARK: - Public + + override func process(viewAction: RoomRolesAndPermissionsScreenViewAction) { + MXLog.info("View model: received view action: \(viewAction)") + + switch viewAction { + case .editRoles(let role): + actionsSubject.send(.editRoles(role)) + case .editPermissions(let permissionsGroup): + actionsSubject.send(.editPermissions(permissionsGroup)) + case .reset: + break + } + } + + // MARK: - Members + + private func updateMembers(_ members: [RoomMemberProxyProtocol]) { + state.administratorCount = members.filter { $0.role == .administrator }.count + state.moderatorCount = members.filter { $0.role == .moderator }.count + } +} diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModelProtocol.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModelProtocol.swift new file mode 100644 index 000000000..2e9367fcc --- /dev/null +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModelProtocol.swift @@ -0,0 +1,23 @@ +// +// Copyright 2022 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 Combine + +@MainActor +protocol RoomRolesAndPermissionsScreenViewModelProtocol { + var actions: AnyPublisher { get } + var context: RoomRolesAndPermissionsScreenViewModelType.Context { get } +} diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/View/RoomRolesAndPermissionsScreen.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/View/RoomRolesAndPermissionsScreen.swift new file mode 100644 index 000000000..7f73826b4 --- /dev/null +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/View/RoomRolesAndPermissionsScreen.swift @@ -0,0 +1,117 @@ +// +// Copyright 2022 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 RoomRolesAndPermissionsScreen: View { + @ObservedObject var context: RoomRolesAndPermissionsScreenViewModel.Context + + var body: some View { + Form { + rolesSection + permissionsSection + + resetSection + } + .compoundList() + .navigationTitle(L10n.screenRoomRolesAndPermissionsTitle) + .navigationBarTitleDisplayMode(.inline) + } + + private var rolesSection: some View { + Section { + ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsAdmins, + icon: \.admin), + details: administratorDetails, + kind: .navigationLink { + context.send(viewAction: .editRoles(.administrators)) + }) + + ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsModerators, + icon: \.chatProblem), + details: moderatorDetails, + kind: .navigationLink { + context.send(viewAction: .editRoles(.moderators)) + }) + } header: { + Text(L10n.screenRoomRolesAndPermissionsRolesHeader) + .compoundListSectionHeader() + } + } + + private var administratorDetails: ListRowDetails { + if let administratorCount = context.viewState.administratorCount { + .title("\(administratorCount)") + } else { + .isWaiting(true) + } + } + + private var moderatorDetails: ListRowDetails { + if let moderatorCount = context.viewState.moderatorCount { + .title("\(moderatorCount)") + } else { + .isWaiting(true) + } + } + + private var permissionsSection: some View { + Section { + ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsRoomDetails, + icon: \.info), + kind: .navigationLink { + context.send(viewAction: .editPermissions(.roomDetails)) + }) + + ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsMessagesAndContent, + icon: \.chat), + kind: .navigationLink { + context.send(viewAction: .editPermissions(.messagesAndContent)) + }) + + ListRow(label: .default(title: L10n.screenRoomRolesAndPermissionsMemberModeration, + icon: \.user), + kind: .navigationLink { + context.send(viewAction: .editPermissions(.memberModeration)) + }) + } header: { + Text(L10n.screenRoomRolesAndPermissionsPermissionsHeader) + .compoundListSectionHeader() + } + } + + private var resetSection: some View { + Section { + ListRow(label: .plain(title: L10n.screenRoomRolesAndPermissionsReset, + role: .destructive), + kind: .button { + context.send(viewAction: .reset) + }) + } + } +} + +// MARK: - Previews + +struct RoomRolesAndPermissionsScreen_Previews: PreviewProvider, TestablePreview { + static let viewModel = RoomRolesAndPermissionsScreenViewModel(roomProxy: RoomProxyMock(with: .init(members: .allMembersAsAdmin))) + static var previews: some View { + NavigationStack { + RoomRolesAndPermissionsScreen(context: viewModel.context) + } + } +} diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomRolesAndPermissionsScreen.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomRolesAndPermissionsScreen.1.png new file mode 100644 index 000000000..9e0dab3c4 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomRolesAndPermissionsScreen.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb68d85ebb6e0b8300d0c6a2b99c2fdbefc56a4ff68d93c17705b675626c1f49 +size 135130 diff --git a/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift b/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift new file mode 100644 index 000000000..7938f2532 --- /dev/null +++ b/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift @@ -0,0 +1,40 @@ +// +// Copyright 2022 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 XCTest + +@testable import ElementX + +@MainActor +class RoomRolesAndPermissionsScreenViewModelTests: XCTestCase { + var viewModel: RoomRolesAndPermissionsScreenViewModelProtocol! + + var context: RoomRolesAndPermissionsScreenViewModelType.Context { + viewModel.context + } + + func testEmptyCounters() { + viewModel = RoomRolesAndPermissionsScreenViewModel(roomProxy: RoomProxyMock(with: .init())) + XCTAssertEqual(context.viewState.administratorCount, 0) + XCTAssertEqual(context.viewState.moderatorCount, 0) + } + + func testFilledCounters() async throws { + viewModel = RoomRolesAndPermissionsScreenViewModel(roomProxy: RoomProxyMock(with: .init(members: .allMembersAsAdmin))) + XCTAssertEqual(context.viewState.administratorCount, 2) + XCTAssertEqual(context.viewState.moderatorCount, 1) + } +} diff --git a/changelog.d/pr-2505.wip b/changelog.d/pr-2505.wip new file mode 100644 index 000000000..c63c4047e --- /dev/null +++ b/changelog.d/pr-2505.wip @@ -0,0 +1 @@ +Create the Roles and Permissions screen. \ No newline at end of file