mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Fixes #734 - Add a "View logs" option to the report a problem screen
Move bug report and log viewer responsibility to a separate flow coordinator. Reuse it as a child coordinator in the authentication, userSessionFlow and settings flow coordinators.
This commit is contained in:
@@ -219,6 +219,7 @@
|
|||||||
36AC963F2F04069B7FF1AA0C /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */; };
|
36AC963F2F04069B7FF1AA0C /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */; };
|
||||||
36AD4DD4C798E22584ED3200 /* Emojibase in Frameworks */ = {isa = PBXBuildFile; productRef = C05729B1684C331F5FFE9232 /* Emojibase */; };
|
36AD4DD4C798E22584ED3200 /* Emojibase in Frameworks */ = {isa = PBXBuildFile; productRef = C05729B1684C331F5FFE9232 /* Emojibase */; };
|
||||||
36CD6E11B37396E14F032CB6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; };
|
36CD6E11B37396E14F032CB6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; };
|
||||||
|
36DE961B784087D5E18EF9BA /* LogViewerScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A07692536D66E3DA32C4964 /* LogViewerScreen.swift */; };
|
||||||
370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */; };
|
370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */; };
|
||||||
377980ABF16525114E72DDE2 /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = 2B9ACE4FCACB5A8812154424 /* Version */; };
|
377980ABF16525114E72DDE2 /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = 2B9ACE4FCACB5A8812154424 /* Version */; };
|
||||||
37906355E207DB5703754675 /* AppLockSetupBiometricsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F893F4A111CB7BA5C96949 /* AppLockSetupBiometricsScreenViewModel.swift */; };
|
37906355E207DB5703754675 /* AppLockSetupBiometricsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F893F4A111CB7BA5C96949 /* AppLockSetupBiometricsScreenViewModel.swift */; };
|
||||||
@@ -332,6 +333,8 @@
|
|||||||
5455147CAC63F71E48F7D699 /* NSELogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3D455BC2423D911A62ACFB2 /* NSELogger.swift */; };
|
5455147CAC63F71E48F7D699 /* NSELogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3D455BC2423D911A62ACFB2 /* NSELogger.swift */; };
|
||||||
54AE8860D668AFD96E7E177B /* UITestsScreenIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */; };
|
54AE8860D668AFD96E7E177B /* UITestsScreenIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */; };
|
||||||
54C774874BED4A8FAD1F22FE /* AnalyticsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77B3D4950F1707E66E4A45A /* AnalyticsConfiguration.swift */; };
|
54C774874BED4A8FAD1F22FE /* AnalyticsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77B3D4950F1707E66E4A45A /* AnalyticsConfiguration.swift */; };
|
||||||
|
5518DA4A6C9B4FC4B497EA9A /* LogViewerScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B795AAAB7B8747FE2FF311 /* LogViewerScreenModels.swift */; };
|
||||||
|
558E2673B04FDD06A1A12DD3 /* LogViewerScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7463464054DDF194C54F0B04 /* LogViewerScreenViewModelProtocol.swift */; };
|
||||||
55CDD3968D95D1A820B5491E /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */; };
|
55CDD3968D95D1A820B5491E /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */; };
|
||||||
562EFB9AB62B38830D9AA778 /* TimelineMediaFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 933B074F006F8E930DB98B4E /* TimelineMediaFrame.swift */; };
|
562EFB9AB62B38830D9AA778 /* TimelineMediaFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 933B074F006F8E930DB98B4E /* TimelineMediaFrame.swift */; };
|
||||||
564BF06B3E93D6DD55F903B2 /* CreateRoomCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C618CA2B6C8758B06C88013C /* CreateRoomCoordinator.swift */; };
|
564BF06B3E93D6DD55F903B2 /* CreateRoomCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C618CA2B6C8758B06C88013C /* CreateRoomCoordinator.swift */; };
|
||||||
@@ -654,6 +657,7 @@
|
|||||||
A6B83EB78F025D21B6EBA90C /* CompoundIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044E501B8331B339874D1B96 /* CompoundIcon.swift */; };
|
A6B83EB78F025D21B6EBA90C /* CompoundIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044E501B8331B339874D1B96 /* CompoundIcon.swift */; };
|
||||||
A6D4C5EEA85A6A0ABA1559D6 /* RoomDetailsEditScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16D09C79746BDCD9173EB3A7 /* RoomDetailsEditScreenModels.swift */; };
|
A6D4C5EEA85A6A0ABA1559D6 /* RoomDetailsEditScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16D09C79746BDCD9173EB3A7 /* RoomDetailsEditScreenModels.swift */; };
|
||||||
A6DEC1ADEC8FEEC206A0FA37 /* AttributedStringBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */; };
|
A6DEC1ADEC8FEEC206A0FA37 /* AttributedStringBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */; };
|
||||||
|
A6F345328CCC5C9B0DAE2257 /* LogViewerScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */; };
|
||||||
A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; };
|
A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; };
|
||||||
A743841F91B62B0E56217B04 /* SecureBackupKeyBackupScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DCB219D7B7B0299358FF81 /* SecureBackupKeyBackupScreenUITests.swift */; };
|
A743841F91B62B0E56217B04 /* SecureBackupKeyBackupScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DCB219D7B7B0299358FF81 /* SecureBackupKeyBackupScreenUITests.swift */; };
|
||||||
A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; };
|
A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; };
|
||||||
@@ -663,6 +667,7 @@
|
|||||||
A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; };
|
A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; };
|
||||||
A8771F5975A82759FA5138AE /* RoomMemberDetailsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F19DBE940499D3E3DD405D8 /* RoomMemberDetailsScreenUITests.swift */; };
|
A8771F5975A82759FA5138AE /* RoomMemberDetailsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F19DBE940499D3E3DD405D8 /* RoomMemberDetailsScreenUITests.swift */; };
|
||||||
A896998A6784DB6F16E912F4 /* MockMediaLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AB7D7DAAAF662DED9D02379 /* MockMediaLoader.swift */; };
|
A896998A6784DB6F16E912F4 /* MockMediaLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AB7D7DAAAF662DED9D02379 /* MockMediaLoader.swift */; };
|
||||||
|
A8FA7671948E3DF27F320026 /* BugReportFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7367B3B9A8CAF902220F31D1 /* BugReportFlowCoordinator.swift */; };
|
||||||
A93661C962B12942C08864B6 /* DSWaveformImageViews in Frameworks */ = {isa = PBXBuildFile; productRef = 2A4106A0A96DC4C273128AA5 /* DSWaveformImageViews */; };
|
A93661C962B12942C08864B6 /* DSWaveformImageViews in Frameworks */ = {isa = PBXBuildFile; productRef = 2A4106A0A96DC4C273128AA5 /* DSWaveformImageViews */; };
|
||||||
A9482B967FC85DA611514D35 /* VoiceMessageRoomPlaybackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCD41CD67DB5DA0D436BFE9 /* VoiceMessageRoomPlaybackView.swift */; };
|
A9482B967FC85DA611514D35 /* VoiceMessageRoomPlaybackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCD41CD67DB5DA0D436BFE9 /* VoiceMessageRoomPlaybackView.swift */; };
|
||||||
A969147E0EEE0E27EE226570 /* MediaUploadPreviewScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F29139BC2A804CE5E0757E /* MediaUploadPreviewScreenViewModel.swift */; };
|
A969147E0EEE0E27EE226570 /* MediaUploadPreviewScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F29139BC2A804CE5E0757E /* MediaUploadPreviewScreenViewModel.swift */; };
|
||||||
@@ -817,6 +822,7 @@
|
|||||||
CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; };
|
CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; };
|
||||||
CEB8FB1269DE20536608B957 /* LoginMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41FABA2B0AEF4389986495 /* LoginMode.swift */; };
|
CEB8FB1269DE20536608B957 /* LoginMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41FABA2B0AEF4389986495 /* LoginMode.swift */; };
|
||||||
CF3827071B0BC9638BD44F5D /* WaitlistScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB58EF0176D4CFB1040DA22 /* WaitlistScreenViewModel.swift */; };
|
CF3827071B0BC9638BD44F5D /* WaitlistScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB58EF0176D4CFB1040DA22 /* WaitlistScreenViewModel.swift */; };
|
||||||
|
CF38B70D8C6DD42C00A56A27 /* LogViewerScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */; };
|
||||||
CF4044A8EED5C41BC0ED6ABE /* SoftLogoutScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D316BB02636AF2174F2580E6 /* SoftLogoutScreenViewModelProtocol.swift */; };
|
CF4044A8EED5C41BC0ED6ABE /* SoftLogoutScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D316BB02636AF2174F2580E6 /* SoftLogoutScreenViewModelProtocol.swift */; };
|
||||||
CFEC53440C572CEEABC4A6A0 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; };
|
CFEC53440C572CEEABC4A6A0 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; };
|
||||||
D02AA6208C7ACB9BE6332394 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; };
|
D02AA6208C7ACB9BE6332394 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; };
|
||||||
@@ -1054,6 +1060,7 @@
|
|||||||
00245D40CD90FD71D6A05239 /* EmojiPickerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreen.swift; sourceTree = "<group>"; };
|
00245D40CD90FD71D6A05239 /* EmojiPickerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreen.swift; sourceTree = "<group>"; };
|
||||||
00E5B2CBEF8F96424F095508 /* RoomDetailsEditScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelTests.swift; sourceTree = "<group>"; };
|
00E5B2CBEF8F96424F095508 /* RoomDetailsEditScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
0135A608FFAD86E6674EE730 /* RoomScreenInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenInteractionHandler.swift; sourceTree = "<group>"; };
|
0135A608FFAD86E6674EE730 /* RoomScreenInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenInteractionHandler.swift; sourceTree = "<group>"; };
|
||||||
|
01B795AAAB7B8747FE2FF311 /* LogViewerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenModels.swift; sourceTree = "<group>"; };
|
||||||
01C4C7DB37597D7D8379511A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
01C4C7DB37597D7D8379511A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
022E6BD64CB4610B9C95FC02 /* UserDetailsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenViewModel.swift; sourceTree = "<group>"; };
|
022E6BD64CB4610B9C95FC02 /* UserDetailsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
024F7398C5FC12586FB10E9D /* EffectsScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectsScene.swift; sourceTree = "<group>"; };
|
024F7398C5FC12586FB10E9D /* EffectsScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectsScene.swift; sourceTree = "<group>"; };
|
||||||
@@ -1091,6 +1098,7 @@
|
|||||||
0A634D8DD1E10D858CF7995D /* VoiceMessageRecordingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecordingView.swift; sourceTree = "<group>"; };
|
0A634D8DD1E10D858CF7995D /* VoiceMessageRecordingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecordingView.swift; sourceTree = "<group>"; };
|
||||||
0AE449DFBA7CC863EEB2FD2A /* FormattingToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattingToolbar.swift; sourceTree = "<group>"; };
|
0AE449DFBA7CC863EEB2FD2A /* FormattingToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattingToolbar.swift; sourceTree = "<group>"; };
|
||||||
0B987FC3FDBAA0E1C5AA235C /* PaginationIndicatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationIndicatorRoomTimelineItem.swift; sourceTree = "<group>"; };
|
0B987FC3FDBAA0E1C5AA235C /* PaginationIndicatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationIndicatorRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
|
0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
0BC588051E6572A1AF51D738 /* TimelineSenderAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSenderAvatarView.swift; sourceTree = "<group>"; };
|
0BC588051E6572A1AF51D738 /* TimelineSenderAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSenderAvatarView.swift; sourceTree = "<group>"; };
|
||||||
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>"; };
|
||||||
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>"; };
|
||||||
@@ -1387,6 +1395,7 @@
|
|||||||
592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLibreStaticMapView.swift; sourceTree = "<group>"; };
|
592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLibreStaticMapView.swift; sourceTree = "<group>"; };
|
||||||
596AA8843AC1A234F3387767 /* SecureBackupRecoveryKeyScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupRecoveryKeyScreenCoordinator.swift; sourceTree = "<group>"; };
|
596AA8843AC1A234F3387767 /* SecureBackupRecoveryKeyScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupRecoveryKeyScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
59846FA04E1DBBFDD8829C2A /* MessageForwardingScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenUITests.swift; sourceTree = "<group>"; };
|
59846FA04E1DBBFDD8829C2A /* MessageForwardingScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
|
5A07692536D66E3DA32C4964 /* LogViewerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreen.swift; sourceTree = "<group>"; };
|
||||||
5A1119E9C63AE530252640D2 /* SecureBackupController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupController.swift; sourceTree = "<group>"; };
|
5A1119E9C63AE530252640D2 /* SecureBackupController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupController.swift; sourceTree = "<group>"; };
|
||||||
5A2FCA3D0F239B9E911B966B /* SecureBackupRecoveryKeyScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupRecoveryKeyScreen.swift; sourceTree = "<group>"; };
|
5A2FCA3D0F239B9E911B966B /* SecureBackupRecoveryKeyScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupRecoveryKeyScreen.swift; sourceTree = "<group>"; };
|
||||||
5A37E2FACFD041CE466223CD /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
5A37E2FACFD041CE466223CD /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
@@ -1467,8 +1476,10 @@
|
|||||||
71D52BAA5BADB06E5E8C295D /* Assets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Assets.swift; sourceTree = "<group>"; };
|
71D52BAA5BADB06E5E8C295D /* Assets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Assets.swift; sourceTree = "<group>"; };
|
||||||
72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilderProtocol.swift; sourceTree = "<group>"; };
|
72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilderProtocol.swift; sourceTree = "<group>"; };
|
||||||
7310D8DFE01AF45F0689C3AA /* Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Publisher.swift; sourceTree = "<group>"; };
|
7310D8DFE01AF45F0689C3AA /* Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Publisher.swift; sourceTree = "<group>"; };
|
||||||
|
7367B3B9A8CAF902220F31D1 /* BugReportFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportFlowCoordinator.swift; sourceTree = "<group>"; };
|
||||||
745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedLabelItem.swift; sourceTree = "<group>"; };
|
745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedLabelItem.swift; sourceTree = "<group>"; };
|
||||||
74611A4182DCF5F4D42696EC /* XCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.swift; sourceTree = "<group>"; };
|
74611A4182DCF5F4D42696EC /* XCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.swift; sourceTree = "<group>"; };
|
||||||
|
7463464054DDF194C54F0B04 /* LogViewerScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
7475C5AE20BA896930907EA8 /* AudioRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
7475C5AE20BA896930907EA8 /* AudioRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
||||||
748AE77AC3B0A01223033B87 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
748AE77AC3B0A01223033B87 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||||
74C6F3DAD167F972702C8893 /* TimelineItemAccessibilityModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemAccessibilityModifier.swift; sourceTree = "<group>"; };
|
74C6F3DAD167F972702C8893 /* TimelineItemAccessibilityModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemAccessibilityModifier.swift; sourceTree = "<group>"; };
|
||||||
@@ -1635,6 +1646,7 @@
|
|||||||
A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = "<group>"; };
|
A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = "<group>"; };
|
||||||
A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = "<group>"; };
|
A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = "<group>"; };
|
||||||
A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; };
|
A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
|
A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; };
|
A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
A8903A9F615BBD0E6D7CD133 /* ApplicationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationProtocol.swift; sourceTree = "<group>"; };
|
A8903A9F615BBD0E6D7CD133 /* ApplicationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationProtocol.swift; sourceTree = "<group>"; };
|
||||||
A9FAFE1C2149E6AC8156ED2B /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = "<group>"; };
|
A9FAFE1C2149E6AC8156ED2B /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = "<group>"; };
|
||||||
@@ -2996,6 +3008,7 @@
|
|||||||
children = (
|
children = (
|
||||||
FCE93F0CBF0D96B77111C413 /* AppLockFlowCoordinator.swift */,
|
FCE93F0CBF0D96B77111C413 /* AppLockFlowCoordinator.swift */,
|
||||||
0DBB08A95EFA668F2CF27211 /* AppLockSetupFlowCoordinator.swift */,
|
0DBB08A95EFA668F2CF27211 /* AppLockSetupFlowCoordinator.swift */,
|
||||||
|
7367B3B9A8CAF902220F31D1 /* BugReportFlowCoordinator.swift */,
|
||||||
9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */,
|
9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */,
|
||||||
D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */,
|
D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */,
|
||||||
C99FDEEB71173C4C6FA2734C /* UserSessionFlowCoordinator.swift */,
|
C99FDEEB71173C4C6FA2734C /* UserSessionFlowCoordinator.swift */,
|
||||||
@@ -3336,6 +3349,18 @@
|
|||||||
path = Sources;
|
path = Sources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
73E032ADD008D63812791D97 /* LogViewerScreen */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */,
|
||||||
|
01B795AAAB7B8747FE2FF311 /* LogViewerScreenModels.swift */,
|
||||||
|
0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */,
|
||||||
|
7463464054DDF194C54F0B04 /* LogViewerScreenViewModelProtocol.swift */,
|
||||||
|
786BF682AB6BA65DC8F53D3D /* View */,
|
||||||
|
);
|
||||||
|
path = LogViewerScreen;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
7431C962E314ADAE38B6D708 /* Analytics */ = {
|
7431C962E314ADAE38B6D708 /* Analytics */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -3408,6 +3433,14 @@
|
|||||||
path = Navigation;
|
path = Navigation;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
786BF682AB6BA65DC8F53D3D /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5A07692536D66E3DA32C4964 /* LogViewerScreen.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
78915D878159D302395D57BF /* SupportingFiles */ = {
|
78915D878159D302395D57BF /* SupportingFiles */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -4490,6 +4523,7 @@
|
|||||||
E3EA13D6E41AD76151C2D100 /* InvitesScreen */,
|
E3EA13D6E41AD76151C2D100 /* InvitesScreen */,
|
||||||
F12966DF3DA87FEF21348D60 /* InviteUsersScreen */,
|
F12966DF3DA87FEF21348D60 /* InviteUsersScreen */,
|
||||||
948DD12A5533BE1BC260E437 /* LocationSharing */,
|
948DD12A5533BE1BC260E437 /* LocationSharing */,
|
||||||
|
73E032ADD008D63812791D97 /* LogViewerScreen */,
|
||||||
87E2774157D9C4894BCFF3F8 /* MediaPickerScreen */,
|
87E2774157D9C4894BCFF3F8 /* MediaPickerScreen */,
|
||||||
23605DD08620BE6558242469 /* MediaUploadPreviewScreen */,
|
23605DD08620BE6558242469 /* MediaUploadPreviewScreen */,
|
||||||
3348D14DBDB54E72FC67E2F3 /* MessageForwardingScreen */,
|
3348D14DBDB54E72FC67E2F3 /* MessageForwardingScreen */,
|
||||||
@@ -5404,6 +5438,7 @@
|
|||||||
5EE1D4E316D66943E97FDCF2 /* BloomView.swift in Sources */,
|
5EE1D4E316D66943E97FDCF2 /* BloomView.swift in Sources */,
|
||||||
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */,
|
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */,
|
||||||
E794AB6ABE1FF5AF0573FEA1 /* BlurHashEncode.swift in Sources */,
|
E794AB6ABE1FF5AF0573FEA1 /* BlurHashEncode.swift in Sources */,
|
||||||
|
A8FA7671948E3DF27F320026 /* BugReportFlowCoordinator.swift in Sources */,
|
||||||
6AD722DD92E465E56D2885AB /* BugReportScreen.swift in Sources */,
|
6AD722DD92E465E56D2885AB /* BugReportScreen.swift in Sources */,
|
||||||
B98A20A093A4FB785BFCCA53 /* BugReportScreenCoordinator.swift in Sources */,
|
B98A20A093A4FB785BFCCA53 /* BugReportScreenCoordinator.swift in Sources */,
|
||||||
4FFDC274824F7CC0BBDF581E /* BugReportScreenModels.swift in Sources */,
|
4FFDC274824F7CC0BBDF581E /* BugReportScreenModels.swift in Sources */,
|
||||||
@@ -5558,6 +5593,11 @@
|
|||||||
854E82E064BA53CD0BC45600 /* LocationRoomTimelineItemContent.swift in Sources */,
|
854E82E064BA53CD0BC45600 /* LocationRoomTimelineItemContent.swift in Sources */,
|
||||||
D9473FC9B077A6EDB7A12001 /* LocationRoomTimelineView.swift in Sources */,
|
D9473FC9B077A6EDB7A12001 /* LocationRoomTimelineView.swift in Sources */,
|
||||||
29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */,
|
29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */,
|
||||||
|
36DE961B784087D5E18EF9BA /* LogViewerScreen.swift in Sources */,
|
||||||
|
CF38B70D8C6DD42C00A56A27 /* LogViewerScreenCoordinator.swift in Sources */,
|
||||||
|
5518DA4A6C9B4FC4B497EA9A /* LogViewerScreenModels.swift in Sources */,
|
||||||
|
A6F345328CCC5C9B0DAE2257 /* LogViewerScreenViewModel.swift in Sources */,
|
||||||
|
558E2673B04FDD06A1A12DD3 /* LogViewerScreenViewModelProtocol.swift in Sources */,
|
||||||
872A6457DF573AF8CEAE927A /* LoginHomeserver.swift in Sources */,
|
872A6457DF573AF8CEAE927A /* LoginHomeserver.swift in Sources */,
|
||||||
CEB8FB1269DE20536608B957 /* LoginMode.swift in Sources */,
|
CEB8FB1269DE20536608B957 /* LoginMode.swift in Sources */,
|
||||||
5375902175B2FEA2949D7D74 /* LoginScreen.swift in Sources */,
|
5375902175B2FEA2949D7D74 /* LoginScreen.swift in Sources */,
|
||||||
|
|||||||
@@ -342,6 +342,7 @@
|
|||||||
"screen_bug_report_include_logs" = "Allow logs";
|
"screen_bug_report_include_logs" = "Allow logs";
|
||||||
"screen_bug_report_include_screenshot" = "Send screenshot";
|
"screen_bug_report_include_screenshot" = "Send screenshot";
|
||||||
"screen_bug_report_logs_description" = "Logs will be included with your message to make sure that everything is working properly. To send your message without logs, turn off this setting.";
|
"screen_bug_report_logs_description" = "Logs will be included with your message to make sure that everything is working properly. To send your message without logs, turn off this setting.";
|
||||||
|
"screen_bug_report_view_logs" = "View logs";
|
||||||
"screen_change_account_provider_matrix_org_subtitle" = "Matrix.org is a large, free server on the public Matrix network for secure, decentralised communication, run by the Matrix.org Foundation.";
|
"screen_change_account_provider_matrix_org_subtitle" = "Matrix.org is a large, free server on the public Matrix network for secure, decentralised communication, run by the Matrix.org Foundation.";
|
||||||
"screen_change_account_provider_other" = "Other";
|
"screen_change_account_provider_other" = "Other";
|
||||||
"screen_change_account_provider_subtitle" = "Use a different account provider, such as your own private server or a work account.";
|
"screen_change_account_provider_subtitle" = "Use a different account provider, such as your own private server or a work account.";
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import Foundation
|
|||||||
// periphery:ignore - markdown protocol
|
// periphery:ignore - markdown protocol
|
||||||
@MainActor
|
@MainActor
|
||||||
protocol FlowCoordinatorProtocol {
|
protocol FlowCoordinatorProtocol {
|
||||||
|
func start()
|
||||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool)
|
func handleAppRoute(_ appRoute: AppRoute, animated: Bool)
|
||||||
func clearRoute(animated: Bool)
|
func clearRoute(animated: Bool)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2024 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
struct BugReportFlowCoordinatorParameters {
|
||||||
|
enum PresentationMode {
|
||||||
|
case sheet(NavigationStackCoordinator)
|
||||||
|
case push(NavigationStackCoordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
let presentationMode: PresentationMode
|
||||||
|
let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
let bugReportService: BugReportServiceProtocol
|
||||||
|
let userID: String?
|
||||||
|
let deviceID: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
class BugReportFlowCoordinator: FlowCoordinatorProtocol {
|
||||||
|
private let parameters: BugReportFlowCoordinatorParameters
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
private var internalNavigationStackCoordinator: NavigationStackCoordinator?
|
||||||
|
|
||||||
|
private var isModallyPresented: Bool {
|
||||||
|
switch parameters.presentationMode {
|
||||||
|
case .sheet:
|
||||||
|
return true
|
||||||
|
case .push:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: BugReportFlowCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
presentBugReportScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearRoute(animated: Bool) {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private func presentBugReportScreen() {
|
||||||
|
let params = BugReportScreenCoordinatorParameters(bugReportService: parameters.bugReportService,
|
||||||
|
userID: parameters.userID,
|
||||||
|
deviceID: parameters.deviceID,
|
||||||
|
userIndicatorController: parameters.userIndicatorController,
|
||||||
|
screenshot: nil,
|
||||||
|
isModallyPresented: isModallyPresented)
|
||||||
|
let coordinator = BugReportScreenCoordinator(parameters: params)
|
||||||
|
coordinator.actions.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case .cancel:
|
||||||
|
dismiss()
|
||||||
|
case .viewLogs:
|
||||||
|
presentLogViewerScreen()
|
||||||
|
case .finish:
|
||||||
|
showSuccess(label: L10n.actionDone)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
switch parameters.presentationMode {
|
||||||
|
case .sheet(let navigationStackCoordinator):
|
||||||
|
let internalNavigationStackCoordinator = NavigationStackCoordinator()
|
||||||
|
internalNavigationStackCoordinator.setRootCoordinator(coordinator)
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(internalNavigationStackCoordinator)
|
||||||
|
self.internalNavigationStackCoordinator = internalNavigationStackCoordinator
|
||||||
|
case .push(let navigationStackCoordinator):
|
||||||
|
internalNavigationStackCoordinator = navigationStackCoordinator
|
||||||
|
navigationStackCoordinator.push(coordinator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentLogViewerScreen() {
|
||||||
|
let coordinator = LogViewerScreenCoordinator(parameters: .init())
|
||||||
|
coordinator.actions.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case .done:
|
||||||
|
internalNavigationStackCoordinator?.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
internalNavigationStackCoordinator?.push(coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dismiss() {
|
||||||
|
switch parameters.presentationMode {
|
||||||
|
case .push(let navigationStackCoordinator):
|
||||||
|
navigationStackCoordinator.pop()
|
||||||
|
case .sheet(let navigationStackCoordinator):
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showSuccess(label: String) {
|
||||||
|
parameters.userIndicatorController.submitIndicator(UserIndicator(title: label))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,6 +91,10 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
// MARK: - FlowCoordinatorProtocol
|
// MARK: - FlowCoordinatorProtocol
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
fatalError("This flow coordinator expect a route")
|
||||||
|
}
|
||||||
|
|
||||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||||
switch appRoute {
|
switch appRoute {
|
||||||
case .room(let roomID):
|
case .room(let roomID):
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
// periphery:ignore - retaining purpose
|
// periphery:ignore - retaining purpose
|
||||||
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
|
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
|
||||||
|
|
||||||
|
// periphery:ignore - retaining purpose
|
||||||
|
private var bugReportFlowCoordinator: BugReportFlowCoordinator?
|
||||||
|
|
||||||
private let actionsSubject: PassthroughSubject<SettingsFlowCoordinatorAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<SettingsFlowCoordinatorAction, Never> = .init()
|
||||||
var actions: AnyPublisher<SettingsFlowCoordinatorAction, Never> {
|
var actions: AnyPublisher<SettingsFlowCoordinatorAction, Never> {
|
||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
@@ -57,6 +60,10 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
fatalError("Unavailable")
|
||||||
|
}
|
||||||
|
|
||||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||||
switch appRoute {
|
switch appRoute {
|
||||||
case .settings:
|
case .settings:
|
||||||
@@ -76,17 +83,17 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearRoute(animated: Bool) { }
|
func clearRoute(animated: Bool) {
|
||||||
|
fatalError("Unavailable")
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func presentSettingsScreen(animated: Bool) {
|
private func presentSettingsScreen(animated: Bool) {
|
||||||
navigationStackCoordinator = NavigationStackCoordinator()
|
navigationStackCoordinator = NavigationStackCoordinator()
|
||||||
|
|
||||||
let parameters = SettingsScreenCoordinatorParameters(userSession: parameters.userSession,
|
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: .init(userSession: parameters.userSession,
|
||||||
appSettings: parameters.appSettings)
|
appSettings: parameters.appSettings))
|
||||||
|
|
||||||
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters)
|
|
||||||
|
|
||||||
settingsScreenCoordinator.actions
|
settingsScreenCoordinator.actions
|
||||||
.sink { [weak self] action in
|
.sink { [weak self] action in
|
||||||
@@ -94,9 +101,9 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case .dismiss:
|
case .dismiss:
|
||||||
self.parameters.navigationSplitCoordinator.setSheetCoordinator(nil)
|
parameters.navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||||
case .logout:
|
case .logout:
|
||||||
self.parameters.navigationSplitCoordinator.setSheetCoordinator(nil)
|
parameters.navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||||
|
|
||||||
// The settings sheet needs to be dismissed before the alert can be shown
|
// The settings sheet needs to be dismissed before the alert can be shown
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
@@ -113,7 +120,12 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
case .appLock:
|
case .appLock:
|
||||||
presentAppLockSetupFlow()
|
presentAppLockSetupFlow()
|
||||||
case .bugReport:
|
case .bugReport:
|
||||||
presentBugReportScreen()
|
bugReportFlowCoordinator = BugReportFlowCoordinator(parameters: .init(presentationMode: .push(navigationStackCoordinator),
|
||||||
|
userIndicatorController: parameters.userIndicatorController,
|
||||||
|
bugReportService: parameters.bugReportService,
|
||||||
|
userID: parameters.userSession.userID,
|
||||||
|
deviceID: parameters.userSession.deviceID))
|
||||||
|
bugReportFlowCoordinator?.start()
|
||||||
case .about:
|
case .about:
|
||||||
presentLegalInformationScreen()
|
presentLegalInformationScreen()
|
||||||
case .sessionVerification:
|
case .sessionVerification:
|
||||||
@@ -132,7 +144,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
navigationStackCoordinator.setRootCoordinator(settingsScreenCoordinator, animated: animated)
|
navigationStackCoordinator.setRootCoordinator(settingsScreenCoordinator, animated: animated)
|
||||||
|
|
||||||
self.parameters.navigationSplitCoordinator.setSheetCoordinator(navigationStackCoordinator) { [weak self] in
|
parameters.navigationSplitCoordinator.setSheetCoordinator(navigationStackCoordinator) { [weak self] in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|
||||||
navigationStackCoordinator = nil
|
navigationStackCoordinator = nil
|
||||||
@@ -187,28 +199,6 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
coordinator.start()
|
coordinator.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentBugReportScreen() {
|
|
||||||
let params = BugReportScreenCoordinatorParameters(bugReportService: parameters.bugReportService,
|
|
||||||
userID: parameters.userSession.userID,
|
|
||||||
deviceID: parameters.userSession.deviceID,
|
|
||||||
userIndicatorController: parameters.userIndicatorController,
|
|
||||||
screenshot: nil,
|
|
||||||
isModallyPresented: false)
|
|
||||||
let coordinator = BugReportScreenCoordinator(parameters: params)
|
|
||||||
coordinator.completion = { [weak self] result in
|
|
||||||
switch result {
|
|
||||||
case .finish:
|
|
||||||
self?.showSuccess(label: L10n.actionDone)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
self?.navigationStackCoordinator.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
navigationStackCoordinator.push(coordinator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentLegalInformationScreen() {
|
private func presentLegalInformationScreen() {
|
||||||
navigationStackCoordinator.push(LegalInformationScreenCoordinator(appSettings: parameters.appSettings))
|
navigationStackCoordinator.push(LegalInformationScreenCoordinator(appSettings: parameters.appSettings))
|
||||||
}
|
}
|
||||||
@@ -269,10 +259,6 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
navigationStackCoordinator.push(coordinator)
|
navigationStackCoordinator.push(coordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showSuccess(label: String) {
|
|
||||||
parameters.userIndicatorController.submitIndicator(UserIndicator(title: label))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: OIDC Account Management
|
// MARK: OIDC Account Management
|
||||||
|
|
||||||
private func presentAccountProfileURL() {
|
private func presentAccountProfileURL() {
|
||||||
|
|||||||
@@ -33,9 +33,14 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
private let actionsSubject: PassthroughSubject<UserSessionFlowCoordinatorAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<UserSessionFlowCoordinatorAction, Never> = .init()
|
||||||
|
|
||||||
private let stateMachine: UserSessionFlowCoordinatorStateMachine
|
private let stateMachine: UserSessionFlowCoordinatorStateMachine
|
||||||
|
|
||||||
private let roomFlowCoordinator: RoomFlowCoordinator
|
private let roomFlowCoordinator: RoomFlowCoordinator
|
||||||
|
|
||||||
private let settingsFlowCoordinator: SettingsFlowCoordinator
|
private let settingsFlowCoordinator: SettingsFlowCoordinator
|
||||||
|
|
||||||
|
// periphery:ignore - retaining purpose
|
||||||
|
private var bugReportFlowCoordinator: BugReportFlowCoordinator?
|
||||||
|
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
private var migrationCancellable: AnyCancellable?
|
private var migrationCancellable: AnyCancellable?
|
||||||
|
|
||||||
@@ -250,7 +255,12 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case (.roomList, .feedbackScreen, .feedbackScreen):
|
case (.roomList, .feedbackScreen, .feedbackScreen):
|
||||||
presentFeedbackScreen(animated: animated)
|
bugReportFlowCoordinator = BugReportFlowCoordinator(parameters: .init(presentationMode: .sheet(sidebarNavigationStackCoordinator),
|
||||||
|
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||||
|
bugReportService: bugReportService,
|
||||||
|
userID: userSession.userID,
|
||||||
|
deviceID: userSession.deviceID))
|
||||||
|
bugReportFlowCoordinator?.start()
|
||||||
case (.feedbackScreen, .dismissedFeedbackScreen, .roomList):
|
case (.feedbackScreen, .dismissedFeedbackScreen, .roomList):
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -483,30 +493,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
self?.stateMachine.processEvent(.dismissedStartChatScreen)
|
self?.stateMachine.processEvent(.dismissedStartChatScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Bug reporting
|
|
||||||
|
|
||||||
private func presentFeedbackScreen(animated: Bool, for image: UIImage? = nil) {
|
|
||||||
let feedbackNavigationStackCoordinator = NavigationStackCoordinator()
|
|
||||||
|
|
||||||
let parameters = BugReportScreenCoordinatorParameters(bugReportService: bugReportService,
|
|
||||||
userID: userSession.userID,
|
|
||||||
deviceID: userSession.deviceID,
|
|
||||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
|
||||||
screenshot: image,
|
|
||||||
isModallyPresented: true)
|
|
||||||
let coordinator = BugReportScreenCoordinator(parameters: parameters)
|
|
||||||
coordinator.completion = { [weak self] _ in
|
|
||||||
self?.navigationSplitCoordinator.setSheetCoordinator(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
feedbackNavigationStackCoordinator.setRootCoordinator(coordinator)
|
|
||||||
|
|
||||||
navigationSplitCoordinator.setSheetCoordinator(feedbackNavigationStackCoordinator, animated: animated) { [weak self] in
|
|
||||||
self?.stateMachine.processEvent(.dismissedFeedbackScreen)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Invites list
|
// MARK: Invites list
|
||||||
|
|
||||||
private func presentInvitesList(animated: Bool) {
|
private func presentInvitesList(animated: Bool) {
|
||||||
|
|||||||
@@ -838,6 +838,8 @@ public enum L10n {
|
|||||||
public static func screenBugReportRashLogsAlertTitle(_ p1: Any) -> String {
|
public static func screenBugReportRashLogsAlertTitle(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "screen_bug_report_rash_logs_alert_title", String(describing: p1))
|
return L10n.tr("Localizable", "screen_bug_report_rash_logs_alert_title", String(describing: p1))
|
||||||
}
|
}
|
||||||
|
/// View logs
|
||||||
|
public static var screenBugReportViewLogs: String { return L10n.tr("Localizable", "screen_bug_report_view_logs") }
|
||||||
/// Matrix.org is a large, free server on the public Matrix network for secure, decentralised communication, run by the Matrix.org Foundation.
|
/// Matrix.org is a large, free server on the public Matrix network for secure, decentralised communication, run by the Matrix.org Foundation.
|
||||||
public static var screenChangeAccountProviderMatrixOrgSubtitle: String { return L10n.tr("Localizable", "screen_change_account_provider_matrix_org_subtitle") }
|
public static var screenChangeAccountProviderMatrixOrgSubtitle: String { return L10n.tr("Localizable", "screen_change_account_provider_matrix_org_subtitle") }
|
||||||
/// Other
|
/// Other
|
||||||
|
|||||||
@@ -34,9 +34,13 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
|||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
private var oidcPresenter: OIDCAuthenticationPresenter?
|
private var oidcPresenter: OIDCAuthenticationPresenter?
|
||||||
|
|
||||||
// periphery: ignore - used to store the coordinator to avoid deallocation
|
// periphery: ignore - used to store the coordinator to avoid deallocation
|
||||||
private var appLockFlowCoordinator: AppLockSetupFlowCoordinator?
|
private var appLockFlowCoordinator: AppLockSetupFlowCoordinator?
|
||||||
|
|
||||||
|
// periphery:ignore - retaining purpose
|
||||||
|
private var bugReportFlowCoordinator: BugReportFlowCoordinator?
|
||||||
|
|
||||||
weak var delegate: AuthenticationCoordinatorDelegate?
|
weak var delegate: AuthenticationCoordinatorDelegate?
|
||||||
|
|
||||||
init(authenticationService: AuthenticationServiceProxyProtocol,
|
init(authenticationService: AuthenticationServiceProxyProtocol,
|
||||||
@@ -94,24 +98,12 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func showReportProblemScreen() {
|
private func showReportProblemScreen() {
|
||||||
let feedbackNavigationStackCoordinator = NavigationStackCoordinator()
|
bugReportFlowCoordinator = BugReportFlowCoordinator(parameters: .init(presentationMode: .sheet(navigationStackCoordinator),
|
||||||
|
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||||
let parameters = BugReportScreenCoordinatorParameters(bugReportService: bugReportService,
|
bugReportService: bugReportService,
|
||||||
userID: nil,
|
userID: nil,
|
||||||
deviceID: nil,
|
deviceID: nil))
|
||||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
bugReportFlowCoordinator?.start()
|
||||||
screenshot: nil,
|
|
||||||
isModallyPresented: true)
|
|
||||||
|
|
||||||
let coordinator = BugReportScreenCoordinator(parameters: parameters)
|
|
||||||
|
|
||||||
coordinator.completion = { [weak self] _ in
|
|
||||||
self?.navigationStackCoordinator.setSheetCoordinator(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
feedbackNavigationStackCoordinator.setRootCoordinator(coordinator)
|
|
||||||
|
|
||||||
navigationStackCoordinator.setSheetCoordinator(feedbackNavigationStackCoordinator, animated: true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startAuthentication() async {
|
private func startAuthentication() async {
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
import Combine
|
import Combine
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
enum BugReportScreenCoordinatorResult {
|
enum BugReportScreenCoordinatorAction {
|
||||||
case cancel
|
case cancel
|
||||||
|
case viewLogs
|
||||||
case finish
|
case finish
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +38,10 @@ final class BugReportScreenCoordinator: CoordinatorProtocol {
|
|||||||
private var viewModel: BugReportScreenViewModelProtocol
|
private var viewModel: BugReportScreenViewModelProtocol
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
var completion: ((BugReportScreenCoordinatorResult) -> Void)?
|
private let actionsSubject: PassthroughSubject<BugReportScreenCoordinatorAction, Never> = .init()
|
||||||
|
var actions: AnyPublisher<BugReportScreenCoordinatorAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
init(parameters: BugReportScreenCoordinatorParameters) {
|
init(parameters: BugReportScreenCoordinatorParameters) {
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
@@ -56,18 +60,21 @@ final class BugReportScreenCoordinator: CoordinatorProtocol {
|
|||||||
.actions
|
.actions
|
||||||
.sink { [weak self] action in
|
.sink { [weak self] action in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|
||||||
MXLog.info("BugReportViewModel did complete with result: \(action).")
|
MXLog.info("BugReportViewModel did complete with result: \(action).")
|
||||||
switch action {
|
switch action {
|
||||||
case .cancel:
|
case .cancel:
|
||||||
self.completion?(.cancel)
|
actionsSubject.send(.cancel)
|
||||||
|
case .viewLogs:
|
||||||
|
actionsSubject.send(.viewLogs)
|
||||||
case let .submitStarted(progressPublisher):
|
case let .submitStarted(progressPublisher):
|
||||||
self.startLoading(label: L10n.commonSending, progressPublisher: progressPublisher)
|
startLoading(label: L10n.commonSending, progressPublisher: progressPublisher)
|
||||||
case .submitFinished:
|
case .submitFinished:
|
||||||
self.stopLoading()
|
stopLoading()
|
||||||
self.completion?(.finish)
|
actionsSubject.send(.finish)
|
||||||
case .submitFailed(let error):
|
case .submitFailed(let error):
|
||||||
self.stopLoading()
|
stopLoading()
|
||||||
self.showError(label: error.localizedDescription)
|
showError(label: error.localizedDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import UIKit
|
|||||||
|
|
||||||
enum BugReportScreenViewModelAction {
|
enum BugReportScreenViewModelAction {
|
||||||
case cancel
|
case cancel
|
||||||
|
case viewLogs
|
||||||
case submitStarted(progressPublisher: CurrentValuePublisher<Double, Never>)
|
case submitStarted(progressPublisher: CurrentValuePublisher<Double, Never>)
|
||||||
case submitFinished
|
case submitFinished
|
||||||
case submitFailed(error: Error)
|
case submitFailed(error: Error)
|
||||||
@@ -42,4 +43,5 @@ enum BugReportScreenViewAction {
|
|||||||
case submit
|
case submit
|
||||||
case removeScreenshot
|
case removeScreenshot
|
||||||
case attachScreenshot(UIImage)
|
case attachScreenshot(UIImage)
|
||||||
|
case viewLogs
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ class BugReportScreenViewModel: BugReportScreenViewModelType, BugReportScreenVie
|
|||||||
case .cancel:
|
case .cancel:
|
||||||
uploadTask = nil
|
uploadTask = nil
|
||||||
actionsSubject.send(.cancel)
|
actionsSubject.send(.cancel)
|
||||||
|
case .viewLogs:
|
||||||
|
actionsSubject.send(.viewLogs)
|
||||||
case .submit:
|
case .submit:
|
||||||
state.shouldDisableInteraction = true
|
state.shouldDisableInteraction = true
|
||||||
uploadTask = Task { await submitBugReport() }
|
uploadTask = Task { await submitBugReport() }
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ struct BugReportScreen: View {
|
|||||||
ListRow(label: .plain(title: L10n.screenBugReportIncludeLogs),
|
ListRow(label: .plain(title: L10n.screenBugReportIncludeLogs),
|
||||||
kind: .toggle($context.sendingLogsEnabled))
|
kind: .toggle($context.sendingLogsEnabled))
|
||||||
.accessibilityIdentifier(A11yIdentifiers.bugReportScreen.sendLogs)
|
.accessibilityIdentifier(A11yIdentifiers.bugReportScreen.sendLogs)
|
||||||
|
ListRow(label: .plain(title: L10n.screenBugReportViewLogs),
|
||||||
|
kind: .navigationLink { context.send(viewAction: .viewLogs) })
|
||||||
|
.accessibilityIdentifier(A11yIdentifiers.bugReportScreen.sendLogs)
|
||||||
} footer: {
|
} footer: {
|
||||||
Text(L10n.screenBugReportLogsDescription)
|
Text(L10n.screenBugReportLogsDescription)
|
||||||
.compoundListSectionFooter()
|
.compoundListSectionFooter()
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// periphery:ignore:all - this is just a logViewer remove this comment once generating the final file
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LogViewerScreenCoordinatorParameters { }
|
||||||
|
|
||||||
|
enum LogViewerScreenCoordinatorAction {
|
||||||
|
case done
|
||||||
|
}
|
||||||
|
|
||||||
|
final class LogViewerScreenCoordinator: CoordinatorProtocol {
|
||||||
|
private let parameters: LogViewerScreenCoordinatorParameters
|
||||||
|
private var viewModel: LogViewerScreenViewModelProtocol
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<LogViewerScreenCoordinatorAction, Never> = .init()
|
||||||
|
var actions: AnyPublisher<LogViewerScreenCoordinatorAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: LogViewerScreenCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
|
||||||
|
viewModel = LogViewerScreenViewModel()
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
viewModel.actions.sink { [weak self] action in
|
||||||
|
MXLog.info("Coordinator: received view model action: \(action)")
|
||||||
|
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .done:
|
||||||
|
self.actionsSubject.send(.done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> AnyView {
|
||||||
|
AnyView(LogViewerScreen(context: viewModel.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum LogViewerScreenViewModelAction {
|
||||||
|
case done
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LogViewerScreenViewState: BindableState {
|
||||||
|
let urls: [URL]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LogViewerScreenViewAction {
|
||||||
|
case done
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
typealias LogViewerScreenViewModelType = StateStoreViewModel<LogViewerScreenViewState, LogViewerScreenViewAction>
|
||||||
|
|
||||||
|
class LogViewerScreenViewModel: LogViewerScreenViewModelType, LogViewerScreenViewModelProtocol {
|
||||||
|
private var actionsSubject: PassthroughSubject<LogViewerScreenViewModelAction, Never> = .init()
|
||||||
|
|
||||||
|
var actions: AnyPublisher<LogViewerScreenViewModelAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
super.init(initialViewState: LogViewerScreenViewState(urls: MXLogger.logFiles))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
override func process(viewAction: LogViewerScreenViewAction) {
|
||||||
|
MXLog.info("View model: received view action: \(viewAction)")
|
||||||
|
|
||||||
|
switch viewAction {
|
||||||
|
case .done:
|
||||||
|
actionsSubject.send(.done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
protocol LogViewerScreenViewModelProtocol {
|
||||||
|
var actions: AnyPublisher<LogViewerScreenViewModelAction, Never> { get }
|
||||||
|
var context: LogViewerScreenViewModelType.Context { get }
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
|
import QuickLook
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LogViewerScreen: View {
|
||||||
|
@ObservedObject var context: LogViewerScreenViewModel.Context
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
PreviewView(urls: context.viewState.urls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PreviewView: UIViewControllerRepresentable {
|
||||||
|
let urls: [URL]
|
||||||
|
|
||||||
|
func makeUIViewController(context: Context) -> UIViewController {
|
||||||
|
let previewController = QLPreviewController()
|
||||||
|
previewController.dataSource = context.coordinator
|
||||||
|
previewController.delegate = context.coordinator
|
||||||
|
|
||||||
|
if ProcessInfo.processInfo.isiOSAppOnMac {
|
||||||
|
return previewController
|
||||||
|
} else {
|
||||||
|
return UINavigationController(rootViewController: previewController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }
|
||||||
|
|
||||||
|
func makeCoordinator() -> Coordinator {
|
||||||
|
Coordinator(view: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Coordinator: NSObject, QLPreviewControllerDataSource, QLPreviewControllerDelegate {
|
||||||
|
let view: PreviewView
|
||||||
|
|
||||||
|
init(view: PreviewView) {
|
||||||
|
self.view = view
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - QLPreviewControllerDataSource
|
||||||
|
|
||||||
|
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
|
||||||
|
view.urls.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
|
||||||
|
let url = view.urls[index]
|
||||||
|
|
||||||
|
return PreviewItem(previewItemURL: url, previewItemTitle: url.lastPathComponent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - QLPreviewControllerDelegate
|
||||||
|
|
||||||
|
func previewController(_ controller: QLPreviewController, editingModeFor previewItem: QLPreviewItem) -> QLPreviewItemEditingMode {
|
||||||
|
.disabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PreviewItem: NSObject, QLPreviewItem {
|
||||||
|
var previewItemURL: URL?
|
||||||
|
var previewItemTitle: String?
|
||||||
|
|
||||||
|
init(previewItemURL: URL?, previewItemTitle: String?) {
|
||||||
|
self.previewItemURL = previewItemURL
|
||||||
|
self.previewItemTitle = previewItemTitle
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -206,12 +206,12 @@ class MockScreen: Identifiable {
|
|||||||
fatalError("Failed to start listening for notifications.")
|
fatalError("Failed to start listening for notifications.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let coordinator = AppLockFlowCoordinator(initialState: .unlocked,
|
let flowCoordinator = AppLockFlowCoordinator(initialState: .unlocked,
|
||||||
appLockService: appLockService,
|
appLockService: appLockService,
|
||||||
navigationCoordinator: navigationCoordinator,
|
navigationCoordinator: navigationCoordinator,
|
||||||
notificationCenter: notificationCenter)
|
notificationCenter: notificationCenter)
|
||||||
|
|
||||||
coordinator.actions
|
flowCoordinator.actions
|
||||||
.sink { [weak self] action in
|
.sink { [weak self] action in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|
||||||
@@ -226,7 +226,9 @@ class MockScreen: Identifiable {
|
|||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
return coordinator
|
retainedState.append(flowCoordinator)
|
||||||
|
|
||||||
|
return navigationCoordinator
|
||||||
case .appLockSetupFlow, .appLockSetupFlowUnlock, .appLockSetupFlowMandatory:
|
case .appLockSetupFlow, .appLockSetupFlowUnlock, .appLockSetupFlowMandatory:
|
||||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||||
// The flow expects an existing root coordinator, use a blank form as a placeholder.
|
// The flow expects an existing root coordinator, use a blank form as a placeholder.
|
||||||
@@ -248,11 +250,12 @@ class MockScreen: Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let flow: AppLockSetupFlowCoordinator.PresentationFlow = id == .appLockSetupFlowMandatory ? .onboarding : .settings
|
let flow: AppLockSetupFlowCoordinator.PresentationFlow = id == .appLockSetupFlowMandatory ? .onboarding : .settings
|
||||||
let coordinator = AppLockSetupFlowCoordinator(presentingFlow: flow,
|
let flowCoordinator = AppLockSetupFlowCoordinator(presentingFlow: flow,
|
||||||
appLockService: appLockService,
|
appLockService: appLockService,
|
||||||
navigationStackCoordinator: navigationStackCoordinator)
|
navigationStackCoordinator: navigationStackCoordinator)
|
||||||
coordinator.start()
|
flowCoordinator.start()
|
||||||
retainedState.append(coordinator)
|
|
||||||
|
retainedState.append(flowCoordinator)
|
||||||
|
|
||||||
return navigationStackCoordinator
|
return navigationStackCoordinator
|
||||||
case .home:
|
case .home:
|
||||||
@@ -559,19 +562,19 @@ class MockScreen: Identifiable {
|
|||||||
ServiceLocator.shared.settings.migratedAccounts[clientProxy.userID] = true
|
ServiceLocator.shared.settings.migratedAccounts[clientProxy.userID] = true
|
||||||
ServiceLocator.shared.settings.hasShownWelcomeScreen = true
|
ServiceLocator.shared.settings.hasShownWelcomeScreen = true
|
||||||
|
|
||||||
let coordinator = UserSessionFlowCoordinator(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider(), voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
let flowCoordinator = UserSessionFlowCoordinator(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider(), voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
||||||
navigationSplitCoordinator: navigationSplitCoordinator,
|
navigationSplitCoordinator: navigationSplitCoordinator,
|
||||||
windowManager: windowManager,
|
windowManager: windowManager,
|
||||||
appLockService: AppLockService(keychainController: KeychainControllerMock(),
|
appLockService: AppLockService(keychainController: KeychainControllerMock(),
|
||||||
appSettings: ServiceLocator.shared.settings),
|
appSettings: ServiceLocator.shared.settings),
|
||||||
bugReportService: BugReportServiceMock(),
|
bugReportService: BugReportServiceMock(),
|
||||||
roomTimelineControllerFactory: MockRoomTimelineControllerFactory(),
|
roomTimelineControllerFactory: MockRoomTimelineControllerFactory(),
|
||||||
appSettings: appSettings,
|
appSettings: appSettings,
|
||||||
analytics: ServiceLocator.shared.analytics)
|
analytics: ServiceLocator.shared.analytics)
|
||||||
|
|
||||||
coordinator.start()
|
flowCoordinator.start()
|
||||||
|
|
||||||
retainedState.append(coordinator)
|
retainedState.append(flowCoordinator)
|
||||||
|
|
||||||
return navigationSplitCoordinator
|
return navigationSplitCoordinator
|
||||||
case .roomDetailsScreen:
|
case .roomDetailsScreen:
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a030e3bae9b20079e98682c35a8fb18a2016c57e6fc2541e808408b4eee56346
|
oid sha256:d29521672f8d636c5c3f44424d72f93f2e827360d14ec6500e881c885e91a7ed
|
||||||
size 126288
|
size 132888
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:646ab427a87537496aca2498a646c554779aafe402fbf68ee7836edd8737e39f
|
oid sha256:36c87320366601556a66eb27330a4a0318394717a4498b2d583258777df4868b
|
||||||
size 192564
|
size 197037
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a17e180923e77c0a8e156f4c5410833f2c5d449d53e4589d4940d67bf8d27fb7
|
oid sha256:f3669c7652d24c0397d9b2954fa44114b280d44afebc5bf94f948349572500c7
|
||||||
size 198747
|
size 204790
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:529a0ff29bda2dfa01be74109e2bfa3d69ec6fa9941db0c4fc24d4396cd6e482
|
oid sha256:8278f60d55de91a6380989a5fc6c7286f005e28ae0652a3b9a1ec1447fcdf562
|
||||||
size 168109
|
size 172368
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:41ea4ea40a7130c845aaa750bf0fd5622a3c6f7196a4e750196be07159df161c
|
oid sha256:f3bc350a472366c1b5d0ee816760d4d5796f8a38a70f1cb0126c8929c5cbaf5b
|
||||||
size 167036
|
size 173275
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:56e8df51695c554dbc19bc80e2f004a584451927ce0f9c38847c706946ff79c7
|
oid sha256:836341a4506378018e653208c02fd35477aaa1fe86f4c7965f911f5f3004a4d4
|
||||||
size 207411
|
size 190903
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9505d4872ab00c16afdbd91245bd8ed3ba43b928080a0fa9ca467ef64356c689
|
oid sha256:0340b1504e92350ffcee66aa393057a211b47f9a012fd2f2fbd63a8b849121d8
|
||||||
size 214258
|
size 196998
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9f5afc62779254c8432eefa058690e00ce1709507a3b2d5b19574b574d2ae53f
|
oid sha256:bc57a02c6148f559e3cf7e18840d4f4e9a06bc96753f2d5f632c162965e0795b
|
||||||
size 241787
|
size 249420
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:96793f47feb3746e6630dc1fe387574a020a091ff2d8482202300083897cdb62
|
oid sha256:509d3539b0ff0c9a46b5756605f61160ce1becb06b8e69eca3d8b5fbf43e86e4
|
||||||
size 164437
|
size 168405
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0962939d9e4e25e58de95247810e1e392f1793733104822c7fa10aaa93ea47ce
|
oid sha256:69c6584e25a26adee6f23b4d68ef75ab29a99d4196322b39bd024d738511e8ac
|
||||||
size 228989
|
size 234152
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0dfcaf6c963c8ddf79d3f40906b0e499a0aab4f1efacb96ab21f904688f73b69
|
oid sha256:d33c61f7e7cf6a1b17019967364cc65f3cd152c6d7f67c19744b9f8ab96523da
|
||||||
size 234890
|
size 239805
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:3f73d9fcff69d33d95e645fee81328b9981cdb8eca44ae9c178b3df15a24966e
|
oid sha256:93e656155b8811e71e332fb357e934c54afe8fcdba7bfad440f5fb0d800027a3
|
||||||
size 202922
|
size 207913
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9193d085cf66079ca1db4e67cdc2f74c1884102a6957cac4f0f50c5e78166d49
|
oid sha256:fe78b8687073c5909126ada93ae8dea86417baa84de897fb6bf0a8b622737a1b
|
||||||
size 236203
|
size 242210
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e22ac126938c1924a1027559a6656e454d0223aea326548fefa210f1b31161e4
|
oid sha256:e795ccedbac57cc9beeed357268e54ba57266edeb4f7e40e555f6678c009432b
|
||||||
size 214293
|
size 219856
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4a7546c4e537da63b57b5afe1ef527a62ab9de67a636c74857152798f6f8a09c
|
oid sha256:3b6f3d8a34cfe9f3767cadc7cba72d4c4d52447916d45d637863fee88198ec85
|
||||||
size 220086
|
size 227116
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:6a5d47938ca196eb361632bf3956797c18f5ad4ddeb277eb915712e778f630a6
|
oid sha256:f34624eec2f6c815176dd140f1a84c0faa4d2982fe29f2f44977f25145301d3f
|
||||||
size 294756
|
size 288460
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:29d00818b332c8c1c33c8540099fe41ffaa45a70c3df28959819f841f005d6c7
|
oid sha256:bb8091f6bc6eb52326bdf97886fe65b5ee05a79dbcdcd9a932fe376b0daa2d18
|
||||||
size 176727
|
size 183696
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:99253b776ad880042ed56f785b4112ebbe00cc8c6ee12758416a127d19385aeb
|
oid sha256:3702bb587932d15ade8a69fb01eb24a7a8e4603b58b16eec628abca50c069902
|
||||||
size 268418
|
size 274343
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Enable log previewing before reporting a problem
|
||||||
Reference in New Issue
Block a user