diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 260a433c0..83649b966 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -253,6 +253,7 @@ 3C549A0BF39F8A854D45D9FD /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 0DD568A494247444A4B56031 /* Kingfisher */; }; 3C73442084BF8A6939F0F80B /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5445FCE0CE15E634FDC1A2E2 /* AnalyticsService.swift */; }; 3CE4C5071B6D2576E2473989 /* OrderedSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62B07B296D7A9D2F09120853 /* OrderedSet.swift */; }; + 3D2E3E1B01D4389DCBE8F0E8 /* ResetRecoveryKeyScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E995E3F726488F8938F0BCD1 /* ResetRecoveryKeyScreenCoordinator.swift */; }; 3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DC38E64A5ED3FDB201029A /* BugReportService.swift */; }; 3DAD62988F072607441CB7A5 /* PollFormScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */; }; 3DAF325D8AE461F7CDB282BD /* StartChatScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6861FE915C7B5466E6962BBA /* StartChatScreen.swift */; }; @@ -424,6 +425,7 @@ 67C05C50AD734283374605E3 /* MatrixEntityRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */; }; 67D6E0700A9C1E676F6231F8 /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = AD544C0FA48DFFB080920061 /* Collections */; }; 67E9926C4572C54F59FCA91A /* AuthenticationFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B069D7772DDF6513E0F1B8 /* AuthenticationFlowCoordinator.swift */; }; + 680062C402ECB8FCAAE85A5C /* ResetRecoveryKeyScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99637028A8BD2843A35A92D4 /* ResetRecoveryKeyScreenViewModelProtocol.swift */; }; 6817EAD73DC1FFD8B943B5B9 /* HomeScreenRoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73587C2E3CF5998361AE516 /* HomeScreenRoomTests.swift */; }; 68184EF36396424FE19A727D /* MediaLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AFCE895ECFFA53FEE64D62B /* MediaLoader.swift */; }; 6832733838C57A7D3FE8FEB5 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 78A5A8DE1E2B09C978C7F3B0 /* KeychainAccess */; }; @@ -643,6 +645,7 @@ 9BEA56957B3AF954E7321658 /* ComposerToolbarViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E44928D844E16EE48A311FCA /* ComposerToolbarViewModelProtocol.swift */; }; 9C4EC28A921486B1775D7F8C /* IdentityConfirmedScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307702DD66E7DDCDD9214784 /* IdentityConfirmedScreen.swift */; }; 9C55746D8F6A3E35CFCF4A7A /* AuthenticationStartLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 598F01EBD0C4CC550C644418 /* AuthenticationStartLogo.swift */; }; + 9C9838B68C00C980A498050C /* ResetRecoveryKeyScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DC30DEC0097B9D217493007 /* ResetRecoveryKeyScreen.swift */; }; 9D2E03DB175A6AB14589076D /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = 2A3F7BCCB18C15B30CCA39A9 /* AnalyticsEvents */; }; 9D79B94493FB32249F7E472F /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */; }; 9D9690D2FD4CD26FF670620F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75EF87651B00A176AB08E97 /* AppDelegate.swift */; }; @@ -913,6 +916,7 @@ DFCA89C4EC2A5332ED6B441F /* DataProtectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4959CECEC984B3995616F427 /* DataProtectionManager.swift */; }; DFD5AA8688A34C72D48AF3B1 /* StaticLocationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5311C989EC15B4C2D699025 /* StaticLocationScreenViewModel.swift */; }; DFF7D6A6C26DDD40D00AE579 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = F012CB5EE3F2B67359F6CC52 /* target.yml */; }; + E07ABB9FD1C87EBBDDE81DC5 /* ResetRecoveryKeyScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63616A8920EC6948B31EA1B /* ResetRecoveryKeyScreenViewModel.swift */; }; E0A4DCA633D174EB43AD599F /* BackgroundTaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */; }; E0B6A569AC3E81D233B43D60 /* SettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E625B0EB2F86B37C14EF7E6 /* SettingsScreenViewModel.swift */; }; E0FB26262689F04D66A949D7 /* TestablePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E227F34BE43B08E098796E /* TestablePreview.swift */; }; @@ -967,6 +971,7 @@ EBDB339A7C127F068B6E52E5 /* VoiceMessageRecordingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A634D8DD1E10D858CF7995D /* VoiceMessageRecordingView.swift */; }; EBE13FAB4E29738AC41BD3E5 /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; }; EC280623A42904341363EAAF /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = A20EA00CCB9DBE0FFB17DD09 /* Collections */; }; + EC65AF0D9240A248DC9917BB /* ResetRecoveryKeyScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76911C322BC4CD117A8A0AF1 /* ResetRecoveryKeyScreenModels.swift */; }; ECA636DAF071C611FDC2BB57 /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; }; ED564C8C7C43CF5F67000368 /* PlatformViewVersionPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26813CCE39221FE30BF22CD /* PlatformViewVersionPredicate.swift */; }; ED90A59F068FD0CA27E602ED /* UserProfileListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10DA51DBC8C7E1460DBCCBD /* UserProfileListRow.swift */; }; @@ -1521,6 +1526,7 @@ 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsScreenIdentifier.swift; sourceTree = ""; }; 6D0A27607AB09784C8501B5C /* DeveloperOptionsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenViewModelTests.swift; sourceTree = ""; }; 6D4777F0142E330A75C46FE4 /* SessionVerificationUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationUITests.swift; sourceTree = ""; }; + 6DC30DEC0097B9D217493007 /* ResetRecoveryKeyScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetRecoveryKeyScreen.swift; sourceTree = ""; }; 6DF438EAFC732D2D95D34BF6 /* StartChatViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatViewModelTests.swift; sourceTree = ""; }; 6DF81D7F2A6BA9DE3F6F8D9D /* InvitesScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenViewModel.swift; sourceTree = ""; }; 6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundTaskTests.swift; sourceTree = ""; }; @@ -1557,6 +1563,7 @@ 7509AB72755DCC4B4E721B36 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/SAS.strings; sourceTree = ""; }; 752A0EB49BF5BCEA37EDF7A3 /* Signposter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signposter.swift; sourceTree = ""; }; 76310030C831D4610A705603 /* URLComponentsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLComponentsTests.swift; sourceTree = ""; }; + 76911C322BC4CD117A8A0AF1 /* ResetRecoveryKeyScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetRecoveryKeyScreenModels.swift; sourceTree = ""; }; 772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = ""; }; 7773CBFDBD458E0B7E270507 /* PillView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillView.swift; sourceTree = ""; }; 780258F1B9D15E30549FF4BE /* NotificationSettingsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenViewModel.swift; sourceTree = ""; }; @@ -1685,6 +1692,7 @@ 9873076F224E4CE09D8BD47D /* TemplateScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenUITests.swift; sourceTree = ""; }; 989D7380D9C86B3A10D30B13 /* AppLockSetupPINScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupPINScreenViewModelTests.swift; sourceTree = ""; }; 98A2932515EA11D3DD8A3506 /* TimelineItemBubbledStylerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemBubbledStylerView.swift; sourceTree = ""; }; + 99637028A8BD2843A35A92D4 /* ResetRecoveryKeyScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetRecoveryKeyScreenViewModelProtocol.swift; sourceTree = ""; }; 9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomFlowCoordinator.swift; sourceTree = ""; }; 9A22A05E472533ED3C5A31B3 /* NavigationModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModule.swift; sourceTree = ""; }; 9A2AC7BE17C05CF7D2A22338 /* landscape_test_video.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = landscape_test_video.mov; sourceTree = ""; }; @@ -1863,6 +1871,7 @@ C5F06F2F09B2EDD067DC2174 /* NotificationSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreen.swift; sourceTree = ""; }; C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenViewModelProtocol.swift; sourceTree = ""; }; C618CA2B6C8758B06C88013C /* CreateRoomCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomCoordinator.swift; sourceTree = ""; }; + C63616A8920EC6948B31EA1B /* ResetRecoveryKeyScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetRecoveryKeyScreenViewModel.swift; sourceTree = ""; }; C687844F60BFF532D49A994C /* AnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsTests.swift; sourceTree = ""; }; C6A9F49B3EE59147AF2F70BB /* SeparatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineItem.swift; sourceTree = ""; }; C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportUITests.swift; sourceTree = ""; }; @@ -2008,6 +2017,7 @@ E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIFont+AttributedStringBuilder.m"; sourceTree = ""; }; E96ED747FF90332EA1333C22 /* RoomTimelineItemFixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFixtures.swift; sourceTree = ""; }; E992D7B8BE54B2AB454613AF /* XCUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; + E995E3F726488F8938F0BCD1 /* ResetRecoveryKeyScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetRecoveryKeyScreenCoordinator.swift; sourceTree = ""; }; E9A3D3CFA199FA7897364547 /* CallInviteRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallInviteRoomTimelineItem.swift; sourceTree = ""; }; E9D059BFE329BE09B6D96A9F /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ro; path = ro.lproj/Localizable.stringsdict; sourceTree = ""; }; EA4D639E27D5882A6A71AECF /* GlobalSearchScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchScreenViewModelTests.swift; sourceTree = ""; }; @@ -2199,6 +2209,14 @@ path = VoiceMessage; sourceTree = ""; }; + 01DF58ADE41080A419AD424A /* View */ = { + isa = PBXGroup; + children = ( + 6DC30DEC0097B9D217493007 /* ResetRecoveryKeyScreen.swift */, + ); + path = View; + sourceTree = ""; + }; 0210F4932B59277E2EEEF7BC /* RoomNotificationSettingsScreen */ = { isa = PBXGroup; children = ( @@ -2468,6 +2486,7 @@ 2565414373E6F68005966B8E /* SecureBackup */ = { isa = PBXGroup; children = ( + EE703B39AC7A2862CFDCA12C /* ResetKeyScreen */, B1FD4FD6CEB987AE274AEEE5 /* SecureBackupKeyBackupScreen */, 63E514D74481A3D9556DFFC3 /* SecureBackupLogoutConfirmationScreen */, 6E8F16377AD462BBD4951271 /* SecureBackupRecoveryKeyScreen */, @@ -4909,6 +4928,18 @@ path = StartChatScreen; sourceTree = ""; }; + EE703B39AC7A2862CFDCA12C /* ResetKeyScreen */ = { + isa = PBXGroup; + children = ( + E995E3F726488F8938F0BCD1 /* ResetRecoveryKeyScreenCoordinator.swift */, + 76911C322BC4CD117A8A0AF1 /* ResetRecoveryKeyScreenModels.swift */, + C63616A8920EC6948B31EA1B /* ResetRecoveryKeyScreenViewModel.swift */, + 99637028A8BD2843A35A92D4 /* ResetRecoveryKeyScreenViewModelProtocol.swift */, + 01DF58ADE41080A419AD424A /* View */, + ); + path = ResetKeyScreen; + sourceTree = ""; + }; EFD4F7FCAAAB3EF45EE7A067 /* BlockedUsersScreen */ = { isa = PBXGroup; children = ( @@ -6117,6 +6148,11 @@ 46A261AA898344A1F3C406B1 /* ReportContentScreenModels.swift in Sources */, 42A5A42ACF063EEE6B1980D2 /* ReportContentScreenViewModel.swift in Sources */, 8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */, + 9C9838B68C00C980A498050C /* ResetRecoveryKeyScreen.swift in Sources */, + 3D2E3E1B01D4389DCBE8F0E8 /* ResetRecoveryKeyScreenCoordinator.swift in Sources */, + EC65AF0D9240A248DC9917BB /* ResetRecoveryKeyScreenModels.swift in Sources */, + E07ABB9FD1C87EBBDDE81DC5 /* ResetRecoveryKeyScreenViewModel.swift in Sources */, + 680062C402ECB8FCAAE85A5C /* ResetRecoveryKeyScreenViewModelProtocol.swift in Sources */, A494741843F087881299ACF0 /* RestorationToken.swift in Sources */, 1772AFA97DDA51CF1B293A78 /* RoomAttachmentPicker.swift in Sources */, F8C87130FD999F7F1076208C /* RoomChangePermissionsScreen.swift in Sources */, diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index 910754018..fa75dc032 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -156,7 +156,7 @@ "common_privacy_policy" = "Privacy policy"; "common_reaction" = "Reaction"; "common_reactions" = "Reactions"; -"common_recovery_key" = "Recovery key"; +"common_recovery_key" = "Recovery key or passcode"; "common_refreshing" = "Refreshing…"; "common_replying_to" = "Replying to %1$@"; "common_report_a_bug" = "Report a bug"; @@ -374,6 +374,13 @@ "screen_chat_backup_recovery_action_confirm_description" = "Your chat backup is currently out of sync."; "screen_chat_backup_recovery_action_setup" = "Set up recovery"; "screen_chat_backup_recovery_action_setup_description" = "Get access to your encrypted messages if you lose all your devices or are signed out of %1$@ everywhere."; +"screen_create_new_recovery_key_list_item_1" = "Open Element in a desktop device"; +"screen_create_new_recovery_key_list_item_2" = "Sign into your account again"; +"screen_create_new_recovery_key_list_item_3" = "When asked to verify your device, select %1$@"; +"screen_create_new_recovery_key_list_item_3_reset_all" = "“Reset all”"; +"screen_create_new_recovery_key_list_item_4" = "Follow the instructions to create a new recovery key"; +"screen_create_new_recovery_key_list_item_5" = "Save your new recovery key in a password manager or encrypted note"; +"screen_create_new_recovery_key_title" = "Reset the encryption for your account using another device"; "screen_create_poll_add_option_btn" = "Add option"; "screen_create_poll_anonymous_desc" = "Show results only after poll ends"; "screen_create_poll_anonymous_headline" = "Hide votes"; @@ -398,6 +405,7 @@ "screen_edit_profile_error_title" = "Unable to update profile"; "screen_edit_profile_title" = "Edit profile"; "screen_edit_profile_updating_details" = "Updating profile…"; +"screen_identity_confirmation_create_new_recovery_key" = "Create a new recovery key"; "screen_identity_confirmation_subtitle" = "Verify this device to set up secure messaging."; "screen_identity_confirmation_title" = "Confirm that it's you"; "screen_identity_confirmed_subtitle" = "Now you can read or send messages securely, and anyone you chat with can also trust this device."; @@ -473,13 +481,14 @@ "screen_recovery_key_change_generate_key_description" = "Make sure you can store your recovery key somewhere safe"; "screen_recovery_key_change_success" = "Recovery key changed"; "screen_recovery_key_change_title" = "Change recovery key?"; -"screen_recovery_key_confirm_description" = "Enter your recovery key to confirm access to your chat backup."; +"screen_recovery_key_confirm_create_new_recovery_key" = "Create new recovery key"; +"screen_recovery_key_confirm_description" = "Make sure nobody can see this screen!"; "screen_recovery_key_confirm_error_content" = "Please try again to confirm access to your chat backup."; "screen_recovery_key_confirm_error_title" = "Incorrect recovery key"; -"screen_recovery_key_confirm_key_description" = "Enter the 48 character code."; +"screen_recovery_key_confirm_key_description" = "If you have a recovery passphrase or secret passphrase/key, this will work too."; "screen_recovery_key_confirm_key_placeholder" = "Enter…"; "screen_recovery_key_confirm_success" = "Recovery key confirmed"; -"screen_recovery_key_confirm_title" = "Enter your recovery key"; +"screen_recovery_key_confirm_title" = "Enter your recovery key or passcode"; "screen_recovery_key_copied_to_clipboard" = "Copied recovery key"; "screen_recovery_key_generating_key" = "Generating…"; "screen_recovery_key_save_action" = "Save recovery key"; diff --git a/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift index 3e59558a9..bf3c84d31 100644 --- a/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift @@ -258,6 +258,8 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol { case .recoveryFixed: appSettings.hasRunIdentityConfirmationOnboarding = true stateMachine.tryEvent(.next) + case .showResetKeyInfo: + presentResetRecoveryKeyScreen() default: fatalError("Other flows shouldn't be possible") } @@ -267,6 +269,18 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol { presentCoordinator(coordinator) } + private func presentResetRecoveryKeyScreen() { + let coordinator = ResetRecoveryKeyScreenCoordinator() + coordinator.actionsPublisher.sink { [weak self] action in + switch action { + case .cancel: + self?.navigationStackCoordinator.setSheetCoordinator(nil) + } + } + .store(in: &cancellables) + navigationStackCoordinator.setSheetCoordinator(coordinator) + } + private func presentIdentityConfirmedScreen() { let coordinator = IdentityConfirmedScreenCoordinator(parameters: .init()) coordinator.actionsPublisher diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index 0fbd9a536..75cfd80bf 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -364,7 +364,7 @@ internal enum L10n { internal static var commonReaction: String { return L10n.tr("Localizable", "common_reaction") } /// Reactions internal static var commonReactions: String { return L10n.tr("Localizable", "common_reactions") } - /// Recovery key + /// Recovery key or passcode internal static var commonRecoveryKey: String { return L10n.tr("Localizable", "common_recovery_key") } /// Refreshing… internal static var commonRefreshing: String { return L10n.tr("Localizable", "common_refreshing") } @@ -919,6 +919,22 @@ internal enum L10n { internal static func screenChatBackupRecoveryActionSetupDescription(_ p1: Any) -> String { return L10n.tr("Localizable", "screen_chat_backup_recovery_action_setup_description", String(describing: p1)) } + /// Open Element in a desktop device + internal static var screenCreateNewRecoveryKeyListItem1: String { return L10n.tr("Localizable", "screen_create_new_recovery_key_list_item_1") } + /// Sign into your account again + internal static var screenCreateNewRecoveryKeyListItem2: String { return L10n.tr("Localizable", "screen_create_new_recovery_key_list_item_2") } + /// When asked to verify your device, select %1$@ + internal static func screenCreateNewRecoveryKeyListItem3(_ p1: Any) -> String { + return L10n.tr("Localizable", "screen_create_new_recovery_key_list_item_3", String(describing: p1)) + } + /// “Reset all” + internal static var screenCreateNewRecoveryKeyListItem3ResetAll: String { return L10n.tr("Localizable", "screen_create_new_recovery_key_list_item_3_reset_all") } + /// Follow the instructions to create a new recovery key + internal static var screenCreateNewRecoveryKeyListItem4: String { return L10n.tr("Localizable", "screen_create_new_recovery_key_list_item_4") } + /// Save your new recovery key in a password manager or encrypted note + internal static var screenCreateNewRecoveryKeyListItem5: String { return L10n.tr("Localizable", "screen_create_new_recovery_key_list_item_5") } + /// Reset the encryption for your account using another device + internal static var screenCreateNewRecoveryKeyTitle: String { return L10n.tr("Localizable", "screen_create_new_recovery_key_title") } /// Add option internal static var screenCreatePollAddOptionBtn: String { return L10n.tr("Localizable", "screen_create_poll_add_option_btn") } /// Show results only after poll ends @@ -991,6 +1007,8 @@ internal enum L10n { internal static var screenEditProfileTitle: String { return L10n.tr("Localizable", "screen_edit_profile_title") } /// Updating profile… internal static var screenEditProfileUpdatingDetails: String { return L10n.tr("Localizable", "screen_edit_profile_updating_details") } + /// Create a new recovery key + internal static var screenIdentityConfirmationCreateNewRecoveryKey: String { return L10n.tr("Localizable", "screen_identity_confirmation_create_new_recovery_key") } /// Verify this device to set up secure messaging. internal static var screenIdentityConfirmationSubtitle: String { return L10n.tr("Localizable", "screen_identity_confirmation_subtitle") } /// Confirm that it's you @@ -1159,19 +1177,21 @@ internal enum L10n { internal static var screenRecoveryKeyChangeSuccess: String { return L10n.tr("Localizable", "screen_recovery_key_change_success") } /// Change recovery key? internal static var screenRecoveryKeyChangeTitle: String { return L10n.tr("Localizable", "screen_recovery_key_change_title") } - /// Enter your recovery key to confirm access to your chat backup. + /// Create new recovery key + internal static var screenRecoveryKeyConfirmCreateNewRecoveryKey: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_create_new_recovery_key") } + /// Make sure nobody can see this screen! internal static var screenRecoveryKeyConfirmDescription: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_description") } /// Please try again to confirm access to your chat backup. internal static var screenRecoveryKeyConfirmErrorContent: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_error_content") } /// Incorrect recovery key internal static var screenRecoveryKeyConfirmErrorTitle: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_error_title") } - /// Enter the 48 character code. + /// If you have a recovery passphrase or secret passphrase/key, this will work too. internal static var screenRecoveryKeyConfirmKeyDescription: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_key_description") } /// Enter… internal static var screenRecoveryKeyConfirmKeyPlaceholder: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_key_placeholder") } /// Recovery key confirmed internal static var screenRecoveryKeyConfirmSuccess: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_success") } - /// Enter your recovery key + /// Enter your recovery key or passcode internal static var screenRecoveryKeyConfirmTitle: String { return L10n.tr("Localizable", "screen_recovery_key_confirm_title") } /// Copied recovery key internal static var screenRecoveryKeyCopiedToClipboard: String { return L10n.tr("Localizable", "screen_recovery_key_copied_to_clipboard") } diff --git a/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift b/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift index b9ca45e04..41f6d6dfe 100644 --- a/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift +++ b/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift @@ -24,6 +24,7 @@ struct HeroImage: View { enum Style { case normal case positive + case subtle var foregroundColor: Color { switch self { @@ -31,6 +32,8 @@ struct HeroImage: View { return .compound.iconPrimary case .positive: return .compound.iconSuccessPrimary + case .subtle: + return .compound.iconSecondary } } @@ -40,6 +43,8 @@ struct HeroImage: View { return .compound.bgSubtleSecondary case .positive: return .compound.bgSuccessSubtle + case .subtle: + return .compound.bgSubtlePrimary } } } diff --git a/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenCoordinator.swift b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenCoordinator.swift new file mode 100644 index 000000000..986ed1495 --- /dev/null +++ b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenCoordinator.swift @@ -0,0 +1,56 @@ +// +// 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 resetKey remove this comment once generating the final file + +import Combine +import SwiftUI + +enum ResetRecoveryKeyScreenCoordinatorAction { + case cancel +} + +final class ResetRecoveryKeyScreenCoordinator: CoordinatorProtocol { + private let viewModel: ResetRecoveryKeyScreenViewModelProtocol + + private var cancellables = Set() + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init() { + viewModel = ResetRecoveryKeyScreenViewModel() + } + + func start() { + viewModel.actionsPublisher.sink { [weak self] action in + MXLog.info("Coordinator: received view model action: \(action)") + + guard let self else { return } + switch action { + case .cancel: + self.actionsSubject.send(.cancel) + } + } + .store(in: &cancellables) + } + + func toPresentable() -> AnyView { + AnyView(ResetRecoveryKeyScreen(context: viewModel.context)) + } +} diff --git a/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenModels.swift b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenModels.swift new file mode 100644 index 000000000..e00308621 --- /dev/null +++ b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenModels.swift @@ -0,0 +1,36 @@ +// +// 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 ResetRecoveryKeyScreenViewModelAction { + case cancel +} + +struct ResetRecoveryKeyScreenViewState: BindableState { + let listItem3AttributedText = { + let boldPlaceholder = "{bold}" + var finalString = AttributedString(L10n.screenCreateNewRecoveryKeyListItem3(boldPlaceholder)) + var boldString = AttributedString(L10n.screenCreateNewRecoveryKeyListItem3ResetAll) + boldString.bold() + finalString.replace(boldPlaceholder, with: boldString) + return finalString + }() +} + +enum ResetRecoveryKeyScreenViewAction { + case cancel +} diff --git a/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenViewModel.swift b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenViewModel.swift new file mode 100644 index 000000000..fc19bf485 --- /dev/null +++ b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenViewModel.swift @@ -0,0 +1,40 @@ +// +// 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 ResetRecoveryKeyScreenViewModelType = StateStoreViewModel + +class ResetRecoveryKeyScreenViewModel: ResetRecoveryKeyScreenViewModelType, ResetRecoveryKeyScreenViewModelProtocol { + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init() { + super.init(initialViewState: ResetRecoveryKeyScreenViewState()) + } + + // MARK: - Public + + override func process(viewAction: ResetRecoveryKeyScreenViewAction) { + switch viewAction { + case .cancel: + actionsSubject.send(.cancel) + } + } +} diff --git a/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenViewModelProtocol.swift b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenViewModelProtocol.swift new file mode 100644 index 000000000..842fa48b3 --- /dev/null +++ b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/ResetRecoveryKeyScreenViewModelProtocol.swift @@ -0,0 +1,23 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Combine + +@MainActor +protocol ResetRecoveryKeyScreenViewModelProtocol { + var actionsPublisher: AnyPublisher { get } + var context: ResetRecoveryKeyScreenViewModelType.Context { get } +} diff --git a/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/View/ResetRecoveryKeyScreen.swift b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/View/ResetRecoveryKeyScreen.swift new file mode 100644 index 000000000..a233536bb --- /dev/null +++ b/ElementX/Sources/Screens/SecureBackup/ResetKeyScreen/View/ResetRecoveryKeyScreen.swift @@ -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 Compound +import SwiftUI + +struct ResetRecoveryKeyScreen: View { + @ObservedObject var context: ResetRecoveryKeyScreenViewModel.Context + + var body: some View { + NavigationStack { + FullscreenDialog { + mainContent + } bottomContent: { + EmptyView() + } + .toolbar { toolbar } + .toolbar(.visible, for: .navigationBar) + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgSubtleSecondary)) + .interactiveDismissDisabled() + } + } + + private var mainContent: some View { + VStack(spacing: 40) { + header + list + } + } + + private var header: some View { + VStack(spacing: 16) { + HeroImage(icon: \.computer, style: .subtle) + + Text(L10n.screenCreateNewRecoveryKeyTitle) + .foregroundColor(.compound.textPrimary) + .font(.compound.headingMDBold) + .multilineTextAlignment(.center) + } + } + + private var list: some View { + VStack(alignment: .leading, spacing: 24) { + Label { + Text(L10n.screenCreateNewRecoveryKeyListItem1) + } icon: { + Image(systemSymbol: ._1Circle) + .imageScale(.large) + .fontWeight(.light) + .foregroundColor(.compound.textPlaceholder) + } + .foregroundColor(.compound.textPrimary) + .font(.compound.bodyMD) + + Label { + Text(L10n.screenCreateNewRecoveryKeyListItem2) + } icon: { + Image(systemSymbol: ._2Circle) + .imageScale(.large) + .fontWeight(.light) + .foregroundColor(.compound.textPlaceholder) + } + .foregroundColor(.compound.textPrimary) + .font(.compound.bodyMD) + + Label { + Text(context.viewState.listItem3AttributedText) + } icon: { + Image(systemSymbol: ._3Circle) + .imageScale(.large) + .fontWeight(.light) + .foregroundColor(.compound.textPlaceholder) + } + .foregroundColor(.compound.textPrimary) + .font(.compound.bodyMD) + + Label { + Text(L10n.screenCreateNewRecoveryKeyListItem4) + } icon: { + Image(systemSymbol: ._4Circle) + .imageScale(.large) + .fontWeight(.light) + .foregroundColor(.compound.textPlaceholder) + } + .foregroundColor(.compound.textPrimary) + .font(.compound.bodyMD) + + Label { + Text(L10n.screenCreateNewRecoveryKeyListItem5) + } icon: { + Image(systemSymbol: ._5Circle) + .imageScale(.large) + .fontWeight(.light) + .foregroundColor(.compound.textPlaceholder) + } + .foregroundColor(.compound.textPrimary) + .font(.compound.bodyMD) + } + } + + @ToolbarContentBuilder + private var toolbar: some ToolbarContent { + ToolbarItem(placement: .cancellationAction) { + Button(L10n.actionCancel) { + context.send(viewAction: .cancel) + } + } + } +} + +// MARK: - Previews + +struct ResetRecoveryKeyScreen_Previews: PreviewProvider, TestablePreview { + static let viewModel = ResetRecoveryKeyScreenViewModel() + static var previews: some View { + NavigationStack { + ResetRecoveryKeyScreen(context: viewModel.context) + } + } +} diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift index 28dbf0f38..d7ea324c7 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift @@ -28,6 +28,7 @@ enum SecureBackupRecoveryKeyScreenCoordinatorAction { case recoverySetUp case recoveryChanged case recoveryFixed + case showResetKeyInfo } final class SecureBackupRecoveryKeyScreenCoordinator: CoordinatorProtocol { @@ -62,6 +63,8 @@ final class SecureBackupRecoveryKeyScreenCoordinator: CoordinatorProtocol { case .fixRecovery: self.actionsSubject.send(.recoveryFixed) } + case .showResetKeyInfo: + self.actionsSubject.send(.showResetKeyInfo) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift index b5d9e9273..cb5655fd4 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift @@ -19,6 +19,7 @@ import Foundation enum SecureBackupRecoveryKeyScreenViewModelAction { case done(mode: SecureBackupRecoveryKeyScreenViewMode) case cancel + case showResetKeyInfo } enum SecureBackupRecoveryKeyScreenViewMode { @@ -82,6 +83,7 @@ enum SecureBackupRecoveryKeyScreenViewAction { case copyKey case keySaved case confirmKey + case resetKey case done case cancel } diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift index 08a19cb43..112a6a3fe 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift @@ -100,6 +100,8 @@ class SecureBackupRecoveryKeyScreenViewModel: SecureBackupRecoveryKeyScreenViewM guard let self else { return } actionsSubject.send(.done(mode: context.viewState.mode)) })) + case .resetKey: + actionsSubject.send(.showResetKeyInfo) } } } diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift index a7cae0abd..06fffee2f 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift @@ -64,6 +64,12 @@ struct SecureBackupRecoveryKeyScreen: View { case .setupRecovery, .changeRecovery: recoveryCreatedActionButtons case .fixRecovery: + incompleteVerificationActionButtons + } + } + + private var incompleteVerificationActionButtons: some View { + VStack(spacing: 16) { Button { context.send(viewAction: .confirmKey) } label: { @@ -71,6 +77,14 @@ struct SecureBackupRecoveryKeyScreen: View { } .buttonStyle(.compound(.primary)) .disabled(context.confirmationRecoveryKey.isEmpty) + + Button { + context.send(viewAction: .resetKey) + } label: { + Text(L10n.screenIdentityConfirmationCreateNewRecoveryKey) + .padding(.vertical, 14) + } + .buttonStyle(.compound(.plain)) } } @@ -127,7 +141,7 @@ struct SecureBackupRecoveryKeyScreen: View { VStack(alignment: .leading, spacing: 8) { Text(L10n.commonRecoveryKey) .foregroundColor(.compound.textPrimary) - .font(.compound.bodySM) + .font(.compound.bodySMSemibold) Group { if context.viewState.recoveryKey == nil { @@ -180,7 +194,7 @@ struct SecureBackupRecoveryKeyScreen: View { VStack(alignment: .leading, spacing: 8) { Text(L10n.commonRecoveryKey) .foregroundColor(.compound.textPrimary) - .font(.compound.bodySM) + .font(.compound.bodySMSemibold) SecureField(L10n.screenRecoveryKeyConfirmKeyPlaceholder, text: $context.confirmationRecoveryKey) .textContentType(.password) // Not ideal but stops random suggestions diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift index 2bfe65c09..6fc89bf7c 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift @@ -51,18 +51,20 @@ final class SecureBackupScreenCoordinator: CoordinatorProtocol { recoveryKeyCoordinator.actions.sink { [weak self] action in guard let self else { return } - - parameters.navigationStackCoordinator?.setSheetCoordinator(nil) - switch action { case .cancel: break case .recoverySetUp: showSuccessIndicator(title: L10n.screenRecoveryKeySetupSuccess) + parameters.navigationStackCoordinator?.setSheetCoordinator(nil) case .recoveryChanged: showSuccessIndicator(title: L10n.screenRecoveryKeyChangeSuccess) + parameters.navigationStackCoordinator?.setSheetCoordinator(nil) case .recoveryFixed: showSuccessIndicator(title: L10n.screenRecoveryKeyConfirmSuccess) + parameters.navigationStackCoordinator?.setSheetCoordinator(nil) + case .showResetKeyInfo: + showResetRecoveryKeyScreen(navigationStackCoordinator: navigationStackCoordinator) } } .store(in: &cancellables) @@ -105,4 +107,16 @@ final class SecureBackupScreenCoordinator: CoordinatorProtocol { iconName: "checkmark", persistent: false)) } + + private func showResetRecoveryKeyScreen(navigationStackCoordinator: NavigationStackCoordinator) { + let coordinator = ResetRecoveryKeyScreenCoordinator() + coordinator.actionsPublisher.sink { action in + switch action { + case .cancel: + navigationStackCoordinator.setSheetCoordinator(nil) + } + } + .store(in: &cancellables) + navigationStackCoordinator.setSheetCoordinator(coordinator) + } } diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPad-en-GB.1.png new file mode 100644 index 000000000..4ccd0fdcb --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3303937c869aad78bb9acb85beafe9b02eb0e9acde9c1ac4bd70cf575ac08402 +size 213322 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPad-pseudo.1.png new file mode 100644 index 000000000..15f03e899 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd455454c11100fd8d3f3ba8faea10bd04f63f470b741ec5a5ba57d9aa885221 +size 313655 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPhone-15-en-GB.1.png new file mode 100644 index 000000000..eb1c71858 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPhone-15-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:faab9d5032622652e2b1d8b11e29178e2f5fe3fce7782191d827dbef7ae58b28 +size 152737 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPhone-15-pseudo.1.png new file mode 100644 index 000000000..094922b62 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_resetRecoveryKeyScreen-iPhone-15-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4e2af88b1092f2cb395b042d65c7dc8ed8159e9d9d2fb35df22071e1ffb5cd0 +size 261128 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png index b069f3a26..6ed798e02 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aaf99b0c04be35c9757bf006f075e26ae1bda61564962816d894f4d07d0f0495 -size 137141 +oid sha256:ab3efcdfc97332d810f01cb838ac615f0770121c2c1f0de42d393f68bda82ff8 +size 174129 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png index f332c9442..ae619b740 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7c5c210baa3a397ea02c6a1af578b71d74a9ec0b16f0fb3bdfba95d5ff07232 -size 179233 +oid sha256:3111ff0c737c3116be2be066883fe9c465cf11f87c010d72e858c9817c43b2f2 +size 182959 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png index 60bb1ea1a..22c682366 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28e9bbf6e09a25bb02a9a9f678520d64b75544923628ee730c3565402daa5ee5 -size 182095 +oid sha256:ee8e9679c7c5fd3006b8e2f576f2b519955593dc98478982e73e9f13cc91947e +size 186442 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png index 9b7478717..fb3d03bf6 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cded1706bb49163ed41ddd900481b1582bb8b69ec763e4643b180ab60155a5f7 -size 195631 +oid sha256:7e13e97f37061d85c029343f3150da714ce14f6729a738e7813fb17ca38e7878 +size 267815 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png index f01b76933..6df916f76 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7aa089fb7520df5dcdb62e350db2342b0510f6ef62a31864f376b17cfe3c295b -size 278457 +oid sha256:019a816ecb2b43f9173cf9c7f0a1bd33dc1fd18b8054226b0eb669cab27dde9b +size 285018 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png index 575e3c37b..52f40680e 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3adfc60a26f525cecdd61437ddc2bddac5b21cbe265bd0ce1ecfd406c2750bed -size 267003 +oid sha256:28ae819adccdbe3a102bfc2ad9da4ff62def05028ad5d6c7f1ebbf2f797a2558 +size 272591 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png index 1876baa50..1b6fc412d 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4127ef91593989d15b2f3c4a2548f2ae076b1a90e461bce581a2b3d60a5f99bf -size 90851 +oid sha256:bb1c63c646edd81cdaf6fef9e1303ae71262aaf20ba42957fece706861ad0c7e +size 123884 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png index d7084d53c..0e95a0c61 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2a76ee26b4f5d690f67aabd7f86494621823eacab9e5400c203ef5b85abab11 -size 129082 +oid sha256:a01669ff928c0e666c3ed63f792687c4885a0aae5367a8ea76f6c367c9545a08 +size 132763 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png index c0e6eaf50..d43e922d2 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94f45a1eef76250e677b87a35231bfe17b2ee3e27495c907b8e3b0ebe876898c -size 129889 +oid sha256:35a14da7a9341751d62f96ff820ff732b4960fba569c5aabb6f2e9c5c8d30adc +size 133546 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png index 57f53a02a..08ecf7710 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f65099fba0c10ebc1e834ec4ad313ae2d3d263718375ee67122aa5ff399fdc2a -size 138206 +oid sha256:da2f523dae023dd72a82edb161668f407eca3bc6988dee12bd2a6b08170701f1 +size 196851 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png index 6dc9435a7..c6be50935 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:201ba4003d78745c4b6387726d640604d80e9f05cf9e9f44e4e26c0583d18394 -size 224523 +oid sha256:ce892eda5eee6cdcb632db5e85952c1cc272ddc01c99055abb3c8361e22ce3d8 +size 233922 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png index 93b8d2194..7518f6989 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d12dc8245858d615eb22ddb811d9663a3845c0943c6da1a024cd6b7afe3b351 -size 218259 +oid sha256:d957f49d101b3580b8680b7aa93eb8aed9ec61d40e973f63e4628ab8115414d4 +size 226464 diff --git a/changelog.d/2647.feature b/changelog.d/2647.feature new file mode 100644 index 000000000..57c5d14b6 --- /dev/null +++ b/changelog.d/2647.feature @@ -0,0 +1 @@ +Added a view that explains how to reset your recovery key in case the user forgot it. \ No newline at end of file