From b3140f3f9e1d63e4d70f4efc49ae7712b84b5d2a Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 21 Feb 2024 12:19:12 +0200 Subject: [PATCH] Fixes #2486 - Add a blocked users section in the app settings --- ElementX.xcodeproj/project.pbxproj | 40 ++++++++ .../SettingsFlowCoordinator.swift | 8 ++ .../Other/AccessibilityIdentifiers.swift | 1 + ElementX/Sources/Other/AvatarSize.swift | 3 + .../BlockedUsersScreenCoordinator.swift | 47 +++++++++ .../BlockedUsersScreenModels.swift | 39 ++++++++ .../BlockedUsersScreenViewModel.swift | 97 +++++++++++++++++++ .../BlockedUsersScreenViewModelProtocol.swift | 23 +++++ .../View/BlockedUsersScreen.swift | 60 ++++++++++++ .../SettingsScreenCoordinator.swift | 3 + .../SettingsScreen/SettingsScreenModels.swift | 2 + .../SettingsScreenViewModel.swift | 2 + .../SettingsScreen/View/SettingsScreen.swift | 7 ++ .../Services/Client/MockClientProxy.swift | 5 +- .../test_blockedUsersScreen.1.png | 3 + .../PreviewTests/test_settingsScreen.1.png | 4 +- .../en-GB-iPad-9th-generation.settings.png | 4 +- .../Application/en-GB-iPhone-14.settings.png | 4 +- .../pseudo-iPad-9th-generation.settings.png | 4 +- .../Application/pseudo-iPhone-14.settings.png | 4 +- .../BlockedUsersScreenViewModelTests.swift | 32 ++++++ changelog.d/2486.feature | 1 + 22 files changed, 382 insertions(+), 11 deletions(-) create mode 100644 ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenCoordinator.swift create mode 100644 ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenModels.swift create mode 100644 ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift create mode 100644 ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModelProtocol.swift create mode 100644 ElementX/Sources/Screens/BlockedUsersScreen/View/BlockedUsersScreen.swift create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_blockedUsersScreen.1.png create mode 100644 UnitTests/Sources/BlockedUsersScreenViewModelTests.swift create mode 100644 changelog.d/2486.feature diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index a17008a708..5d4f1c690b 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -217,6 +217,7 @@ 35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; }; 366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */; }; 368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */; }; + 369BF960E52BBEE61F8A5BD1 /* BlockedUsersScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */; }; 36AC963F2F04069B7FF1AA0C /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */; }; 36AD4DD4C798E22584ED3200 /* Emojibase in Frameworks */ = {isa = PBXBuildFile; productRef = C05729B1684C331F5FFE9232 /* Emojibase */; }; 36CD6E11B37396E14F032CB6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; }; @@ -562,6 +563,7 @@ 8C1A5ECAF895D4CAF8C4D461 /* AppActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F21ED7205048668BEB44A38 /* AppActivityView.swift */; }; 8C42B5B1642D189C362A5EDF /* SecureBackupScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91831D7042EADD0CC2B5EC36 /* SecureBackupScreenUITests.swift */; }; 8C706DA7EAC0974CA2F8F1CD /* MentionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15748C254911E3654C93B0ED /* MentionBuilder.swift */; }; + 8C91D242BEEC657FABCC0B95 /* BlockedUsersScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8642512079EEFD622E3AA66B /* BlockedUsersScreenModels.swift */; }; 8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */; }; 8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */; }; 8D71E5E53F372202379BECCE /* BugReportScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 303FCADE77DF1F3670C086ED /* BugReportScreenViewModel.swift */; }; @@ -582,6 +584,7 @@ 92720AB0DA9AB5EEF1DAF56B /* SecureBackupLogoutConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DC017C3CB6B0F7C63F460F2 /* SecureBackupLogoutConfirmationScreenViewModel.swift */; }; 9278EC51D24E57445B290521 /* AudioSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */; }; 92D9088B901CEBB1A99ECA4E /* RoomMemberProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */; }; + 934051B17A884AB0635DF81B /* BlockedUsersScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A010B8EAD1A9F6B4686DF2F4 /* BlockedUsersScreenViewModel.swift */; }; 93875ADD456142D20823ED24 /* ServerSelectionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */; }; 93A549135E6C027A0D823BFE /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 593FBBF394712F2963E98A0B /* DTCoreText */; }; 93BA4A81B6D893271101F9F0 /* DeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = A7CA6F33C553805035C3B114 /* DeviceKit */; }; @@ -593,6 +596,7 @@ 94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; }; 95690DDD9D547D3D842ACBE3 /* AnalyticsSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */; }; 9586E90A447C4896C0CA3A8E /* TimelineItemReplyDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE89A8BD65CCE3FCC925CA14 /* TimelineItemReplyDetails.swift */; }; + 95E7B236F7116CACE05A6BC9 /* BlockedUsersScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16D0F226B1819D017531647 /* BlockedUsersScreenCoordinator.swift */; }; 962A4F8AD6312804E2C6BB6E /* PhotoLibraryPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A232D9156D225BD9FD1D0C43 /* PhotoLibraryPicker.swift */; }; 964B9D2EC38C488C360CE0C9 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B902EA6CD3296B0E10EE432B /* HomeScreen.swift */; }; 968A5B890004526AB58A217C /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */; }; @@ -657,6 +661,7 @@ A440D4BC02088482EC633A88 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */; }; A494741843F087881299ACF0 /* RestorationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3558A15CFB934F9229301527 /* RestorationToken.swift */; }; A4B0BAD62A12ED76BD611B79 /* BadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1FA515B3B0D61EF1E907D2D /* BadgeView.swift */; }; + A4B123C635F70DDD4BC2FAC9 /* BlockedUsersScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76A706B3EEA32B882DA5E2D /* BlockedUsersScreenViewModelProtocol.swift */; }; A4C29D373986AFE4559696D5 /* SecureBackupKeyBackupScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4525E8C0FBDD27D1ACE90952 /* SecureBackupKeyBackupScreenViewModelProtocol.swift */; }; A4E885358D7DD5A072A06824 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = CCE5BF78B125320CBF3BB834 /* PostHog */; }; A5B9EF45C7B8ACEB4954AE36 /* LoginScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9780389F8A53E4D26E23DD03 /* LoginScreenViewModelProtocol.swift */; }; @@ -831,6 +836,7 @@ CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; }; CE6F237360875D3D573FD0B2 /* RoomNotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */; }; CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; }; + CEAEA57B7665C8E790599A78 /* BlockedUsersScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 240610DF32F3213BEC5611D7 /* BlockedUsersScreenViewModelTests.swift */; }; CEB8FB1269DE20536608B957 /* LoginMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41FABA2B0AEF4389986495 /* LoginMode.swift */; }; CF3827071B0BC9638BD44F5D /* WaitlistScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB58EF0176D4CFB1040DA22 /* WaitlistScreenViewModel.swift */; }; CF38B70D8C6DD42C00A56A27 /* LogViewerScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */; }; @@ -1223,6 +1229,7 @@ 2355398E4A55DA5A89128AD1 /* EncryptionKeyProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyProvider.swift; sourceTree = ""; }; 2389732B0E115A999A069083 /* NotificationSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenCoordinator.swift; sourceTree = ""; }; 23AA3F4B285570805CB0CCDD /* MapTiler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTiler.swift; sourceTree = ""; }; + 240610DF32F3213BEC5611D7 /* BlockedUsersScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenViewModelTests.swift; sourceTree = ""; }; 24227FF9A2797F6EA7F69CDD /* HomeScreenInvitesButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenInvitesButton.swift; sourceTree = ""; }; 2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerTests.swift; sourceTree = ""; }; 2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderTests.swift; sourceTree = ""; }; @@ -1582,6 +1589,7 @@ 85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = ""; }; 8610C1D21565C950BCA6A454 /* AppLockSetupSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; 86376BEE425704AEE197CA54 /* PillContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContext.swift; sourceTree = ""; }; + 8642512079EEFD622E3AA66B /* BlockedUsersScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenModels.swift; sourceTree = ""; }; 86873A768B13069BB5CAECF6 /* InvitesScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenViewModelProtocol.swift; sourceTree = ""; }; 86A6F283BC574FDB96ABBB07 /* DeveloperOptionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenViewModel.swift; sourceTree = ""; }; 86C8CE2630F54D5FE1591786 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -1665,6 +1673,7 @@ 9F85164F9475FF2867F71AAA /* RoomTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineController.swift; sourceTree = ""; }; 9FB4F169D653296023ED65E6 /* NSESettingsProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESettingsProtocol.swift; sourceTree = ""; }; A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelProtocol.swift; sourceTree = ""; }; + A010B8EAD1A9F6B4686DF2F4 /* BlockedUsersScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenViewModel.swift; sourceTree = ""; }; A019A12C866D64CF072024B9 /* AppLockSetupPINScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupPINScreenViewModel.swift; sourceTree = ""; }; A02D1A490944BF01A37586E1 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/SAS.strings; sourceTree = ""; }; A05707BF550D770168A406DB /* LoginViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModelTests.swift; sourceTree = ""; }; @@ -1673,6 +1682,7 @@ A12D3B1BCF920880CA8BBB6B /* UserIndicatorControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerProtocol.swift; sourceTree = ""; }; A130A2251A15A7AACC84FD37 /* RoomPollsHistoryScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPollsHistoryScreenViewModelProtocol.swift; sourceTree = ""; }; A16CD2C62CB7DB78A4238485 /* ReportContentScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenCoordinator.swift; sourceTree = ""; }; + A16D0F226B1819D017531647 /* BlockedUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenCoordinator.swift; sourceTree = ""; }; A1BF12A5E7C76777C4BF0F2B /* TimelineItemMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenu.swift; sourceTree = ""; }; A1C22B1B5FA3A765EADB2CC9 /* SessionVerificationStateMachineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationStateMachineTests.swift; sourceTree = ""; }; A232D9156D225BD9FD1D0C43 /* PhotoLibraryPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryPicker.swift; sourceTree = ""; }; @@ -1957,6 +1967,7 @@ E6F5D66F158A6662F953733E /* NotificationSettingsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxy.swift; sourceTree = ""; }; E6FCC416A3BFE73DF7B3E6BF /* RoomTimelineControllerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerFactory.swift; sourceTree = ""; }; E71C28CF29CD05B6D6AE8580 /* HomeScreenSessionVerificationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenSessionVerificationBanner.swift; sourceTree = ""; }; + E76A706B3EEA32B882DA5E2D /* BlockedUsersScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenViewModelProtocol.swift; sourceTree = ""; }; E78FC546F28E045A560F2963 /* EncryptionKeyProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyProviderProtocol.swift; sourceTree = ""; }; E8294DB9E95C0C0630418466 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; E8774CF614849664B5B3C2A1 /* UserSessionFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinatorStateMachine.swift; sourceTree = ""; }; @@ -1980,6 +1991,7 @@ ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = ""; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = ""; }; ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = ""; }; + ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = ""; }; ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = ""; }; EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = ""; }; EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = ""; }; @@ -2510,6 +2522,14 @@ path = ServerSelectionScreen; sourceTree = ""; }; + 2E035B978E415C77423FA3C2 /* View */ = { + isa = PBXGroup; + children = ( + ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */, + ); + path = View; + sourceTree = ""; + }; 2ECFF6B05DAA37EB10DBF7E8 /* UITests */ = { isa = PBXGroup; children = ( @@ -3352,6 +3372,7 @@ C55CC239AE12339C565F6C9A /* AudioRecorderStateTests.swift */, 2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */, 6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */, + 240610DF32F3213BEC5611D7 /* BlockedUsersScreenViewModelTests.swift */, EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */, 7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */, CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */, @@ -4623,6 +4644,7 @@ 669239C03835CD8B51E0FFDB /* AnalyticsPromptScreen */, 13263FFEA7749D822B51AA90 /* AppLock */, E74CD7681375AD2EAA34D66B /* Authentication */, + EFD4F7FCAAAB3EF45EE7A067 /* BlockedUsersScreen */, 53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */, 1185EECDD07495D65AC84AFC /* CallScreen */, 27F2500AC8736AAE774520C0 /* ComposerToolbar */, @@ -4771,6 +4793,18 @@ path = StartChatScreen; sourceTree = ""; }; + EFD4F7FCAAAB3EF45EE7A067 /* BlockedUsersScreen */ = { + isa = PBXGroup; + children = ( + A16D0F226B1819D017531647 /* BlockedUsersScreenCoordinator.swift */, + 8642512079EEFD622E3AA66B /* BlockedUsersScreenModels.swift */, + A010B8EAD1A9F6B4686DF2F4 /* BlockedUsersScreenViewModel.swift */, + E76A706B3EEA32B882DA5E2D /* BlockedUsersScreenViewModelProtocol.swift */, + 2E035B978E415C77423FA3C2 /* View */, + ); + path = BlockedUsersScreen; + sourceTree = ""; + }; F12966DF3DA87FEF21348D60 /* InviteUsersScreen */ = { isa = PBXGroup; children = ( @@ -5393,6 +5427,7 @@ 3042527CB344A9EF1157FC26 /* AudioRecorderStateTests.swift in Sources */, 192A3CDCD0174AD1E4A128E4 /* AudioRecorderTests.swift in Sources */, 0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */, + CEAEA57B7665C8E790599A78 /* BlockedUsersScreenViewModelTests.swift in Sources */, 7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */, C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */, 366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */, @@ -5590,6 +5625,11 @@ A4B0BAD62A12ED76BD611B79 /* BadgeView.swift in Sources */, 38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */, EB9F4688006B52E69DF5358F /* BlankFormCoordinator.swift in Sources */, + 369BF960E52BBEE61F8A5BD1 /* BlockedUsersScreen.swift in Sources */, + 95E7B236F7116CACE05A6BC9 /* BlockedUsersScreenCoordinator.swift in Sources */, + 8C91D242BEEC657FABCC0B95 /* BlockedUsersScreenModels.swift in Sources */, + 934051B17A884AB0635DF81B /* BlockedUsersScreenViewModel.swift in Sources */, + A4B123C635F70DDD4BC2FAC9 /* BlockedUsersScreenViewModelProtocol.swift in Sources */, 5EE1D4E316D66943E97FDCF2 /* BloomView.swift in Sources */, B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */, E794AB6ABE1FF5AF0573FEA1 /* BlurHashEncode.swift in Sources */, diff --git a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift index f47eab2765..20c6813d50 100644 --- a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift @@ -128,6 +128,8 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { bugReportFlowCoordinator?.start() case .about: presentLegalInformationScreen() + case .blockedUsers: + presentBlockedUsersScreen() case .sessionVerification: presentSessionVerificationScreen() case .accountSessions: @@ -203,6 +205,12 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { navigationStackCoordinator.push(LegalInformationScreenCoordinator(appSettings: parameters.appSettings)) } + private func presentBlockedUsersScreen() { + let coordinator = BlockedUsersScreenCoordinator(parameters: .init(clientProxy: parameters.userSession.clientProxy, + userIndicatorController: parameters.userIndicatorController)) + navigationStackCoordinator.push(coordinator) + } + private func presentSessionVerificationScreen() { guard let sessionVerificationController = parameters.userSession.sessionVerificationController else { fatalError("The sessionVerificationController should aways be valid at this point") diff --git a/ElementX/Sources/Other/AccessibilityIdentifiers.swift b/ElementX/Sources/Other/AccessibilityIdentifiers.swift index ef0a685145..2dec3ab73e 100644 --- a/ElementX/Sources/Other/AccessibilityIdentifiers.swift +++ b/ElementX/Sources/Other/AccessibilityIdentifiers.swift @@ -210,6 +210,7 @@ enum A11yIdentifiers { let screenLock = "settings-screen_lock" let reportBug = "settings-report_bug" let about = "settings_about" + let blockedUsers = "settings_blocked-users" let advancedSettings = "settings_advanced-settings" let developerOptions = "settings_developer-options" let logout = "settings-logout" diff --git a/ElementX/Sources/Other/AvatarSize.swift b/ElementX/Sources/Other/AvatarSize.swift index a031bbfe84..551ede3029 100644 --- a/ElementX/Sources/Other/AvatarSize.swift +++ b/ElementX/Sources/Other/AvatarSize.swift @@ -53,6 +53,7 @@ enum UserAvatarSizeOnScreen { case readReceiptSheet case editUserDetails case suggestions + case blockedUsers var value: CGFloat { switch self { @@ -66,6 +67,8 @@ enum UserAvatarSizeOnScreen { return 32 case .suggestions: return 32 + case .blockedUsers: + return 32 case .settings: return 52 case .roomDetails: diff --git a/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenCoordinator.swift b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenCoordinator.swift new file mode 100644 index 0000000000..2f44298df4 --- /dev/null +++ b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenCoordinator.swift @@ -0,0 +1,47 @@ +// +// 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 + +struct BlockedUsersScreenCoordinatorParameters { + let clientProxy: ClientProxyProtocol + let userIndicatorController: UserIndicatorControllerProtocol +} + +enum BlockedUsersScreenCoordinatorAction { } + +final class BlockedUsersScreenCoordinator: CoordinatorProtocol { + private let viewModel: BlockedUsersScreenViewModelProtocol + + private var cancellables = Set() + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(parameters: BlockedUsersScreenCoordinatorParameters) { + viewModel = BlockedUsersScreenViewModel(clientProxy: parameters.clientProxy, + userIndicatorController: parameters.userIndicatorController) + } + + func start() { } + + func toPresentable() -> AnyView { + AnyView(BlockedUsersScreen(context: viewModel.context)) + } +} diff --git a/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenModels.swift b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenModels.swift new file mode 100644 index 0000000000..6ab4d32806 --- /dev/null +++ b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenModels.swift @@ -0,0 +1,39 @@ +// +// 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 BlockedUsersScreenViewModelAction { } + +struct BlockedUsersScreenViewState: BindableState { + var blockedUsers: [String] + var processingUserID: String? + + var bindings = BlockedUsersScreenViewStateBindings() +} + +struct BlockedUsersScreenViewStateBindings { + var alertInfo: AlertInfo? +} + +enum BlockedUsersScreenViewAction { + case unblockUser(userID: String) +} + +enum BlockedUsersScreenViewStateAlertType: Hashable { + case unblock + case error +} diff --git a/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift new file mode 100644 index 0000000000..7114f493cb --- /dev/null +++ b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift @@ -0,0 +1,97 @@ +// +// 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 BlockedUsersScreenViewModelType = StateStoreViewModel + +class BlockedUsersScreenViewModel: BlockedUsersScreenViewModelType, BlockedUsersScreenViewModelProtocol { + let clientProxy: ClientProxyProtocol + let userIndicatorController: UserIndicatorControllerProtocol + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(clientProxy: ClientProxyProtocol, + userIndicatorController: UserIndicatorControllerProtocol) { + self.clientProxy = clientProxy + self.userIndicatorController = userIndicatorController + + super.init(initialViewState: BlockedUsersScreenViewState(blockedUsers: clientProxy.ignoredUsersPublisher.value ?? [])) + + showLoadingIndicator() + + clientProxy.ignoredUsersPublisher + .receive(on: DispatchQueue.main) + .sink { [weak self] blockedUsers in + guard let self else { return } + + if let blockedUsers { + hideLoadingIndicator() + state.blockedUsers = blockedUsers + } + } + .store(in: &cancellables) + } + + // MARK: - Public + + override func process(viewAction: BlockedUsersScreenViewAction) { + switch viewAction { + case .unblockUser(let userID): + state.bindings.alertInfo = .init(id: .unblock, + title: L10n.screenBlockedUsersUnblockAlertTitle, + message: L10n.screenBlockedUsersUnblockAlertDescription, + primaryButton: .init(title: L10n.screenBlockedUsersUnblockAlertAction, role: .destructive) { [weak self] in + self?.unblockUser(userID) + }, + secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil)) + } + } + + // MARK: - Private + + private func unblockUser(_ userID: String) { + state.processingUserID = userID + + Task { + if case .failure = await clientProxy.unignoreUser(userID) { + state.bindings.alertInfo = .init(id: .error) + } + + state.processingUserID = nil + } + } + + // MARK: Loading indicator + + private static let loadingIndicatorIdentifier = "BlockedUsersLoading" + + private func showLoadingIndicator() { + userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal(progress: .indeterminate, interactiveDismissDisabled: false, allowsInteraction: true), + title: L10n.commonLoading, + persistent: true), + delay: .milliseconds(100)) + } + + private func hideLoadingIndicator() { + userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) + } +} diff --git a/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModelProtocol.swift b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModelProtocol.swift new file mode 100644 index 0000000000..2e39d0d64d --- /dev/null +++ b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModelProtocol.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 BlockedUsersScreenViewModelProtocol { + var actionsPublisher: AnyPublisher { get } + var context: BlockedUsersScreenViewModelType.Context { get } +} diff --git a/ElementX/Sources/Screens/BlockedUsersScreen/View/BlockedUsersScreen.swift b/ElementX/Sources/Screens/BlockedUsersScreen/View/BlockedUsersScreen.swift new file mode 100644 index 0000000000..f70e107c48 --- /dev/null +++ b/ElementX/Sources/Screens/BlockedUsersScreen/View/BlockedUsersScreen.swift @@ -0,0 +1,60 @@ +// +// 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 BlockedUsersScreen: View { + @ObservedObject var context: BlockedUsersScreenViewModel.Context + + var body: some View { + Form { + ForEach(context.viewState.blockedUsers, id: \.self) { userID in + ListRow(label: .avatar(title: userID, icon: avatar(for: userID)), + details: .isWaiting(context.viewState.processingUserID == userID), + kind: .button(action: { context.send(viewAction: .unblockUser(userID: userID)) })) + } + } + .compoundList() + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(L10n.commonBlockedUsers) + .alert(item: $context.alertInfo) + } + + // MARK: - Private + + private func avatar(for userID: String) -> some View { + LoadableAvatarImage(url: nil, + name: String(userID.dropFirst()), + contentID: userID, + avatarSize: .user(on: .blockedUsers), + imageProvider: nil) + .accessibilityHidden(true) + } +} + +// MARK: - Previews + +struct BlockedUsersScreen_Previews: PreviewProvider, TestablePreview { + static let viewModel = BlockedUsersScreenViewModel(clientProxy: MockClientProxy(userID: RoomMemberProxyMock.mockMe.userID), + userIndicatorController: UserIndicatorControllerMock()) + + static var previews: some View { + NavigationStack { + BlockedUsersScreen(context: viewModel.context) + } + } +} diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift index 3d2256169e..cc3d8afd5c 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift @@ -32,6 +32,7 @@ enum SettingsScreenCoordinatorAction { case appLock case bugReport case about + case blockedUsers case sessionVerification case accountSessions case notifications @@ -74,6 +75,8 @@ final class SettingsScreenCoordinator: CoordinatorProtocol { actionsSubject.send(.bugReport) case .about: actionsSubject.send(.about) + case .blockedUsers: + actionsSubject.send(.blockedUsers) case .sessionVerification: actionsSubject.send(.sessionVerification) case .secureBackup: diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift index d3b4f1e0aa..ae931ec08d 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift @@ -25,6 +25,7 @@ enum SettingsScreenViewModelAction { case appLock case reportBug case about + case blockedUsers case sessionVerification case secureBackup case accountSessionsList @@ -61,6 +62,7 @@ enum SettingsScreenViewAction { case appLock case reportBug case about + case blockedUsers case sessionVerification case secureBackup case accountSessionsList diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift index 2fd24f4689..a74d296b9b 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift @@ -94,6 +94,8 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo actionsSubject.send(.reportBug) case .about: actionsSubject.send(.about) + case .blockedUsers: + actionsSubject.send(.blockedUsers) case .logout: actionsSubject.send(.logout) case .sessionVerification: diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift index 606fd2b0f2..a8ac247ad6 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift @@ -143,6 +143,13 @@ struct SettingsScreen: View { context.send(viewAction: .about) }) .accessibilityIdentifier(A11yIdentifiers.settingsScreen.about) + + ListRow(label: .default(title: L10n.commonBlockedUsers, + icon: \.block), + kind: .navigationLink { + context.send(viewAction: .blockedUsers) + }) + .accessibilityIdentifier(A11yIdentifiers.settingsScreen.blockedUsers) } } diff --git a/ElementX/Sources/Services/Client/MockClientProxy.swift b/ElementX/Sources/Services/Client/MockClientProxy.swift index 3a7bb2f98e..b17051da31 100644 --- a/ElementX/Sources/Services/Client/MockClientProxy.swift +++ b/ElementX/Sources/Services/Client/MockClientProxy.swift @@ -41,7 +41,10 @@ class MockClientProxy: ClientProxyProtocol { var userDisplayNamePublisher: CurrentValuePublisher { CurrentValueSubject("User display name").asCurrentValuePublisher() } - var ignoredUsersPublisher: CurrentValuePublisher<[String]?, Never> { CurrentValueSubject<[String]?, Never>([]).asCurrentValuePublisher() } + var ignoredUsersPublisher: CurrentValuePublisher<[String]?, Never> { + let ignoredUsers = [RoomMemberProxyMock].allMembers.map(\.userID) + return CurrentValueSubject<[String]?, Never>(ignoredUsers).asCurrentValuePublisher() + } var notificationSettings: NotificationSettingsProxyProtocol = NotificationSettingsProxyMock(with: .init()) diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_blockedUsersScreen.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_blockedUsersScreen.1.png new file mode 100644 index 0000000000..98cf94cb7a --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_blockedUsersScreen.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9fdecb8d69665bd20ce42c29a94df8fd912f1c3688207c02c2bf0ef955e80d1 +size 144194 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_settingsScreen.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_settingsScreen.1.png index 46840bfd43..40935f2d2b 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_settingsScreen.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_settingsScreen.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0e4f20a3da82d547d5802aa2dc96db5de6520792be495069ef9c7a80168c655 -size 171367 +oid sha256:ef88023b3f423e15d540d755d987edf4a5d7ea2580a30509d79d23ff93235c13 +size 174925 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.settings.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.settings.png index 206bb8c880..8953bebb93 100644 --- a/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.settings.png +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.settings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3c08ea0ffa71cf6eb554ddc394a7db01325588bb93e3ab094f18a76f669dd9e -size 138739 +oid sha256:1e6b1f4f3a3d38a5a55557a0458c46d2ac4c44fc438230ce059fa8b323a8c8ef +size 145116 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.settings.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.settings.png index baf1c442e7..0a395704f4 100644 --- a/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.settings.png +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.settings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25076c598482ee48360108f0acc67cde09d191a51c296afb763018bbd748291f -size 164268 +oid sha256:13a413c5db74eb8127c9c2c0ae6d0f5633bc40f5c100f7ae679f314785af7116 +size 172723 diff --git a/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.settings.png b/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.settings.png index c9cb63881d..5fc5a5bac9 100644 --- a/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.settings.png +++ b/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.settings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:400e3eba5557dd4138c7b8ff2cc305dd95e74c3e1b86f2bd5675a5c7c8dcf656 -size 148563 +oid sha256:30bebd1f04d98e9a62567e8dc51762b8d0e25baf437a296210652a16fe522c52 +size 155955 diff --git a/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.settings.png b/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.settings.png index 3e90a1b8d8..14a39f96e8 100644 --- a/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.settings.png +++ b/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.settings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e1eb3e2304004c1d0b21f8431678fdbf9c7e751c57ff4c686706d37fec9bc0d3 -size 184449 +oid sha256:666546d6087d733ad951d2d3a64eae1f6b2a2a43962d1f724b2b1d3da43531e0 +size 190544 diff --git a/UnitTests/Sources/BlockedUsersScreenViewModelTests.swift b/UnitTests/Sources/BlockedUsersScreenViewModelTests.swift new file mode 100644 index 0000000000..4c9c7bddb8 --- /dev/null +++ b/UnitTests/Sources/BlockedUsersScreenViewModelTests.swift @@ -0,0 +1,32 @@ +// +// 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 XCTest + +@testable import ElementX + +@MainActor +class BlockedUsersScreenViewModelTests: XCTestCase { + func testInitialState() { + let clientProxy = MockClientProxy(userID: RoomMemberProxyMock.mockMe.userID) + + let viewModel = BlockedUsersScreenViewModel(clientProxy: clientProxy, + userIndicatorController: ServiceLocator.shared.userIndicatorController) + + XCTAssertFalse(viewModel.context.viewState.blockedUsers.isEmpty) + } +} diff --git a/changelog.d/2486.feature b/changelog.d/2486.feature new file mode 100644 index 0000000000..06a557819c --- /dev/null +++ b/changelog.d/2486.feature @@ -0,0 +1 @@ +Add a blocked users section in the app settings \ No newline at end of file