mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 20:09:04 +00:00
Fixes #2486 - Implement blocked users management in the app settings
This commit is contained in:
@@ -217,6 +217,7 @@
|
|||||||
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
||||||
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */; };
|
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */; };
|
||||||
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.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 */; };
|
36AC963F2F04069B7FF1AA0C /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */; };
|
||||||
36AD4DD4C798E22584ED3200 /* Emojibase in Frameworks */ = {isa = PBXBuildFile; productRef = C05729B1684C331F5FFE9232 /* Emojibase */; };
|
36AD4DD4C798E22584ED3200 /* Emojibase in Frameworks */ = {isa = PBXBuildFile; productRef = C05729B1684C331F5FFE9232 /* Emojibase */; };
|
||||||
36CD6E11B37396E14F032CB6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; };
|
36CD6E11B37396E14F032CB6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; };
|
||||||
@@ -562,6 +563,7 @@
|
|||||||
8C1A5ECAF895D4CAF8C4D461 /* AppActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F21ED7205048668BEB44A38 /* AppActivityView.swift */; };
|
8C1A5ECAF895D4CAF8C4D461 /* AppActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F21ED7205048668BEB44A38 /* AppActivityView.swift */; };
|
||||||
8C42B5B1642D189C362A5EDF /* SecureBackupScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91831D7042EADD0CC2B5EC36 /* SecureBackupScreenUITests.swift */; };
|
8C42B5B1642D189C362A5EDF /* SecureBackupScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91831D7042EADD0CC2B5EC36 /* SecureBackupScreenUITests.swift */; };
|
||||||
8C706DA7EAC0974CA2F8F1CD /* MentionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15748C254911E3654C93B0ED /* MentionBuilder.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 */; };
|
8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */; };
|
||||||
8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */; };
|
8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */; };
|
||||||
8D71E5E53F372202379BECCE /* BugReportScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 303FCADE77DF1F3670C086ED /* BugReportScreenViewModel.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 */; };
|
92720AB0DA9AB5EEF1DAF56B /* SecureBackupLogoutConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DC017C3CB6B0F7C63F460F2 /* SecureBackupLogoutConfirmationScreenViewModel.swift */; };
|
||||||
9278EC51D24E57445B290521 /* AudioSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */; };
|
9278EC51D24E57445B290521 /* AudioSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */; };
|
||||||
92D9088B901CEBB1A99ECA4E /* RoomMemberProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.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 */; };
|
93875ADD456142D20823ED24 /* ServerSelectionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */; };
|
||||||
93A549135E6C027A0D823BFE /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 593FBBF394712F2963E98A0B /* DTCoreText */; };
|
93A549135E6C027A0D823BFE /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 593FBBF394712F2963E98A0B /* DTCoreText */; };
|
||||||
93BA4A81B6D893271101F9F0 /* DeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = A7CA6F33C553805035C3B114 /* DeviceKit */; };
|
93BA4A81B6D893271101F9F0 /* DeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = A7CA6F33C553805035C3B114 /* DeviceKit */; };
|
||||||
@@ -593,6 +596,7 @@
|
|||||||
94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; };
|
94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; };
|
||||||
95690DDD9D547D3D842ACBE3 /* AnalyticsSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */; };
|
95690DDD9D547D3D842ACBE3 /* AnalyticsSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */; };
|
||||||
9586E90A447C4896C0CA3A8E /* TimelineItemReplyDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE89A8BD65CCE3FCC925CA14 /* TimelineItemReplyDetails.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 */; };
|
962A4F8AD6312804E2C6BB6E /* PhotoLibraryPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A232D9156D225BD9FD1D0C43 /* PhotoLibraryPicker.swift */; };
|
||||||
964B9D2EC38C488C360CE0C9 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B902EA6CD3296B0E10EE432B /* HomeScreen.swift */; };
|
964B9D2EC38C488C360CE0C9 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B902EA6CD3296B0E10EE432B /* HomeScreen.swift */; };
|
||||||
968A5B890004526AB58A217C /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.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 */; };
|
A440D4BC02088482EC633A88 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */; };
|
||||||
A494741843F087881299ACF0 /* RestorationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3558A15CFB934F9229301527 /* RestorationToken.swift */; };
|
A494741843F087881299ACF0 /* RestorationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3558A15CFB934F9229301527 /* RestorationToken.swift */; };
|
||||||
A4B0BAD62A12ED76BD611B79 /* BadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1FA515B3B0D61EF1E907D2D /* BadgeView.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 */; };
|
A4C29D373986AFE4559696D5 /* SecureBackupKeyBackupScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4525E8C0FBDD27D1ACE90952 /* SecureBackupKeyBackupScreenViewModelProtocol.swift */; };
|
||||||
A4E885358D7DD5A072A06824 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = CCE5BF78B125320CBF3BB834 /* PostHog */; };
|
A4E885358D7DD5A072A06824 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = CCE5BF78B125320CBF3BB834 /* PostHog */; };
|
||||||
A5B9EF45C7B8ACEB4954AE36 /* LoginScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9780389F8A53E4D26E23DD03 /* LoginScreenViewModelProtocol.swift */; };
|
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 */; };
|
CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; };
|
||||||
CE6F237360875D3D573FD0B2 /* RoomNotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */; };
|
CE6F237360875D3D573FD0B2 /* RoomNotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */; };
|
||||||
CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.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 */; };
|
CEB8FB1269DE20536608B957 /* LoginMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41FABA2B0AEF4389986495 /* LoginMode.swift */; };
|
||||||
CF3827071B0BC9638BD44F5D /* WaitlistScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB58EF0176D4CFB1040DA22 /* WaitlistScreenViewModel.swift */; };
|
CF3827071B0BC9638BD44F5D /* WaitlistScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB58EF0176D4CFB1040DA22 /* WaitlistScreenViewModel.swift */; };
|
||||||
CF38B70D8C6DD42C00A56A27 /* LogViewerScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.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 = "<group>"; };
|
2355398E4A55DA5A89128AD1 /* EncryptionKeyProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyProvider.swift; sourceTree = "<group>"; };
|
||||||
2389732B0E115A999A069083 /* NotificationSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
2389732B0E115A999A069083 /* NotificationSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
23AA3F4B285570805CB0CCDD /* MapTiler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTiler.swift; sourceTree = "<group>"; };
|
23AA3F4B285570805CB0CCDD /* MapTiler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTiler.swift; sourceTree = "<group>"; };
|
||||||
|
240610DF32F3213BEC5611D7 /* BlockedUsersScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
24227FF9A2797F6EA7F69CDD /* HomeScreenInvitesButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenInvitesButton.swift; sourceTree = "<group>"; };
|
24227FF9A2797F6EA7F69CDD /* HomeScreenInvitesButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenInvitesButton.swift; sourceTree = "<group>"; };
|
||||||
2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerTests.swift; sourceTree = "<group>"; };
|
2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerTests.swift; sourceTree = "<group>"; };
|
||||||
2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderTests.swift; sourceTree = "<group>"; };
|
2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -1582,6 +1589,7 @@
|
|||||||
85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; };
|
85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; };
|
||||||
8610C1D21565C950BCA6A454 /* AppLockSetupSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
8610C1D21565C950BCA6A454 /* AppLockSetupSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
86376BEE425704AEE197CA54 /* PillContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContext.swift; sourceTree = "<group>"; };
|
86376BEE425704AEE197CA54 /* PillContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContext.swift; sourceTree = "<group>"; };
|
||||||
|
8642512079EEFD622E3AA66B /* BlockedUsersScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenModels.swift; sourceTree = "<group>"; };
|
||||||
86873A768B13069BB5CAECF6 /* InvitesScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
86873A768B13069BB5CAECF6 /* InvitesScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
86A6F283BC574FDB96ABBB07 /* DeveloperOptionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenViewModel.swift; sourceTree = "<group>"; };
|
86A6F283BC574FDB96ABBB07 /* DeveloperOptionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
86C8CE2630F54D5FE1591786 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
86C8CE2630F54D5FE1591786 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
@@ -1665,6 +1673,7 @@
|
|||||||
9F85164F9475FF2867F71AAA /* RoomTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineController.swift; sourceTree = "<group>"; };
|
9F85164F9475FF2867F71AAA /* RoomTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineController.swift; sourceTree = "<group>"; };
|
||||||
9FB4F169D653296023ED65E6 /* NSESettingsProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESettingsProtocol.swift; sourceTree = "<group>"; };
|
9FB4F169D653296023ED65E6 /* NSESettingsProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESettingsProtocol.swift; sourceTree = "<group>"; };
|
||||||
A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
A010B8EAD1A9F6B4686DF2F4 /* BlockedUsersScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
A019A12C866D64CF072024B9 /* AppLockSetupPINScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupPINScreenViewModel.swift; sourceTree = "<group>"; };
|
A019A12C866D64CF072024B9 /* AppLockSetupPINScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupPINScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
A02D1A490944BF01A37586E1 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/SAS.strings; sourceTree = "<group>"; };
|
A02D1A490944BF01A37586E1 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/SAS.strings; sourceTree = "<group>"; };
|
||||||
A05707BF550D770168A406DB /* LoginViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModelTests.swift; sourceTree = "<group>"; };
|
A05707BF550D770168A406DB /* LoginViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -1673,6 +1682,7 @@
|
|||||||
A12D3B1BCF920880CA8BBB6B /* UserIndicatorControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerProtocol.swift; sourceTree = "<group>"; };
|
A12D3B1BCF920880CA8BBB6B /* UserIndicatorControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerProtocol.swift; sourceTree = "<group>"; };
|
||||||
A130A2251A15A7AACC84FD37 /* RoomPollsHistoryScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPollsHistoryScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
A130A2251A15A7AACC84FD37 /* RoomPollsHistoryScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPollsHistoryScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
A16CD2C62CB7DB78A4238485 /* ReportContentScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenCoordinator.swift; sourceTree = "<group>"; };
|
A16CD2C62CB7DB78A4238485 /* ReportContentScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
A16D0F226B1819D017531647 /* BlockedUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
A1BF12A5E7C76777C4BF0F2B /* TimelineItemMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenu.swift; sourceTree = "<group>"; };
|
A1BF12A5E7C76777C4BF0F2B /* TimelineItemMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenu.swift; sourceTree = "<group>"; };
|
||||||
A1C22B1B5FA3A765EADB2CC9 /* SessionVerificationStateMachineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationStateMachineTests.swift; sourceTree = "<group>"; };
|
A1C22B1B5FA3A765EADB2CC9 /* SessionVerificationStateMachineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationStateMachineTests.swift; sourceTree = "<group>"; };
|
||||||
A232D9156D225BD9FD1D0C43 /* PhotoLibraryPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryPicker.swift; sourceTree = "<group>"; };
|
A232D9156D225BD9FD1D0C43 /* PhotoLibraryPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryPicker.swift; sourceTree = "<group>"; };
|
||||||
@@ -1957,6 +1967,7 @@
|
|||||||
E6F5D66F158A6662F953733E /* NotificationSettingsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxy.swift; sourceTree = "<group>"; };
|
E6F5D66F158A6662F953733E /* NotificationSettingsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxy.swift; sourceTree = "<group>"; };
|
||||||
E6FCC416A3BFE73DF7B3E6BF /* RoomTimelineControllerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerFactory.swift; sourceTree = "<group>"; };
|
E6FCC416A3BFE73DF7B3E6BF /* RoomTimelineControllerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerFactory.swift; sourceTree = "<group>"; };
|
||||||
E71C28CF29CD05B6D6AE8580 /* HomeScreenSessionVerificationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenSessionVerificationBanner.swift; sourceTree = "<group>"; };
|
E71C28CF29CD05B6D6AE8580 /* HomeScreenSessionVerificationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenSessionVerificationBanner.swift; sourceTree = "<group>"; };
|
||||||
|
E76A706B3EEA32B882DA5E2D /* BlockedUsersScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
E78FC546F28E045A560F2963 /* EncryptionKeyProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyProviderProtocol.swift; sourceTree = "<group>"; };
|
E78FC546F28E045A560F2963 /* EncryptionKeyProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyProviderProtocol.swift; sourceTree = "<group>"; };
|
||||||
E8294DB9E95C0C0630418466 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
|
E8294DB9E95C0C0630418466 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
E8774CF614849664B5B3C2A1 /* UserSessionFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinatorStateMachine.swift; sourceTree = "<group>"; };
|
E8774CF614849664B5B3C2A1 /* UserSessionFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinatorStateMachine.swift; sourceTree = "<group>"; };
|
||||||
@@ -1980,6 +1991,7 @@
|
|||||||
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; };
|
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; };
|
||||||
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
||||||
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; };
|
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; };
|
||||||
|
ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = "<group>"; };
|
||||||
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
|
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; };
|
EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
||||||
@@ -2510,6 +2522,14 @@
|
|||||||
path = ServerSelectionScreen;
|
path = ServerSelectionScreen;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
2E035B978E415C77423FA3C2 /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
2ECFF6B05DAA37EB10DBF7E8 /* UITests */ = {
|
2ECFF6B05DAA37EB10DBF7E8 /* UITests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -3352,6 +3372,7 @@
|
|||||||
C55CC239AE12339C565F6C9A /* AudioRecorderStateTests.swift */,
|
C55CC239AE12339C565F6C9A /* AudioRecorderStateTests.swift */,
|
||||||
2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */,
|
2441E2424E78A40FC95DBA76 /* AudioRecorderTests.swift */,
|
||||||
6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */,
|
6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */,
|
||||||
|
240610DF32F3213BEC5611D7 /* BlockedUsersScreenViewModelTests.swift */,
|
||||||
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
|
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
|
||||||
7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */,
|
7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */,
|
||||||
CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */,
|
CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */,
|
||||||
@@ -4623,6 +4644,7 @@
|
|||||||
669239C03835CD8B51E0FFDB /* AnalyticsPromptScreen */,
|
669239C03835CD8B51E0FFDB /* AnalyticsPromptScreen */,
|
||||||
13263FFEA7749D822B51AA90 /* AppLock */,
|
13263FFEA7749D822B51AA90 /* AppLock */,
|
||||||
E74CD7681375AD2EAA34D66B /* Authentication */,
|
E74CD7681375AD2EAA34D66B /* Authentication */,
|
||||||
|
EFD4F7FCAAAB3EF45EE7A067 /* BlockedUsersScreen */,
|
||||||
53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */,
|
53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */,
|
||||||
1185EECDD07495D65AC84AFC /* CallScreen */,
|
1185EECDD07495D65AC84AFC /* CallScreen */,
|
||||||
27F2500AC8736AAE774520C0 /* ComposerToolbar */,
|
27F2500AC8736AAE774520C0 /* ComposerToolbar */,
|
||||||
@@ -4771,6 +4793,18 @@
|
|||||||
path = StartChatScreen;
|
path = StartChatScreen;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
EFD4F7FCAAAB3EF45EE7A067 /* BlockedUsersScreen */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A16D0F226B1819D017531647 /* BlockedUsersScreenCoordinator.swift */,
|
||||||
|
8642512079EEFD622E3AA66B /* BlockedUsersScreenModels.swift */,
|
||||||
|
A010B8EAD1A9F6B4686DF2F4 /* BlockedUsersScreenViewModel.swift */,
|
||||||
|
E76A706B3EEA32B882DA5E2D /* BlockedUsersScreenViewModelProtocol.swift */,
|
||||||
|
2E035B978E415C77423FA3C2 /* View */,
|
||||||
|
);
|
||||||
|
path = BlockedUsersScreen;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
F12966DF3DA87FEF21348D60 /* InviteUsersScreen */ = {
|
F12966DF3DA87FEF21348D60 /* InviteUsersScreen */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -5393,6 +5427,7 @@
|
|||||||
3042527CB344A9EF1157FC26 /* AudioRecorderStateTests.swift in Sources */,
|
3042527CB344A9EF1157FC26 /* AudioRecorderStateTests.swift in Sources */,
|
||||||
192A3CDCD0174AD1E4A128E4 /* AudioRecorderTests.swift in Sources */,
|
192A3CDCD0174AD1E4A128E4 /* AudioRecorderTests.swift in Sources */,
|
||||||
0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */,
|
0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */,
|
||||||
|
CEAEA57B7665C8E790599A78 /* BlockedUsersScreenViewModelTests.swift in Sources */,
|
||||||
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
|
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
|
||||||
C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */,
|
C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */,
|
||||||
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */,
|
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */,
|
||||||
@@ -5590,6 +5625,11 @@
|
|||||||
A4B0BAD62A12ED76BD611B79 /* BadgeView.swift in Sources */,
|
A4B0BAD62A12ED76BD611B79 /* BadgeView.swift in Sources */,
|
||||||
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */,
|
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */,
|
||||||
EB9F4688006B52E69DF5358F /* BlankFormCoordinator.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 */,
|
5EE1D4E316D66943E97FDCF2 /* BloomView.swift in Sources */,
|
||||||
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */,
|
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */,
|
||||||
E794AB6ABE1FF5AF0573FEA1 /* BlurHashEncode.swift in Sources */,
|
E794AB6ABE1FF5AF0573FEA1 /* BlurHashEncode.swift in Sources */,
|
||||||
|
|||||||
@@ -336,6 +336,7 @@
|
|||||||
"screen_app_lock_setup_pin_mismatch_dialog_title" = "PINs don't match";
|
"screen_app_lock_setup_pin_mismatch_dialog_title" = "PINs don't match";
|
||||||
"screen_app_lock_signout_alert_message" = "You’ll need to re-login and create a new PIN to proceed";
|
"screen_app_lock_signout_alert_message" = "You’ll need to re-login and create a new PIN to proceed";
|
||||||
"screen_app_lock_signout_alert_title" = "You are being signed out";
|
"screen_app_lock_signout_alert_title" = "You are being signed out";
|
||||||
|
"screen_blocked_users_empty" = "You have no blocked users";
|
||||||
"screen_blocked_users_unblocking" = "Unblocking...";
|
"screen_blocked_users_unblocking" = "Unblocking...";
|
||||||
"screen_bug_report_attach_screenshot" = "Attach screenshot";
|
"screen_bug_report_attach_screenshot" = "Attach screenshot";
|
||||||
"screen_bug_report_contact_me" = "You may contact me if you have any follow up questions.";
|
"screen_bug_report_contact_me" = "You may contact me if you have any follow up questions.";
|
||||||
@@ -491,6 +492,16 @@
|
|||||||
"screen_room_attachment_source_location" = "Location";
|
"screen_room_attachment_source_location" = "Location";
|
||||||
"screen_room_attachment_source_poll" = "Poll";
|
"screen_room_attachment_source_poll" = "Poll";
|
||||||
"screen_room_attachment_text_formatting" = "Text Formatting";
|
"screen_room_attachment_text_formatting" = "Text Formatting";
|
||||||
|
"screen_room_change_permissions_administrators" = "Admins only";
|
||||||
|
"screen_room_change_permissions_ban_people" = "Ban people";
|
||||||
|
"screen_room_change_permissions_delete_messages" = "Delete messages";
|
||||||
|
"screen_room_change_permissions_invite_people" = "Invite people";
|
||||||
|
"screen_room_change_permissions_moderators" = "Admins and moderators";
|
||||||
|
"screen_room_change_permissions_remove_people" = "Remove people";
|
||||||
|
"screen_room_change_permissions_room_avatar" = "Change Room Avatar";
|
||||||
|
"screen_room_change_permissions_room_name" = "Change Room Name";
|
||||||
|
"screen_room_change_permissions_room_topic" = "Change Room Topic";
|
||||||
|
"screen_room_change_permissions_send_messages" = "Send messages";
|
||||||
"screen_room_change_role_confirm_add_admin_description" = "You will not be able to undo this action. You are promoting the user to have the same power level as you.";
|
"screen_room_change_role_confirm_add_admin_description" = "You will not be able to undo this action. You are promoting the user to have the same power level as you.";
|
||||||
"screen_room_change_role_confirm_add_admin_title" = "Add Admin?";
|
"screen_room_change_role_confirm_add_admin_title" = "Add Admin?";
|
||||||
"screen_room_change_role_confirm_demote_self_action" = "Demote";
|
"screen_room_change_role_confirm_demote_self_action" = "Demote";
|
||||||
@@ -736,6 +747,10 @@
|
|||||||
"screen_login_subtitle" = "Matrix is an open network for secure, decentralised communication.";
|
"screen_login_subtitle" = "Matrix is an open network for secure, decentralised communication.";
|
||||||
"screen_report_content_block_user" = "Block user";
|
"screen_report_content_block_user" = "Block user";
|
||||||
"screen_room_attachment_source_camera_photo" = "Take photo";
|
"screen_room_attachment_source_camera_photo" = "Take photo";
|
||||||
|
"screen_room_change_permissions_everyone" = "Everyone";
|
||||||
|
"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_details_invite_people_title" = "Invite people";
|
"screen_room_details_invite_people_title" = "Invite people";
|
||||||
"screen_room_details_leave_conversation_title" = "Leave conversation";
|
"screen_room_details_leave_conversation_title" = "Leave conversation";
|
||||||
"screen_room_details_leave_room_title" = "Leave room";
|
"screen_room_details_leave_room_title" = "Leave room";
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
Task {
|
Task {
|
||||||
let credentials = SoftLogoutScreenCredentials(userID: userSession.userID,
|
let credentials = SoftLogoutScreenCredentials(userID: userSession.userID,
|
||||||
homeserverName: userSession.homeserver,
|
homeserverName: userSession.homeserver,
|
||||||
userDisplayName: userSession.clientProxy.userDisplayName.value ?? "",
|
userDisplayName: userSession.clientProxy.userDisplayNamePublisher.value ?? "",
|
||||||
deviceID: userSession.deviceID)
|
deviceID: userSession.deviceID)
|
||||||
|
|
||||||
let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore,
|
let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore,
|
||||||
@@ -866,7 +866,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
// Be a good citizen, run for a max of 10 SS responses or 10 seconds
|
// Be a good citizen, run for a max of 10 SS responses or 10 seconds
|
||||||
// An SS request will time out after 30 seconds if no new data is available
|
// An SS request will time out after 30 seconds if no new data is available
|
||||||
backgroundRefreshSyncObserver = userSession.clientProxy
|
backgroundRefreshSyncObserver = userSession.clientProxy
|
||||||
.callbacks
|
.actionsPublisher
|
||||||
.filter(\.isSyncUpdate)
|
.filter(\.isSyncUpdate)
|
||||||
.collect(.byTimeOrCount(DispatchQueue.main, .seconds(10), 10))
|
.collect(.byTimeOrCount(DispatchQueue.main, .seconds(10), 10))
|
||||||
.sink(receiveValue: { [weak self] _ in
|
.sink(receiveValue: { [weak self] _ in
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
bugReportFlowCoordinator?.start()
|
bugReportFlowCoordinator?.start()
|
||||||
case .about:
|
case .about:
|
||||||
presentLegalInformationScreen()
|
presentLegalInformationScreen()
|
||||||
|
case .blockedUsers:
|
||||||
|
presentBlockedUsersScreen()
|
||||||
case .sessionVerification:
|
case .sessionVerification:
|
||||||
presentSessionVerificationScreen()
|
presentSessionVerificationScreen()
|
||||||
case .accountSessions:
|
case .accountSessions:
|
||||||
@@ -203,6 +205,12 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
navigationStackCoordinator.push(LegalInformationScreenCoordinator(appSettings: parameters.appSettings))
|
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() {
|
private func presentSessionVerificationScreen() {
|
||||||
guard let sessionVerificationController = parameters.userSession.sessionVerificationController else {
|
guard let sessionVerificationController = parameters.userSession.sessionVerificationController else {
|
||||||
fatalError("The sessionVerificationController should aways be valid at this point")
|
fatalError("The sessionVerificationController should aways be valid at this point")
|
||||||
|
|||||||
@@ -830,6 +830,8 @@ internal enum L10n {
|
|||||||
internal static func screenAppLockSubtitleWrongPin(_ p1: Int) -> String {
|
internal static func screenAppLockSubtitleWrongPin(_ p1: Int) -> String {
|
||||||
return L10n.tr("Localizable", "screen_app_lock_subtitle_wrong_pin", p1)
|
return L10n.tr("Localizable", "screen_app_lock_subtitle_wrong_pin", p1)
|
||||||
}
|
}
|
||||||
|
/// You have no blocked users
|
||||||
|
internal static var screenBlockedUsersEmpty: String { return L10n.tr("Localizable", "screen_blocked_users_empty") }
|
||||||
/// Unblock
|
/// Unblock
|
||||||
internal static var screenBlockedUsersUnblockAlertAction: String { return L10n.tr("Localizable", "screen_blocked_users_unblock_alert_action") }
|
internal static var screenBlockedUsersUnblockAlertAction: String { return L10n.tr("Localizable", "screen_blocked_users_unblock_alert_action") }
|
||||||
/// You'll be able to see all messages from them again.
|
/// You'll be able to see all messages from them again.
|
||||||
@@ -1205,6 +1207,34 @@ internal enum L10n {
|
|||||||
internal static var screenRoomAttachmentSourcePoll: String { return L10n.tr("Localizable", "screen_room_attachment_source_poll") }
|
internal static var screenRoomAttachmentSourcePoll: String { return L10n.tr("Localizable", "screen_room_attachment_source_poll") }
|
||||||
/// Text Formatting
|
/// Text Formatting
|
||||||
internal static var screenRoomAttachmentTextFormatting: String { return L10n.tr("Localizable", "screen_room_attachment_text_formatting") }
|
internal static var screenRoomAttachmentTextFormatting: String { return L10n.tr("Localizable", "screen_room_attachment_text_formatting") }
|
||||||
|
/// Admins only
|
||||||
|
internal static var screenRoomChangePermissionsAdministrators: String { return L10n.tr("Localizable", "screen_room_change_permissions_administrators") }
|
||||||
|
/// Ban people
|
||||||
|
internal static var screenRoomChangePermissionsBanPeople: String { return L10n.tr("Localizable", "screen_room_change_permissions_ban_people") }
|
||||||
|
/// Delete messages
|
||||||
|
internal static var screenRoomChangePermissionsDeleteMessages: String { return L10n.tr("Localizable", "screen_room_change_permissions_delete_messages") }
|
||||||
|
/// Everyone
|
||||||
|
internal static var screenRoomChangePermissionsEveryone: String { return L10n.tr("Localizable", "screen_room_change_permissions_everyone") }
|
||||||
|
/// Invite people
|
||||||
|
internal static var screenRoomChangePermissionsInvitePeople: String { return L10n.tr("Localizable", "screen_room_change_permissions_invite_people") }
|
||||||
|
/// Member moderation
|
||||||
|
internal static var screenRoomChangePermissionsMemberModeration: String { return L10n.tr("Localizable", "screen_room_change_permissions_member_moderation") }
|
||||||
|
/// Messages and content
|
||||||
|
internal static var screenRoomChangePermissionsMessagesAndContent: String { return L10n.tr("Localizable", "screen_room_change_permissions_messages_and_content") }
|
||||||
|
/// Admins and moderators
|
||||||
|
internal static var screenRoomChangePermissionsModerators: String { return L10n.tr("Localizable", "screen_room_change_permissions_moderators") }
|
||||||
|
/// Remove people
|
||||||
|
internal static var screenRoomChangePermissionsRemovePeople: String { return L10n.tr("Localizable", "screen_room_change_permissions_remove_people") }
|
||||||
|
/// Change Room Avatar
|
||||||
|
internal static var screenRoomChangePermissionsRoomAvatar: String { return L10n.tr("Localizable", "screen_room_change_permissions_room_avatar") }
|
||||||
|
/// Room details
|
||||||
|
internal static var screenRoomChangePermissionsRoomDetails: String { return L10n.tr("Localizable", "screen_room_change_permissions_room_details") }
|
||||||
|
/// Change Room Name
|
||||||
|
internal static var screenRoomChangePermissionsRoomName: String { return L10n.tr("Localizable", "screen_room_change_permissions_room_name") }
|
||||||
|
/// Change Room Topic
|
||||||
|
internal static var screenRoomChangePermissionsRoomTopic: String { return L10n.tr("Localizable", "screen_room_change_permissions_room_topic") }
|
||||||
|
/// Send messages
|
||||||
|
internal static var screenRoomChangePermissionsSendMessages: String { return L10n.tr("Localizable", "screen_room_change_permissions_send_messages") }
|
||||||
/// You will not be able to undo this action. You are promoting the user to have the same power level as you.
|
/// You will not be able to undo this action. You are promoting the user to have the same power level as you.
|
||||||
internal static var screenRoomChangeRoleConfirmAddAdminDescription: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_add_admin_description") }
|
internal static var screenRoomChangeRoleConfirmAddAdminDescription: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_add_admin_description") }
|
||||||
/// Add Admin?
|
/// Add Admin?
|
||||||
|
|||||||
@@ -1892,16 +1892,16 @@ class RoomProxyMock: RoomProxyProtocol {
|
|||||||
var name: String?
|
var name: String?
|
||||||
var topic: String?
|
var topic: String?
|
||||||
var avatarURL: URL?
|
var avatarURL: URL?
|
||||||
var members: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
||||||
get { return underlyingMembers }
|
get { return underlyingMembersPublisher }
|
||||||
set(value) { underlyingMembers = value }
|
set(value) { underlyingMembersPublisher = value }
|
||||||
}
|
}
|
||||||
var underlyingMembers: CurrentValuePublisher<[RoomMemberProxyProtocol], Never>!
|
var underlyingMembersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never>!
|
||||||
var typingMembers: CurrentValuePublisher<[String], Never> {
|
var typingMembersPublisher: CurrentValuePublisher<[String], Never> {
|
||||||
get { return underlyingTypingMembers }
|
get { return underlyingTypingMembersPublisher }
|
||||||
set(value) { underlyingTypingMembers = value }
|
set(value) { underlyingTypingMembersPublisher = value }
|
||||||
}
|
}
|
||||||
var underlyingTypingMembers: CurrentValuePublisher<[String], Never>!
|
var underlyingTypingMembersPublisher: CurrentValuePublisher<[String], Never>!
|
||||||
var joinedMembersCount: Int {
|
var joinedMembersCount: Int {
|
||||||
get { return underlyingJoinedMembersCount }
|
get { return underlyingJoinedMembersCount }
|
||||||
set(value) { underlyingJoinedMembersCount = value }
|
set(value) { underlyingJoinedMembersCount = value }
|
||||||
@@ -1912,11 +1912,11 @@ class RoomProxyMock: RoomProxyProtocol {
|
|||||||
set(value) { underlyingActiveMembersCount = value }
|
set(value) { underlyingActiveMembersCount = value }
|
||||||
}
|
}
|
||||||
var underlyingActiveMembersCount: Int!
|
var underlyingActiveMembersCount: Int!
|
||||||
var actions: AnyPublisher<RoomProxyAction, Never> {
|
var actionsPublisher: AnyPublisher<RoomProxyAction, Never> {
|
||||||
get { return underlyingActions }
|
get { return underlyingActionsPublisher }
|
||||||
set(value) { underlyingActions = value }
|
set(value) { underlyingActionsPublisher = value }
|
||||||
}
|
}
|
||||||
var underlyingActions: AnyPublisher<RoomProxyAction, Never>!
|
var underlyingActionsPublisher: AnyPublisher<RoomProxyAction, Never>!
|
||||||
var timeline: TimelineProxyProtocol {
|
var timeline: TimelineProxyProtocol {
|
||||||
get { return underlyingTimeline }
|
get { return underlyingTimeline }
|
||||||
set(value) { underlyingTimeline = value }
|
set(value) { underlyingTimeline = value }
|
||||||
|
|||||||
@@ -69,15 +69,15 @@ extension RoomProxyMock {
|
|||||||
|
|
||||||
ownUserID = configuration.ownUserID
|
ownUserID = configuration.ownUserID
|
||||||
|
|
||||||
members = CurrentValueSubject(configuration.members).asCurrentValuePublisher()
|
membersPublisher = CurrentValueSubject(configuration.members).asCurrentValuePublisher()
|
||||||
typingMembers = CurrentValueSubject([]).asCurrentValuePublisher()
|
typingMembersPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
|
||||||
|
|
||||||
joinedMembersCount = configuration.members.filter { $0.membership == .join }.count
|
joinedMembersCount = configuration.members.filter { $0.membership == .join }.count
|
||||||
activeMembersCount = configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count
|
activeMembersCount = configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count
|
||||||
|
|
||||||
updateMembersClosure = { }
|
updateMembersClosure = { }
|
||||||
acceptInvitationClosure = { .success(()) }
|
acceptInvitationClosure = { .success(()) }
|
||||||
underlyingActions = Empty(completeImmediately: false).eraseToAnyPublisher()
|
underlyingActionsPublisher = Empty(completeImmediately: false).eraseToAnyPublisher()
|
||||||
setNameClosure = { _ in .success(()) }
|
setNameClosure = { _ in .success(()) }
|
||||||
setTopicClosure = { _ in .success(()) }
|
setTopicClosure = { _ in .success(()) }
|
||||||
getMemberUserIDReturnValue = .success(configuration.memberForID)
|
getMemberUserIDReturnValue = .success(configuration.memberForID)
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ enum A11yIdentifiers {
|
|||||||
let screenLock = "settings-screen_lock"
|
let screenLock = "settings-screen_lock"
|
||||||
let reportBug = "settings-report_bug"
|
let reportBug = "settings-report_bug"
|
||||||
let about = "settings_about"
|
let about = "settings_about"
|
||||||
|
let blockedUsers = "settings_blocked-users"
|
||||||
let advancedSettings = "settings_advanced-settings"
|
let advancedSettings = "settings_advanced-settings"
|
||||||
let developerOptions = "settings_developer-options"
|
let developerOptions = "settings_developer-options"
|
||||||
let logout = "settings-logout"
|
let logout = "settings-logout"
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ enum UserAvatarSizeOnScreen {
|
|||||||
case readReceiptSheet
|
case readReceiptSheet
|
||||||
case editUserDetails
|
case editUserDetails
|
||||||
case suggestions
|
case suggestions
|
||||||
|
case blockedUsers
|
||||||
|
|
||||||
var value: CGFloat {
|
var value: CGFloat {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -66,6 +67,8 @@ enum UserAvatarSizeOnScreen {
|
|||||||
return 32
|
return 32
|
||||||
case .suggestions:
|
case .suggestions:
|
||||||
return 32
|
return 32
|
||||||
|
case .blockedUsers:
|
||||||
|
return 32
|
||||||
case .settings:
|
case .settings:
|
||||||
return 52
|
return 52
|
||||||
case .roomDetails:
|
case .roomDetails:
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// 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<AnyCancellable>()
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<BlockedUsersScreenCoordinatorAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<BlockedUsersScreenCoordinatorAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: BlockedUsersScreenCoordinatorParameters) {
|
||||||
|
viewModel = BlockedUsersScreenViewModel(clientProxy: parameters.clientProxy,
|
||||||
|
userIndicatorController: parameters.userIndicatorController)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
viewModel.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> AnyView {
|
||||||
|
AnyView(BlockedUsersScreen(context: viewModel.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<BlockedUsersScreenViewStateAlertType>?
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BlockedUsersScreenViewAction {
|
||||||
|
case unblockUser(userID: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BlockedUsersScreenViewStateAlertType: Hashable {
|
||||||
|
case unblock
|
||||||
|
case error
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// 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<BlockedUsersScreenViewState, BlockedUsersScreenViewAction>
|
||||||
|
|
||||||
|
class BlockedUsersScreenViewModel: BlockedUsersScreenViewModelType, BlockedUsersScreenViewModelProtocol {
|
||||||
|
let clientProxy: ClientProxyProtocol
|
||||||
|
let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<BlockedUsersScreenViewModelAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<BlockedUsersScreenViewModelAction, Never> {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
hideLoadingIndicator()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private func unblockUser(_ userID: String) {
|
||||||
|
showLoadingIndicator()
|
||||||
|
state.processingUserID = userID
|
||||||
|
|
||||||
|
Task {
|
||||||
|
if case .failure = await clientProxy.unignoreUser(userID) {
|
||||||
|
state.bindings.alertInfo = .init(id: .error)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.processingUserID = nil
|
||||||
|
hideLoadingIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// 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<BlockedUsersScreenViewModelAction, Never> { get }
|
||||||
|
var context: BlockedUsersScreenViewModelType.Context { get }
|
||||||
|
|
||||||
|
func stop()
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// 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 {
|
||||||
|
content
|
||||||
|
.compoundList()
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.navigationTitle(L10n.commonBlockedUsers)
|
||||||
|
.alert(item: $context.alertInfo)
|
||||||
|
.disabled(context.viewState.processingUserID != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var content: some View {
|
||||||
|
if context.viewState.blockedUsers.isEmpty {
|
||||||
|
Text(L10n.screenBlockedUsersEmpty)
|
||||||
|
.font(.compound.bodyMD)
|
||||||
|
.foregroundColor(.compound.textSecondary)
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
} else {
|
||||||
|
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)) }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ final class CompletionSuggestionService: CompletionSuggestionServiceProtocol {
|
|||||||
init(roomProxy: RoomProxyProtocol) {
|
init(roomProxy: RoomProxyProtocol) {
|
||||||
self.roomProxy = roomProxy
|
self.roomProxy = roomProxy
|
||||||
suggestionsPublisher = suggestionTriggerSubject
|
suggestionsPublisher = suggestionTriggerSubject
|
||||||
.combineLatest(roomProxy.members)
|
.combineLatest(roomProxy.membersPublisher)
|
||||||
.map { [weak self] suggestionPattern, members -> [SuggestionItem] in
|
.map { [weak self] suggestionPattern, members -> [SuggestionItem] in
|
||||||
guard let self,
|
guard let self,
|
||||||
let suggestionPattern else {
|
let suggestionPattern else {
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
super.init(initialViewState: .init(userID: userSession.userID),
|
super.init(initialViewState: .init(userID: userSession.userID),
|
||||||
imageProvider: userSession.mediaProvider)
|
imageProvider: userSession.mediaProvider)
|
||||||
|
|
||||||
userSession.clientProxy.userAvatarURL
|
userSession.clientProxy.userAvatarURLPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.userAvatarURL, on: self)
|
.weakAssign(to: \.state.userAvatarURL, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
userSession.clientProxy.userDisplayName
|
userSession.clientProxy.userDisplayNamePublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.userDisplayName, on: self)
|
.weakAssign(to: \.state.userDisplayName, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
@@ -256,7 +256,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
|
|
||||||
MXLog.info("Account not migrated, setting view room list mode to \"\(state.roomListMode)\"")
|
MXLog.info("Account not migrated, setting view room list mode to \"\(state.roomListMode)\"")
|
||||||
|
|
||||||
migrationCancellable = userSession.clientProxy.callbacks
|
migrationCancellable = userSession.clientProxy.actionsPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] callback in
|
.sink { [weak self] callback in
|
||||||
guard let self, case .receivedSyncUpdate = callback else { return }
|
guard let self, case .receivedSyncUpdate = callback else { return }
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
|||||||
hideLoader()
|
hideLoader()
|
||||||
}
|
}
|
||||||
|
|
||||||
roomProxy.members
|
roomProxy.membersPublisher
|
||||||
.filter { !$0.isEmpty }
|
.filter { !$0.isEmpty }
|
||||||
.first()
|
.first()
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func setupRoomSubscription() {
|
private func setupRoomSubscription() {
|
||||||
roomProxy.actions
|
roomProxy.actionsPublisher
|
||||||
.filter { $0 == .roomInfoUpdate }
|
.filter { $0 == .roomInfoUpdate }
|
||||||
.throttle(for: .milliseconds(200), scheduler: DispatchQueue.main, latest: true)
|
.throttle(for: .milliseconds(200), scheduler: DispatchQueue.main, latest: true)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
@@ -167,7 +167,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
roomProxy.members
|
roomProxy.membersPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] members in
|
.sink { [weak self] members in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
hideLoader()
|
hideLoader()
|
||||||
}
|
}
|
||||||
|
|
||||||
roomProxy.members
|
roomProxy.membersPublisher
|
||||||
.filter { !$0.isEmpty }
|
.filter { !$0.isEmpty }
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] members in
|
.sink { [weak self] members in
|
||||||
|
|||||||
+2
-2
@@ -31,12 +31,12 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
self.roomProxy = roomProxy
|
self.roomProxy = roomProxy
|
||||||
super.init(initialViewState: RoomRolesAndPermissionsScreenViewState())
|
super.init(initialViewState: RoomRolesAndPermissionsScreenViewState())
|
||||||
|
|
||||||
roomProxy.members.sink { [weak self] members in
|
roomProxy.membersPublisher.sink { [weak self] members in
|
||||||
self?.updateMembers(members)
|
self?.updateMembers(members)
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
updateMembers(roomProxy.members.value)
|
updateMembers(roomProxy.membersPublisher.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Public
|
// MARK: - Public
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
roomProxy
|
roomProxy
|
||||||
.actions
|
.actionsPublisher
|
||||||
.filter { $0 == .roomInfoUpdate }
|
.filter { $0 == .roomInfoUpdate }
|
||||||
.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)
|
.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
@@ -319,7 +319,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
.weakAssign(to: \.state.showReadReceipts, on: self)
|
.weakAssign(to: \.state.showReadReceipts, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
roomProxy.members
|
roomProxy.membersPublisher
|
||||||
.map { members in
|
.map { members in
|
||||||
members.reduce(into: [String: RoomMemberState]()) { dictionary, member in
|
members.reduce(into: [String: RoomMemberState]()) { dictionary, member in
|
||||||
dictionary[member.userID] = RoomMemberState(displayName: member.displayName, avatarURL: member.avatarURL)
|
dictionary[member.userID] = RoomMemberState(displayName: member.displayName, avatarURL: member.avatarURL)
|
||||||
@@ -329,7 +329,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
.weakAssign(to: \.state.members, on: self)
|
.weakAssign(to: \.state.members, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
roomProxy.typingMembers
|
roomProxy.typingMembersPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.filter { [weak self] _ in self?.appSettings.sharePresence ?? false }
|
.filter { [weak self] _ in self?.appSettings.sharePresence ?? false }
|
||||||
.weakAssign(to: \.state.typingMembers, on: self)
|
.weakAssign(to: \.state.typingMembers, on: self)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ enum SettingsScreenCoordinatorAction {
|
|||||||
case appLock
|
case appLock
|
||||||
case bugReport
|
case bugReport
|
||||||
case about
|
case about
|
||||||
|
case blockedUsers
|
||||||
case sessionVerification
|
case sessionVerification
|
||||||
case accountSessions
|
case accountSessions
|
||||||
case notifications
|
case notifications
|
||||||
@@ -74,6 +75,8 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.bugReport)
|
actionsSubject.send(.bugReport)
|
||||||
case .about:
|
case .about:
|
||||||
actionsSubject.send(.about)
|
actionsSubject.send(.about)
|
||||||
|
case .blockedUsers:
|
||||||
|
actionsSubject.send(.blockedUsers)
|
||||||
case .sessionVerification:
|
case .sessionVerification:
|
||||||
actionsSubject.send(.sessionVerification)
|
actionsSubject.send(.sessionVerification)
|
||||||
case .secureBackup:
|
case .secureBackup:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ enum SettingsScreenViewModelAction {
|
|||||||
case appLock
|
case appLock
|
||||||
case reportBug
|
case reportBug
|
||||||
case about
|
case about
|
||||||
|
case blockedUsers
|
||||||
case sessionVerification
|
case sessionVerification
|
||||||
case secureBackup
|
case secureBackup
|
||||||
case accountSessionsList
|
case accountSessionsList
|
||||||
@@ -61,6 +62,7 @@ enum SettingsScreenViewAction {
|
|||||||
case appLock
|
case appLock
|
||||||
case reportBug
|
case reportBug
|
||||||
case about
|
case about
|
||||||
|
case blockedUsers
|
||||||
case sessionVerification
|
case sessionVerification
|
||||||
case secureBackup
|
case secureBackup
|
||||||
case accountSessionsList
|
case accountSessionsList
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
|
|||||||
showDeveloperOptions: appSettings.isDevelopmentBuild),
|
showDeveloperOptions: appSettings.isDevelopmentBuild),
|
||||||
imageProvider: userSession.mediaProvider)
|
imageProvider: userSession.mediaProvider)
|
||||||
|
|
||||||
userSession.clientProxy.userAvatarURL
|
userSession.clientProxy.userAvatarURLPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.userAvatarURL, on: self)
|
.weakAssign(to: \.state.userAvatarURL, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
userSession.clientProxy.userDisplayName
|
userSession.clientProxy.userDisplayNamePublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.userDisplayName, on: self)
|
.weakAssign(to: \.state.userDisplayName, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
@@ -94,6 +94,8 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
|
|||||||
actionsSubject.send(.reportBug)
|
actionsSubject.send(.reportBug)
|
||||||
case .about:
|
case .about:
|
||||||
actionsSubject.send(.about)
|
actionsSubject.send(.about)
|
||||||
|
case .blockedUsers:
|
||||||
|
actionsSubject.send(.blockedUsers)
|
||||||
case .logout:
|
case .logout:
|
||||||
actionsSubject.send(.logout)
|
actionsSubject.send(.logout)
|
||||||
case .sessionVerification:
|
case .sessionVerification:
|
||||||
|
|||||||
@@ -143,6 +143,13 @@ struct SettingsScreen: View {
|
|||||||
context.send(viewAction: .about)
|
context.send(viewAction: .about)
|
||||||
})
|
})
|
||||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.about)
|
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.about)
|
||||||
|
|
||||||
|
ListRow(label: .default(title: L10n.commonBlockedUsers,
|
||||||
|
icon: \.block),
|
||||||
|
kind: .navigationLink {
|
||||||
|
context.send(viewAction: .blockedUsers)
|
||||||
|
})
|
||||||
|
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.blockedUsers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -38,22 +38,22 @@ class UserDetailsEditScreenViewModel: UserDetailsEditScreenViewModelType, UserDe
|
|||||||
super.init(initialViewState: UserDetailsEditScreenViewState(userID: clientProxy.userID,
|
super.init(initialViewState: UserDetailsEditScreenViewState(userID: clientProxy.userID,
|
||||||
bindings: .init()), imageProvider: mediaProvider)
|
bindings: .init()), imageProvider: mediaProvider)
|
||||||
|
|
||||||
clientProxy.userAvatarURL
|
clientProxy.userAvatarURLPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.currentAvatarURL, on: self)
|
.weakAssign(to: \.state.currentAvatarURL, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
clientProxy.userAvatarURL
|
clientProxy.userAvatarURLPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.selectedAvatarURL, on: self)
|
.weakAssign(to: \.state.selectedAvatarURL, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
clientProxy.userDisplayName
|
clientProxy.userDisplayNamePublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.currentDisplayName, on: self)
|
.weakAssign(to: \.state.currentDisplayName, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
clientProxy.userDisplayName
|
clientProxy.userDisplayNamePublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] displayName in
|
.sink { [weak self] displayName in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
// periphery: ignore - only for retain
|
// periphery: ignore - only for retain
|
||||||
private var syncServiceStateUpdateTaskHandle: TaskHandle?
|
private var syncServiceStateUpdateTaskHandle: TaskHandle?
|
||||||
|
|
||||||
|
// periphery:ignore - required for instance retention in the rust codebase
|
||||||
|
private var ignoredUsersListenerTaskHandle: TaskHandle?
|
||||||
|
|
||||||
private var delegateHandle: TaskHandle?
|
private var delegateHandle: TaskHandle?
|
||||||
|
|
||||||
// These following summary providers both operate on the same allRooms() list but
|
// These following summary providers both operate on the same allRooms() list but
|
||||||
@@ -69,15 +72,21 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
|
|
||||||
private var loadCachedAvatarURLTask: Task<Void, Never>?
|
private var loadCachedAvatarURLTask: Task<Void, Never>?
|
||||||
private let userAvatarURLSubject = CurrentValueSubject<URL?, Never>(nil)
|
private let userAvatarURLSubject = CurrentValueSubject<URL?, Never>(nil)
|
||||||
var userAvatarURL: CurrentValuePublisher<URL?, Never> {
|
var userAvatarURLPublisher: CurrentValuePublisher<URL?, Never> {
|
||||||
userAvatarURLSubject.asCurrentValuePublisher()
|
userAvatarURLSubject.asCurrentValuePublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
private let userDisplayNameSubject = CurrentValueSubject<String?, Never>(nil)
|
private let userDisplayNameSubject = CurrentValueSubject<String?, Never>(nil)
|
||||||
var userDisplayName: CurrentValuePublisher<String?, Never> {
|
var userDisplayNamePublisher: CurrentValuePublisher<String?, Never> {
|
||||||
userDisplayNameSubject.asCurrentValuePublisher()
|
userDisplayNameSubject.asCurrentValuePublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let ignoredUsersSubject = CurrentValueSubject<[String]?, Never>(nil)
|
||||||
|
var ignoredUsersPublisher: CurrentValuePublisher<[String]?, Never> {
|
||||||
|
ignoredUsersSubject
|
||||||
|
.asCurrentValuePublisher()
|
||||||
|
}
|
||||||
|
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
/// Will be `true` whilst the app cleans up and forces a logout. Prevents the sync service from restarting
|
/// Will be `true` whilst the app cleans up and forces a logout. Prevents the sync service from restarting
|
||||||
@@ -92,7 +101,10 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let callbacks = PassthroughSubject<ClientProxyCallback, Never>()
|
private let actionsSubject = PassthroughSubject<ClientProxyAction, Never>()
|
||||||
|
var actionsPublisher: AnyPublisher<ClientProxyAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
private let loadingStateSubject = CurrentValueSubject<ClientProxyLoadingState, Never>(.notLoading)
|
private let loadingStateSubject = CurrentValueSubject<ClientProxyLoadingState, Never>(.notLoading)
|
||||||
var loadingStatePublisher: CurrentValuePublisher<ClientProxyLoadingState, Never> {
|
var loadingStatePublisher: CurrentValuePublisher<ClientProxyLoadingState, Never> {
|
||||||
@@ -119,7 +131,7 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
|
|
||||||
delegateHandle = client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in
|
delegateHandle = client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in
|
||||||
self?.hasEncounteredAuthError = true
|
self?.hasEncounteredAuthError = true
|
||||||
self?.callbacks.send(.receivedAuthError(isSoftLogout: isSoftLogout))
|
self?.actionsSubject.send(.receivedAuthError(isSoftLogout: isSoftLogout))
|
||||||
})
|
})
|
||||||
|
|
||||||
networkMonitor.reachabilityPublisher
|
networkMonitor.reachabilityPublisher
|
||||||
@@ -135,6 +147,10 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
await configureAppService()
|
await configureAppService()
|
||||||
|
|
||||||
loadUserAvatarURLFromCache()
|
loadUserAvatarURLFromCache()
|
||||||
|
|
||||||
|
ignoredUsersListenerTaskHandle = client.subscribeToIgnoredUsers(listener: IgnoredUsersListenerProxy { [weak self] ignoredUsers in
|
||||||
|
self?.ignoredUsersSubject.send(ignoredUsers)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var userID: String {
|
var userID: String {
|
||||||
@@ -472,6 +488,28 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Ignored users
|
||||||
|
|
||||||
|
func ignoreUser(_ userID: String) async -> Result<Void, ClientProxyError> {
|
||||||
|
do {
|
||||||
|
try await client.ignoreUser(userId: userID)
|
||||||
|
return .success(())
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed ignoring user with error: \(error)")
|
||||||
|
return .failure(.failedIgnoringUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unignoreUser(_ userID: String) async -> Result<Void, ClientProxyError> {
|
||||||
|
do {
|
||||||
|
try await client.unignoreUser(userId: userID)
|
||||||
|
return .success(())
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed unignoring user with error: \(error)")
|
||||||
|
return .failure(.failedUnignoringUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private func loadUserAvatarURLFromCache() {
|
private func loadUserAvatarURLFromCache() {
|
||||||
@@ -570,7 +608,11 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hide the sync spinner as soon as we get any update back
|
// Hide the sync spinner as soon as we get any update back
|
||||||
callbacks.send(.receivedSyncUpdate)
|
actionsSubject.send(.receivedSyncUpdate)
|
||||||
|
|
||||||
|
if ignoredUsersSubject.value == nil {
|
||||||
|
updateIgnoredUsers()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +662,17 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
return (nil, nil)
|
return (nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateIgnoredUsers() {
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let ignoredUsers = try await client.ignoredUsers()
|
||||||
|
ignoredUsersSubject.send(ignoredUsers)
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed fetching ignored users with error: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ClientProxy: MediaLoaderProtocol {
|
extension ClientProxy: MediaLoaderProtocol {
|
||||||
@@ -690,3 +743,15 @@ private class ClientDelegateWrapper: ClientDelegate {
|
|||||||
MXLog.info("Delegating session updates to the ClientSessionDelegate.")
|
MXLog.info("Delegating session updates to the ClientSessionDelegate.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class IgnoredUsersListenerProxy: IgnoredUsersListener {
|
||||||
|
private let onUpdateClosure: ([String]) -> Void
|
||||||
|
|
||||||
|
init(onUpdateClosure: @escaping ([String]) -> Void) {
|
||||||
|
self.onUpdateClosure = onUpdateClosure
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(ignoredUserIds: [String]) {
|
||||||
|
onUpdateClosure(ignoredUserIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import Combine
|
|||||||
import Foundation
|
import Foundation
|
||||||
import MatrixRustSDK
|
import MatrixRustSDK
|
||||||
|
|
||||||
enum ClientProxyCallback {
|
enum ClientProxyAction {
|
||||||
case receivedSyncUpdate
|
case receivedSyncUpdate
|
||||||
case receivedAuthError(isSoftLogout: Bool)
|
case receivedAuthError(isSoftLogout: Bool)
|
||||||
|
|
||||||
@@ -50,6 +50,8 @@ enum ClientProxyError: Error {
|
|||||||
case failedGettingUserProfile
|
case failedGettingUserProfile
|
||||||
case failedSettingUserAvatar
|
case failedSettingUserAvatar
|
||||||
case failedCheckingIsLastDevice(Error?)
|
case failedCheckingIsLastDevice(Error?)
|
||||||
|
case failedIgnoringUser
|
||||||
|
case failedUnignoringUser
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SlidingSyncConstants {
|
enum SlidingSyncConstants {
|
||||||
@@ -70,7 +72,7 @@ struct PusherConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
||||||
var callbacks: PassthroughSubject<ClientProxyCallback, Never> { get }
|
var actionsPublisher: AnyPublisher<ClientProxyAction, Never> { get }
|
||||||
|
|
||||||
var loadingStatePublisher: CurrentValuePublisher<ClientProxyLoadingState, Never> { get }
|
var loadingStatePublisher: CurrentValuePublisher<ClientProxyLoadingState, Never> { get }
|
||||||
|
|
||||||
@@ -80,9 +82,12 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
|||||||
|
|
||||||
var homeserver: String { get }
|
var homeserver: String { get }
|
||||||
|
|
||||||
var userDisplayName: CurrentValuePublisher<String?, Never> { get }
|
var userDisplayNamePublisher: CurrentValuePublisher<String?, Never> { get }
|
||||||
|
|
||||||
var userAvatarURL: CurrentValuePublisher<URL?, Never> { get }
|
var userAvatarURLPublisher: CurrentValuePublisher<URL?, Never> { get }
|
||||||
|
|
||||||
|
/// We delay fetching this until after the first sync. Nil until then
|
||||||
|
var ignoredUsersPublisher: CurrentValuePublisher<[String]?, Never> { get }
|
||||||
|
|
||||||
var pusherNotificationClientIdentifier: String? { get }
|
var pusherNotificationClientIdentifier: String? { get }
|
||||||
|
|
||||||
@@ -134,4 +139,10 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
|||||||
func searchUsers(searchTerm: String, limit: UInt) async -> Result<SearchUsersResultsProxy, ClientProxyError>
|
func searchUsers(searchTerm: String, limit: UInt) async -> Result<SearchUsersResultsProxy, ClientProxyError>
|
||||||
|
|
||||||
func profile(for userID: String) async -> Result<UserProfileProxy, ClientProxyError>
|
func profile(for userID: String) async -> Result<UserProfileProxy, ClientProxyError>
|
||||||
|
|
||||||
|
// MARK: - Ignored users
|
||||||
|
|
||||||
|
func ignoreUser(_ userID: String) async -> Result<Void, ClientProxyError>
|
||||||
|
|
||||||
|
func unignoreUser(_ userID: String) async -> Result<Void, ClientProxyError>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ import Foundation
|
|||||||
import MatrixRustSDK
|
import MatrixRustSDK
|
||||||
|
|
||||||
class MockClientProxy: ClientProxyProtocol {
|
class MockClientProxy: ClientProxyProtocol {
|
||||||
let callbacks = PassthroughSubject<ClientProxyCallback, Never>()
|
let actionsSubject = PassthroughSubject<ClientProxyAction, Never>()
|
||||||
|
var actionsPublisher: AnyPublisher<ClientProxyAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
let loadingStatePublisher = CurrentValuePublisher<ClientProxyLoadingState, Never>(.notLoading)
|
let loadingStatePublisher = CurrentValuePublisher<ClientProxyLoadingState, Never>(.notLoading)
|
||||||
|
|
||||||
@@ -34,9 +37,14 @@ class MockClientProxy: ClientProxyProtocol {
|
|||||||
|
|
||||||
var inviteSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider()
|
var inviteSummaryProvider: RoomSummaryProviderProtocol? = MockRoomSummaryProvider()
|
||||||
|
|
||||||
var userAvatarURL: CurrentValuePublisher<URL?, Never> { CurrentValueSubject<URL?, Never>(nil).asCurrentValuePublisher() }
|
var userAvatarURLPublisher: CurrentValuePublisher<URL?, Never> { CurrentValueSubject<URL?, Never>(nil).asCurrentValuePublisher() }
|
||||||
|
|
||||||
var userDisplayName: CurrentValuePublisher<String?, Never> { CurrentValueSubject<String?, Never>("User display name").asCurrentValuePublisher() }
|
var userDisplayNamePublisher: CurrentValuePublisher<String?, Never> { CurrentValueSubject<String?, Never>("User display name").asCurrentValuePublisher() }
|
||||||
|
|
||||||
|
var ignoredUsersPublisher: CurrentValuePublisher<[String]?, Never> {
|
||||||
|
let ignoredUsers = [RoomMemberProxyMock].allMembers.map(\.userID)
|
||||||
|
return CurrentValueSubject<[String]?, Never>(ignoredUsers).asCurrentValuePublisher()
|
||||||
|
}
|
||||||
|
|
||||||
var notificationSettings: NotificationSettingsProxyProtocol = NotificationSettingsProxyMock(with: .init())
|
var notificationSettings: NotificationSettingsProxyProtocol = NotificationSettingsProxyMock(with: .init())
|
||||||
|
|
||||||
@@ -166,4 +174,12 @@ class MockClientProxy: ClientProxyProtocol {
|
|||||||
getProfileCalled = true
|
getProfileCalled = true
|
||||||
return getProfileResult
|
return getProfileResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ignoreUser(_ userID: String) async -> Result<Void, ClientProxyError> {
|
||||||
|
.failure(.failedIgnoringUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unignoreUser(_ userID: String) async -> Result<Void, ClientProxyError> {
|
||||||
|
.failure(.failedUnignoringUser)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,17 +39,17 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
private var subscribedForUpdates = false
|
private var subscribedForUpdates = false
|
||||||
|
|
||||||
private let membersSubject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
private let membersSubject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
||||||
var members: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
||||||
membersSubject.asCurrentValuePublisher()
|
membersSubject.asCurrentValuePublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
private let typingMembersSubject = CurrentValueSubject<[String], Never>([])
|
private let typingMembersSubject = CurrentValueSubject<[String], Never>([])
|
||||||
var typingMembers: CurrentValuePublisher<[String], Never> {
|
var typingMembersPublisher: CurrentValuePublisher<[String], Never> {
|
||||||
typingMembersSubject.asCurrentValuePublisher()
|
typingMembersSubject.asCurrentValuePublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
private let actionsSubject = PassthroughSubject<RoomProxyAction, Never>()
|
private let actionsSubject = PassthroughSubject<RoomProxyAction, Never>()
|
||||||
var actions: AnyPublisher<RoomProxyAction, Never> {
|
var actionsPublisher: AnyPublisher<RoomProxyAction, Never> {
|
||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getMember(userID: String) async -> Result<RoomMemberProxyProtocol, RoomProxyError> {
|
func getMember(userID: String) async -> Result<RoomMemberProxyProtocol, RoomProxyError> {
|
||||||
if let member = members.value.filter({ $0.userID == userID }).first {
|
if let member = membersPublisher.value.filter({ $0.userID == userID }).first {
|
||||||
return .success(member)
|
return .success(member)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,23 +473,21 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func subscribeToTypingNotifications() {
|
private func subscribeToTypingNotifications() {
|
||||||
Task {
|
typingNotificationObservationToken = room.subscribeToTypingNotifications(listener: RoomTypingNotificationUpdateListener { [weak self] typingUserIDs in
|
||||||
typingNotificationObservationToken = await room.subscribeToTypingNotifications(listener: RoomTypingNotificationUpdateListener { [weak self] typingUserIDs in
|
guard let self else { return }
|
||||||
guard let self else { return }
|
|
||||||
|
MXLog.info("Received typing notification update, typingUsers: \(typingUserIDs)")
|
||||||
MXLog.info("Received typing notification update, typingUsers: \(typingUserIDs)")
|
|
||||||
|
let typingMembers = typingUserIDs.compactMap { userID in
|
||||||
let typingMembers = typingUserIDs.compactMap { userID in
|
if let member = self.membersPublisher.value.filter({ $0.userID == userID }).first {
|
||||||
if let member = self.members.value.filter({ $0.userID == userID }).first {
|
return member.displayName ?? member.userID
|
||||||
return member.displayName ?? member.userID
|
} else {
|
||||||
} else {
|
return userID
|
||||||
return userID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
typingMembersSubject.send(typingMembers)
|
|
||||||
})
|
typingMembersSubject.send(typingMembers)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,15 +62,15 @@ protocol RoomProxyProtocol {
|
|||||||
|
|
||||||
var avatarURL: URL? { get }
|
var avatarURL: URL? { get }
|
||||||
|
|
||||||
var members: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> { get }
|
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> { get }
|
||||||
|
|
||||||
var typingMembers: CurrentValuePublisher<[String], Never> { get }
|
var typingMembersPublisher: CurrentValuePublisher<[String], Never> { get }
|
||||||
|
|
||||||
var joinedMembersCount: Int { get }
|
var joinedMembersCount: Int { get }
|
||||||
|
|
||||||
var activeMembersCount: Int { get }
|
var activeMembersCount: Int { get }
|
||||||
|
|
||||||
var actions: AnyPublisher<RoomProxyAction, Never> { get }
|
var actionsPublisher: AnyPublisher<RoomProxyAction, Never> { get }
|
||||||
|
|
||||||
var timeline: TimelineProxyProtocol { get }
|
var timeline: TimelineProxyProtocol { get }
|
||||||
|
|
||||||
@@ -167,6 +167,6 @@ extension RoomProxyProtocol {
|
|||||||
|
|
||||||
func members() async -> [RoomMemberProxyProtocol]? {
|
func members() async -> [RoomMemberProxyProtocol]? {
|
||||||
await updateMembers()
|
await updateMembers()
|
||||||
return members.value
|
return membersPublisher.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class UserSession: UserSessionProtocol {
|
|||||||
self.mediaProvider = mediaProvider
|
self.mediaProvider = mediaProvider
|
||||||
self.voiceMessageMediaManager = voiceMessageMediaManager
|
self.voiceMessageMediaManager = voiceMessageMediaManager
|
||||||
|
|
||||||
clientProxy.callbacks
|
clientProxy.actionsPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] callback in
|
.sink { [weak self] callback in
|
||||||
if callback.isSyncUpdate {
|
if callback.isSyncUpdate {
|
||||||
@@ -69,7 +69,7 @@ class UserSession: UserSessionProtocol {
|
|||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
authErrorCancellable = clientProxy.callbacks
|
authErrorCancellable = clientProxy.actionsPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] callback in
|
.sink { [weak self] callback in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c9fdecb8d69665bd20ce42c29a94df8fd912f1c3688207c02c2bf0ef955e80d1
|
||||||
|
size 144194
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a0e4f20a3da82d547d5802aa2dc96db5de6520792be495069ef9c7a80168c655
|
oid sha256:ef88023b3f423e15d540d755d987edf4a5d7ea2580a30509d79d23ff93235c13
|
||||||
size 171367
|
size 174925
|
||||||
|
|||||||
+6
-5
@@ -29,11 +29,12 @@ enum TemplateScreenCoordinatorAction {
|
|||||||
|
|
||||||
final class TemplateScreenCoordinator: CoordinatorProtocol {
|
final class TemplateScreenCoordinator: CoordinatorProtocol {
|
||||||
private let parameters: TemplateScreenCoordinatorParameters
|
private let parameters: TemplateScreenCoordinatorParameters
|
||||||
private var viewModel: TemplateScreenViewModelProtocol
|
private let viewModel: TemplateScreenViewModelProtocol
|
||||||
private let actionsSubject: PassthroughSubject<TemplateScreenCoordinatorAction, Never> = .init()
|
|
||||||
private var cancellables = Set<AnyCancellable>()
|
|
||||||
|
|
||||||
var actions: AnyPublisher<TemplateScreenCoordinatorAction, Never> {
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<TemplateScreenCoordinatorAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<TemplateScreenCoordinatorAction, Never> {
|
||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ final class TemplateScreenCoordinator: CoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func start() {
|
func start() {
|
||||||
viewModel.actions.sink { [weak self] action in
|
viewModel.actionsPublisher.sink { [weak self] action in
|
||||||
MXLog.info("Coordinator: received view model action: \(action)")
|
MXLog.info("Coordinator: received view model action: \(action)")
|
||||||
|
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -20,9 +20,8 @@ import SwiftUI
|
|||||||
typealias TemplateScreenViewModelType = StateStoreViewModel<TemplateScreenViewState, TemplateScreenViewAction>
|
typealias TemplateScreenViewModelType = StateStoreViewModel<TemplateScreenViewState, TemplateScreenViewAction>
|
||||||
|
|
||||||
class TemplateScreenViewModel: TemplateScreenViewModelType, TemplateScreenViewModelProtocol {
|
class TemplateScreenViewModel: TemplateScreenViewModelType, TemplateScreenViewModelProtocol {
|
||||||
private var actionsSubject: PassthroughSubject<TemplateScreenViewModelAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<TemplateScreenViewModelAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<TemplateScreenViewModelAction, Never> {
|
||||||
var actions: AnyPublisher<TemplateScreenViewModelAction, Never> {
|
|
||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -18,6 +18,6 @@ import Combine
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
protocol TemplateScreenViewModelProtocol {
|
protocol TemplateScreenViewModelProtocol {
|
||||||
var actions: AnyPublisher<TemplateScreenViewModelAction, Never> { get }
|
var actionsPublisher: AnyPublisher<TemplateScreenViewModelAction, Never> { get }
|
||||||
var context: TemplateScreenViewModelType.Context { get }
|
var context: TemplateScreenViewModelType.Context { get }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d3c08ea0ffa71cf6eb554ddc394a7db01325588bb93e3ab094f18a76f669dd9e
|
oid sha256:1e6b1f4f3a3d38a5a55557a0458c46d2ac4c44fc438230ce059fa8b323a8c8ef
|
||||||
size 138739
|
size 145116
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:25076c598482ee48360108f0acc67cde09d191a51c296afb763018bbd748291f
|
oid sha256:13a413c5db74eb8127c9c2c0ae6d0f5633bc40f5c100f7ae679f314785af7116
|
||||||
size 164268
|
size 172723
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:400e3eba5557dd4138c7b8ff2cc305dd95e74c3e1b86f2bd5675a5c7c8dcf656
|
oid sha256:30bebd1f04d98e9a62567e8dc51762b8d0e25baf437a296210652a16fe522c52
|
||||||
size 148563
|
size 155955
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e1eb3e2304004c1d0b21f8431678fdbf9c7e751c57ff4c686706d37fec9bc0d3
|
oid sha256:666546d6087d733ad951d2d3a64eae1f6b2a2a43962d1f724b2b1d3da43531e0
|
||||||
size 184449
|
size 190544
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ class PillContextTests: XCTestCase {
|
|||||||
let id = "@test:matrix.org"
|
let id = "@test:matrix.org"
|
||||||
let proxyMock = RoomProxyMock(with: .init(name: "Test"))
|
let proxyMock = RoomProxyMock(with: .init(name: "Test"))
|
||||||
let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
||||||
proxyMock.members = subject.asCurrentValuePublisher()
|
proxyMock.membersPublisher = subject.asCurrentValuePublisher()
|
||||||
let mock = RoomScreenViewModel(roomProxy: proxyMock,
|
let mock = RoomScreenViewModel(roomProxy: proxyMock,
|
||||||
timelineController: MockRoomTimelineController(),
|
timelineController: MockRoomTimelineController(),
|
||||||
mediaProvider: MockMediaProvider(),
|
mediaProvider: MockMediaProvider(),
|
||||||
@@ -54,7 +54,7 @@ class PillContextTests: XCTestCase {
|
|||||||
let id = "@test:matrix.org"
|
let id = "@test:matrix.org"
|
||||||
let proxyMock = RoomProxyMock(with: .init(name: "Test", ownUserID: id))
|
let proxyMock = RoomProxyMock(with: .init(name: "Test", ownUserID: id))
|
||||||
let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
||||||
proxyMock.members = subject.asCurrentValuePublisher()
|
proxyMock.membersPublisher = subject.asCurrentValuePublisher()
|
||||||
let mock = RoomScreenViewModel(roomProxy: proxyMock,
|
let mock = RoomScreenViewModel(roomProxy: proxyMock,
|
||||||
timelineController: MockRoomTimelineController(),
|
timelineController: MockRoomTimelineController(),
|
||||||
mediaProvider: MockMediaProvider(),
|
mediaProvider: MockMediaProvider(),
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
|
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
|
||||||
TextRoomTimelineItem(eventID: "t2"),
|
TextRoomTimelineItem(eventID: "t2"),
|
||||||
SeparatorRoomTimelineItem(timelineID: "v3")]
|
SeparatorRoomTimelineItem(timelineID: "v3")]
|
||||||
let (viewModel, _, timelineProxy, _, _) = readReceiptsConfiguration(with: items)
|
let (viewModel, _, _, _, _) = readReceiptsConfiguration(with: items)
|
||||||
|
|
||||||
// When sending a read receipt for the last item.
|
// When sending a read receipt for the last item.
|
||||||
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
|
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ final class UserSessionTests: XCTestCase {
|
|||||||
isVerified: false,
|
isVerified: false,
|
||||||
requestDelay: .zero)
|
requestDelay: .zero)
|
||||||
clientProxy.sessionVerificationControllerProxyResult = .success(controller)
|
clientProxy.sessionVerificationControllerProxyResult = .success(controller)
|
||||||
clientProxy.callbacks.send(.receivedSyncUpdate)
|
clientProxy.actionsSubject.send(.receivedSyncUpdate)
|
||||||
waitForExpectations(timeout: 1.0)
|
waitForExpectations(timeout: 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ final class UserSessionTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
clientProxy.callbacks.send(.receivedSyncUpdate)
|
clientProxy.actionsSubject.send(.receivedSyncUpdate)
|
||||||
controller.callbacks.send(.finished)
|
controller.callbacks.send(.finished)
|
||||||
waitForExpectations(timeout: 1.0)
|
waitForExpectations(timeout: 1.0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Add a blocked users section in the app settings
|
||||||
Reference in New Issue
Block a user