mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
feat: report a room
updated tests updated tests added a feature flag to report room removed delay rename
This commit is contained in:
@@ -95,6 +95,7 @@
|
|||||||
0EEC614342F823E5BF966C2C /* AppLockTimerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */; };
|
0EEC614342F823E5BF966C2C /* AppLockTimerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */; };
|
||||||
0F4709282FCCFBEFED427B8A /* AuthenticationClientBuilderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4760CE2128FBC217304272AB /* AuthenticationClientBuilderMock.swift */; };
|
0F4709282FCCFBEFED427B8A /* AuthenticationClientBuilderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4760CE2128FBC217304272AB /* AuthenticationClientBuilderMock.swift */; };
|
||||||
0F6C8033FA60CFD36F7CA205 /* AppLockSetupPINScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A019A12C866D64CF072024B9 /* AppLockSetupPINScreenViewModel.swift */; };
|
0F6C8033FA60CFD36F7CA205 /* AppLockSetupPINScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A019A12C866D64CF072024B9 /* AppLockSetupPINScreenViewModel.swift */; };
|
||||||
|
0FA03F5A33C0857231B32B44 /* ReportRoomScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FDB0B87D925AE830E32621 /* ReportRoomScreenViewModel.swift */; };
|
||||||
108D3C0707A90B0F848CDBB9 /* ResolveVerifiedUserSendFailureScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60011EF0086E49DBD78E16E5 /* ResolveVerifiedUserSendFailureScreenModels.swift */; };
|
108D3C0707A90B0F848CDBB9 /* ResolveVerifiedUserSendFailureScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60011EF0086E49DBD78E16E5 /* ResolveVerifiedUserSendFailureScreenModels.swift */; };
|
||||||
109AEB7D33C4497727AFB87F /* TimelineInteractionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA894BC09972DC45E497D37 /* TimelineInteractionHandler.swift */; };
|
109AEB7D33C4497727AFB87F /* TimelineInteractionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA894BC09972DC45E497D37 /* TimelineInteractionHandler.swift */; };
|
||||||
10D60D287025B71F4743A425 /* RoomDirectorySearchProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471BB7276C97AF60B3A5463B /* RoomDirectorySearchProxy.swift */; };
|
10D60D287025B71F4743A425 /* RoomDirectorySearchProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471BB7276C97AF60B3A5463B /* RoomDirectorySearchProxy.swift */; };
|
||||||
@@ -138,6 +139,7 @@
|
|||||||
1795EA6A6C4942CAE0459DF0 /* SecureBackupKeyBackupScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82B612853BFB68373249777B /* SecureBackupKeyBackupScreenViewModel.swift */; };
|
1795EA6A6C4942CAE0459DF0 /* SecureBackupKeyBackupScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82B612853BFB68373249777B /* SecureBackupKeyBackupScreenViewModel.swift */; };
|
||||||
17BC15DA08A52587466698C5 /* RoomMessageEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */; };
|
17BC15DA08A52587466698C5 /* RoomMessageEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */; };
|
||||||
1801F1467ABCEA080419E150 /* preview_avatar_user.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 87FC42213E86E8182CFD3A49 /* preview_avatar_user.jpg */; };
|
1801F1467ABCEA080419E150 /* preview_avatar_user.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 87FC42213E86E8182CFD3A49 /* preview_avatar_user.jpg */; };
|
||||||
|
182D532B736178A1DED9F76E /* ReportRoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FCAE847556719BBE7A0882 /* ReportRoomScreenModels.swift */; };
|
||||||
18867F4F1C8991EEC56EA932 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
|
18867F4F1C8991EEC56EA932 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
|
||||||
18978C9438206828C1D5AF2A /* test_animated_image.gif in Resources */ = {isa = PBXBuildFile; fileRef = 53FD6D3D38F556CEAA280C58 /* test_animated_image.gif */; };
|
18978C9438206828C1D5AF2A /* test_animated_image.gif in Resources */ = {isa = PBXBuildFile; fileRef = 53FD6D3D38F556CEAA280C58 /* test_animated_image.gif */; };
|
||||||
18E3786918486D4C9726BC84 /* FormButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */; };
|
18E3786918486D4C9726BC84 /* FormButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */; };
|
||||||
@@ -162,6 +164,7 @@
|
|||||||
1B8E30B35BF8F541C1318F19 /* SecureBackupScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */; };
|
1B8E30B35BF8F541C1318F19 /* SecureBackupScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */; };
|
||||||
1BA04D05EBC6646958B1BE60 /* PlaceholderScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF34A2FD6797535C95AC918D /* PlaceholderScreenCoordinator.swift */; };
|
1BA04D05EBC6646958B1BE60 /* PlaceholderScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF34A2FD6797535C95AC918D /* PlaceholderScreenCoordinator.swift */; };
|
||||||
1C409A26A99F0371C47AFA51 /* UserDiscoveryServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F615A00DB223FF3280204D2 /* UserDiscoveryServiceProtocol.swift */; };
|
1C409A26A99F0371C47AFA51 /* UserDiscoveryServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F615A00DB223FF3280204D2 /* UserDiscoveryServiceProtocol.swift */; };
|
||||||
|
1C598D3B785645AAC7B35760 /* ReportRoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 292EEE1F71DCC205C45728F7 /* ReportRoomScreenCoordinator.swift */; };
|
||||||
1C8BC70A18060677E295A846 /* ShareToMapsAppActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4481799F455B3DA243BDA2AC /* ShareToMapsAppActivity.swift */; };
|
1C8BC70A18060677E295A846 /* ShareToMapsAppActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4481799F455B3DA243BDA2AC /* ShareToMapsAppActivity.swift */; };
|
||||||
1C9BB74711E5F24C77B7FED0 /* RoomMembersListScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AEA0B743847CFA5B3C38EE4 /* RoomMembersListScreenCoordinator.swift */; };
|
1C9BB74711E5F24C77B7FED0 /* RoomMembersListScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AEA0B743847CFA5B3C38EE4 /* RoomMembersListScreenCoordinator.swift */; };
|
||||||
1D5DC685CED904386C89B7DA /* NSRegularExpresion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */; };
|
1D5DC685CED904386C89B7DA /* NSRegularExpresion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */; };
|
||||||
@@ -218,6 +221,7 @@
|
|||||||
298F9EC30E918F12AB7F1EE8 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F0325E252B057FAEEE1B2D /* TypingIndicatorView.swift */; };
|
298F9EC30E918F12AB7F1EE8 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F0325E252B057FAEEE1B2D /* TypingIndicatorView.swift */; };
|
||||||
29EE1791E0AFA1ABB7F23D2F /* SwiftState in Frameworks */ = {isa = PBXBuildFile; productRef = 3853B78FB8531B83936C5DA6 /* SwiftState */; };
|
29EE1791E0AFA1ABB7F23D2F /* SwiftState in Frameworks */ = {isa = PBXBuildFile; productRef = 3853B78FB8531B83936C5DA6 /* SwiftState */; };
|
||||||
2A56B00B070F83E0FE571193 /* TimelineMediaPreviewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18A454132A5A5247802821E /* TimelineMediaPreviewDataSource.swift */; };
|
2A56B00B070F83E0FE571193 /* TimelineMediaPreviewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18A454132A5A5247802821E /* TimelineMediaPreviewDataSource.swift */; };
|
||||||
|
2A61D2B4A225332CECA3B937 /* ReportRoomScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20403084A320D588ACED200 /* ReportRoomScreenViewModelProtocol.swift */; };
|
||||||
2AAB2A77F1762A2648078A30 /* InteractiveQuickLook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638A81B97D51591D0FCFA598 /* InteractiveQuickLook.swift */; };
|
2AAB2A77F1762A2648078A30 /* InteractiveQuickLook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638A81B97D51591D0FCFA598 /* InteractiveQuickLook.swift */; };
|
||||||
2AB9D4146C8748CF1D007B67 /* test_pdf.pdf in Resources */ = {isa = PBXBuildFile; fileRef = BE98688578F8B0541D853695 /* test_pdf.pdf */; };
|
2AB9D4146C8748CF1D007B67 /* test_pdf.pdf in Resources */ = {isa = PBXBuildFile; fileRef = BE98688578F8B0541D853695 /* test_pdf.pdf */; };
|
||||||
2AED12987603157C32C2114D /* TimelineBubbleLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D8FEB1FED10E995CB002F7 /* TimelineBubbleLayout.swift */; };
|
2AED12987603157C32C2114D /* TimelineBubbleLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D8FEB1FED10E995CB002F7 /* TimelineBubbleLayout.swift */; };
|
||||||
@@ -415,6 +419,7 @@
|
|||||||
50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0FF64B0E6470F66F42E182 /* EstimatedWaveformView.swift */; };
|
50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0FF64B0E6470F66F42E182 /* EstimatedWaveformView.swift */; };
|
||||||
5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; };
|
5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; };
|
||||||
5139F4BD5A5DF6F8D11A9BDE /* NotificationPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */; };
|
5139F4BD5A5DF6F8D11A9BDE /* NotificationPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */; };
|
||||||
|
513AF15E0E84711B80D04B1B /* ReportRoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3E9684DCE6B66BD0B5DF67 /* ReportRoomScreenViewModelTests.swift */; };
|
||||||
518C93DC6516D3D018DE065F /* UNNotificationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */; };
|
518C93DC6516D3D018DE065F /* UNNotificationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */; };
|
||||||
51B3B19FA5F91B455C807BA7 /* RoomPollsHistoryScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E964AF2DFEB31E2B799999F /* RoomPollsHistoryScreenModels.swift */; };
|
51B3B19FA5F91B455C807BA7 /* RoomPollsHistoryScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E964AF2DFEB31E2B799999F /* RoomPollsHistoryScreenModels.swift */; };
|
||||||
523C6800ED85D5810CF18C19 /* OIDCAccountSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D737F4672021D0A7D218CD /* OIDCAccountSettingsPresenter.swift */; };
|
523C6800ED85D5810CF18C19 /* OIDCAccountSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D737F4672021D0A7D218CD /* OIDCAccountSettingsPresenter.swift */; };
|
||||||
@@ -797,6 +802,7 @@
|
|||||||
9C55746D8F6A3E35CFCF4A7A /* AuthenticationStartLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 598F01EBD0C4CC550C644418 /* AuthenticationStartLogo.swift */; };
|
9C55746D8F6A3E35CFCF4A7A /* AuthenticationStartLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 598F01EBD0C4CC550C644418 /* AuthenticationStartLogo.swift */; };
|
||||||
9C63171267E22FEB288EC860 /* RoomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1627F2D56477BD331F6D732C /* RoomHeaderView.swift */; };
|
9C63171267E22FEB288EC860 /* RoomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1627F2D56477BD331F6D732C /* RoomHeaderView.swift */; };
|
||||||
9CBB04365408F9D6F46BA3A7 /* PinnedEventsTimelineFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54AAF72E821B4084B7E4298 /* PinnedEventsTimelineFlowCoordinator.swift */; };
|
9CBB04365408F9D6F46BA3A7 /* PinnedEventsTimelineFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54AAF72E821B4084B7E4298 /* PinnedEventsTimelineFlowCoordinator.swift */; };
|
||||||
|
9CCF6711DD50BFF8B5ACE9CF /* ReportRoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 276833816F5DEB1CE3B8BE1E /* ReportRoomScreen.swift */; };
|
||||||
9D2E03DB175A6AB14589076D /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = 2A3F7BCCB18C15B30CCA39A9 /* AnalyticsEvents */; };
|
9D2E03DB175A6AB14589076D /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = 2A3F7BCCB18C15B30CCA39A9 /* AnalyticsEvents */; };
|
||||||
9D79B94493FB32249F7E472F /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */; };
|
9D79B94493FB32249F7E472F /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */; };
|
||||||
9D9690D2FD4CD26FF670620F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75EF87651B00A176AB08E97 /* AppDelegate.swift */; };
|
9D9690D2FD4CD26FF670620F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75EF87651B00A176AB08E97 /* AppDelegate.swift */; };
|
||||||
@@ -1408,6 +1414,7 @@
|
|||||||
0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModel.swift; sourceTree = "<group>"; };
|
0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
0BD116096CAA9139B95EEA9C /* UserProfileScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenViewModel.swift; sourceTree = "<group>"; };
|
0BD116096CAA9139B95EEA9C /* UserProfileScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
0C34667458773B02AB5FB0B2 /* LegalInformationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenViewModel.swift; sourceTree = "<group>"; };
|
0C34667458773B02AB5FB0B2 /* LegalInformationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
0C3E9684DCE6B66BD0B5DF67 /* ReportRoomScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
0C62E07C1164F5120727A2A8 /* AppLockSetupBiometricsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenCoordinator.swift; sourceTree = "<group>"; };
|
0C62E07C1164F5120727A2A8 /* AppLockSetupBiometricsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
0CB569EAA5017B5B23970655 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = "<group>"; };
|
0CB569EAA5017B5B23970655 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
0CCC6C31102E1D8B9106DEDE /* AppLockSetupBiometricsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
0CCC6C31102E1D8B9106DEDE /* AppLockSetupBiometricsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -1433,6 +1440,7 @@
|
|||||||
11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
111B698739E3410E2CDB7144 /* MXLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = "<group>"; };
|
111B698739E3410E2CDB7144 /* MXLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = "<group>"; };
|
||||||
113356152C099951A6D17D85 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
|
113356152C099951A6D17D85 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
11FCAE847556719BBE7A0882 /* ReportRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenModels.swift; sourceTree = "<group>"; };
|
||||||
1215A4FC53D2319E81AE8970 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
1215A4FC53D2319E81AE8970 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
|
1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
|
||||||
127A57D053CE8C87B5EFB089 /* Consumable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Consumable.swift; sourceTree = "<group>"; };
|
127A57D053CE8C87B5EFB089 /* Consumable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Consumable.swift; sourceTree = "<group>"; };
|
||||||
@@ -1548,6 +1556,7 @@
|
|||||||
2711E5996016ABD6EAAEB58A /* LogLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogLevel.swift; sourceTree = "<group>"; };
|
2711E5996016ABD6EAAEB58A /* LogLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogLevel.swift; sourceTree = "<group>"; };
|
||||||
2721D7B051F0159AA919DA05 /* RoomChangePermissionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
2721D7B051F0159AA919DA05 /* RoomChangePermissionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
2757B1BE23DF8AA239937243 /* AudioConverterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioConverterProtocol.swift; sourceTree = "<group>"; };
|
2757B1BE23DF8AA239937243 /* AudioConverterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioConverterProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
276833816F5DEB1CE3B8BE1E /* ReportRoomScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreen.swift; sourceTree = "<group>"; };
|
||||||
277C20CDD5B64510401B6D0D /* ServerConfigurationScreenViewStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfigurationScreenViewStateTests.swift; sourceTree = "<group>"; };
|
277C20CDD5B64510401B6D0D /* ServerConfigurationScreenViewStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfigurationScreenViewStateTests.swift; sourceTree = "<group>"; };
|
||||||
27A1AD6389A4659AF0CEAE62 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = "<group>"; };
|
27A1AD6389A4659AF0CEAE62 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = "<group>"; };
|
||||||
27A9E3FBE8A66B5A17AD7F74 /* AppRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRoutes.swift; sourceTree = "<group>"; };
|
27A9E3FBE8A66B5A17AD7F74 /* AppRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRoutes.swift; sourceTree = "<group>"; };
|
||||||
@@ -1561,6 +1570,7 @@
|
|||||||
28C202C1C7E330F124981A31 /* GenericCallLinkWidgetDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericCallLinkWidgetDriver.swift; sourceTree = "<group>"; };
|
28C202C1C7E330F124981A31 /* GenericCallLinkWidgetDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericCallLinkWidgetDriver.swift; sourceTree = "<group>"; };
|
||||||
28EA8BE9EEDBD17555141C7E /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = el; path = el.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
28EA8BE9EEDBD17555141C7E /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = el; path = el.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
2910422CB628D3B2BBE47449 /* SeparatorRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineView.swift; sourceTree = "<group>"; };
|
2910422CB628D3B2BBE47449 /* SeparatorRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
|
292EEE1F71DCC205C45728F7 /* ReportRoomScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
|
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
|
||||||
2A2BB38DF61F5100B8723112 /* TimelineMediaPreviewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModels.swift; sourceTree = "<group>"; };
|
2A2BB38DF61F5100B8723112 /* TimelineMediaPreviewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModels.swift; sourceTree = "<group>"; };
|
||||||
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
||||||
@@ -2201,6 +2211,7 @@
|
|||||||
B172057567E049007A5C4D92 /* Strings+SAS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+SAS.swift"; sourceTree = "<group>"; };
|
B172057567E049007A5C4D92 /* Strings+SAS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+SAS.swift"; sourceTree = "<group>"; };
|
||||||
B18A454132A5A5247802821E /* TimelineMediaPreviewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDataSource.swift; sourceTree = "<group>"; };
|
B18A454132A5A5247802821E /* TimelineMediaPreviewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDataSource.swift; sourceTree = "<group>"; };
|
||||||
B1E227F34BE43B08E098796E /* TestablePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestablePreview.swift; sourceTree = "<group>"; };
|
B1E227F34BE43B08E098796E /* TestablePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestablePreview.swift; sourceTree = "<group>"; };
|
||||||
|
B1FDB0B87D925AE830E32621 /* ReportRoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = "<group>"; };
|
B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = "<group>"; };
|
||||||
B2AD8A56CD37E23071A2F4BF /* PHGPostHogMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogMock.swift; sourceTree = "<group>"; };
|
B2AD8A56CD37E23071A2F4BF /* PHGPostHogMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogMock.swift; sourceTree = "<group>"; };
|
||||||
B2AF1828A5B76B7C371240FE /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
|
B2AF1828A5B76B7C371240FE /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
@@ -2426,6 +2437,7 @@
|
|||||||
E1A5FEF17ED7E6176D922D4F /* RoomDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreen.swift; sourceTree = "<group>"; };
|
E1A5FEF17ED7E6176D922D4F /* RoomDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreen.swift; sourceTree = "<group>"; };
|
||||||
E1E0B4A34E69BD2132BEC521 /* MessageText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageText.swift; sourceTree = "<group>"; };
|
E1E0B4A34E69BD2132BEC521 /* MessageText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageText.swift; sourceTree = "<group>"; };
|
||||||
E1ED17433ADC77287F8904F9 /* CallNotificationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallNotificationRoomTimelineItem.swift; sourceTree = "<group>"; };
|
E1ED17433ADC77287F8904F9 /* CallNotificationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallNotificationRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
|
E20403084A320D588ACED200 /* ReportRoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
E2520C4F33AA0C061D209C28 /* RoomMembersListScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenTests.swift; sourceTree = "<group>"; };
|
E2520C4F33AA0C061D209C28 /* RoomMembersListScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenTests.swift; sourceTree = "<group>"; };
|
||||||
E2776E63E02719B20758EB78 /* EditRoomAddressListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressListRow.swift; sourceTree = "<group>"; };
|
E2776E63E02719B20758EB78 /* EditRoomAddressListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressListRow.swift; sourceTree = "<group>"; };
|
||||||
E2B1CC9AA154F4D5435BF60A /* Comparable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = "<group>"; };
|
E2B1CC9AA154F4D5435BF60A /* Comparable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = "<group>"; };
|
||||||
@@ -3093,6 +3105,14 @@
|
|||||||
path = AppLockSetupSettingsScreen;
|
path = AppLockSetupSettingsScreen;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
2B27F01BB7B839E543DFE025 /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
276833816F5DEB1CE3B8BE1E /* ReportRoomScreen.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
2C0F49BD446849654C0D24E0 /* RoomMember */ = {
|
2C0F49BD446849654C0D24E0 /* RoomMember */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -3765,6 +3785,18 @@
|
|||||||
path = RoomMembershipDetails;
|
path = RoomMembershipDetails;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4DDB6973795DA09189CF64A5 /* ReportRoomScreen */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
292EEE1F71DCC205C45728F7 /* ReportRoomScreenCoordinator.swift */,
|
||||||
|
11FCAE847556719BBE7A0882 /* ReportRoomScreenModels.swift */,
|
||||||
|
B1FDB0B87D925AE830E32621 /* ReportRoomScreenViewModel.swift */,
|
||||||
|
E20403084A320D588ACED200 /* ReportRoomScreenViewModelProtocol.swift */,
|
||||||
|
2B27F01BB7B839E543DFE025 /* View */,
|
||||||
|
);
|
||||||
|
path = ReportRoomScreen;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
4EC4EBBC4F6885775F198875 /* Sources */ = {
|
4EC4EBBC4F6885775F198875 /* Sources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -4247,6 +4279,7 @@
|
|||||||
347D708104CCEF771428C9A3 /* PollFormScreenViewModelTests.swift */,
|
347D708104CCEF771428C9A3 /* PollFormScreenViewModelTests.swift */,
|
||||||
25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */,
|
25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */,
|
||||||
086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */,
|
086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */,
|
||||||
|
0C3E9684DCE6B66BD0B5DF67 /* ReportRoomScreenViewModelTests.swift */,
|
||||||
57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */,
|
57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */,
|
||||||
A7978C9EFBDD7DE39BD86726 /* RestorationTokenTests.swift */,
|
A7978C9EFBDD7DE39BD86726 /* RestorationTokenTests.swift */,
|
||||||
41D041A857614A9AE13C7795 /* RoomChangePermissionsScreenViewModelTests.swift */,
|
41D041A857614A9AE13C7795 /* RoomChangePermissionsScreenViewModelTests.swift */,
|
||||||
@@ -5718,6 +5751,7 @@
|
|||||||
3E535010B850B53DDD3CFF2A /* PinnedEventsTimelineScreen */,
|
3E535010B850B53DDD3CFF2A /* PinnedEventsTimelineScreen */,
|
||||||
3D733E8352DD4C461CFD8B8A /* QRCodeLoginScreen */,
|
3D733E8352DD4C461CFD8B8A /* QRCodeLoginScreen */,
|
||||||
5970F275D6014548DCED6106 /* ReportContentScreen */,
|
5970F275D6014548DCED6106 /* ReportContentScreen */,
|
||||||
|
4DDB6973795DA09189CF64A5 /* ReportRoomScreen */,
|
||||||
A040ACE4D778FFCD65DDF5F8 /* ResolveVerifiedUserSendFailureScreen */,
|
A040ACE4D778FFCD65DDF5F8 /* ResolveVerifiedUserSendFailureScreen */,
|
||||||
DAB7DC51866A6D1B51BDC3A2 /* RoomChangePermissionsScreen */,
|
DAB7DC51866A6D1B51BDC3A2 /* RoomChangePermissionsScreen */,
|
||||||
D8388454B5909D862CAC78F7 /* RoomChangeRolesScreen */,
|
D8388454B5909D862CAC78F7 /* RoomChangeRolesScreen */,
|
||||||
@@ -6731,6 +6765,7 @@
|
|||||||
E3EBC3BF7CE3960B41757BAA /* Publisher.swift in Sources */,
|
E3EBC3BF7CE3960B41757BAA /* Publisher.swift in Sources */,
|
||||||
BDC4EB54CC3036730475CB8B /* QRCodeLoginScreenViewModelTests.swift in Sources */,
|
BDC4EB54CC3036730475CB8B /* QRCodeLoginScreenViewModelTests.swift in Sources */,
|
||||||
D53B80EF02C1062E68659EDD /* ReportContentViewModelTests.swift in Sources */,
|
D53B80EF02C1062E68659EDD /* ReportContentViewModelTests.swift in Sources */,
|
||||||
|
513AF15E0E84711B80D04B1B /* ReportRoomScreenViewModelTests.swift in Sources */,
|
||||||
09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */,
|
09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */,
|
||||||
C5627BCC3EBBB96A943B6D93 /* RestorationTokenTests.swift in Sources */,
|
C5627BCC3EBBB96A943B6D93 /* RestorationTokenTests.swift in Sources */,
|
||||||
9B03943616A1147539DF7F08 /* RoomChangePermissionsScreenViewModelTests.swift in Sources */,
|
9B03943616A1147539DF7F08 /* RoomChangePermissionsScreenViewModelTests.swift in Sources */,
|
||||||
@@ -7347,6 +7382,11 @@
|
|||||||
46A261AA898344A1F3C406B1 /* ReportContentScreenModels.swift in Sources */,
|
46A261AA898344A1F3C406B1 /* ReportContentScreenModels.swift in Sources */,
|
||||||
42A5A42ACF063EEE6B1980D2 /* ReportContentScreenViewModel.swift in Sources */,
|
42A5A42ACF063EEE6B1980D2 /* ReportContentScreenViewModel.swift in Sources */,
|
||||||
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */,
|
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */,
|
||||||
|
9CCF6711DD50BFF8B5ACE9CF /* ReportRoomScreen.swift in Sources */,
|
||||||
|
1C598D3B785645AAC7B35760 /* ReportRoomScreenCoordinator.swift in Sources */,
|
||||||
|
182D532B736178A1DED9F76E /* ReportRoomScreenModels.swift in Sources */,
|
||||||
|
0FA03F5A33C0857231B32B44 /* ReportRoomScreenViewModel.swift in Sources */,
|
||||||
|
2A61D2B4A225332CECA3B937 /* ReportRoomScreenViewModelProtocol.swift in Sources */,
|
||||||
4715FE33667C5899E64DD0E6 /* ResolveVerifiedUserSendFailureScreen.swift in Sources */,
|
4715FE33667C5899E64DD0E6 /* ResolveVerifiedUserSendFailureScreen.swift in Sources */,
|
||||||
583A41A4BE76E2E9E0B97881 /* ResolveVerifiedUserSendFailureScreenCoordinator.swift in Sources */,
|
583A41A4BE76E2E9E0B97881 /* ResolveVerifiedUserSendFailureScreenCoordinator.swift in Sources */,
|
||||||
108D3C0707A90B0F848CDBB9 /* ResolveVerifiedUserSendFailureScreenModels.swift in Sources */,
|
108D3C0707A90B0F848CDBB9 /* ResolveVerifiedUserSendFailureScreenModels.swift in Sources */,
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ final class AppSettings {
|
|||||||
case fuzzyRoomListSearchEnabled
|
case fuzzyRoomListSearchEnabled
|
||||||
case enableOnlySignedDeviceIsolationMode
|
case enableOnlySignedDeviceIsolationMode
|
||||||
case knockingEnabled
|
case knockingEnabled
|
||||||
|
case reportRoomEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
||||||
@@ -330,6 +331,8 @@ final class AppSettings {
|
|||||||
@UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
var knockingEnabled
|
var knockingEnabled
|
||||||
|
|
||||||
|
@UserPreference(key: UserDefaultsKeys.reportRoomEnabled, defaultValue: false, storageType: .userDefaults(store)) var reportRoomEnabled
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MARK: - Shared
|
// MARK: - Shared
|
||||||
|
|||||||
@@ -414,6 +414,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
return .securityAndPrivacy(previousState: fromState)
|
return .securityAndPrivacy(previousState: fromState)
|
||||||
case (.securityAndPrivacy(let previousState), .dismissSecurityAndPrivacyScreen):
|
case (.securityAndPrivacy(let previousState), .dismissSecurityAndPrivacyScreen):
|
||||||
return previousState
|
return previousState
|
||||||
|
|
||||||
|
case (.roomDetails, .presentReportRoomScreen):
|
||||||
|
return .reportRoom(previousState: fromState)
|
||||||
|
case (.reportRoom(let previousState), .dismissReportRoomScreen):
|
||||||
|
return previousState
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
@@ -585,6 +590,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
presentSecurityAndPrivacyScreen()
|
presentSecurityAndPrivacyScreen()
|
||||||
case (.securityAndPrivacy, .dismissSecurityAndPrivacyScreen, .roomDetails):
|
case (.securityAndPrivacy, .dismissSecurityAndPrivacyScreen, .roomDetails):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case (.roomDetails, .presentReportRoomScreen, .reportRoom):
|
||||||
|
presentReportRoom()
|
||||||
|
case (.reportRoom, .dismissReportRoomScreen, .roomDetails):
|
||||||
|
break
|
||||||
|
|
||||||
// Child flow
|
// Child flow
|
||||||
case (_, .startChildFlow(let roomID, let via, let entryPoint), .presentingChild):
|
case (_, .startChildFlow(let roomID, let via, let entryPoint), .presentingChild):
|
||||||
@@ -869,6 +879,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
stateMachine.tryEvent(.presentSecurityAndPrivacyScreen)
|
stateMachine.tryEvent(.presentSecurityAndPrivacyScreen)
|
||||||
case .presentRecipientDetails(let userID):
|
case .presentRecipientDetails(let userID):
|
||||||
stateMachine.tryEvent(.presentRoomMemberDetails(userID: userID))
|
stateMachine.tryEvent(.presentRoomMemberDetails(userID: userID))
|
||||||
|
case .presentReportRoomScreen:
|
||||||
|
stateMachine.tryEvent(.presentReportRoomScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
@@ -1516,6 +1528,29 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
navigationStackCoordinator.setSheetCoordinator(stackCoordinator)
|
navigationStackCoordinator.setSheetCoordinator(stackCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func presentReportRoom() {
|
||||||
|
let stackCoordinator = NavigationStackCoordinator()
|
||||||
|
let coordinator = ReportRoomScreenCoordinator(parameters: .init(roomProxy: roomProxy,
|
||||||
|
userIndicatorController: userIndicatorController))
|
||||||
|
|
||||||
|
coordinator.actionsPublisher.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .dismiss(let shouldLeaveRoom):
|
||||||
|
if shouldLeaveRoom {
|
||||||
|
stateMachine.tryEvent(.dismissFlow)
|
||||||
|
}
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
stackCoordinator.setRootCoordinator(coordinator)
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(stackCoordinator) { [weak self] in
|
||||||
|
self?.stateMachine.tryEvent(.dismissReportRoomScreen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Other flows
|
// MARK: - Other flows
|
||||||
|
|
||||||
private func startChildFlow(for roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint) async {
|
private func startChildFlow(for roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint) async {
|
||||||
@@ -1686,6 +1721,7 @@ private extension RoomFlowCoordinator {
|
|||||||
case knockRequestsList(previousState: State)
|
case knockRequestsList(previousState: State)
|
||||||
case mediaEventsTimeline(previousState: State)
|
case mediaEventsTimeline(previousState: State)
|
||||||
case securityAndPrivacy(previousState: State)
|
case securityAndPrivacy(previousState: State)
|
||||||
|
case reportRoom(previousState: State)
|
||||||
|
|
||||||
/// A child flow is in progress.
|
/// A child flow is in progress.
|
||||||
case presentingChild(childRoomID: String, previousState: State)
|
case presentingChild(childRoomID: String, previousState: State)
|
||||||
@@ -1772,5 +1808,8 @@ private extension RoomFlowCoordinator {
|
|||||||
|
|
||||||
case presentSecurityAndPrivacyScreen
|
case presentSecurityAndPrivacyScreen
|
||||||
case dismissSecurityAndPrivacyScreen
|
case dismissSecurityAndPrivacyScreen
|
||||||
|
|
||||||
|
case presentReportRoomScreen
|
||||||
|
case dismissReportRoomScreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case .roomDetails(let roomID):
|
case .roomDetails(let roomID):
|
||||||
if stateMachine.state.selectedRoomID == roomID {
|
if stateMachine.state.roomListSelectedRoomID == roomID {
|
||||||
roomFlowCoordinator?.handleAppRoute(appRoute, animated: animated)
|
roomFlowCoordinator?.handleAppRoute(appRoute, animated: animated)
|
||||||
} else {
|
} else {
|
||||||
stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .roomDetails), userInfo: .init(animated: animated))
|
stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .roomDetails), userInfo: .init(animated: animated))
|
||||||
@@ -245,8 +245,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
case (.initial, .start, .roomList):
|
case (.initial, .start, .roomList):
|
||||||
presentHomeScreen()
|
presentHomeScreen()
|
||||||
attemptStartingOnboarding()
|
attemptStartingOnboarding()
|
||||||
case(.roomList(let selectedRoomID), .selectRoom(let roomID, let via, let entryPoint), .roomList):
|
case(.roomList(let roomListSelectedRoomID), .selectRoom(let roomID, let via, let entryPoint), .roomList):
|
||||||
if selectedRoomID == roomID,
|
if roomListSelectedRoomID == roomID,
|
||||||
!entryPoint.isEventID, // Don't reuse the existing room so the live timeline is hidden while the detached timeline is loading.
|
!entryPoint.isEventID, // Don't reuse the existing room so the live timeline is hidden while the detached timeline is loading.
|
||||||
let roomFlowCoordinator {
|
let roomFlowCoordinator {
|
||||||
let route: AppRoute = switch entryPoint {
|
let route: AppRoute = switch entryPoint {
|
||||||
@@ -307,9 +307,14 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
case (.userProfileScreen, .dismissedUserProfileScreen, .roomList):
|
case (.userProfileScreen, .dismissedUserProfileScreen, .roomList):
|
||||||
break
|
break
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .showShareExtensionRoomList, .shareExtensionRoomList(let sharePayload)):
|
case (.roomList, .presentReportRoomScreen(let roomID), .reportRoomScreen):
|
||||||
|
Task { await self.presentReportRoom(for: roomID) }
|
||||||
|
case (.reportRoomScreen, .dismissedReportRoomScreen, .roomList):
|
||||||
|
break
|
||||||
|
|
||||||
|
case (.roomList(let roomListSelectedRoomID), .showShareExtensionRoomList, .shareExtensionRoomList(let sharePayload)):
|
||||||
Task {
|
Task {
|
||||||
if selectedRoomID != nil {
|
if roomListSelectedRoomID != nil {
|
||||||
self.clearRoute(animated: animated)
|
self.clearRoute(animated: animated)
|
||||||
try? await Task.sleep(for: .seconds(1.5))
|
try? await Task.sleep(for: .seconds(1.5))
|
||||||
}
|
}
|
||||||
@@ -326,8 +331,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
stateMachine.addTransitionHandler { [weak self] context in
|
stateMachine.addTransitionHandler { [weak self] context in
|
||||||
switch context.toState {
|
switch context.toState {
|
||||||
case .roomList(let selectedRoomID):
|
case .roomList(let roomListSelectedRoomID):
|
||||||
self?.selectedRoomSubject.send(selectedRoomID)
|
self?.selectedRoomSubject.send(roomListSelectedRoomID)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -496,9 +501,11 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
handleAppRoute(.room(roomID: roomID, via: []), animated: true)
|
handleAppRoute(.room(roomID: roomID, via: []), animated: true)
|
||||||
case .presentRoomDetails(let roomID):
|
case .presentRoomDetails(let roomID):
|
||||||
handleAppRoute(.roomDetails(roomID: roomID), animated: true)
|
handleAppRoute(.roomDetails(roomID: roomID), animated: true)
|
||||||
|
case .presentReportRoom(let roomID):
|
||||||
|
stateMachine.processEvent(.presentReportRoomScreen(roomID: roomID))
|
||||||
case .roomLeft(let roomID):
|
case .roomLeft(let roomID):
|
||||||
if case .roomList(selectedRoomID: let selectedRoomID) = stateMachine.state,
|
if case .roomList(roomListSelectedRoomID: let roomListSelectedRoomID) = stateMachine.state,
|
||||||
selectedRoomID == roomID {
|
roomListSelectedRoomID == roomID {
|
||||||
clearRoute(animated: true)
|
clearRoute(animated: true)
|
||||||
}
|
}
|
||||||
case .presentSettingsScreen:
|
case .presentSettingsScreen:
|
||||||
@@ -528,6 +535,35 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
navigationRootCoordinator.setRootCoordinator(navigationSplitCoordinator)
|
navigationRootCoordinator.setRootCoordinator(navigationSplitCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func presentReportRoom(for roomID: String) async {
|
||||||
|
guard let roomProxyType = await userSession.clientProxy.roomForIdentifier(roomID),
|
||||||
|
case let .joined(roomProxy) = roomProxyType else {
|
||||||
|
MXLog.error("Failed to get room proxy for room: \(roomID)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||||
|
let coordinator = ReportRoomScreenCoordinator(parameters: .init(roomProxy: roomProxy,
|
||||||
|
userIndicatorController: ServiceLocator.shared.userIndicatorController))
|
||||||
|
coordinator.actionsPublisher.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .dismiss(let shouldLeaveRoom):
|
||||||
|
if shouldLeaveRoom,
|
||||||
|
case .roomList(let roomListSelectedRoomID) = stateMachine.state,
|
||||||
|
roomListSelectedRoomID == roomID {
|
||||||
|
clearRoute(animated: true)
|
||||||
|
}
|
||||||
|
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||||
|
navigationSplitCoordinator.setSheetCoordinator(navigationStackCoordinator) { [weak self] in
|
||||||
|
self?.stateMachine.processEvent(.dismissedReportRoomScreen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func runLogoutFlow() async {
|
private func runLogoutFlow() async {
|
||||||
let secureBackupController = userSession.clientProxy.secureBackupController
|
let secureBackupController = userSession.clientProxy.secureBackupController
|
||||||
|
|
||||||
|
|||||||
@@ -15,49 +15,53 @@ class UserSessionFlowCoordinatorStateMachine {
|
|||||||
/// The initial state, used before the coordinator starts
|
/// The initial state, used before the coordinator starts
|
||||||
case initial
|
case initial
|
||||||
|
|
||||||
/// Showing the home screen. The `selectedRoomID` represents the timeline shown on the detail panel (if any)
|
/// Showing the home screen. The `roomListSelectedRoomID` represents the timeline shown on the detail panel (if any)
|
||||||
case roomList(selectedRoomID: String?)
|
case roomList(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing the feedback screen.
|
/// Showing the feedback screen.
|
||||||
case feedbackScreen(selectedRoomID: String?)
|
case feedbackScreen(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing the settings screen
|
/// Showing the settings screen
|
||||||
case settingsScreen(selectedRoomID: String?)
|
case settingsScreen(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing the recovery key screen.
|
/// Showing the recovery key screen.
|
||||||
case recoveryKeyScreen(selectedRoomID: String?)
|
case recoveryKeyScreen(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing the encryption reset flow.
|
/// Showing the encryption reset flow.
|
||||||
case encryptionResetFlow(selectedRoomID: String?)
|
case encryptionResetFlow(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing the start chat screen
|
/// Showing the start chat screen
|
||||||
case startChatScreen(selectedRoomID: String?)
|
case startChatScreen(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing the logout flows
|
/// Showing the logout flows
|
||||||
case logoutConfirmationScreen(selectedRoomID: String?)
|
case logoutConfirmationScreen(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing Room Directory Search screen
|
/// Showing Room Directory Search screen
|
||||||
case roomDirectorySearchScreen(selectedRoomID: String?)
|
case roomDirectorySearchScreen(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
/// Showing the user profile screen. This screen clears the navigation.
|
/// Showing the user profile screen. This screen clears the navigation.
|
||||||
case userProfileScreen
|
case userProfileScreen
|
||||||
|
|
||||||
|
/// Showing the report room screen, for the given room identrifier
|
||||||
|
case reportRoomScreen(roomListSelectedRoomID: String?)
|
||||||
|
|
||||||
case shareExtensionRoomList(sharePayload: ShareExtensionPayload)
|
case shareExtensionRoomList(sharePayload: ShareExtensionPayload)
|
||||||
|
|
||||||
/// The selected room ID from the state if available.
|
/// The selected room ID from the state if available.
|
||||||
var selectedRoomID: String? {
|
var roomListSelectedRoomID: String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .initial, .userProfileScreen, .shareExtensionRoomList:
|
case .initial, .userProfileScreen, .shareExtensionRoomList:
|
||||||
nil
|
nil
|
||||||
case .roomList(let selectedRoomID),
|
case .roomList(let roomListSelectedRoomID),
|
||||||
.feedbackScreen(let selectedRoomID),
|
.feedbackScreen(let roomListSelectedRoomID),
|
||||||
.settingsScreen(let selectedRoomID),
|
.settingsScreen(let roomListSelectedRoomID),
|
||||||
.recoveryKeyScreen(let selectedRoomID),
|
.recoveryKeyScreen(let roomListSelectedRoomID),
|
||||||
.encryptionResetFlow(let selectedRoomID),
|
.encryptionResetFlow(let roomListSelectedRoomID),
|
||||||
.startChatScreen(let selectedRoomID),
|
.startChatScreen(let roomListSelectedRoomID),
|
||||||
.logoutConfirmationScreen(let selectedRoomID),
|
.logoutConfirmationScreen(let roomListSelectedRoomID),
|
||||||
.roomDirectorySearchScreen(let selectedRoomID):
|
.roomDirectorySearchScreen(let roomListSelectedRoomID),
|
||||||
selectedRoomID
|
.reportRoomScreen(let roomListSelectedRoomID):
|
||||||
|
roomListSelectedRoomID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +125,9 @@ class UserSessionFlowCoordinatorStateMachine {
|
|||||||
|
|
||||||
case showShareExtensionRoomList(sharePayload: ShareExtensionPayload)
|
case showShareExtensionRoomList(sharePayload: ShareExtensionPayload)
|
||||||
case dismissedShareExtensionRoomList
|
case dismissedShareExtensionRoomList
|
||||||
|
|
||||||
|
case presentReportRoomScreen(roomID: String)
|
||||||
|
case dismissedReportRoomScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
private let stateMachine: StateMachine<State, Event>
|
private let stateMachine: StateMachine<State, Event>
|
||||||
@@ -140,59 +147,64 @@ class UserSessionFlowCoordinatorStateMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func configure() {
|
private func configure() {
|
||||||
stateMachine.addRoutes(event: .start, transitions: [.initial => .roomList(selectedRoomID: nil)])
|
stateMachine.addRoutes(event: .start, transitions: [.initial => .roomList(roomListSelectedRoomID: nil)])
|
||||||
|
|
||||||
stateMachine.addRouteMapping { event, fromState, _ in
|
stateMachine.addRouteMapping { event, fromState, _ in
|
||||||
switch (fromState, event) {
|
switch (fromState, event) {
|
||||||
case (.roomList, .selectRoom(let roomID, _, _)):
|
case (.roomList, .selectRoom(let roomID, _, _)):
|
||||||
return .roomList(selectedRoomID: roomID)
|
return .roomList(roomListSelectedRoomID: roomID)
|
||||||
case (.roomList, .deselectRoom):
|
case (.roomList, .deselectRoom):
|
||||||
return .roomList(selectedRoomID: nil)
|
return .roomList(roomListSelectedRoomID: nil)
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .showSettingsScreen):
|
case (.roomList(let roomListSelectedRoomID), .showSettingsScreen):
|
||||||
return .settingsScreen(selectedRoomID: selectedRoomID)
|
return .settingsScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
case (.settingsScreen(let selectedRoomID), .dismissedSettingsScreen):
|
case (.settingsScreen(let roomListSelectedRoomID), .dismissedSettingsScreen):
|
||||||
return .roomList(selectedRoomID: selectedRoomID)
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .feedbackScreen):
|
case (.roomList(let roomListSelectedRoomID), .feedbackScreen):
|
||||||
return .feedbackScreen(selectedRoomID: selectedRoomID)
|
return .feedbackScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
case (.feedbackScreen(let selectedRoomID), .dismissedFeedbackScreen):
|
case (.feedbackScreen(let roomListSelectedRoomID), .dismissedFeedbackScreen):
|
||||||
return .roomList(selectedRoomID: selectedRoomID)
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .showRecoveryKeyScreen):
|
case (.roomList(let roomListSelectedRoomID), .showRecoveryKeyScreen):
|
||||||
return .recoveryKeyScreen(selectedRoomID: selectedRoomID)
|
return .recoveryKeyScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
case (.recoveryKeyScreen(let selectedRoomID), .dismissedRecoveryKeyScreen):
|
case (.recoveryKeyScreen(let roomListSelectedRoomID), .dismissedRecoveryKeyScreen):
|
||||||
return .roomList(selectedRoomID: selectedRoomID)
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .startEncryptionResetFlow):
|
case (.roomList(let roomListSelectedRoomID), .startEncryptionResetFlow):
|
||||||
return .encryptionResetFlow(selectedRoomID: selectedRoomID)
|
return .encryptionResetFlow(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
case (.encryptionResetFlow(let selectedRoomID), .finishedEncryptionResetFlow):
|
case (.encryptionResetFlow(let roomListSelectedRoomID), .finishedEncryptionResetFlow):
|
||||||
return .roomList(selectedRoomID: selectedRoomID)
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .showStartChatScreen):
|
case (.roomList(let roomListSelectedRoomID), .showStartChatScreen):
|
||||||
return .startChatScreen(selectedRoomID: selectedRoomID)
|
return .startChatScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
case (.startChatScreen(let selectedRoomID), .dismissedStartChatScreen):
|
case (.startChatScreen(let roomListSelectedRoomID), .dismissedStartChatScreen):
|
||||||
return .roomList(selectedRoomID: selectedRoomID)
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .showLogoutConfirmationScreen):
|
case (.roomList(let roomListSelectedRoomID), .showLogoutConfirmationScreen):
|
||||||
return .logoutConfirmationScreen(selectedRoomID: selectedRoomID)
|
return .logoutConfirmationScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
case (.logoutConfirmationScreen(let selectedRoomID), .dismissedLogoutConfirmationScreen):
|
case (.logoutConfirmationScreen(let roomListSelectedRoomID), .dismissedLogoutConfirmationScreen):
|
||||||
return .roomList(selectedRoomID: selectedRoomID)
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
case (.roomList(let selectedRoomID), .showRoomDirectorySearchScreen):
|
case (.roomList(let roomListSelectedRoomID), .showRoomDirectorySearchScreen):
|
||||||
return .roomDirectorySearchScreen(selectedRoomID: selectedRoomID)
|
return .roomDirectorySearchScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
case (.roomDirectorySearchScreen(let selectedRoomID), .dismissedRoomDirectorySearchScreen):
|
case (.roomDirectorySearchScreen(let roomListSelectedRoomID), .dismissedRoomDirectorySearchScreen):
|
||||||
return .roomList(selectedRoomID: selectedRoomID)
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
case (_, .showUserProfileScreen):
|
case (_, .showUserProfileScreen):
|
||||||
return .userProfileScreen
|
return .userProfileScreen
|
||||||
case (.userProfileScreen, .dismissedUserProfileScreen):
|
case (.userProfileScreen, .dismissedUserProfileScreen):
|
||||||
return .roomList(selectedRoomID: nil)
|
return .roomList(roomListSelectedRoomID: nil)
|
||||||
|
|
||||||
case (.roomList, .showShareExtensionRoomList(let sharePayload)):
|
case (.roomList, .showShareExtensionRoomList(let sharePayload)):
|
||||||
return .shareExtensionRoomList(sharePayload: sharePayload)
|
return .shareExtensionRoomList(sharePayload: sharePayload)
|
||||||
case (.shareExtensionRoomList, .dismissedShareExtensionRoomList):
|
case (.shareExtensionRoomList, .dismissedShareExtensionRoomList):
|
||||||
return .roomList(selectedRoomID: nil)
|
return .roomList(roomListSelectedRoomID: nil)
|
||||||
|
|
||||||
|
case (.roomList(let roomListSelectedRoomID), .presentReportRoomScreen):
|
||||||
|
return .reportRoomScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
case (.reportRoomScreen(let roomListSelectedRoomID), .dismissedReportRoomScreen):
|
||||||
|
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
@@ -231,8 +243,8 @@ class UserSessionFlowCoordinatorStateMachine {
|
|||||||
/// Flag indicating the machine is displaying room screen with given room identifier
|
/// Flag indicating the machine is displaying room screen with given room identifier
|
||||||
func isDisplayingRoomScreen(withRoomID roomID: String) -> Bool {
|
func isDisplayingRoomScreen(withRoomID roomID: String) -> Bool {
|
||||||
switch stateMachine.state {
|
switch stateMachine.state {
|
||||||
case .roomList(let selectedRoomID):
|
case .roomList(let roomListSelectedRoomID):
|
||||||
return roomID == selectedRoomID
|
return roomID == roomListSelectedRoomID
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6689,6 +6689,76 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable {
|
|||||||
return reportContentReasonReturnValue
|
return reportContentReasonReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//MARK: - reportRoom
|
||||||
|
|
||||||
|
var reportRoomReasonUnderlyingCallsCount = 0
|
||||||
|
var reportRoomReasonCallsCount: Int {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return reportRoomReasonUnderlyingCallsCount
|
||||||
|
} else {
|
||||||
|
var returnValue: Int? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = reportRoomReasonUnderlyingCallsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
reportRoomReasonUnderlyingCallsCount = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
reportRoomReasonUnderlyingCallsCount = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var reportRoomReasonCalled: Bool {
|
||||||
|
return reportRoomReasonCallsCount > 0
|
||||||
|
}
|
||||||
|
var reportRoomReasonReceivedReason: String?
|
||||||
|
var reportRoomReasonReceivedInvocations: [String?] = []
|
||||||
|
|
||||||
|
var reportRoomReasonUnderlyingReturnValue: Result<Void, RoomProxyError>!
|
||||||
|
var reportRoomReasonReturnValue: Result<Void, RoomProxyError>! {
|
||||||
|
get {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
return reportRoomReasonUnderlyingReturnValue
|
||||||
|
} else {
|
||||||
|
var returnValue: Result<Void, RoomProxyError>? = nil
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
returnValue = reportRoomReasonUnderlyingReturnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if Thread.isMainThread {
|
||||||
|
reportRoomReasonUnderlyingReturnValue = newValue
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.sync {
|
||||||
|
reportRoomReasonUnderlyingReturnValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var reportRoomReasonClosure: ((String?) async -> Result<Void, RoomProxyError>)?
|
||||||
|
|
||||||
|
func reportRoom(reason: String?) async -> Result<Void, RoomProxyError> {
|
||||||
|
reportRoomReasonCallsCount += 1
|
||||||
|
reportRoomReasonReceivedReason = reason
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.reportRoomReasonReceivedInvocations.append(reason)
|
||||||
|
}
|
||||||
|
if let reportRoomReasonClosure = reportRoomReasonClosure {
|
||||||
|
return await reportRoomReasonClosure(reason)
|
||||||
|
} else {
|
||||||
|
return reportRoomReasonReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
//MARK: - leaveRoom
|
//MARK: - leaveRoom
|
||||||
|
|
||||||
var leaveRoomUnderlyingCallsCount = 0
|
var leaveRoomUnderlyingCallsCount = 0
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ struct HomeScreenCoordinatorParameters {
|
|||||||
enum HomeScreenCoordinatorAction {
|
enum HomeScreenCoordinatorAction {
|
||||||
case presentRoom(roomIdentifier: String)
|
case presentRoom(roomIdentifier: String)
|
||||||
case presentRoomDetails(roomIdentifier: String)
|
case presentRoomDetails(roomIdentifier: String)
|
||||||
|
case presentReportRoom(roomIdentifier: String)
|
||||||
case roomLeft(roomIdentifier: String)
|
case roomLeft(roomIdentifier: String)
|
||||||
case presentSettingsScreen
|
case presentSettingsScreen
|
||||||
case presentFeedbackScreen
|
case presentFeedbackScreen
|
||||||
@@ -58,6 +59,8 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.presentRoom(roomIdentifier: roomIdentifier))
|
actionsSubject.send(.presentRoom(roomIdentifier: roomIdentifier))
|
||||||
case .presentRoomDetails(roomIdentifier: let roomIdentifier):
|
case .presentRoomDetails(roomIdentifier: let roomIdentifier):
|
||||||
actionsSubject.send(.presentRoomDetails(roomIdentifier: roomIdentifier))
|
actionsSubject.send(.presentRoomDetails(roomIdentifier: roomIdentifier))
|
||||||
|
case .presentReportRoom(let roomIdentifier):
|
||||||
|
actionsSubject.send(.presentReportRoom(roomIdentifier: roomIdentifier))
|
||||||
case .roomLeft(roomIdentifier: let roomIdentifier):
|
case .roomLeft(roomIdentifier: let roomIdentifier):
|
||||||
actionsSubject.send(.roomLeft(roomIdentifier: roomIdentifier))
|
actionsSubject.send(.roomLeft(roomIdentifier: roomIdentifier))
|
||||||
case .presentFeedbackScreen:
|
case .presentFeedbackScreen:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import UIKit
|
|||||||
enum HomeScreenViewModelAction: Equatable {
|
enum HomeScreenViewModelAction: Equatable {
|
||||||
case presentRoom(roomIdentifier: String)
|
case presentRoom(roomIdentifier: String)
|
||||||
case presentRoomDetails(roomIdentifier: String)
|
case presentRoomDetails(roomIdentifier: String)
|
||||||
|
case presentReportRoom(roomIdentifier: String)
|
||||||
case roomLeft(roomIdentifier: String)
|
case roomLeft(roomIdentifier: String)
|
||||||
case presentSecureBackupSettings
|
case presentSecureBackupSettings
|
||||||
case presentRecoveryKeyScreen
|
case presentRecoveryKeyScreen
|
||||||
@@ -29,6 +30,7 @@ enum HomeScreenViewAction {
|
|||||||
case showRoomDetails(roomIdentifier: String)
|
case showRoomDetails(roomIdentifier: String)
|
||||||
case leaveRoom(roomIdentifier: String)
|
case leaveRoom(roomIdentifier: String)
|
||||||
case confirmLeaveRoom(roomIdentifier: String)
|
case confirmLeaveRoom(roomIdentifier: String)
|
||||||
|
case reportRoom(roomIdentifier: String)
|
||||||
case showSettings
|
case showSettings
|
||||||
case startChat
|
case startChat
|
||||||
case setupRecovery
|
case setupRecovery
|
||||||
@@ -98,6 +100,10 @@ struct HomeScreenViewState: BindableState {
|
|||||||
|
|
||||||
var selectedRoomID: String?
|
var selectedRoomID: String?
|
||||||
|
|
||||||
|
var hideInviteAvatars = false
|
||||||
|
|
||||||
|
var reportRoomEnabled = false
|
||||||
|
|
||||||
var visibleRooms: [HomeScreenRoom] {
|
var visibleRooms: [HomeScreenRoom] {
|
||||||
if roomListMode == .skeletons {
|
if roomListMode == .skeletons {
|
||||||
return placeholderRooms
|
return placeholderRooms
|
||||||
@@ -105,9 +111,7 @@ struct HomeScreenViewState: BindableState {
|
|||||||
|
|
||||||
return rooms
|
return rooms
|
||||||
}
|
}
|
||||||
|
|
||||||
var hideInviteAvatars = false
|
|
||||||
|
|
||||||
var bindings = HomeScreenViewStateBindings()
|
var bindings = HomeScreenViewStateBindings()
|
||||||
|
|
||||||
var placeholderRooms: [HomeScreenRoom] {
|
var placeholderRooms: [HomeScreenRoom] {
|
||||||
|
|||||||
@@ -105,6 +105,10 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
.weakAssign(to: \.state.hideInviteAvatars, on: self)
|
.weakAssign(to: \.state.hideInviteAvatars, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
appSettings.$reportRoomEnabled
|
||||||
|
.weakAssign(to: \.state.reportRoomEnabled, on: self)
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
let isSearchFieldFocused = context.$viewState.map(\.bindings.isSearchFieldFocused)
|
let isSearchFieldFocused = context.$viewState.map(\.bindings.isSearchFieldFocused)
|
||||||
let searchQuery = context.$viewState.map(\.bindings.searchQuery)
|
let searchQuery = context.$viewState.map(\.bindings.searchQuery)
|
||||||
let activeFilters = context.$viewState.map(\.bindings.filtersState.activeFilters)
|
let activeFilters = context.$viewState.map(\.bindings.filtersState.activeFilters)
|
||||||
@@ -136,12 +140,14 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
switch viewAction {
|
switch viewAction {
|
||||||
case .selectRoom(let roomIdentifier):
|
case .selectRoom(let roomIdentifier):
|
||||||
actionsSubject.send(.presentRoom(roomIdentifier: roomIdentifier))
|
actionsSubject.send(.presentRoom(roomIdentifier: roomIdentifier))
|
||||||
case .showRoomDetails(roomIdentifier: let roomIdentifier):
|
case .showRoomDetails(let roomIdentifier):
|
||||||
actionsSubject.send(.presentRoomDetails(roomIdentifier: roomIdentifier))
|
actionsSubject.send(.presentRoomDetails(roomIdentifier: roomIdentifier))
|
||||||
case .leaveRoom(roomIdentifier: let roomIdentifier):
|
case .leaveRoom(let roomIdentifier):
|
||||||
startLeaveRoomProcess(roomID: roomIdentifier)
|
startLeaveRoomProcess(roomID: roomIdentifier)
|
||||||
case .confirmLeaveRoom(roomIdentifier: let roomIdentifier):
|
case .confirmLeaveRoom(let roomIdentifier):
|
||||||
Task { await leaveRoom(roomID: roomIdentifier) }
|
Task { await leaveRoom(roomID: roomIdentifier) }
|
||||||
|
case .reportRoom(let roomIdentifier):
|
||||||
|
actionsSubject.send(.presentReportRoom(roomIdentifier: roomIdentifier))
|
||||||
case .showSettings:
|
case .showSettings:
|
||||||
actionsSubject.send(.presentSettingsScreen)
|
actionsSubject.send(.presentSettingsScreen)
|
||||||
case .setupRecovery:
|
case .setupRecovery:
|
||||||
|
|||||||
@@ -69,6 +69,14 @@ struct HomeScreenRoomList: View {
|
|||||||
Label(L10n.commonSettings, icon: \.settings)
|
Label(L10n.commonSettings, icon: \.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if context.viewState.reportRoomEnabled {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
context.send(viewAction: .reportRoom(roomIdentifier: room.id))
|
||||||
|
} label: {
|
||||||
|
Label(L10n.actionReportRoom, icon: \.chatProblem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
context.send(viewAction: .leaveRoom(roomIdentifier: room.id))
|
context.send(viewAction: .leaveRoom(roomIdentifier: room.id))
|
||||||
} label: {
|
} label: {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022-2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
// periphery:ignore:all - this is just a reportRoom remove this comment once generating the final file
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ReportRoomScreenCoordinatorParameters {
|
||||||
|
let roomProxy: JoinedRoomProxyProtocol
|
||||||
|
let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ReportRoomScreenCoordinatorAction {
|
||||||
|
case dismiss(shouldLeaveRoom: Bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ReportRoomScreenCoordinator: CoordinatorProtocol {
|
||||||
|
private let parameters: ReportRoomScreenCoordinatorParameters
|
||||||
|
private let viewModel: ReportRoomScreenViewModelProtocol
|
||||||
|
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<ReportRoomScreenCoordinatorAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<ReportRoomScreenCoordinatorAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: ReportRoomScreenCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
|
||||||
|
viewModel = ReportRoomScreenViewModel(roomProxy: parameters.roomProxy,
|
||||||
|
userIndicatorController: parameters.userIndicatorController)
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
viewModel.actionsPublisher.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .dismiss(let shouldLeaveRoom):
|
||||||
|
actionsSubject.send(.dismiss(shouldLeaveRoom: shouldLeaveRoom))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> AnyView {
|
||||||
|
AnyView(ReportRoomScreen(context: viewModel.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022-2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ReportRoomScreenViewModelAction: Equatable {
|
||||||
|
case dismiss(shouldLeaveRoom: Bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReportRoomScreenViewState: BindableState {
|
||||||
|
var bindings = ReportRoomScreenViewStateBindings()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReportRoomScreenViewStateBindings {
|
||||||
|
var reason = ""
|
||||||
|
var shouldLeaveRoom = false
|
||||||
|
var alert: AlertInfo<ReportRoomScreenAlertType>?
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ReportRoomScreenViewAction {
|
||||||
|
case report
|
||||||
|
case dismiss
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ReportRoomScreenAlertType {
|
||||||
|
case leaveRoomFailed
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022-2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
typealias ReportRoomScreenViewModelType = StateStoreViewModel<ReportRoomScreenViewState, ReportRoomScreenViewAction>
|
||||||
|
|
||||||
|
class ReportRoomScreenViewModel: ReportRoomScreenViewModelType, ReportRoomScreenViewModelProtocol {
|
||||||
|
let roomProxy: JoinedRoomProxyProtocol
|
||||||
|
let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<ReportRoomScreenViewModelAction, Never> = .init()
|
||||||
|
var actionsPublisher: AnyPublisher<ReportRoomScreenViewModelAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(roomProxy: JoinedRoomProxyProtocol, userIndicatorController: UserIndicatorControllerProtocol) {
|
||||||
|
self.roomProxy = roomProxy
|
||||||
|
self.userIndicatorController = userIndicatorController
|
||||||
|
super.init(initialViewState: ReportRoomScreenViewState())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
override func process(viewAction: ReportRoomScreenViewAction) {
|
||||||
|
switch viewAction {
|
||||||
|
case .report:
|
||||||
|
Task { await report() }
|
||||||
|
case .dismiss:
|
||||||
|
actionsSubject.send(.dismiss(shouldLeaveRoom: false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func report() async {
|
||||||
|
showLoadingIndicator()
|
||||||
|
let result = await roomProxy.reportRoom(reason: state.bindings.reason.isBlank ? nil : state.bindings.reason)
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
if state.bindings.shouldLeaveRoom {
|
||||||
|
await leaveRoom(showLoading: false)
|
||||||
|
} else {
|
||||||
|
hideLoadingIndicator()
|
||||||
|
userIndicatorController.submitIndicator(.init(title: L10n.dialogRoomReported, iconName: "checkmark"))
|
||||||
|
actionsSubject.send(.dismiss(shouldLeaveRoom: false))
|
||||||
|
}
|
||||||
|
case .failure:
|
||||||
|
hideLoadingIndicator()
|
||||||
|
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func leaveRoom(showLoading: Bool) async {
|
||||||
|
if showLoading {
|
||||||
|
showLoadingIndicator()
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = await roomProxy.leaveRoom()
|
||||||
|
hideLoadingIndicator()
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
userIndicatorController.submitIndicator(.init(title: L10n.dialogRoomReportedAndLeft, iconName: "checkmark"))
|
||||||
|
actionsSubject.send(.dismiss(shouldLeaveRoom: true))
|
||||||
|
case .failure:
|
||||||
|
state.bindings.alert = .init(id: .leaveRoomFailed,
|
||||||
|
title: L10n.screenReportRoomLeaveFailedAlertTitle,
|
||||||
|
message: L10n.screenReportRoomLeaveFailedAlertMessage,
|
||||||
|
primaryButton: .init(title: L10n.actionDismiss, role: .cancel) { [weak self] in self?.actionsSubject.send(.dismiss(shouldLeaveRoom: false)) },
|
||||||
|
secondaryButton: .init(title: L10n.actionRetry) { [weak self] in Task { await self?.leaveRoom(showLoading: true) } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static let loadingIndicatorIdentifier = "\(BugReportScreenCoordinator.self)-Loading"
|
||||||
|
|
||||||
|
private func showLoadingIndicator() {
|
||||||
|
userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier,
|
||||||
|
type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false),
|
||||||
|
title: L10n.commonLoading,
|
||||||
|
persistent: true))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func hideLoadingIndicator() {
|
||||||
|
userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022-2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
protocol ReportRoomScreenViewModelProtocol {
|
||||||
|
var actionsPublisher: AnyPublisher<ReportRoomScreenViewModelAction, Never> { get }
|
||||||
|
var context: ReportRoomScreenViewModelType.Context { get }
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022-2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ReportRoomScreen: View {
|
||||||
|
@ObservedObject var context: ReportRoomScreenViewModel.Context
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Form {
|
||||||
|
reasonSection
|
||||||
|
leaveRoomSection
|
||||||
|
}
|
||||||
|
.compoundList()
|
||||||
|
.navigationTitle(L10n.screenReportRoomTitle)
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar { toolbar }
|
||||||
|
.alert(item: $context.alert)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var reasonSection: some View {
|
||||||
|
Section {
|
||||||
|
ListRow(label: .plain(title: L10n.screenReportRoomReasonPlaceholder),
|
||||||
|
kind: .textField(text: $context.reason, axis: .vertical))
|
||||||
|
.lineLimit(4, reservesSpace: true)
|
||||||
|
} footer: {
|
||||||
|
Text(L10n.screenReportRoomReasonFooter)
|
||||||
|
.compoundListSectionFooter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var leaveRoomSection: some View {
|
||||||
|
Section {
|
||||||
|
ListRow(label: .plain(title: L10n.actionLeaveRoom),
|
||||||
|
kind: .toggle($context.shouldLeaveRoom))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToolbarContentBuilder
|
||||||
|
private var toolbar: some ToolbarContent {
|
||||||
|
ToolbarItem(placement: .cancellationAction) {
|
||||||
|
Button(L10n.actionCancel) {
|
||||||
|
context.send(viewAction: .dismiss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
|
Button(L10n.actionReport) {
|
||||||
|
context.send(viewAction: .report)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
|
struct ReportRoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
|
static let viewModel = ReportRoomScreenViewModel(roomProxy: JoinedRoomProxyMock(.init()),
|
||||||
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
|
static var previews: some View {
|
||||||
|
NavigationStack {
|
||||||
|
ReportRoomScreen(context: viewModel.context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ enum RoomDetailsScreenCoordinatorAction {
|
|||||||
case presentMediaEventsTimeline
|
case presentMediaEventsTimeline
|
||||||
case presentKnockingRequestsListScreen
|
case presentKnockingRequestsListScreen
|
||||||
case presentSecurityAndPrivacyScreen
|
case presentSecurityAndPrivacyScreen
|
||||||
|
case presentReportRoomScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||||
@@ -91,6 +92,8 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.presentSecurityAndPrivacyScreen)
|
actionsSubject.send(.presentSecurityAndPrivacyScreen)
|
||||||
case .requestRecipientDetailsPresentation(let userID):
|
case .requestRecipientDetailsPresentation(let userID):
|
||||||
actionsSubject.send(.presentRecipientDetails(userID: userID))
|
actionsSubject.send(.presentRecipientDetails(userID: userID))
|
||||||
|
case .displayReportRoom:
|
||||||
|
actionsSubject.send(.presentReportRoomScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ enum RoomDetailsScreenViewModelAction: Equatable {
|
|||||||
case displayMediaEventsTimeline
|
case displayMediaEventsTimeline
|
||||||
case displayKnockingRequests
|
case displayKnockingRequests
|
||||||
case displaySecurityAndPrivacy
|
case displaySecurityAndPrivacy
|
||||||
|
case displayReportRoom
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: View
|
// MARK: View
|
||||||
@@ -64,6 +65,8 @@ struct RoomDetailsScreenViewState: BindableState {
|
|||||||
var isKnockableRoom = false
|
var isKnockableRoom = false
|
||||||
var knockRequestsCount = 0
|
var knockRequestsCount = 0
|
||||||
|
|
||||||
|
var reportRoomEnabled = false
|
||||||
|
|
||||||
var canSeeKnockingRequests: Bool {
|
var canSeeKnockingRequests: Bool {
|
||||||
knockingEnabled && dmRecipientInfo == nil && isKnockableRoom && (canInviteUsers || canKickUsers || canBanUsers)
|
knockingEnabled && dmRecipientInfo == nil && isKnockableRoom && (canInviteUsers || canKickUsers || canBanUsers)
|
||||||
}
|
}
|
||||||
@@ -218,6 +221,7 @@ enum RoomDetailsScreenViewAction {
|
|||||||
case processTapPinnedEvents
|
case processTapPinnedEvents
|
||||||
case processTapMediaEvents
|
case processTapMediaEvents
|
||||||
case processTapRequestsToJoin
|
case processTapRequestsToJoin
|
||||||
|
case processTapReport
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RoomDetailsScreenViewShortcut {
|
enum RoomDetailsScreenViewShortcut {
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
.weakAssign(to: \.state.knockingEnabled, on: self)
|
.weakAssign(to: \.state.knockingEnabled, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
appSettings.$reportRoomEnabled
|
||||||
|
.weakAssign(to: \.state.reportRoomEnabled, on: self)
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
appMediator.networkMonitor.reachabilityPublisher
|
appMediator.networkMonitor.reachabilityPublisher
|
||||||
.filter { $0 == .reachable }
|
.filter { $0 == .reachable }
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
@@ -174,6 +178,8 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
actionsSubject.send(.requestRecipientDetailsPresentation(userID: userID))
|
actionsSubject.send(.requestRecipientDetailsPresentation(userID: userID))
|
||||||
|
case .processTapReport:
|
||||||
|
actionsSubject.send(.displayReportRoom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -275,9 +275,19 @@ struct RoomDetailsScreen: View {
|
|||||||
private var leaveRoomTitle: String {
|
private var leaveRoomTitle: String {
|
||||||
context.viewState.dmRecipientInfo == nil ? L10n.screenRoomDetailsLeaveRoomTitle : L10n.screenRoomDetailsLeaveConversationTitle
|
context.viewState.dmRecipientInfo == nil ? L10n.screenRoomDetailsLeaveRoomTitle : L10n.screenRoomDetailsLeaveConversationTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var reportRoomTitle: String {
|
||||||
|
context.viewState.dmRecipientInfo == nil ? L10n.actionReportRoom : L10n.actionReport
|
||||||
|
}
|
||||||
|
|
||||||
private var leaveRoomSection: some View {
|
private var leaveRoomSection: some View {
|
||||||
Section {
|
Section {
|
||||||
|
if context.viewState.reportRoomEnabled {
|
||||||
|
ListRow(label: .action(title: reportRoomTitle,
|
||||||
|
icon: \.chatProblem,
|
||||||
|
role: .destructive),
|
||||||
|
kind: .button { context.send(viewAction: .processTapReport) })
|
||||||
|
}
|
||||||
ListRow(label: .action(title: leaveRoomTitle,
|
ListRow(label: .action(title: leaveRoomTitle,
|
||||||
icon: \.leave,
|
icon: \.leave,
|
||||||
role: .destructive),
|
role: .destructive),
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
case .kickMember(let member):
|
case .kickMember(let member):
|
||||||
var reason: String?
|
var reason: String?
|
||||||
let binding: Binding<String> = .init(get: { reason ?? "" },
|
let binding: Binding<String> = .init(get: { reason ?? "" },
|
||||||
set: { reason = $0.isEmpty ? nil : $0 })
|
set: { reason = $0.isBlank ? nil : $0 })
|
||||||
state.bindings.alertInfo = .init(id: .kickConfirmation,
|
state.bindings.alertInfo = .init(id: .kickConfirmation,
|
||||||
title: L10n.screenRoomMemberListKickMemberConfirmationTitle,
|
title: L10n.screenRoomMemberListKickMemberConfirmationTitle,
|
||||||
message: L10n.screenRoomMemberListKickMemberConfirmationDescription,
|
message: L10n.screenRoomMemberListKickMemberConfirmationDescription,
|
||||||
@@ -66,7 +66,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
case .banMember(let member):
|
case .banMember(let member):
|
||||||
var reason: String?
|
var reason: String?
|
||||||
let binding: Binding<String> = .init(get: { reason ?? "" },
|
let binding: Binding<String> = .init(get: { reason ?? "" },
|
||||||
set: { reason = $0.isEmpty ? nil : $0 })
|
set: { reason = $0.isBlank ? nil : $0 })
|
||||||
state.bindings.alertInfo = .init(id: .banConfirmation,
|
state.bindings.alertInfo = .init(id: .banConfirmation,
|
||||||
title: L10n.screenRoomMemberListBanMemberConfirmationTitle,
|
title: L10n.screenRoomMemberListBanMemberConfirmationTitle,
|
||||||
message: L10n.screenRoomMemberListBanMemberConfirmationDescription,
|
message: L10n.screenRoomMemberListBanMemberConfirmationDescription,
|
||||||
|
|||||||
+1
@@ -44,6 +44,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
|||||||
var enableOnlySignedDeviceIsolationMode: Bool { get set }
|
var enableOnlySignedDeviceIsolationMode: Bool { get set }
|
||||||
var elementCallBaseURLOverride: URL? { get set }
|
var elementCallBaseURLOverride: URL? { get set }
|
||||||
var knockingEnabled: Bool { get set }
|
var knockingEnabled: Bool { get set }
|
||||||
|
var reportRoomEnabled: Bool { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppSettings: DeveloperOptionsProtocol { }
|
extension AppSettings: DeveloperOptionsProtocol { }
|
||||||
|
|||||||
+7
@@ -62,6 +62,13 @@ struct DeveloperOptionsScreen: View {
|
|||||||
} footer: {
|
} footer: {
|
||||||
Text("This setting controls how end-to-end encryption (E2EE) keys are exchanged. Enabling it will prevent the inclusion of devices that have not been explicitly verified by their owners.")
|
Text("This setting controls how end-to-end encryption (E2EE) keys are exchanged. Enabling it will prevent the inclusion of devices that have not been explicitly verified by their owners.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Section("Reporting") {
|
||||||
|
Toggle(isOn: $context.reportRoomEnabled) {
|
||||||
|
Text("Report rooms")
|
||||||
|
Text("Report API might not work properly")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString)
|
TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString)
|
||||||
|
|||||||
@@ -255,6 +255,16 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reportRoom(reason: String?) async -> Result<Void, RoomProxyError> {
|
||||||
|
do {
|
||||||
|
try await room.reportRoom(reason: reason)
|
||||||
|
return .success(())
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed reporting room: \(id) with error: \(error)")
|
||||||
|
return .failure(.sdkError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updateMembers() async {
|
func updateMembers() async {
|
||||||
// We always update members first using the no sync API in case internet is not readily available
|
// We always update members first using the no sync API in case internet is not readily available
|
||||||
// To get the members stored on disk first, this API call is very fast.
|
// To get the members stored on disk first, this API call is very fast.
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
|||||||
func redact(_ eventID: String) async -> Result<Void, RoomProxyError>
|
func redact(_ eventID: String) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
func reportContent(_ eventID: String, reason: String?) async -> Result<Void, RoomProxyError>
|
func reportContent(_ eventID: String, reason: String?) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
|
func reportRoom(reason: String?) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
func leaveRoom() async -> Result<Void, RoomProxyError>
|
func leaveRoom() async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
|
|||||||
@@ -593,6 +593,12 @@ extension PreviewTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testReportRoomScreen() async throws {
|
||||||
|
for (index, preview) in ReportRoomScreen_Previews._allPreviews.enumerated() {
|
||||||
|
try await assertSnapshots(matching: preview, step: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testResolveVerifiedUserSendFailureScreen() async throws {
|
func testResolveVerifiedUserSendFailureScreen() async throws {
|
||||||
for (index, preview) in ResolveVerifiedUserSendFailureScreen_Previews._allPreviews.enumerated() {
|
for (index, preview) in ResolveVerifiedUserSendFailureScreen_Previews._allPreviews.enumerated() {
|
||||||
try await assertSnapshots(matching: preview, step: index)
|
try await assertSnapshots(matching: preview, step: index)
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:ac131e760c33abc71ff2561532486148184b2145ab8908fc93c8f59fd52a63bd
|
||||||
|
size 111036
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:ce3deae0c993d297780b9983f7864252b38ec5eb139b82c34eac5f66c344f30c
|
||||||
|
size 124615
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:71fabe839f7069969d2064f39430d6044ae176b057d355f26871e86f563b4bf1
|
||||||
|
size 63941
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:1277567cb86dde2a5d0af84a0c0ec71405fea0a094a5c246757220316662e6f9
|
||||||
|
size 83244
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022-2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@testable import ElementX
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class ReportRoomScreenViewModelTests: XCTestCase {
|
||||||
|
var viewModel: ReportRoomScreenViewModelProtocol!
|
||||||
|
var roomProxy: JoinedRoomProxyMock!
|
||||||
|
|
||||||
|
var context: ReportRoomScreenViewModelType.Context {
|
||||||
|
viewModel.context
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
roomProxy = JoinedRoomProxyMock(.init())
|
||||||
|
viewModel = ReportRoomScreenViewModel(roomProxy: roomProxy, userIndicatorController: UserIndicatorControllerMock())
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInitialState() {
|
||||||
|
XCTAssertTrue(context.viewState.bindings.reason.isEmpty)
|
||||||
|
XCTAssertFalse(context.viewState.bindings.shouldLeaveRoom)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReportSuccess() async throws {
|
||||||
|
let reason = "Spam"
|
||||||
|
let expectation = XCTestExpectation(description: "Report success")
|
||||||
|
roomProxy.reportRoomReasonClosure = { reasonArgument in
|
||||||
|
defer { expectation.fulfill() }
|
||||||
|
XCTAssertEqual(reasonArgument, reason)
|
||||||
|
return .success(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { action in
|
||||||
|
action == .dismiss(shouldLeaveRoom: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.reason = reason
|
||||||
|
context.send(viewAction: .report)
|
||||||
|
|
||||||
|
try await deferred.fulfill()
|
||||||
|
await fulfillment(of: [expectation])
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReportAndLeaveSuccess() async throws {
|
||||||
|
let reason = "Spam"
|
||||||
|
let reportExpectation = XCTestExpectation(description: "Report success")
|
||||||
|
roomProxy.reportRoomReasonClosure = { reasonArgument in
|
||||||
|
defer { reportExpectation.fulfill() }
|
||||||
|
XCTAssertEqual(reasonArgument, reason)
|
||||||
|
return .success(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let leaveExpectation = XCTestExpectation(description: "Leave success")
|
||||||
|
roomProxy.leaveRoomClosure = {
|
||||||
|
defer { leaveExpectation.fulfill() }
|
||||||
|
return .success(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { action in
|
||||||
|
action == .dismiss(shouldLeaveRoom: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.reason = reason
|
||||||
|
context.shouldLeaveRoom = true
|
||||||
|
context.send(viewAction: .report)
|
||||||
|
|
||||||
|
await fulfillment(of: [reportExpectation, leaveExpectation])
|
||||||
|
try await deferred.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReportSuccessLeaveFails() async throws {
|
||||||
|
let reason = "Spam"
|
||||||
|
let reportExpectation = XCTestExpectation(description: "Report success")
|
||||||
|
roomProxy.reportRoomReasonClosure = { reasonArgument in
|
||||||
|
defer { reportExpectation.fulfill() }
|
||||||
|
XCTAssertEqual(reasonArgument, reason)
|
||||||
|
return .success(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let leaveExpectation = XCTestExpectation(description: "Leave fails")
|
||||||
|
roomProxy.leaveRoomClosure = {
|
||||||
|
defer { leaveExpectation.fulfill() }
|
||||||
|
return .failure(.eventNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
let deferred = deferFulfillment(context.$viewState) { state in
|
||||||
|
state.bindings.alert != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
context.reason = reason
|
||||||
|
context.shouldLeaveRoom = true
|
||||||
|
context.send(viewAction: .report)
|
||||||
|
|
||||||
|
await fulfillment(of: [reportExpectation, leaveExpectation])
|
||||||
|
try await deferred.fulfill()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,29 +46,29 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
notificationManager: notificationManager,
|
notificationManager: notificationManager,
|
||||||
isNewLogin: false)
|
isNewLogin: false)
|
||||||
|
|
||||||
let deferred = deferFulfillment(userSessionFlowCoordinator.statePublisher) { $0 == .roomList(selectedRoomID: nil) }
|
let deferred = deferFulfillment(userSessionFlowCoordinator.statePublisher) { $0 == .roomList(roomListSelectedRoomID: nil) }
|
||||||
userSessionFlowCoordinator.start()
|
userSessionFlowCoordinator.start()
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRoomPresentation() async throws {
|
func testRoomPresentation() async throws {
|
||||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .roomList, expectedState: .roomList(selectedRoomID: nil))
|
try await process(route: .roomList, expectedState: .roomList(roomListSelectedRoomID: nil))
|
||||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||||
XCTAssertNil(detailCoordinator)
|
XCTAssertNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(selectedRoomID: "2"))
|
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(roomListSelectedRoomID: "2"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .roomList, expectedState: .roomList(selectedRoomID: nil))
|
try await process(route: .roomList, expectedState: .roomList(roomListSelectedRoomID: nil))
|
||||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||||
XCTAssertNil(detailCoordinator)
|
XCTAssertNil(detailCoordinator)
|
||||||
|
|
||||||
@@ -78,25 +78,25 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
func testRoomAliasPresentation() async throws {
|
func testRoomAliasPresentation() async throws {
|
||||||
clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "1", servers: []))
|
clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "1", servers: []))
|
||||||
|
|
||||||
try await process(route: .roomAlias("#alias:matrix.org"), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .roomAlias("#alias:matrix.org"), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .roomList, expectedState: .roomList(selectedRoomID: nil))
|
try await process(route: .roomList, expectedState: .roomList(roomListSelectedRoomID: nil))
|
||||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||||
XCTAssertNil(detailCoordinator)
|
XCTAssertNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "2", servers: []))
|
clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "2", servers: []))
|
||||||
|
|
||||||
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(selectedRoomID: "2"))
|
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(roomListSelectedRoomID: "2"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .roomList, expectedState: .roomList(selectedRoomID: nil))
|
try await process(route: .roomList, expectedState: .roomList(roomListSelectedRoomID: nil))
|
||||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||||
XCTAssertNil(detailCoordinator)
|
XCTAssertNil(detailCoordinator)
|
||||||
|
|
||||||
@@ -104,27 +104,27 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testRoomDetailsPresentation() async throws {
|
func testRoomDetailsPresentation() async throws {
|
||||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .roomList, expectedState: .roomList(selectedRoomID: nil))
|
try await process(route: .roomList, expectedState: .roomList(roomListSelectedRoomID: nil))
|
||||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||||
XCTAssertNil(detailCoordinator)
|
XCTAssertNil(detailCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStackUnwinding() async throws {
|
func testStackUnwinding() async throws {
|
||||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(selectedRoomID: "2"))
|
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(roomListSelectedRoomID: "2"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNoOp() async throws {
|
func testNoOp() async throws {
|
||||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
@@ -137,17 +137,17 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testSwitchToDifferentDetails() async throws {
|
func testSwitchToDifferentDetails() async throws {
|
||||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .roomDetails(roomID: "2"), expectedState: .roomList(selectedRoomID: "2"))
|
try await process(route: .roomDetails(roomID: "2"), expectedState: .roomList(roomListSelectedRoomID: "2"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPushDetails() async throws {
|
func testPushDetails() async throws {
|
||||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
@@ -162,17 +162,17 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testReplaceDetailsWithTimeline() async throws {
|
func testReplaceDetailsWithTimeline() async throws {
|
||||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUserProfileClearsStack() async throws {
|
func testUserProfileClearsStack() async throws {
|
||||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
XCTAssertNil(splitCoordinator?.sheetCoordinator)
|
XCTAssertNil(splitCoordinator?.sheetCoordinator)
|
||||||
@@ -187,7 +187,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testRoomClearsStack() async throws {
|
func testRoomClearsStack() async throws {
|
||||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
@@ -199,7 +199,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
XCTAssertTrue(detailNavigationStack?.stackCoordinators.first is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.stackCoordinators.first is RoomScreenCoordinator)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
|
|
||||||
try await process(route: .room(roomID: "3", via: []), expectedState: .roomList(selectedRoomID: "3"))
|
try await process(route: .room(roomID: "3", via: []), expectedState: .roomList(roomListSelectedRoomID: "3"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
@@ -207,7 +207,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
|
|
||||||
func testEventRoutes() async throws {
|
func testEventRoutes() async throws {
|
||||||
// A regular event route should set its room as the root of the stack and focus on the event.
|
// A regular event route should set its room as the root of the stack and focus on the event.
|
||||||
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
@@ -225,7 +225,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "2")
|
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "2")
|
||||||
|
|
||||||
// A subsequent regular event route should clear the stack and set the new room as the root of the stack.
|
// A subsequent regular event route should clear the stack and set the new room as the root of the stack.
|
||||||
try await process(route: .event(eventID: "3", roomID: "3", via: []), expectedState: .roomList(selectedRoomID: "3"))
|
try await process(route: .event(eventID: "3", roomID: "3", via: []), expectedState: .roomList(roomListSelectedRoomID: "3"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
@@ -233,7 +233,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "3")
|
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "3")
|
||||||
|
|
||||||
// A regular event route for the same room should set a new instance of the room as the root of the stack.
|
// A regular event route for the same room should set a new instance of the room as the root of the stack.
|
||||||
try await process(route: .event(eventID: "4", roomID: "3", via: []), expectedState: .roomList(selectedRoomID: "3"))
|
try await process(route: .event(eventID: "4", roomID: "3", via: []), expectedState: .roomList(roomListSelectedRoomID: "3"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||||
XCTAssertNotNil(detailCoordinator)
|
XCTAssertNotNil(detailCoordinator)
|
||||||
@@ -243,7 +243,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testShareMediaRouteWithoutRoom() async throws {
|
func testShareMediaRouteWithoutRoom() async throws {
|
||||||
try await process(route: .settings, expectedState: .settingsScreen(selectedRoomID: nil))
|
try await process(route: .settings, expectedState: .settingsScreen(roomListSelectedRoomID: nil))
|
||||||
XCTAssertTrue((splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is SettingsScreenCoordinator)
|
XCTAssertTrue((splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is SettingsScreenCoordinator)
|
||||||
|
|
||||||
let sharePayload: ShareExtensionPayload = .mediaFile(roomID: nil, mediaFile: .init(url: .picturesDirectory, suggestedName: nil))
|
let sharePayload: ShareExtensionPayload = .mediaFile(roomID: nil, mediaFile: .init(url: .picturesDirectory, suggestedName: nil))
|
||||||
@@ -254,19 +254,19 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testShareMediaRouteWithRoom() async throws {
|
func testShareMediaRouteWithRoom() async throws {
|
||||||
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
|
|
||||||
let sharePayload: ShareExtensionPayload = .mediaFile(roomID: "2", mediaFile: .init(url: .picturesDirectory, suggestedName: nil))
|
let sharePayload: ShareExtensionPayload = .mediaFile(roomID: "2", mediaFile: .init(url: .picturesDirectory, suggestedName: nil))
|
||||||
try await process(route: .share(sharePayload),
|
try await process(route: .share(sharePayload),
|
||||||
expectedState: .roomList(selectedRoomID: "2"))
|
expectedState: .roomList(roomListSelectedRoomID: "2"))
|
||||||
|
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertTrue((splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is MediaUploadPreviewScreenCoordinator)
|
XCTAssertTrue((splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is MediaUploadPreviewScreenCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testShareTextRouteWithoutRoom() async throws {
|
func testShareTextRouteWithoutRoom() async throws {
|
||||||
try await process(route: .settings, expectedState: .settingsScreen(selectedRoomID: nil))
|
try await process(route: .settings, expectedState: .settingsScreen(roomListSelectedRoomID: nil))
|
||||||
XCTAssertTrue((splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is SettingsScreenCoordinator)
|
XCTAssertTrue((splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is SettingsScreenCoordinator)
|
||||||
|
|
||||||
let sharePayload: ShareExtensionPayload = .text(roomID: nil, text: "Important Text")
|
let sharePayload: ShareExtensionPayload = .text(roomID: nil, text: "Important Text")
|
||||||
@@ -277,12 +277,12 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testShareTextRouteWithRoom() async throws {
|
func testShareTextRouteWithRoom() async throws {
|
||||||
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(selectedRoomID: "1"))
|
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(roomListSelectedRoomID: "1"))
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
|
|
||||||
let sharePayload: ShareExtensionPayload = .text(roomID: "2", text: "Important text")
|
let sharePayload: ShareExtensionPayload = .text(roomID: "2", text: "Important text")
|
||||||
try await process(route: .share(sharePayload),
|
try await process(route: .share(sharePayload),
|
||||||
expectedState: .roomList(selectedRoomID: "2"))
|
expectedState: .roomList(roomListSelectedRoomID: "2"))
|
||||||
|
|
||||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||||
XCTAssertNil(splitCoordinator?.sheetCoordinator, "The media upload sheet shouldn't be shown when sharing text.")
|
XCTAssertNil(splitCoordinator?.sheetCoordinator, "The media upload sheet shouldn't be shown when sharing text.")
|
||||||
|
|||||||
Reference in New Issue
Block a user