Key backup returns (#1951)
* Converge on UserSessionFlowCoordinator logout confirmation * Add logout confirmation screen strings to untranslated. * Fix chat backup learn more URl fragment. * Implement logout flows that check recovery and key backup for the last session * Move logout confirmation screen strings to localazy * Change encrypted timeline item copy to "Waiting for decryption key" * Use different encrypted history banner based on key backup states * Introduce a SettingsFlowCoordinator and implement navigation directly to the secure backup screen from the logout flows. * Fix **mocked** secure backup controller flows * Simplify encrypted history banner logic * Address PR comments
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -93,6 +93,7 @@
|
||||
1795EA6A6C4942CAE0459DF0 /* SecureBackupKeyBackupScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82B612853BFB68373249777B /* SecureBackupKeyBackupScreenViewModel.swift */; };
|
||||
17BC15DA08A52587466698C5 /* RoomMessageEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */; };
|
||||
1830E5431DB426E2F3660D58 /* NotificationSettingsEditScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F52419AEEDA2C006CB7181 /* NotificationSettingsEditScreenUITests.swift */; };
|
||||
184D68B82AE7A01400141160 /* SettingsFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184D68B72AE7A01400141160 /* SettingsFlowCoordinator.swift */; };
|
||||
18867F4F1C8991EEC56EA932 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
|
||||
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; };
|
||||
19DED23340D0855B59693ED2 /* VoiceMessageRecorderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45C9EAA86423D7D3126DE4F /* VoiceMessageRecorderProtocol.swift */; };
|
||||
@@ -326,6 +327,7 @@
|
||||
5992EF10AA157EBD97D88910 /* AudioRecorderState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6569593FA36B22259E806A67 /* AudioRecorderState.swift */; };
|
||||
5995C63B1C61DE1373AA2BCE /* ComposerToolbarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95B3714F806AC9CF9A557B /* ComposerToolbarViewModel.swift */; };
|
||||
59F940FCBE6BC343AECEF75E /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E2245243369B99216C7D84E /* ImageCache.swift */; };
|
||||
5AE6404C4FD4848ACCFF9EDC /* SecureBackupLogoutConfirmationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1573D28C8A9FB6399D0EEFB /* SecureBackupLogoutConfirmationScreenCoordinator.swift */; };
|
||||
5B2D1210B40570D87B11BD3B /* ThreadDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA3F8E905DF50BF22ECC18F /* ThreadDecorator.swift */; };
|
||||
5B6E5AD224509E6C0B520D6E /* RoomMemberDetailsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDF49CEBC0DFC59C308335F /* RoomMemberDetailsScreenViewModelProtocol.swift */; };
|
||||
5BC6C4ADFE7F2A795ECDE130 /* SecureBackupKeyBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */; };
|
||||
@@ -541,6 +543,7 @@
|
||||
91ABC91758A6E4A5FAA2E9C4 /* ReadReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 314F1C79850BE46E8ABEAFCB /* ReadReceipt.swift */; };
|
||||
92133B170A1F917685E9FF78 /* OnboardingScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D168471461717AF5689F64B /* OnboardingScreenUITests.swift */; };
|
||||
9219640F4D980CFC5FE855AD /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 536E72DCBEEC4A1FE66CFDCE /* target.yml */; };
|
||||
92720AB0DA9AB5EEF1DAF56B /* SecureBackupLogoutConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DC017C3CB6B0F7C63F460F2 /* SecureBackupLogoutConfirmationScreenViewModel.swift */; };
|
||||
92D9088B901CEBB1A99ECA4E /* RoomMemberProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */; };
|
||||
93875ADD456142D20823ED24 /* ServerSelectionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */; };
|
||||
93A549135E6C027A0D823BFE /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 593FBBF394712F2963E98A0B /* DTCoreText */; };
|
||||
@@ -689,6 +692,7 @@
|
||||
B5903E48CF43259836BF2DBF /* EncryptedRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56C1BCB9E83B09A45387FCA2 /* EncryptedRoomTimelineView.swift */; };
|
||||
B5E455C9689EA600EDB3E9E0 /* NavigationRootCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA28F29C9F93E93CC3C2C715 /* NavigationRootCoordinator.swift */; };
|
||||
B6048166B4AA4CEFEA9B77A6 /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
|
||||
B6064D82FCDCB829601C1F59 /* SecureBackupLogoutConfirmationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FEE10AB666891E6A675E5E /* SecureBackupLogoutConfirmationScreen.swift */; };
|
||||
B64C9BCE61E77D578D40D689 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 232F7D3C19F1FEF0E0450110 /* MatrixRustSDK */; };
|
||||
B659E3A49889E749E3239EA7 /* MockMediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6E621CC5E6D4830D96D2D /* MockMediaProvider.swift */; };
|
||||
B66757D0254843162595B25D /* MXLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = A34A814CBD56230BC74FFCF4 /* MXLogger.swift */; };
|
||||
@@ -790,7 +794,9 @@
|
||||
CF4044A8EED5C41BC0ED6ABE /* SoftLogoutScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D316BB02636AF2174F2580E6 /* SoftLogoutScreenViewModelProtocol.swift */; };
|
||||
CFEC53440C572CEEABC4A6A0 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; };
|
||||
D02AA6208C7ACB9BE6332394 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; };
|
||||
D050D7756E92CA061ED0ABF0 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */; };
|
||||
D0550B8E0AE2C0CDBE52C88F /* MediaPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */; };
|
||||
D0A965852D6C04138FA55181 /* SecureBackupLogoutConfirmationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */; };
|
||||
D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */; };
|
||||
D181AC8FF236B7F91C0A8C28 /* MapTiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23AA3F4B285570805CB0CCDD /* MapTiler.swift */; };
|
||||
D19A748E95E2FAB2940570F0 /* CallScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4103AB4340F2974D690A12A /* CallScreen.swift */; };
|
||||
@@ -883,6 +889,7 @@
|
||||
EA974337FA7D040E7C74FE6E /* RoomDetailsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EFE1922F39398ABFB36DF3F /* RoomDetailsViewModelTests.swift */; };
|
||||
EAC6FE2CD4F50A43068ADCD8 /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 997C7385E1A07E061D7E2100 /* GZIP */; };
|
||||
EAF2B3E6C6AEC4AD3A8BD454 /* RoomMemberDetailsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A87D0471D438A233C2CF4A /* RoomMemberDetailsScreenViewModel.swift */; };
|
||||
EB87DF90CF6F8D5D12404C6E /* SecureBackupLogoutConfirmationScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848F69921527D31CAACB93AF /* SecureBackupLogoutConfirmationScreenViewModelTests.swift */; };
|
||||
EB88DBD77221E2CFE463018C /* NSE.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0D8F620C8B314840D8602E3F /* NSE.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
EBDB339A7C127F068B6E52E5 /* VoiceMessageRecordingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A634D8DD1E10D858CF7995D /* VoiceMessageRecordingView.swift */; };
|
||||
EBE13FAB4E29738AC41BD3E5 /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
|
||||
@@ -918,6 +925,7 @@
|
||||
F3E2D3F7ACDED65A4E5CD8DE /* RoomMembersListScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */; };
|
||||
F3F38062C6CA21CF403C5C90 /* AudioConverterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2757B1BE23DF8AA239937243 /* AudioConverterProtocol.swift */; };
|
||||
F40B097470D3110DFDB1FAAA /* LegalInformationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47873756E45B46683D97DC32 /* LegalInformationScreenModels.swift */; };
|
||||
F421FD5979EF53C8204BDC77 /* SecureBackupLogoutConfirmationScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC09F30B0E1010951952BDC /* SecureBackupLogoutConfirmationScreenUITests.swift */; };
|
||||
F4433EF57B4BB3C077F8B00E /* SessionVerificationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADD9E0FFA29EAACFF3AB9732 /* SessionVerificationScreenViewModel.swift */; };
|
||||
F508683B76EF7B23BB2CBD6D /* TimelineItemPlainStylerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94BCC8A9C73C1F838122C645 /* TimelineItemPlainStylerView.swift */; };
|
||||
F519DE17A3A0F760307B2E6D /* InviteUsersScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D155E09BF961BBA8F85263 /* InviteUsersScreenViewModel.swift */; };
|
||||
@@ -1079,7 +1087,7 @@
|
||||
127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = "<group>"; };
|
||||
12EDAFB64FA5F6812D54F39A /* MigrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
12F1E7F9C2BE8BB751037826 /* WaitlistScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
|
||||
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
|
||||
130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; };
|
||||
13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
1423AB065857FA546444DB15 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
||||
@@ -1095,6 +1103,7 @@
|
||||
1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalyticsClient.swift; sourceTree = "<group>"; };
|
||||
1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationTests.swift; sourceTree = "<group>"; };
|
||||
184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
||||
184D68B72AE7A01400141160 /* SettingsFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFlowCoordinator.swift; sourceTree = "<group>"; };
|
||||
1877038D1AD3D5A029F8AE2C /* TimelineReadReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReadReceiptsView.swift; sourceTree = "<group>"; };
|
||||
18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxy.swift; sourceTree = "<group>"; };
|
||||
18FE0CDF1FFA92EA7EE17B0B /* RoomTimelineControllerFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerFactoryProtocol.swift; sourceTree = "<group>"; };
|
||||
@@ -1115,6 +1124,7 @@
|
||||
1B8E176484A89BAC389D4076 /* RoomMembersListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreen.swift; sourceTree = "<group>"; };
|
||||
1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxyProtocol.swift; sourceTree = "<group>"; };
|
||||
1C21A715237F2B6D6E80998C /* SecureBackupControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerProtocol.swift; sourceTree = "<group>"; };
|
||||
1CC09F30B0E1010951952BDC /* SecureBackupLogoutConfirmationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenUITests.swift; sourceTree = "<group>"; };
|
||||
1CC575D1895FA62591451A93 /* RoomMemberDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreen.swift; sourceTree = "<group>"; };
|
||||
1D56469A9EE0CFA2B7BA9760 /* SessionVerificationControllerProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationControllerProxyProtocol.swift; sourceTree = "<group>"; };
|
||||
1D67E616BCA82D8A1258D488 /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = "<group>"; };
|
||||
@@ -1205,6 +1215,7 @@
|
||||
37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringTests.swift; sourceTree = "<group>"; };
|
||||
37E727F7E0BCE8A0BBFD33FF /* OnboardingScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
37FEE10AB666891E6A675E5E /* SecureBackupLogoutConfirmationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreen.swift; sourceTree = "<group>"; };
|
||||
382B50F7E379B3DBBD174364 /* NotificationSettingsProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxyMock.swift; sourceTree = "<group>"; };
|
||||
38345442415E07A931197C55 /* AppLockScreenPINKeypad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenPINKeypad.swift; sourceTree = "<group>"; };
|
||||
38E521D6C2BF8DF0DFB35146 /* DeveloperOptionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreen.swift; sourceTree = "<group>"; };
|
||||
@@ -1413,6 +1424,7 @@
|
||||
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>"; };
|
||||
74DD0855F2F76D47E5555082 /* MediaUploadPreviewScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
752A0EB49BF5BCEA37EDF7A3 /* Signposter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signposter.swift; sourceTree = "<group>"; };
|
||||
75697AB5E64A12F1F069F511 /* EncryptedHistoryRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
75910F5A36EA8FF9BAD08D18 /* MigrationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenUITests.swift; sourceTree = "<group>"; };
|
||||
@@ -1435,6 +1447,7 @@
|
||||
7CA3F8E905DF50BF22ECC18F /* ThreadDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDecorator.swift; sourceTree = "<group>"; };
|
||||
7D0CBC76C80E04345E11F2DB /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||
7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactoryProtocol.swift; sourceTree = "<group>"; };
|
||||
7DC017C3CB6B0F7C63F460F2 /* SecureBackupLogoutConfirmationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
7DDBF99755A9008CF8C8499E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
7DDF49CEBC0DFC59C308335F /* RoomMemberDetailsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
7E492690C8B27A892C194CC4 /* AdvancedSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
@@ -1455,6 +1468,7 @@
|
||||
840E86A67DB2C92C09771EAD /* AnalyticsPromptScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenModels.swift; sourceTree = "<group>"; };
|
||||
845DDBDE5A0887E73D38B826 /* InviteUsersViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersViewModelTests.swift; sourceTree = "<group>"; };
|
||||
84816E0D2F34E368BF64FA60 /* SessionVerificationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreen.swift; sourceTree = "<group>"; };
|
||||
848F69921527D31CAACB93AF /* SecureBackupLogoutConfirmationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||
84A00BB9CD12CF6AC98D5485 /* SecureBackupScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreen.swift; sourceTree = "<group>"; };
|
||||
84A87D0471D438A233C2CF4A /* RoomMemberDetailsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
84B7A28A6606D58D1E38C55A /* ExpiringTaskRunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpiringTaskRunnerTests.swift; sourceTree = "<group>"; };
|
||||
@@ -1489,7 +1503,7 @@
|
||||
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
|
||||
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = "<group>"; };
|
||||
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; };
|
||||
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = "<group>"; };
|
||||
8E1BBA73B611EDEEA6E20E05 /* InvitesScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenModels.swift; sourceTree = "<group>"; };
|
||||
8EC57A32ABC80D774CC663DB /* SettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenUITests.swift; sourceTree = "<group>"; };
|
||||
8F21ED7205048668BEB44A38 /* AppActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppActivityView.swift; sourceTree = "<group>"; };
|
||||
@@ -1624,7 +1638,7 @@
|
||||
B4CFE236419E830E8946639C /* Analytics+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Analytics+SwiftUI.swift"; sourceTree = "<group>"; };
|
||||
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; };
|
||||
B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; };
|
||||
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = "<group>"; };
|
||||
B6311F21F911E23BE4DF51B4 /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
B697816AF93DA06EC58C5D70 /* WaitlistScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
@@ -1727,7 +1741,7 @@
|
||||
CD95B3714F806AC9CF9A557B /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; };
|
||||
CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = "<group>"; };
|
||||
CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
|
||||
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; };
|
||||
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
|
||||
CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; sourceTree = "<group>"; };
|
||||
D0140615D2232612C813FD6C /* EncryptedHistoryRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||
D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = "<group>"; };
|
||||
@@ -1777,6 +1791,7 @@
|
||||
DBFEAC3AC691CBB84983E275 /* ElementXTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementXTests.swift; sourceTree = "<group>"; };
|
||||
DC0AEA686E425F86F6BA0404 /* UNNotification+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNNotification+Creator.swift"; sourceTree = "<group>"; };
|
||||
DC10CCC8D68B863E20660DBC /* MessageForwardingScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = "<group>"; };
|
||||
DD97F9661ABF08CE002054A2 /* AppLockServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceTests.swift; sourceTree = "<group>"; };
|
||||
DE846DDA83BFD7EC5C03760B /* ServerConfirmationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenUITests.swift; sourceTree = "<group>"; };
|
||||
DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaFileHandleProxy.swift; sourceTree = "<group>"; };
|
||||
@@ -1784,6 +1799,7 @@
|
||||
DF3D25B3EDB283B5807EADCF /* ReadMarkerRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||
E062C1750EFC8627DE4CAB8E /* MapTilerAuthorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerAuthorization.swift; sourceTree = "<group>"; };
|
||||
E0FCA0957FAA0E15A9F5579D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Untranslated.stringsdict; sourceTree = "<group>"; };
|
||||
E1573D28C8A9FB6399D0EEFB /* SecureBackupLogoutConfirmationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenCoordinator.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>"; };
|
||||
E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarSize.swift; sourceTree = "<group>"; };
|
||||
@@ -1827,7 +1843,7 @@
|
||||
ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; };
|
||||
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
||||
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; };
|
||||
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = "<group>"; };
|
||||
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; };
|
||||
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
||||
@@ -1842,7 +1858,7 @@
|
||||
F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenModels.swift; sourceTree = "<group>"; };
|
||||
F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = "<group>"; };
|
||||
F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||
F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = "<group>"; };
|
||||
F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = "<group>"; };
|
||||
F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; };
|
||||
F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||
F36C0A6D59717193F49EA986 /* UserSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionTests.swift; sourceTree = "<group>"; };
|
||||
@@ -2279,6 +2295,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B1FD4FD6CEB987AE274AEEE5 /* SecureBackupKeyBackupScreen */,
|
||||
63E514D74481A3D9556DFFC3 /* SecureBackupLogoutConfirmationScreen */,
|
||||
6E8F16377AD462BBD4951271 /* SecureBackupRecoveryKeyScreen */,
|
||||
3B4C46F36A42B42C4EB14933 /* SecureBackupScreen */,
|
||||
);
|
||||
@@ -2901,6 +2918,7 @@
|
||||
9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */,
|
||||
C99FDEEB71173C4C6FA2734C /* UserSessionFlowCoordinator.swift */,
|
||||
E8774CF614849664B5B3C2A1 /* UserSessionFlowCoordinatorStateMachine.swift */,
|
||||
184D68B72AE7A01400141160 /* SettingsFlowCoordinator.swift */,
|
||||
);
|
||||
path = FlowCoordinators;
|
||||
sourceTree = "<group>";
|
||||
@@ -2954,6 +2972,18 @@
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
63E514D74481A3D9556DFFC3 /* SecureBackupLogoutConfirmationScreen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E1573D28C8A9FB6399D0EEFB /* SecureBackupLogoutConfirmationScreenCoordinator.swift */,
|
||||
DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */,
|
||||
7DC017C3CB6B0F7C63F460F2 /* SecureBackupLogoutConfirmationScreenViewModel.swift */,
|
||||
74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */,
|
||||
FB4987F1C660F2085258866B /* View */,
|
||||
);
|
||||
path = SecureBackupLogoutConfirmationScreen;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
669239C03835CD8B51E0FFDB /* AnalyticsPromptScreen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -3179,6 +3209,7 @@
|
||||
93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */,
|
||||
AEEAFB646E583655652C3D04 /* RoomStateEventStringBuilderTests.swift */,
|
||||
2E88534A39781D76487D59DF /* SecureBackupKeyBackupScreenViewModelTests.swift */,
|
||||
848F69921527D31CAACB93AF /* SecureBackupLogoutConfirmationScreenViewModelTests.swift */,
|
||||
C0FF08D0BD7D0B4B6877AB7D /* SecureBackupRecoveryKeyScreenViewModelTests.swift */,
|
||||
40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */,
|
||||
277C20CDD5B64510401B6D0D /* ServerConfigurationScreenViewStateTests.swift */,
|
||||
@@ -3645,6 +3676,7 @@
|
||||
66901977F6469D03C333DF32 /* RoomNotificationSettingsScreenUITests.swift */,
|
||||
086B997409328F091EBA43CE /* RoomScreenUITests.swift */,
|
||||
58DCB219D7B7B0299358FF81 /* SecureBackupKeyBackupScreenUITests.swift */,
|
||||
1CC09F30B0E1010951952BDC /* SecureBackupLogoutConfirmationScreenUITests.swift */,
|
||||
FDBA358C79F0DCBC4FA14A88 /* SecureBackupRecoveryKeyScreenUITests.swift */,
|
||||
91831D7042EADD0CC2B5EC36 /* SecureBackupScreenUITests.swift */,
|
||||
DE846DDA83BFD7EC5C03760B /* ServerConfirmationScreenUITests.swift */,
|
||||
@@ -4544,6 +4576,14 @@
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB4987F1C660F2085258866B /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37FEE10AB666891E6A675E5E /* SecureBackupLogoutConfirmationScreen.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FCDF06BDB123505F0334B4F9 /* Timeline */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -5136,6 +5176,7 @@
|
||||
46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */,
|
||||
CC0D088F505F33A20DC5590F /* RoomStateEventStringBuilderTests.swift in Sources */,
|
||||
7691233E3572A9173FD96CB3 /* SecureBackupKeyBackupScreenViewModelTests.swift in Sources */,
|
||||
EB87DF90CF6F8D5D12404C6E /* SecureBackupLogoutConfirmationScreenViewModelTests.swift in Sources */,
|
||||
06B31F84CE52A7A7C271267C /* SecureBackupRecoveryKeyScreenViewModelTests.swift in Sources */,
|
||||
1B8E30B35BF8F541C1318F19 /* SecureBackupScreenViewModelTests.swift in Sources */,
|
||||
53A55748D5F587C9061F98BF /* ServerConfigurationScreenViewStateTests.swift in Sources */,
|
||||
@@ -5351,6 +5392,7 @@
|
||||
2C5E832434EE94E21AB3B238 /* EmojiPickerScreenViewModel.swift in Sources */,
|
||||
1D69E31913DF66426985909B /* EmojiPickerScreenViewModelProtocol.swift in Sources */,
|
||||
FBF09B6C900415800DDF2A21 /* EmojiProvider.swift in Sources */,
|
||||
184D68B82AE7A01400141160 /* SettingsFlowCoordinator.swift in Sources */,
|
||||
5D27B6537591471A42C89027 /* EmoteRoomTimelineItem.swift in Sources */,
|
||||
8B41D0357B91CD3B6F6A3BCA /* EmoteRoomTimelineItemContent.swift in Sources */,
|
||||
68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */,
|
||||
@@ -5656,6 +5698,11 @@
|
||||
B7888FC1E1DEF816D175C8D6 /* SecureBackupKeyBackupScreenModels.swift in Sources */,
|
||||
1795EA6A6C4942CAE0459DF0 /* SecureBackupKeyBackupScreenViewModel.swift in Sources */,
|
||||
A4C29D373986AFE4559696D5 /* SecureBackupKeyBackupScreenViewModelProtocol.swift in Sources */,
|
||||
B6064D82FCDCB829601C1F59 /* SecureBackupLogoutConfirmationScreen.swift in Sources */,
|
||||
5AE6404C4FD4848ACCFF9EDC /* SecureBackupLogoutConfirmationScreenCoordinator.swift in Sources */,
|
||||
D0A965852D6C04138FA55181 /* SecureBackupLogoutConfirmationScreenModels.swift in Sources */,
|
||||
92720AB0DA9AB5EEF1DAF56B /* SecureBackupLogoutConfirmationScreenViewModel.swift in Sources */,
|
||||
D050D7756E92CA061ED0ABF0 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift in Sources */,
|
||||
FA71CD334F2D2289BEF0D749 /* SecureBackupRecoveryKeyScreen.swift in Sources */,
|
||||
B1387648C6F71F1B98244803 /* SecureBackupRecoveryKeyScreenCoordinator.swift in Sources */,
|
||||
8AA84EF202F2EFC8453A97BD /* SecureBackupRecoveryKeyScreenModels.swift in Sources */,
|
||||
@@ -5874,6 +5921,7 @@
|
||||
06AA515C7053FD7E17A5CF81 /* RoomNotificationSettingsScreenUITests.swift in Sources */,
|
||||
2F1CF90A3460C153154427F0 /* RoomScreenUITests.swift in Sources */,
|
||||
A743841F91B62B0E56217B04 /* SecureBackupKeyBackupScreenUITests.swift in Sources */,
|
||||
F421FD5979EF53C8204BDC77 /* SecureBackupLogoutConfirmationScreenUITests.swift in Sources */,
|
||||
FC4F6BA083A64840B38CE269 /* SecureBackupRecoveryKeyScreenUITests.swift in Sources */,
|
||||
8C42B5B1642D189C362A5EDF /* SecureBackupScreenUITests.swift in Sources */,
|
||||
A1D4033881320C9EB88196E6 /* ServerConfirmationScreenUITests.swift in Sources */,
|
||||
|
||||
@@ -438,7 +438,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .signOut:
|
||||
case .logout:
|
||||
stateMachine.processEvent(.signOut(isSoft: false))
|
||||
case .clearCache:
|
||||
stateMachine.processEvent(.clearCache)
|
||||
|
||||
@@ -118,7 +118,7 @@ final class AppSettings {
|
||||
/// An email address that should be used for support requests.
|
||||
let supportEmailAddress = "support@element.io"
|
||||
// A URL where users can go read more about the chat backup.
|
||||
let chatBackupDetailsURL: URL = "https://element.io/help#encryption"
|
||||
let chatBackupDetailsURL: URL = "https://element.io/help#encryption5"
|
||||
|
||||
// MARK: - Security
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ enum AppRoute: Equatable {
|
||||
case roomMemberDetails(userID: String)
|
||||
case invites
|
||||
case genericCallLink(url: URL)
|
||||
case settings
|
||||
case chatBackupSettings
|
||||
}
|
||||
|
||||
struct AppRouteURLParser {
|
||||
|
||||
@@ -106,9 +106,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
MXLog.error("[RoomFlowCoordinator] Failed to get member: RoomProxy is nil")
|
||||
}
|
||||
}
|
||||
case .invites:
|
||||
break
|
||||
case .genericCallLink, .oidcCallback:
|
||||
case .invites, .genericCallLink, .oidcCallback, .settings, .chatBackupSettings:
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -347,7 +345,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: userSession.mediaProvider,
|
||||
mediaPlayerProvider: mediaPlayerProvider,
|
||||
voiceMessageMediaManager: userSession.voiceMessageMediaManager)
|
||||
voiceMessageMediaManager: userSession.voiceMessageMediaManager,
|
||||
secureBackupController: userSession.clientProxy.secureBackupController)
|
||||
self.timelineController = timelineController
|
||||
|
||||
analytics.trackViewRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace)
|
||||
|
||||
135
ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift
Normal file
135
ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift
Normal file
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// Copyright 2023 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 Foundation
|
||||
|
||||
enum SettingsFlowCoordinatorAction {
|
||||
case presentedSettings
|
||||
case dismissedSettings
|
||||
case runLogoutFlow
|
||||
case clearCache
|
||||
}
|
||||
|
||||
struct SettingsFlowCoordinatorParameters {
|
||||
let userSession: UserSessionProtocol
|
||||
let appLockService: AppLockServiceProtocol
|
||||
let bugReportService: BugReportServiceProtocol
|
||||
let notificationSettings: NotificationSettingsProxyProtocol
|
||||
let secureBackupController: SecureBackupControllerProtocol
|
||||
let appSettings: AppSettings
|
||||
let navigationSplitCoordinator: NavigationSplitCoordinator
|
||||
}
|
||||
|
||||
class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let parameters: SettingsFlowCoordinatorParameters
|
||||
|
||||
private var navigationStackCoordinator: NavigationStackCoordinator!
|
||||
private var userIndicatorController: UserIndicatorControllerProtocol!
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
private let actionsSubject: PassthroughSubject<SettingsFlowCoordinatorAction, Never> = .init()
|
||||
var actions: AnyPublisher<SettingsFlowCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(parameters: SettingsFlowCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
}
|
||||
|
||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||
switch appRoute {
|
||||
case .settings:
|
||||
presentSettingsScreen(animated: animated)
|
||||
case .chatBackupSettings:
|
||||
if navigationStackCoordinator == nil {
|
||||
presentSettingsScreen(animated: animated)
|
||||
}
|
||||
|
||||
// The navigation stack doesn't like it if the root and the push happen
|
||||
// on the same loop run
|
||||
DispatchQueue.main.async {
|
||||
self.presentSecureBackupScreen(animated: animated)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func clearRoute(animated: Bool) { }
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func presentSettingsScreen(animated: Bool) {
|
||||
navigationStackCoordinator = NavigationStackCoordinator()
|
||||
|
||||
userIndicatorController = UserIndicatorController(rootCoordinator: navigationStackCoordinator)
|
||||
|
||||
let parameters = SettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator,
|
||||
userIndicatorController: userIndicatorController,
|
||||
userSession: parameters.userSession,
|
||||
appLockService: parameters.appLockService,
|
||||
bugReportService: parameters.bugReportService,
|
||||
notificationSettings: parameters.userSession.clientProxy.notificationSettings,
|
||||
secureBackupController: parameters.userSession.clientProxy.secureBackupController,
|
||||
appSettings: parameters.appSettings)
|
||||
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters)
|
||||
|
||||
settingsScreenCoordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .dismiss:
|
||||
self.parameters.navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
case .logout:
|
||||
self.parameters.navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
|
||||
// The settings sheet needs to be dismissed before the alert can be shown
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.actionsSubject.send(.runLogoutFlow)
|
||||
}
|
||||
case .clearCache:
|
||||
actionsSubject.send(.clearCache)
|
||||
case .secureBackup:
|
||||
presentSecureBackupScreen(animated: true)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationStackCoordinator.setRootCoordinator(settingsScreenCoordinator, animated: animated)
|
||||
|
||||
self.parameters.navigationSplitCoordinator.setSheetCoordinator(userIndicatorController) { [weak self] in
|
||||
guard let self else { return }
|
||||
|
||||
navigationStackCoordinator = nil
|
||||
userIndicatorController = nil
|
||||
actionsSubject.send(.dismissedSettings)
|
||||
}
|
||||
|
||||
actionsSubject.send(.presentedSettings)
|
||||
}
|
||||
|
||||
private func presentSecureBackupScreen(animated: Bool) {
|
||||
let coordinator = SecureBackupScreenCoordinator(parameters: .init(appSettings: parameters.appSettings,
|
||||
secureBackupController: parameters.userSession.clientProxy.secureBackupController,
|
||||
navigationStackCoordinator: navigationStackCoordinator,
|
||||
userIndicatorController: userIndicatorController))
|
||||
|
||||
navigationStackCoordinator.push(coordinator, animated: animated)
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import Combine
|
||||
import SwiftUI
|
||||
|
||||
enum UserSessionFlowCoordinatorAction {
|
||||
case signOut
|
||||
case logout
|
||||
case clearCache
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
private let stateMachine: UserSessionFlowCoordinatorStateMachine
|
||||
private let roomFlowCoordinator: RoomFlowCoordinator
|
||||
private let settingsFlowCoordinator: SettingsFlowCoordinator
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
private var migrationCancellable: AnyCancellable?
|
||||
@@ -76,11 +77,20 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
appSettings: appSettings,
|
||||
analytics: analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
settingsFlowCoordinator = SettingsFlowCoordinator(parameters: .init(userSession: userSession,
|
||||
appLockService: appLockService,
|
||||
bugReportService: bugReportService,
|
||||
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||
secureBackupController: userSession.clientProxy.secureBackupController,
|
||||
appSettings: appSettings,
|
||||
navigationSplitCoordinator: navigationSplitCoordinator))
|
||||
|
||||
setupStateMachine()
|
||||
|
||||
roomFlowCoordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .presentedRoom(let roomID):
|
||||
analytics.signpost.beginRoomFlow(roomID)
|
||||
@@ -93,6 +103,22 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
settingsFlowCoordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .presentedSettings:
|
||||
stateMachine.processEvent(.showSettingsScreen)
|
||||
case .dismissedSettings:
|
||||
stateMachine.processEvent(.dismissedSettingsScreen)
|
||||
case .runLogoutFlow:
|
||||
runLogoutFlow()
|
||||
case .clearCache:
|
||||
actionsSubject.send(.clearCache)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func start() {
|
||||
@@ -131,6 +157,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self.navigationSplitCoordinator.setSheetCoordinator(GenericCallLinkCoordinator(parameters: .init(url: url)), animated: animated)
|
||||
case .oidcCallback:
|
||||
break
|
||||
case .settings, .chatBackupSettings:
|
||||
settingsFlowCoordinator.handleAppRoute(appRoute, animated: animated)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,7 +221,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
break
|
||||
|
||||
case (.roomList, .showSettingsScreen, .settingsScreen):
|
||||
presentSettingsScreen(animated: animated)
|
||||
break
|
||||
case (.settingsScreen, .dismissedSettingsScreen, .roomList):
|
||||
break
|
||||
|
||||
@@ -211,7 +239,12 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
presentInvitesList(animated: animated)
|
||||
case (.invitesScreen, .showInvitesScreen, .invitesScreen):
|
||||
break
|
||||
case (.invitesScreen, .closedInvitesScreen, .roomList):
|
||||
case (.invitesScreen, .dismissedInvitesScreen, .roomList):
|
||||
break
|
||||
|
||||
case (.roomList, .showLogoutConfirmationScreen, .logoutConfirmationScreen):
|
||||
presentSecureBackupConfirmationScreen()
|
||||
case (.logoutConfirmationScreen, .dismissedLogoutConfirmationScreen, .roomList):
|
||||
break
|
||||
|
||||
default:
|
||||
@@ -288,15 +321,15 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
roomFlowCoordinator.handleAppRoute(.roomList, animated: true)
|
||||
}
|
||||
case .presentSettingsScreen:
|
||||
stateMachine.processEvent(.showSettingsScreen)
|
||||
settingsFlowCoordinator.handleAppRoute(.settings, animated: true)
|
||||
case .presentFeedbackScreen:
|
||||
stateMachine.processEvent(.feedbackScreen)
|
||||
case .presentSessionVerificationScreen:
|
||||
stateMachine.processEvent(.showSessionVerificationScreen)
|
||||
case .presentStartChatScreen:
|
||||
stateMachine.processEvent(.showStartChatScreen)
|
||||
case .signOut:
|
||||
actionsSubject.send(.signOut)
|
||||
case .logout:
|
||||
runLogoutFlow()
|
||||
case .presentInvitesScreen:
|
||||
stateMachine.processEvent(.showInvitesScreen)
|
||||
}
|
||||
@@ -321,44 +354,44 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Settings
|
||||
|
||||
private func presentSettingsScreen(animated: Bool) {
|
||||
let settingsNavigationStackCoordinator = NavigationStackCoordinator()
|
||||
private func runLogoutFlow() {
|
||||
let secureBackupController = userSession.clientProxy.secureBackupController
|
||||
|
||||
let userIndicatorController = UserIndicatorController(rootCoordinator: settingsNavigationStackCoordinator)
|
||||
|
||||
let parameters = SettingsScreenCoordinatorParameters(navigationStackCoordinator: settingsNavigationStackCoordinator,
|
||||
userIndicatorController: userIndicatorController,
|
||||
userSession: userSession,
|
||||
appLockService: appLockService,
|
||||
bugReportService: bugReportService,
|
||||
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||
secureBackupController: userSession.clientProxy.secureBackupController,
|
||||
appSettings: appSettings)
|
||||
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters)
|
||||
|
||||
settingsScreenCoordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .dismiss:
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
case .logout:
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
actionsSubject.send(.signOut)
|
||||
case .clearCache:
|
||||
actionsSubject.send(.clearCache)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
settingsNavigationStackCoordinator.setRootCoordinator(settingsScreenCoordinator, animated: animated)
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(userIndicatorController) { [weak self] in
|
||||
self?.stateMachine.processEvent(.dismissedSettingsScreen)
|
||||
guard secureBackupController.isLastSession, appSettings.chatBackupEnabled else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutRecoveryDisabledTitle,
|
||||
message: L10n.screenSignoutRecoveryDisabledSubtitle,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
guard secureBackupController.recoveryKeyState.value == .enabled else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutRecoveryDisabledTitle,
|
||||
message: L10n.screenSignoutRecoveryDisabledSubtitle,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
}, secondaryButton: .init(title: L10n.commonSettings, role: .cancel) { [weak self] in
|
||||
self?.settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
guard secureBackupController.keyBackupState.value == .enabled else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutKeyBackupDisabledTitle,
|
||||
message: L10n.screenSignoutKeyBackupDisabledSubtitle,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
}, secondaryButton: .init(title: L10n.commonSettings, role: .cancel) { [weak self] in
|
||||
self?.settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
presentSecureBackupConfirmationScreen()
|
||||
}
|
||||
|
||||
// MARK: Session verification
|
||||
@@ -457,7 +490,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
.store(in: &cancellables)
|
||||
|
||||
sidebarNavigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
|
||||
self?.stateMachine.processEvent(.closedInvitesScreen)
|
||||
self?.stateMachine.processEvent(.dismissedInvitesScreen)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,4 +512,28 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(callScreenCoordinator, animated: true)
|
||||
}
|
||||
|
||||
// MARK: Secure backup confirmation
|
||||
|
||||
private func presentSecureBackupConfirmationScreen() {
|
||||
let coordinator = SecureBackupLogoutConfirmationScreenCoordinator(parameters: .init(secureBackupController: userSession.clientProxy.secureBackupController,
|
||||
networkMonitor: ServiceLocator.shared.networkMonitor))
|
||||
|
||||
coordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .cancel:
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
case .settings:
|
||||
settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(coordinator, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
|
||||
/// Showing invites list screen
|
||||
case invitesScreen(selectedRoomID: String?)
|
||||
|
||||
// Showing the logout flows
|
||||
case logoutConfirmationScreen(selectedRoomID: String?)
|
||||
}
|
||||
|
||||
struct EventUserInfo {
|
||||
@@ -100,7 +103,12 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
/// Request presentation of the invites screen
|
||||
case showInvitesScreen
|
||||
/// The invites screen has been dismissed
|
||||
case closedInvitesScreen
|
||||
case dismissedInvitesScreen
|
||||
|
||||
/// Logout has been requested and this is the last sesion
|
||||
case showLogoutConfirmationScreen
|
||||
/// Logout has been cancelled
|
||||
case dismissedLogoutConfirmationScreen
|
||||
}
|
||||
|
||||
private let stateMachine: StateMachine<State, Event>
|
||||
@@ -157,12 +165,17 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
case (.showInvitesScreen, .invitesScreen(let selectedRoomID)):
|
||||
return .invitesScreen(selectedRoomID: selectedRoomID)
|
||||
|
||||
case (.closedInvitesScreen, .invitesScreen(let selectedRoomID)):
|
||||
case (.dismissedInvitesScreen, .invitesScreen(let selectedRoomID)):
|
||||
return .roomList(selectedRoomID: selectedRoomID)
|
||||
|
||||
case (.presentWelcomeScreen, .roomList):
|
||||
return .welcomeScreen
|
||||
|
||||
case (.showLogoutConfirmationScreen, .roomList(let selectedRoomID)):
|
||||
return .logoutConfirmationScreen(selectedRoomID: selectedRoomID)
|
||||
case (.dismissedLogoutConfirmationScreen, .logoutConfirmationScreen(let selectedRoomID)):
|
||||
return .roomList(selectedRoomID: selectedRoomID)
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -984,6 +984,24 @@ class MediaPlayerProviderMock: MediaPlayerProviderProtocol {
|
||||
await detachAllStatesExceptClosure?(exception)
|
||||
}
|
||||
}
|
||||
class NetworkMonitorMock: NetworkMonitorProtocol {
|
||||
var reachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> {
|
||||
get { return underlyingReachabilityPublisher }
|
||||
set(value) { underlyingReachabilityPublisher = value }
|
||||
}
|
||||
var underlyingReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>!
|
||||
var isCurrentConnectionExpensive: Bool {
|
||||
get { return underlyingIsCurrentConnectionExpensive }
|
||||
set(value) { underlyingIsCurrentConnectionExpensive = value }
|
||||
}
|
||||
var underlyingIsCurrentConnectionExpensive: Bool!
|
||||
var isCurrentConnectionConstrained: Bool {
|
||||
get { return underlyingIsCurrentConnectionConstrained }
|
||||
set(value) { underlyingIsCurrentConnectionConstrained = value }
|
||||
}
|
||||
var underlyingIsCurrentConnectionConstrained: Bool!
|
||||
|
||||
}
|
||||
class NotificationCenterMock: NotificationCenterProtocol {
|
||||
|
||||
//MARK: - post
|
||||
@@ -2400,6 +2418,11 @@ class SecureBackupControllerMock: SecureBackupControllerProtocol {
|
||||
set(value) { underlyingKeyBackupState = value }
|
||||
}
|
||||
var underlyingKeyBackupState: CurrentValuePublisher<SecureBackupKeyBackupState, Never>!
|
||||
var isLastSession: Bool {
|
||||
get { return underlyingIsLastSession }
|
||||
set(value) { underlyingIsLastSession = value }
|
||||
}
|
||||
var underlyingIsLastSession: Bool!
|
||||
|
||||
//MARK: - enableBackup
|
||||
|
||||
@@ -2473,6 +2496,18 @@ class SecureBackupControllerMock: SecureBackupControllerProtocol {
|
||||
return confirmRecoveryKeyReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - waitForKeyBackup
|
||||
|
||||
var waitForKeyBackupCallsCount = 0
|
||||
var waitForKeyBackupCalled: Bool {
|
||||
return waitForKeyBackupCallsCount > 0
|
||||
}
|
||||
var waitForKeyBackupClosure: (() async -> Void)?
|
||||
|
||||
func waitForKeyBackup() async {
|
||||
waitForKeyBackupCallsCount += 1
|
||||
await waitForKeyBackupClosure?()
|
||||
}
|
||||
}
|
||||
class SessionVerificationControllerProxyMock: SessionVerificationControllerProxyProtocol {
|
||||
var callbacks: PassthroughSubject<SessionVerificationControllerProxyCallback, Never> {
|
||||
|
||||
@@ -26,3 +26,6 @@ protocol NetworkMonitorProtocol {
|
||||
var isCurrentConnectionExpensive: Bool { get }
|
||||
var isCurrentConnectionConstrained: Bool { get }
|
||||
}
|
||||
|
||||
// sourcery: AutoMockable
|
||||
extension NetworkMonitorProtocol { }
|
||||
|
||||
@@ -34,7 +34,7 @@ enum HomeScreenCoordinatorAction {
|
||||
case presentSessionVerificationScreen
|
||||
case presentStartChatScreen
|
||||
case presentInvitesScreen
|
||||
case signOut
|
||||
case logout
|
||||
}
|
||||
|
||||
final class HomeScreenCoordinator: CoordinatorProtocol {
|
||||
@@ -75,8 +75,8 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.send(.presentSettingsScreen)
|
||||
case .presentSessionVerificationScreen:
|
||||
actionsSubject.send(.presentSessionVerificationScreen)
|
||||
case .signOut:
|
||||
actionsSubject.send(.signOut)
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
case .presentStartChatScreen:
|
||||
actionsSubject.send(.presentStartChatScreen)
|
||||
case .presentInvitesScreen:
|
||||
|
||||
@@ -27,13 +27,13 @@ enum HomeScreenViewModelAction {
|
||||
case presentFeedbackScreen
|
||||
case presentStartChatScreen
|
||||
case presentInvitesScreen
|
||||
case signOut
|
||||
case logout
|
||||
}
|
||||
|
||||
enum HomeScreenViewUserMenuAction {
|
||||
case settings
|
||||
case feedback
|
||||
case signOut
|
||||
case logout
|
||||
}
|
||||
|
||||
enum HomeScreenViewAction {
|
||||
|
||||
@@ -138,8 +138,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
actionsSubject.send(.presentFeedbackScreen)
|
||||
case .settings:
|
||||
actionsSubject.send(.presentSettingsScreen)
|
||||
case .signOut:
|
||||
actionsSubject.send(.signOut)
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
}
|
||||
case .verifySession:
|
||||
actionsSubject.send(.presentSessionVerificationScreen)
|
||||
|
||||
@@ -18,7 +18,6 @@ import Compound
|
||||
import SwiftUI
|
||||
|
||||
struct HomeScreenUserMenuButton: View {
|
||||
@State private var showingLogoutConfirmation = false
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
@ObservedObject var context: HomeScreenViewModel.Context
|
||||
@@ -53,7 +52,7 @@ struct HomeScreenUserMenuButton: View {
|
||||
}
|
||||
Section {
|
||||
Button(role: .destructive) {
|
||||
showingLogoutConfirmation = true
|
||||
context.send(viewAction: .userMenu(action: .logout))
|
||||
} label: {
|
||||
Label(L10n.screenSignoutPreferenceItem, systemImage: "rectangle.portrait.and.arrow.right")
|
||||
}
|
||||
@@ -68,15 +67,6 @@ struct HomeScreenUserMenuButton: View {
|
||||
.overlayBadge(10, isBadged: context.viewState.showUserMenuBadge)
|
||||
.compositingGroup()
|
||||
}
|
||||
.alert(L10n.screenSignoutConfirmationDialogTitle,
|
||||
isPresented: $showingLogoutConfirmation) {
|
||||
Button(L10n.screenSignoutConfirmationDialogSubmit,
|
||||
role: .destructive) {
|
||||
context.send(viewAction: .userMenu(action: .signOut))
|
||||
}
|
||||
} message: {
|
||||
Text(L10n.screenSignoutConfirmationDialogContent)
|
||||
}
|
||||
.accessibilityLabel(L10n.a11yUserMenu)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ struct EncryptedHistoryRoomTimelineView: View {
|
||||
|
||||
var body: some View {
|
||||
Label {
|
||||
Text(L10n.screenRoomEncryptedHistoryBanner)
|
||||
Text(title)
|
||||
.font(.compound.bodyMDSemibold)
|
||||
.foregroundColor(.compound.textInfoPrimary)
|
||||
} icon: {
|
||||
@@ -43,6 +43,10 @@ struct EncryptedHistoryRoomTimelineView: View {
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 16)
|
||||
}
|
||||
|
||||
private var title: String {
|
||||
timelineItem.isSessionVerified ? L10n.screenRoomEncryptedHistoryBanner : L10n.screenRoomEncryptedHistoryBannerUnverified
|
||||
}
|
||||
}
|
||||
|
||||
private struct EncryptedHistoryLabelStyle: LabelStyle {
|
||||
@@ -56,7 +60,9 @@ private struct EncryptedHistoryLabelStyle: LabelStyle {
|
||||
|
||||
struct EncryptedHistoryRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||
static var previews: some View {
|
||||
let item = EncryptedHistoryRoomTimelineItem(id: .random)
|
||||
EncryptedHistoryRoomTimelineView(timelineItem: item)
|
||||
VStack {
|
||||
EncryptedHistoryRoomTimelineView(timelineItem: .init(id: .random, isSessionVerified: true))
|
||||
EncryptedHistoryRoomTimelineView(timelineItem: .init(id: .random, isSessionVerified: false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ import SwiftUI
|
||||
struct SecureBackupKeyBackupScreen: View {
|
||||
@ObservedObject var context: SecureBackupKeyBackupScreenViewModel.Context
|
||||
|
||||
@ScaledMetric private var iconSize = 70
|
||||
|
||||
var body: some View {
|
||||
mainContent
|
||||
.padding()
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct SecureBackupLogoutConfirmationScreenCoordinatorParameters {
|
||||
let secureBackupController: SecureBackupControllerProtocol
|
||||
let networkMonitor: NetworkMonitorProtocol
|
||||
}
|
||||
|
||||
enum SecureBackupLogoutConfirmationScreenCoordinatorAction {
|
||||
case cancel
|
||||
case settings
|
||||
case logout
|
||||
}
|
||||
|
||||
final class SecureBackupLogoutConfirmationScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: SecureBackupLogoutConfirmationScreenCoordinatorParameters
|
||||
private var viewModel: SecureBackupLogoutConfirmationScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<SecureBackupLogoutConfirmationScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
var actions: AnyPublisher<SecureBackupLogoutConfirmationScreenCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(parameters: SecureBackupLogoutConfirmationScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = SecureBackupLogoutConfirmationScreenViewModel(secureBackupController: parameters.secureBackupController,
|
||||
networkMonitor: parameters.networkMonitor)
|
||||
}
|
||||
|
||||
func start() {
|
||||
viewModel.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
MXLog.info("Coordinator: received view model action: \(action)")
|
||||
|
||||
switch action {
|
||||
case .cancel:
|
||||
actionsSubject.send(.cancel)
|
||||
case .settings:
|
||||
actionsSubject.send(.settings)
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(SecureBackupLogoutConfirmationScreen(context: viewModel.context))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum SecureBackupLogoutConfirmationScreenViewModelAction {
|
||||
case cancel
|
||||
case settings
|
||||
case logout
|
||||
}
|
||||
|
||||
enum SecureBackupLogoutConfirmationScreenViewMode {
|
||||
case saveRecoveryKey
|
||||
case backupOngoing
|
||||
case offline
|
||||
}
|
||||
|
||||
struct SecureBackupLogoutConfirmationScreenViewState: BindableState {
|
||||
var mode: SecureBackupLogoutConfirmationScreenViewMode
|
||||
}
|
||||
|
||||
enum SecureBackupLogoutConfirmationScreenViewAction {
|
||||
case cancel
|
||||
case settings
|
||||
case logout
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// 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 SecureBackupLogoutConfirmationScreenViewModelType = StateStoreViewModel<SecureBackupLogoutConfirmationScreenViewState, SecureBackupLogoutConfirmationScreenViewAction>
|
||||
|
||||
class SecureBackupLogoutConfirmationScreenViewModel: SecureBackupLogoutConfirmationScreenViewModelType, SecureBackupLogoutConfirmationScreenViewModelProtocol {
|
||||
private let secureBackupController: SecureBackupControllerProtocol
|
||||
private let networkMonitor: NetworkMonitorProtocol
|
||||
|
||||
@CancellableTask
|
||||
private var keyUploadWaitingTask: Task<Void, Never>?
|
||||
|
||||
private var actionsSubject: PassthroughSubject<SecureBackupLogoutConfirmationScreenViewModelAction, Never> = .init()
|
||||
var actions: AnyPublisher<SecureBackupLogoutConfirmationScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(secureBackupController: SecureBackupControllerProtocol, networkMonitor: NetworkMonitorProtocol) {
|
||||
self.secureBackupController = secureBackupController
|
||||
self.networkMonitor = networkMonitor
|
||||
|
||||
super.init(initialViewState: .init(mode: .saveRecoveryKey))
|
||||
|
||||
networkMonitor.reachabilityPublisher
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] reachability in
|
||||
guard let self,
|
||||
state.mode != .saveRecoveryKey else {
|
||||
return
|
||||
}
|
||||
|
||||
if reachability == .reachable {
|
||||
state.mode = .backupOngoing
|
||||
} else {
|
||||
state.mode = .offline
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: SecureBackupLogoutConfirmationScreenViewAction) {
|
||||
MXLog.info("View model: received view action: \(viewAction)")
|
||||
|
||||
switch viewAction {
|
||||
case .cancel:
|
||||
keyUploadWaitingTask = nil
|
||||
actionsSubject.send(.cancel)
|
||||
case .settings:
|
||||
actionsSubject.send(.settings)
|
||||
case .logout:
|
||||
attemptLogout()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func attemptLogout() {
|
||||
if state.mode == .saveRecoveryKey {
|
||||
state.mode = networkMonitor.reachabilityPublisher.value == .reachable ? .backupOngoing : .offline
|
||||
|
||||
keyUploadWaitingTask = Task {
|
||||
await secureBackupController.waitForKeyBackup()
|
||||
|
||||
guard !Task.isCancelled else { return }
|
||||
|
||||
actionsSubject.send(.logout)
|
||||
}
|
||||
} else {
|
||||
actionsSubject.send(.logout)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 SecureBackupLogoutConfirmationScreenViewModelProtocol {
|
||||
var actions: AnyPublisher<SecureBackupLogoutConfirmationScreenViewModelAction, Never> { get }
|
||||
var context: SecureBackupLogoutConfirmationScreenViewModelType.Context { get }
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// 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 Compound
|
||||
import SwiftUI
|
||||
|
||||
struct SecureBackupLogoutConfirmationScreen: View {
|
||||
@ObservedObject var context: SecureBackupLogoutConfirmationScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
ScrollView {
|
||||
VStack(spacing: 16) {
|
||||
header
|
||||
content
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.toolbar { toolbar }
|
||||
.background(Color.compound.bgCanvasDefault.ignoresSafeArea())
|
||||
.safeAreaInset(edge: .bottom) { footer.padding() }
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var header: some View {
|
||||
HeroImage(image: Image(asset: Asset.Images.secureBackupOff))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var content: some View {
|
||||
Text(title)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
.font(.compound.headingMDBold)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
Text(subtitle)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
.font(.compound.bodyMD)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
if context.viewState.mode == .backupOngoing {
|
||||
Spacer()
|
||||
ProgressView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var footer: some View {
|
||||
if context.viewState.mode == .saveRecoveryKey {
|
||||
Button {
|
||||
context.send(viewAction: .settings)
|
||||
} label: {
|
||||
Text(L10n.commonSettings)
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
}
|
||||
|
||||
Button(role: .destructive) {
|
||||
context.send(viewAction: .logout)
|
||||
} label: {
|
||||
Text(L10n.actionSignout)
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
}
|
||||
|
||||
@ToolbarContentBuilder
|
||||
private var toolbar: some ToolbarContent {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(L10n.actionCancel) {
|
||||
context.send(viewAction: .cancel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var title: String {
|
||||
switch context.viewState.mode {
|
||||
case .saveRecoveryKey:
|
||||
return L10n.screenSignoutSaveRecoveryKeyTitle
|
||||
case .backupOngoing:
|
||||
return L10n.screenSignoutKeyBackupOngoingTitle
|
||||
case .offline:
|
||||
return L10n.screenSignoutKeyBackupOfflineTitle
|
||||
}
|
||||
}
|
||||
|
||||
var subtitle: String {
|
||||
switch context.viewState.mode {
|
||||
case .saveRecoveryKey:
|
||||
return L10n.screenSignoutSaveRecoveryKeySubtitle
|
||||
case .backupOngoing:
|
||||
return L10n.screenSignoutKeyBackupOngoingSubtitle
|
||||
case .offline:
|
||||
return L10n.screenSignoutKeyBackupOfflineSubtitle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct SecureBackupLogoutConfirmationScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = buildViewModel()
|
||||
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
SecureBackupLogoutConfirmationScreen(context: viewModel.context)
|
||||
}
|
||||
}
|
||||
|
||||
static func buildViewModel() -> SecureBackupLogoutConfirmationScreenViewModelType {
|
||||
let secureBackupController = SecureBackupControllerMock()
|
||||
secureBackupController.underlyingKeyBackupState = CurrentValueSubject<SecureBackupKeyBackupState, Never>(.enabled).asCurrentValuePublisher()
|
||||
|
||||
let networkMonitor = NetworkMonitorMock()
|
||||
networkMonitor.underlyingReachabilityPublisher = CurrentValueSubject<NetworkMonitorReachability, Never>(.reachable).asCurrentValuePublisher()
|
||||
|
||||
return SecureBackupLogoutConfirmationScreenViewModel(secureBackupController: secureBackupController,
|
||||
networkMonitor: networkMonitor)
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,6 @@ import SwiftUI
|
||||
struct SecureBackupRecoveryKeyScreen: View {
|
||||
@ObservedObject var context: SecureBackupRecoveryKeyScreenViewModel.Context
|
||||
|
||||
@ScaledMetric private var iconSize = 70
|
||||
|
||||
var body: some View {
|
||||
mainContent
|
||||
.padding()
|
||||
|
||||
@@ -32,6 +32,7 @@ enum SettingsScreenCoordinatorAction {
|
||||
case dismiss
|
||||
case logout
|
||||
case clearCache
|
||||
case secureBackup
|
||||
}
|
||||
|
||||
final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||
@@ -75,7 +76,7 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||
case .sessionVerification:
|
||||
presentSessionVerificationScreen()
|
||||
case .secureBackup:
|
||||
presentSecureBackupScreen()
|
||||
actionsSubject.send(.secureBackup)
|
||||
case .accountSessionsList:
|
||||
presentAccountSessionsListURL()
|
||||
case .notifications:
|
||||
@@ -200,15 +201,6 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func presentSecureBackupScreen() {
|
||||
let coordinator = SecureBackupScreenCoordinator(parameters: .init(appSettings: parameters.appSettings,
|
||||
secureBackupController: parameters.userSession.clientProxy.secureBackupController,
|
||||
navigationStackCoordinator: parameters.navigationStackCoordinator,
|
||||
userIndicatorController: parameters.userIndicatorController))
|
||||
|
||||
parameters.navigationStackCoordinator?.push(coordinator)
|
||||
}
|
||||
|
||||
private func presentNotificationSettings() {
|
||||
let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator,
|
||||
userSession: parameters.userSession,
|
||||
|
||||
@@ -19,8 +19,6 @@ import SFSafeSymbols
|
||||
import SwiftUI
|
||||
|
||||
struct SettingsScreen: View {
|
||||
@State private var showingLogoutConfirmation = false
|
||||
|
||||
@ObservedObject var context: SettingsScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
@@ -196,16 +194,9 @@ struct SettingsScreen: View {
|
||||
ListRow(label: .default(title: L10n.screenSignoutPreferenceItem,
|
||||
systemIcon: .rectanglePortraitAndArrowRight),
|
||||
kind: .button {
|
||||
showingLogoutConfirmation = true
|
||||
context.send(viewAction: .logout)
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.logout)
|
||||
.alert(L10n.screenSignoutConfirmationDialogTitle, isPresented: $showingLogoutConfirmation) {
|
||||
Button(L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) {
|
||||
context.send(viewAction: .logout)
|
||||
}
|
||||
} message: {
|
||||
Text(L10n.screenSignoutConfirmationDialogContent)
|
||||
}
|
||||
} footer: {
|
||||
VStack {
|
||||
versionText
|
||||
|
||||
@@ -29,6 +29,11 @@ class SecureBackupController: SecureBackupControllerProtocol {
|
||||
keyBackupStateSubject.asCurrentValuePublisher()
|
||||
}
|
||||
|
||||
var isLastSession: Bool {
|
||||
#warning("FIXME")
|
||||
return true
|
||||
}
|
||||
|
||||
func enableBackup() async -> Result<Void, SecureBackupControllerError> {
|
||||
keyBackupStateSubject.send(.enabling)
|
||||
|
||||
@@ -76,4 +81,8 @@ class SecureBackupController: SecureBackupControllerProtocol {
|
||||
|
||||
return .success(())
|
||||
}
|
||||
|
||||
func waitForKeyBackup() async {
|
||||
try? await Task.sleep(for: .seconds(5))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,11 +49,15 @@ protocol SecureBackupControllerProtocol {
|
||||
|
||||
var keyBackupState: CurrentValuePublisher<SecureBackupKeyBackupState, Never> { get }
|
||||
|
||||
var isLastSession: Bool { get }
|
||||
|
||||
func enableBackup() async -> Result<Void, SecureBackupControllerError>
|
||||
func disableBackup() async -> Result<Void, SecureBackupControllerError>
|
||||
|
||||
func generateRecoveryKey() async -> Result<String, SecureBackupControllerError>
|
||||
func confirmRecoveryKey(_ key: String) async -> Result<Void, SecureBackupControllerError>
|
||||
|
||||
func waitForKeyBackup() async
|
||||
}
|
||||
|
||||
extension SecureBackupControllerMock {
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
import Foundation
|
||||
|
||||
struct MockRoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol {
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func buildRoomTimelineController(roomProxy: RoomProxyProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
mediaPlayerProvider: MediaPlayerProviderProtocol,
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol) -> RoomTimelineControllerProtocol {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol,
|
||||
secureBackupController: SecureBackupControllerProtocol) -> RoomTimelineControllerProtocol {
|
||||
let timelineController = MockRoomTimelineController()
|
||||
timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk
|
||||
return timelineController
|
||||
|
||||
@@ -26,6 +26,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
private let mediaPlayerProvider: MediaPlayerProviderProtocol
|
||||
private let voiceMessageMediaManager: VoiceMessageMediaManagerProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let secureBackupController: SecureBackupControllerProtocol
|
||||
private let serialDispatchQueue: DispatchQueue
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -48,7 +49,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
mediaPlayerProvider: MediaPlayerProviderProtocol,
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol,
|
||||
appSettings: AppSettings) {
|
||||
appSettings: AppSettings,
|
||||
secureBackupController: SecureBackupControllerProtocol) {
|
||||
self.roomProxy = roomProxy
|
||||
timelineProvider = roomProxy.timelineProvider
|
||||
self.timelineItemFactory = timelineItemFactory
|
||||
@@ -56,6 +58,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
self.mediaPlayerProvider = mediaPlayerProvider
|
||||
self.voiceMessageMediaManager = voiceMessageMediaManager
|
||||
self.appSettings = appSettings
|
||||
self.secureBackupController = secureBackupController
|
||||
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomtimelineprovider", qos: .utility)
|
||||
|
||||
timelineProvider
|
||||
@@ -442,8 +445,14 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
case .event(let eventTimelineItem):
|
||||
let timelineItem = timelineItemFactory.buildTimelineItem(for: eventTimelineItem)
|
||||
|
||||
if timelineItem is EncryptedRoomTimelineItem, isItemInEncryptionHistory(eventTimelineItem) {
|
||||
return EncryptedHistoryRoomTimelineItem(id: eventTimelineItem.id)
|
||||
// When backup is enabled just show the timeline items, they will most likely
|
||||
// resolve eventually. If we don't know the backup state then we assume the session is not verified yet,
|
||||
// otherwise we just treat it as fully disabled.
|
||||
if secureBackupController.keyBackupState.value != .enabled {
|
||||
if timelineItem is EncryptedRoomTimelineItem, isItemInEncryptionHistory(eventTimelineItem) {
|
||||
return EncryptedHistoryRoomTimelineItem(id: eventTimelineItem.id,
|
||||
isSessionVerified: secureBackupController.keyBackupState.value != .unknown)
|
||||
}
|
||||
}
|
||||
|
||||
if let messageTimelineItem = timelineItem as? EventBasedMessageTimelineItemProtocol {
|
||||
|
||||
@@ -17,16 +17,19 @@
|
||||
import Foundation
|
||||
|
||||
struct RoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol {
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func buildRoomTimelineController(roomProxy: RoomProxyProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
mediaPlayerProvider: MediaPlayerProviderProtocol,
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol) -> RoomTimelineControllerProtocol {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol,
|
||||
secureBackupController: SecureBackupControllerProtocol) -> RoomTimelineControllerProtocol {
|
||||
RoomTimelineController(roomProxy: roomProxy,
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: mediaProvider,
|
||||
mediaPlayerProvider: mediaPlayerProvider,
|
||||
voiceMessageMediaManager: voiceMessageMediaManager,
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
secureBackupController: secureBackupController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ import Foundation
|
||||
|
||||
@MainActor
|
||||
protocol RoomTimelineControllerFactoryProtocol {
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func buildRoomTimelineController(roomProxy: RoomProxyProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
mediaPlayerProvider: MediaPlayerProviderProtocol,
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol) -> RoomTimelineControllerProtocol
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol,
|
||||
secureBackupController: SecureBackupControllerProtocol) -> RoomTimelineControllerProtocol
|
||||
}
|
||||
|
||||
@@ -18,4 +18,5 @@ import Foundation
|
||||
|
||||
struct EncryptedHistoryRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
|
||||
let id: TimelineItemIdentifier
|
||||
let isSessionVerified: Bool
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
}
|
||||
|
||||
return EncryptedRoomTimelineItem(id: eventItemProxy.id,
|
||||
body: L10n.commonUnableToDecrypt,
|
||||
body: L10n.commonWaitingForDecryptionKey,
|
||||
encryptionType: encryptionType,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// 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 ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
class SecureBackupLogoutConfirmationScreenUITests: XCTestCase { }
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class SecureBackupLogoutConfirmationScreenViewModelTests: XCTestCase { }
|
||||
Reference in New Issue
Block a user