Merge branch 'develop' into riot_3296

This commit is contained in:
manuroe 2020-06-25 17:20:47 +02:00
commit 4207ec4be2
86 changed files with 3277 additions and 56 deletions

View file

@ -8,6 +8,8 @@ Improvements:
* Timeline: Hide encrypted history (pre-invite) (#3239).
* Complete security: Add recovery from 4S (#3304).
* Key backup: Connect/restore backup created with SSSS (#3124).
* E2E by default: Disable it if the HS admin disabled it (#3305).
* Key backup: Add secure backup creation flow (#3344).
Bug fix:
* CallVC: Declined calls now properly reset call view controller, thanks to @Legi429 (#2877).

View file

@ -249,6 +249,15 @@
B157FAA523264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B157FA9D23264AE800EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift */; };
B157FAA623264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B157FA9E23264AE800EBFBD4 /* SettingsDiscoveryThreePidDetailsViewController.swift */; };
B157FAA823264BED00EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B157FAA723264BED00EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift */; };
B15F076924A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F076124A0FBA3005E26A1 /* SecretsSetupRecoveryPassphraseViewAction.swift */; };
B15F076A24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F076224A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseViewController.swift */; };
B15F076B24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B15F076324A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseViewController.storyboard */; };
B15F076C24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F076424A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseCoordinatorType.swift */; };
B15F076D24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F076524A0FBA5005E26A1 /* SecretsSetupRecoveryPassphraseViewState.swift */; };
B15F076E24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F076624A0FBA5005E26A1 /* SecretsSetupRecoveryPassphraseViewModel.swift */; };
B15F076F24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F076724A0FBA6005E26A1 /* SecretsSetupRecoveryPassphraseViewModelType.swift */; };
B15F077024A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F076824A0FBA6005E26A1 /* SecretsSetupRecoveryPassphraseCoordinator.swift */; };
B15F077224A1F315005E26A1 /* SecretsSetupRecoveryPassphraseInputMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F077124A1F314005E26A1 /* SecretsSetupRecoveryPassphraseInputMode.swift */; };
B1664BC520F4E67600808783 /* FallbackViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1664BAD20F4E67500808783 /* FallbackViewController.xib */; };
B1664BC620F4E67600808783 /* FallbackViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1664BAE20F4E67500808783 /* FallbackViewController.m */; };
B1664BC720F4E67600808783 /* SharePresentingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1664BB220F4E67500808783 /* SharePresentingViewController.m */; };
@ -293,6 +302,7 @@
B183226623F55D6B0035B2E8 /* CameraAccessManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B183226523F55D6B0035B2E8 /* CameraAccessManager.swift */; };
B183226823F561380035B2E8 /* CameraAccessAlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B183226723F561380035B2E8 /* CameraAccessAlertPresenter.swift */; };
B183226C23F59F810035B2E8 /* CloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B183226B23F59F810035B2E8 /* CloseButton.swift */; };
B185AF4F24A2672D00EE7D30 /* SecretsRecoveryCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B185AF4E24A2672D00EE7D30 /* SecretsRecoveryCoordinatorBridgePresenter.swift */; };
B18DEDD4243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18DEDCC243377C00075FEF7 /* KeyVerificationSelfVerifyWaitViewModelType.swift */; };
B18DEDD5243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18DEDCD243377C00075FEF7 /* KeyVerificationSelfVerifyWaitViewModel.swift */; };
B18DEDD6243377C10075FEF7 /* KeyVerificationSelfVerifyWaitCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18DEDCE243377C00075FEF7 /* KeyVerificationSelfVerifyWaitCoordinator.swift */; };
@ -662,7 +672,6 @@
B1C960F02458308D00C5704B /* RoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C960EF2458308D00C5704B /* RoundedButton.swift */; };
B1CA3A2721EF6914000D1D89 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA3A2621EF6913000D1D89 /* UIViewController.swift */; };
B1CA3A2921EF692B000D1D89 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA3A2821EF692B000D1D89 /* UIView.swift */; };
B1CA93742493BDDF00575122 /* SecretsRecoveryCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA93732493BDDF00575122 /* SecretsRecoveryCoordinatorBridgePresenter.swift */; };
B1CA93762493CBF200575122 /* MXRecoveryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA93752493CBF200575122 /* MXRecoveryService.swift */; };
B1CE83B62422812100D07506 /* KeyVerificationCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CE83B52422812000D07506 /* KeyVerificationCoordinatorBridgePresenter.swift */; };
B1CE83B92422815C00D07506 /* KeyVerificationKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CE83B72422815900D07506 /* KeyVerificationKind.swift */; };
@ -730,6 +739,21 @@
B1DCC63922E85E9A00625807 /* EmojiMartStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DCC63822E85E9A00625807 /* EmojiMartStore.swift */; };
B1DCC63B22E85EF800625807 /* EmojiMartCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DCC63A22E85EF800625807 /* EmojiMartCategory.swift */; };
B1DCC63F22E9A3AE00625807 /* EmojiItem+EmojiMart.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DCC63E22E9A3AE00625807 /* EmojiItem+EmojiMart.swift */; };
B1DE85E7249A5733006454AF /* SecureKeyBackupSetupCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE85E4249A5732006454AF /* SecureKeyBackupSetupCoordinatorType.swift */; };
B1DE85E8249A5733006454AF /* SecureKeyBackupSetupCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE85E5249A5732006454AF /* SecureKeyBackupSetupCoordinator.swift */; };
B1DE85E9249A5733006454AF /* SecureKeyBackupSetupCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE85E6249A5732006454AF /* SecureKeyBackupSetupCoordinatorBridgePresenter.swift */; };
B1DE85EC249A5819006454AF /* SecureKeyBackupSetupIntroViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE85EB249A5819006454AF /* SecureKeyBackupSetupIntroViewController.swift */; };
B1DE85EE249A5981006454AF /* SecureKeyBackupSetupIntroViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1DE85ED249A5981006454AF /* SecureKeyBackupSetupIntroViewController.storyboard */; };
B1DE8608249A5C4B006454AF /* SecretsSetupRecoveryKeyViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8600249A5C4A006454AF /* SecretsSetupRecoveryKeyViewAction.swift */; };
B1DE8609249A5C4B006454AF /* SecretsSetupRecoveryKeyViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8601249A5C4A006454AF /* SecretsSetupRecoveryKeyViewState.swift */; };
B1DE860A249A5C4B006454AF /* SecretsSetupRecoveryKeyCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8602249A5C4A006454AF /* SecretsSetupRecoveryKeyCoordinator.swift */; };
B1DE860B249A5C4B006454AF /* SecretsSetupRecoveryKeyCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8603249A5C4A006454AF /* SecretsSetupRecoveryKeyCoordinatorType.swift */; };
B1DE860C249A5C4B006454AF /* SecretsSetupRecoveryKeyViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8604249A5C4A006454AF /* SecretsSetupRecoveryKeyViewModelType.swift */; };
B1DE860D249A5C4B006454AF /* SecretsSetupRecoveryKeyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8605249A5C4B006454AF /* SecretsSetupRecoveryKeyViewModel.swift */; };
B1DE860E249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8606249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.swift */; };
B1DE860F249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1DE8607249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.storyboard */; };
B1DE8611249BB448006454AF /* SecureKeyBackupSetupIntroCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8610249BB448006454AF /* SecureKeyBackupSetupIntroCell.swift */; };
B1DE8613249BB470006454AF /* SecureKeyBackupSetupIntroCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1DE8612249BB470006454AF /* SecureKeyBackupSetupIntroCell.xib */; };
B1E5368921FB1E20001F3AFF /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E5368821FB1E20001F3AFF /* UIButton.swift */; };
B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E5368C21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift */; };
B1E5368F21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1E5368E21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard */; };
@ -1076,6 +1100,15 @@
B157FA9D23264AE800EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryThreePidDetailsViewModel.swift; sourceTree = "<group>"; };
B157FA9E23264AE800EBFBD4 /* SettingsDiscoveryThreePidDetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryThreePidDetailsViewController.swift; sourceTree = "<group>"; };
B157FAA723264BED00EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
B15F076124A0FBA3005E26A1 /* SecretsSetupRecoveryPassphraseViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseViewAction.swift; sourceTree = "<group>"; };
B15F076224A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseViewController.swift; sourceTree = "<group>"; };
B15F076324A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SecretsSetupRecoveryPassphraseViewController.storyboard; sourceTree = "<group>"; };
B15F076424A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseCoordinatorType.swift; sourceTree = "<group>"; };
B15F076524A0FBA5005E26A1 /* SecretsSetupRecoveryPassphraseViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseViewState.swift; sourceTree = "<group>"; };
B15F076624A0FBA5005E26A1 /* SecretsSetupRecoveryPassphraseViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseViewModel.swift; sourceTree = "<group>"; };
B15F076724A0FBA6005E26A1 /* SecretsSetupRecoveryPassphraseViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseViewModelType.swift; sourceTree = "<group>"; };
B15F076824A0FBA6005E26A1 /* SecretsSetupRecoveryPassphraseCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseCoordinator.swift; sourceTree = "<group>"; };
B15F077124A1F314005E26A1 /* SecretsSetupRecoveryPassphraseInputMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryPassphraseInputMode.swift; sourceTree = "<group>"; };
B1664BAD20F4E67500808783 /* FallbackViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FallbackViewController.xib; sourceTree = "<group>"; };
B1664BAE20F4E67500808783 /* FallbackViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FallbackViewController.m; sourceTree = "<group>"; };
B1664BAF20F4E67500808783 /* FallbackViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FallbackViewController.h; sourceTree = "<group>"; };
@ -1168,6 +1201,7 @@
B183226523F55D6B0035B2E8 /* CameraAccessManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraAccessManager.swift; sourceTree = "<group>"; };
B183226723F561380035B2E8 /* CameraAccessAlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraAccessAlertPresenter.swift; sourceTree = "<group>"; };
B183226B23F59F810035B2E8 /* CloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseButton.swift; sourceTree = "<group>"; };
B185AF4E24A2672D00EE7D30 /* SecretsRecoveryCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsRecoveryCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
B18DEDCC243377C00075FEF7 /* KeyVerificationSelfVerifyWaitViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationSelfVerifyWaitViewModelType.swift; sourceTree = "<group>"; };
B18DEDCD243377C00075FEF7 /* KeyVerificationSelfVerifyWaitViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationSelfVerifyWaitViewModel.swift; sourceTree = "<group>"; };
B18DEDCE243377C00075FEF7 /* KeyVerificationSelfVerifyWaitCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationSelfVerifyWaitCoordinator.swift; sourceTree = "<group>"; };
@ -1677,7 +1711,6 @@
B1C960EF2458308D00C5704B /* RoundedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedButton.swift; sourceTree = "<group>"; };
B1CA3A2621EF6913000D1D89 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = "<group>"; };
B1CA3A2821EF692B000D1D89 /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = "<group>"; };
B1CA93732493BDDF00575122 /* SecretsRecoveryCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretsRecoveryCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
B1CA93752493CBF200575122 /* MXRecoveryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXRecoveryService.swift; sourceTree = "<group>"; };
B1CE83B52422812000D07506 /* KeyVerificationCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
B1CE83B72422815900D07506 /* KeyVerificationKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationKind.swift; sourceTree = "<group>"; };
@ -1742,6 +1775,21 @@
B1DCC63822E85E9A00625807 /* EmojiMartStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiMartStore.swift; sourceTree = "<group>"; };
B1DCC63A22E85EF800625807 /* EmojiMartCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiMartCategory.swift; sourceTree = "<group>"; };
B1DCC63E22E9A3AE00625807 /* EmojiItem+EmojiMart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiItem+EmojiMart.swift"; sourceTree = "<group>"; };
B1DE85E4249A5732006454AF /* SecureKeyBackupSetupCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureKeyBackupSetupCoordinatorType.swift; sourceTree = "<group>"; };
B1DE85E5249A5732006454AF /* SecureKeyBackupSetupCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureKeyBackupSetupCoordinator.swift; sourceTree = "<group>"; };
B1DE85E6249A5732006454AF /* SecureKeyBackupSetupCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureKeyBackupSetupCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
B1DE85EB249A5819006454AF /* SecureKeyBackupSetupIntroViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureKeyBackupSetupIntroViewController.swift; sourceTree = "<group>"; };
B1DE85ED249A5981006454AF /* SecureKeyBackupSetupIntroViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SecureKeyBackupSetupIntroViewController.storyboard; sourceTree = "<group>"; };
B1DE8600249A5C4A006454AF /* SecretsSetupRecoveryKeyViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewAction.swift; sourceTree = "<group>"; };
B1DE8601249A5C4A006454AF /* SecretsSetupRecoveryKeyViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewState.swift; sourceTree = "<group>"; };
B1DE8602249A5C4A006454AF /* SecretsSetupRecoveryKeyCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyCoordinator.swift; sourceTree = "<group>"; };
B1DE8603249A5C4A006454AF /* SecretsSetupRecoveryKeyCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyCoordinatorType.swift; sourceTree = "<group>"; };
B1DE8604249A5C4A006454AF /* SecretsSetupRecoveryKeyViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewModelType.swift; sourceTree = "<group>"; };
B1DE8605249A5C4B006454AF /* SecretsSetupRecoveryKeyViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewModel.swift; sourceTree = "<group>"; };
B1DE8606249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewController.swift; sourceTree = "<group>"; };
B1DE8607249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SecretsSetupRecoveryKeyViewController.storyboard; sourceTree = "<group>"; };
B1DE8610249BB448006454AF /* SecureKeyBackupSetupIntroCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureKeyBackupSetupIntroCell.swift; sourceTree = "<group>"; };
B1DE8612249BB470006454AF /* SecureKeyBackupSetupIntroCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SecureKeyBackupSetupIntroCell.xib; sourceTree = "<group>"; };
B1E5368821FB1E20001F3AFF /* UIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = "<group>"; };
B1E5368C21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPassphraseViewController.swift; sourceTree = "<group>"; };
B1E5368E21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = KeyBackupRecoverFromPassphraseViewController.storyboard; sourceTree = "<group>"; };
@ -2251,6 +2299,7 @@
B1098BE921ECFE64000DDA48 /* KeyBackup */ = {
isa = PBXGroup;
children = (
B1DE85E3249A51F7006454AF /* SecureSetup */,
B1098C0221ECFEAF000DDA48 /* Setup */,
B1FDF56421F726AD00BA3834 /* Recover */,
B1107ECB2201BE800038014B /* Banners */,
@ -2506,6 +2555,22 @@
path = ThreePidDetails;
sourceTree = "<group>";
};
B15F075C24A0A196005E26A1 /* RecoveryPassphrase */ = {
isa = PBXGroup;
children = (
B15F077124A1F314005E26A1 /* SecretsSetupRecoveryPassphraseInputMode.swift */,
B15F076424A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseCoordinatorType.swift */,
B15F076824A0FBA6005E26A1 /* SecretsSetupRecoveryPassphraseCoordinator.swift */,
B15F076124A0FBA3005E26A1 /* SecretsSetupRecoveryPassphraseViewAction.swift */,
B15F076524A0FBA5005E26A1 /* SecretsSetupRecoveryPassphraseViewState.swift */,
B15F076724A0FBA6005E26A1 /* SecretsSetupRecoveryPassphraseViewModelType.swift */,
B15F076624A0FBA5005E26A1 /* SecretsSetupRecoveryPassphraseViewModel.swift */,
B15F076224A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseViewController.swift */,
B15F076324A0FBA4005E26A1 /* SecretsSetupRecoveryPassphraseViewController.storyboard */,
);
path = RecoveryPassphrase;
sourceTree = "<group>";
};
B1664BAB20F4E67500808783 /* Modules */ = {
isa = PBXGroup;
children = (
@ -2818,18 +2883,13 @@
path = Riot/Modules/Common/CollectionView;
sourceTree = SOURCE_ROOT;
};
B19C4E6A248E98B9009A423F /* SecretsRecovery */ = {
B19C4E6A248E98B9009A423F /* Secrets */ = {
isa = PBXGroup;
children = (
B1CA93732493BDDF00575122 /* SecretsRecoveryCoordinatorBridgePresenter.swift */,
B19C4E6D248F79EE009A423F /* SecretsRecoveryCoordinatorType.swift */,
B19C4E6E248F79EF009A423F /* SecretsRecoveryCoordinator.swift */,
B19C4E9324922403009A423F /* SecretsRecoveryMode.swift */,
B19C4E91249223D0009A423F /* SecretsRecoveryGoal.swift */,
B19C4E6B248E993F009A423F /* RecoverWithPassphrase */,
B19C4E6C248E994D009A423F /* RecoverWithKey */,
B1DE85E1249A5007006454AF /* Setup */,
B1B408EE249A4F39004A331C /* Recover */,
);
path = SecretsRecovery;
path = Secrets;
sourceTree = "<group>";
};
B19C4E6B248E993F009A423F /* RecoverWithPassphrase */ = {
@ -2937,6 +2997,20 @@
path = SelfVerifyStart;
sourceTree = "<group>";
};
B1B408EE249A4F39004A331C /* Recover */ = {
isa = PBXGroup;
children = (
B185AF4E24A2672D00EE7D30 /* SecretsRecoveryCoordinatorBridgePresenter.swift */,
B19C4E6D248F79EE009A423F /* SecretsRecoveryCoordinatorType.swift */,
B19C4E6E248F79EF009A423F /* SecretsRecoveryCoordinator.swift */,
B19C4E9324922403009A423F /* SecretsRecoveryMode.swift */,
B19C4E91249223D0009A423F /* SecretsRecoveryGoal.swift */,
B19C4E6B248E993F009A423F /* RecoverWithPassphrase */,
B19C4E6C248E994D009A423F /* RecoverWithKey */,
);
path = Recover;
sourceTree = "<group>";
};
B1B5567620EE6C4C00210D55 /* Modules */ = {
isa = PBXGroup;
children = (
@ -2965,7 +3039,7 @@
B1B556B020EE6C4C00210D55 /* BugReport */,
B1098BE921ECFE64000DDA48 /* KeyBackup */,
B1550FCF242148FA00CE097B /* KeyVerification */,
B19C4E6A248E98B9009A423F /* SecretsRecovery */,
B19C4E6A248E98B9009A423F /* Secrets */,
B1A6C10523881ECB002882FD /* SlidingModal */,
32DB556722FDADE50016329E /* ServiceTerms */,
B1550FC52420E8F400CE097B /* QRCode */,
@ -4289,6 +4363,52 @@
path = Store;
sourceTree = "<group>";
};
B1DE85E1249A5007006454AF /* Setup */ = {
isa = PBXGroup;
children = (
B1DE85E2249A5034006454AF /* RecoveryKey */,
B15F075C24A0A196005E26A1 /* RecoveryPassphrase */,
);
path = Setup;
sourceTree = "<group>";
};
B1DE85E2249A5034006454AF /* RecoveryKey */ = {
isa = PBXGroup;
children = (
B1DE8603249A5C4A006454AF /* SecretsSetupRecoveryKeyCoordinatorType.swift */,
B1DE8602249A5C4A006454AF /* SecretsSetupRecoveryKeyCoordinator.swift */,
B1DE8600249A5C4A006454AF /* SecretsSetupRecoveryKeyViewAction.swift */,
B1DE8601249A5C4A006454AF /* SecretsSetupRecoveryKeyViewState.swift */,
B1DE8604249A5C4A006454AF /* SecretsSetupRecoveryKeyViewModelType.swift */,
B1DE8605249A5C4B006454AF /* SecretsSetupRecoveryKeyViewModel.swift */,
B1DE8606249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.swift */,
B1DE8607249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.storyboard */,
);
path = RecoveryKey;
sourceTree = "<group>";
};
B1DE85E3249A51F7006454AF /* SecureSetup */ = {
isa = PBXGroup;
children = (
B1DE85E6249A5732006454AF /* SecureKeyBackupSetupCoordinatorBridgePresenter.swift */,
B1DE85E4249A5732006454AF /* SecureKeyBackupSetupCoordinatorType.swift */,
B1DE85E5249A5732006454AF /* SecureKeyBackupSetupCoordinator.swift */,
B1DE85EA249A5737006454AF /* Intro */,
);
path = SecureSetup;
sourceTree = "<group>";
};
B1DE85EA249A5737006454AF /* Intro */ = {
isa = PBXGroup;
children = (
B1DE85EB249A5819006454AF /* SecureKeyBackupSetupIntroViewController.swift */,
B1DE85ED249A5981006454AF /* SecureKeyBackupSetupIntroViewController.storyboard */,
B1DE8610249BB448006454AF /* SecureKeyBackupSetupIntroCell.swift */,
B1DE8612249BB470006454AF /* SecureKeyBackupSetupIntroCell.xib */,
);
path = Intro;
sourceTree = "<group>";
};
B1E5368A21FB6FC0001F3AFF /* Passphrase */ = {
isa = PBXGroup;
children = (
@ -4767,10 +4887,12 @@
F083BDF21E7009ED00A9B29C /* GoogleService-Info.plist in Resources */,
329E746622CD02EA006F9797 /* BubbleReactionActionViewCell.xib in Resources */,
B1B558E320EF768F00210D55 /* RoomEmptyBubbleCell.xib in Resources */,
B1DE85EE249A5981006454AF /* SecureKeyBackupSetupIntroViewController.storyboard in Resources */,
B1E5368F21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard in Resources */,
B1B5590420EF768F00210D55 /* RoomOutgoingAttachmentBubbleCell.xib in Resources */,
B1B558F120EF768F00210D55 /* RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib in Resources */,
B1B557CB20EF5D8000210D55 /* DirectoryServerTableViewCell.xib in Resources */,
B1DE860F249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.storyboard in Resources */,
B1B558EC20EF768F00210D55 /* RoomMembershipCollapsedBubbleCell.xib in Resources */,
B1B558D720EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.xib in Resources */,
B1B5590820EF768F00210D55 /* RoomMembershipWithPaginationTitleBubbleCell.xib in Resources */,
@ -4817,6 +4939,7 @@
F083BE061E7009ED00A9B29C /* Riot-Defaults.plist in Resources */,
B1B558D120EF768F00210D55 /* RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.xib in Resources */,
B1B558FE20EF768F00210D55 /* RoomMembershipExpandedWithPaginationTitleBubbleCell.xib in Resources */,
B15F076B24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewController.storyboard in Resources */,
B1B5581D20EF625800210D55 /* RoomAvatarTitleView.xib in Resources */,
B1BEE74923E093260003A4CB /* UserVerificationSessionStatusViewController.storyboard in Resources */,
B1B5590B20EF768F00210D55 /* RoomMembershipExpandedBubbleCell.xib in Resources */,
@ -4855,6 +4978,7 @@
B105778F2213052A00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.storyboard in Resources */,
B19C4E90248F7A0E009A423F /* SecretsRecoveryWithPassphraseViewController.storyboard in Resources */,
B1B5590F20EF782800210D55 /* TableViewCellWithPhoneNumberTextField.xib in Resources */,
B1DE8613249BB470006454AF /* SecureKeyBackupSetupIntroCell.xib in Resources */,
B19C4E80248F79FD009A423F /* SecretsRecoveryWithKeyViewController.storyboard in Resources */,
B1B5578520EF564900210D55 /* GroupTableViewCellWithSwitch.xib in Resources */,
B1B557B320EF5AEF00210D55 /* EventDetailsView.xib in Resources */,
@ -5084,6 +5208,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B1DE8611249BB448006454AF /* SecureKeyBackupSetupIntroCell.swift in Sources */,
B1B557D120EF5E3500210D55 /* MediaAlbumTableCell.m in Sources */,
32607D71243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift in Sources */,
324A2053225FC571004FE8B0 /* DeviceVerificationIncomingViewModel.swift in Sources */,
@ -5109,6 +5234,7 @@
B1B5581C20EF625800210D55 /* RoomAvatarTitleView.m in Sources */,
B169330820F3CA0E00746532 /* ContactsDataSource.m in Sources */,
B1B5574B20EE6C4D00210D55 /* MediaAlbumContentViewController.m in Sources */,
B1DE85E9249A5733006454AF /* SecureKeyBackupSetupCoordinatorBridgePresenter.swift in Sources */,
B1B5598820EFC3E000210D55 /* WidgetManager.m in Sources */,
B1DB4F0E22316FFF0065DBFA /* UserNameColorGenerator.swift in Sources */,
6E6F1CB524506FA40068B78B /* UITableView.swift in Sources */,
@ -5143,6 +5269,7 @@
B1B558E820EF768F00210D55 /* RoomIncomingAttachmentWithPaginationTitleBubbleCell.m in Sources */,
B1B558F320EF768F00210D55 /* RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m in Sources */,
B12D79FE23E2462200FACEDC /* UserVerificationStartViewController.swift in Sources */,
B15F077224A1F315005E26A1 /* SecretsSetupRecoveryPassphraseInputMode.swift in Sources */,
32607D73243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyCoordinator.swift in Sources */,
B1B557BD20EF5B4500210D55 /* KeyboardGrowingTextView.m in Sources */,
B1A68593229E807A00D6C09A /* RoomBubbleCellLayout.swift in Sources */,
@ -5156,6 +5283,7 @@
B1C960F02458308D00C5704B /* RoundedButton.swift in Sources */,
B1CE83D52422817200D07506 /* KeyVerificationVerifyByScanningViewController.swift in Sources */,
B19C4E8C248F7A0E009A423F /* SecretsRecoveryWithPassphraseViewState.swift in Sources */,
B1DE860C249A5C4B006454AF /* SecretsSetupRecoveryKeyViewModelType.swift in Sources */,
3232ABA3225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift in Sources */,
3232AB4D2256558300AD6A5C /* TemplateScreenCoordinatorType.swift in Sources */,
B1B5581720EF625800210D55 /* PreviewRoomTitleView.m in Sources */,
@ -5173,6 +5301,7 @@
B1B558CB20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
B11291EA238D35590077B478 /* SlidingModalPresentable.swift in Sources */,
B157FAA823264BED00EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift in Sources */,
B1DE85E8249A5733006454AF /* SecureKeyBackupSetupCoordinator.swift in Sources */,
B169330B20F3CA3A00746532 /* Contact.m in Sources */,
B1A5B33E227ADF2A004CBA85 /* UIImage.swift in Sources */,
6E6F1CB324506EC50068B78B /* UITableViewCell.swift in Sources */,
@ -5193,6 +5322,7 @@
B1CE83DC2422817200D07506 /* KeyVerificationVerifyByScanningViewState.swift in Sources */,
B139C21B21FE5B9200BB68EC /* KeyBackupRecoverFromPassphraseViewModel.swift in Sources */,
B1C45A8C232A8C2600165425 /* SettingsIdentityServerViewAction.swift in Sources */,
B1DE85E7249A5733006454AF /* SecureKeyBackupSetupCoordinatorType.swift in Sources */,
32A6001E22C661100042C1D9 /* EditHistoryCoordinatorBridgePresenter.swift in Sources */,
B1B5574A20EE6C4D00210D55 /* MediaPickerViewController.m in Sources */,
B1BEE74623E093260003A4CB /* UserVerificationSessionStatusViewState.swift in Sources */,
@ -5215,6 +5345,7 @@
B157A7BA2445BD86008A5504 /* KeyVerificationScanConfirmationCoordinator.swift in Sources */,
B125FE1D231D5DE400B72806 /* SettingsDiscoveryViewModel.swift in Sources */,
32863A5A2384070300D07C4A /* RiotSharedSettings.swift in Sources */,
B1DE860E249A5C4B006454AF /* SecretsSetupRecoveryKeyViewController.swift in Sources */,
B1B5594720EF7BD000210D55 /* RoomCollectionViewCell.m in Sources */,
B14B17652462C69000C2751E /* KeyVerificationManuallyVerifyViewModel.swift in Sources */,
B14B17662462C69000C2751E /* KeyVerificationManuallyVerifyCoordinatorType.swift in Sources */,
@ -5222,6 +5353,7 @@
B1A6C10B23882B6C002882FD /* SlidingModalPresentationAnimator.swift in Sources */,
B1B558C120EF768F00210D55 /* RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.m in Sources */,
B1B5573E20EE6C4D00210D55 /* RiotNavigationController.m in Sources */,
B15F076C24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseCoordinatorType.swift in Sources */,
B1B5593B20EF7BAC00210D55 /* TableViewCellWithCheckBoxAndLabel.m in Sources */,
B1B5581A20EF625800210D55 /* ExpandedRoomTitleView.m in Sources */,
B1107EC82200B0720038014B /* KeyBackupRecoverSuccessViewController.swift in Sources */,
@ -5241,6 +5373,7 @@
32DB557F22FDADE50016329E /* ServiceTermsModalScreenCoordinator.swift in Sources */,
B157A7B72445BD86008A5504 /* KeyVerificationScanConfirmationViewModel.swift in Sources */,
B1098C1121ED07E4000DDA48 /* NavigationRouterType.swift in Sources */,
B1DE860D249A5C4B006454AF /* SecretsSetupRecoveryKeyViewModel.swift in Sources */,
B1B5573D20EE6C4D00210D55 /* WebViewViewController.m in Sources */,
3209451221F1C1430088CAA2 /* BlackTheme.swift in Sources */,
B1B5572720EE6C4D00210D55 /* RoomSearchViewController.m in Sources */,
@ -5271,7 +5404,6 @@
3232ABC2225B996200AD6A5C /* Themable.swift in Sources */,
32A6001B22C661100042C1D9 /* EditHistoryViewAction.swift in Sources */,
3232ABA7225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift in Sources */,
B1CA93742493BDDF00575122 /* SecretsRecoveryCoordinatorBridgePresenter.swift in Sources */,
6E75C3E32458797D00AF497D /* UniversalLink.m in Sources */,
B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */,
B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */,
@ -5292,6 +5424,7 @@
B1B558E420EF768F00210D55 /* RoomMembershipWithPaginationTitleBubbleCell.m in Sources */,
B18DEDD8243377C10075FEF7 /* KeyVerificationSelfVerifyWaitCoordinatorType.swift in Sources */,
B1B5573620EE6C4D00210D55 /* GroupsViewController.m in Sources */,
B15F077024A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseCoordinator.swift in Sources */,
B125FE21231D5E1D00B72806 /* SettingsDiscoveryViewAction.swift in Sources */,
B108932323AB908A00802670 /* KeyVerificationRequestStatusViewData.swift in Sources */,
B19C4E70248F79EF009A423F /* SecretsRecoveryCoordinator.swift in Sources */,
@ -5311,6 +5444,7 @@
B12D7A0123E2462200FACEDC /* UserVerificationStartViewModel.swift in Sources */,
B12C56EF2396CB5E00FAC6DE /* RoomMessageURLParser.swift in Sources */,
B1BEE73623DF44A60003A4CB /* UserVerificationSessionsStatusCoordinatorType.swift in Sources */,
B1DE8608249A5C4B006454AF /* SecretsSetupRecoveryKeyViewAction.swift in Sources */,
B1C45A86232A8C2600165425 /* SettingsIdentityServerViewModelType.swift in Sources */,
F083BE031E7009ED00A9B29C /* EventFormatter.m in Sources */,
B157FAA623264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewController.swift in Sources */,
@ -5334,12 +5468,14 @@
F0D2ADA11F6AA5FD00A7097D /* MXRoomSummary+Riot.m in Sources */,
B19C4E7C248F79FD009A423F /* SecretsRecoveryWithKeyViewModel.swift in Sources */,
B1CE83B92422815C00D07506 /* KeyVerificationKind.swift in Sources */,
B15F076E24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewModel.swift in Sources */,
B1BEE71423DF2ACF0003A4CB /* UserVerificationCoordinatorType.swift in Sources */,
B1B5596F20EFA85D00210D55 /* EncryptionInfoView.m in Sources */,
B1B5573820EE6C4D00210D55 /* GroupParticipantsViewController.m in Sources */,
3232ABAB225730E100AD6A5C /* KeyVerificationCoordinator.swift in Sources */,
B1BEE73B23DF44A60003A4CB /* UserVerificationSessionsStatusCoordinator.swift in Sources */,
B1B5583E20EF6E7F00210D55 /* GroupRoomTableViewCell.m in Sources */,
B15F076924A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewAction.swift in Sources */,
B14F143522144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewController.swift in Sources */,
B1DCC61E22E5E17100625807 /* EmojiPickerViewModel.swift in Sources */,
B1B5574F20EE6C4D00210D55 /* RoomsViewController.m in Sources */,
@ -5358,6 +5494,7 @@
B183226623F55D6B0035B2E8 /* CameraAccessManager.swift in Sources */,
B1B5571D20EE6C4D00210D55 /* HomeViewController.m in Sources */,
B1CE83DD2422817200D07506 /* KeyVerificationVerifyBySASViewAction.swift in Sources */,
B185AF4F24A2672D00EE7D30 /* SecretsRecoveryCoordinatorBridgePresenter.swift in Sources */,
B1C45A84232A8C2600165425 /* SettingsIdentityServerCoordinatorType.swift in Sources */,
B1DCC63722E8541700625807 /* EmojiStore.swift in Sources */,
3232ABA6225730E100AD6A5C /* DeviceVerificationStartViewController.swift in Sources */,
@ -5454,6 +5591,7 @@
32607D6E243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewModelType.swift in Sources */,
B1B558D020EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */,
B1B558CF20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */,
B1DE8609249A5C4B006454AF /* SecretsSetupRecoveryKeyViewState.swift in Sources */,
B140B4A221F87F7100E3F5FE /* OperationQueue.swift in Sources */,
B14B17612462C69000C2751E /* KeyVerificationManuallyVerifyCoordinator.swift in Sources */,
B183226C23F59F810035B2E8 /* CloseButton.swift in Sources */,
@ -5500,6 +5638,7 @@
B1098BFF21ECFE65000DDA48 /* PasswordStrengthView.swift in Sources */,
B1B558D220EF768F00210D55 /* RoomEncryptedDataBubbleCell.m in Sources */,
B1B558FA20EF768F00210D55 /* RoomMembershipBubbleCell.m in Sources */,
B1DE860B249A5C4B006454AF /* SecretsSetupRecoveryKeyCoordinatorType.swift in Sources */,
B157FAA223264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewAction.swift in Sources */,
B1CE83D72422817200D07506 /* KeyVerificationVerifyByScanningViewModelType.swift in Sources */,
3232ABA1225730E100AD6A5C /* KeyVerificationCoordinatorType.swift in Sources */,
@ -5520,6 +5659,7 @@
324A2050225FC571004FE8B0 /* DeviceVerificationIncomingViewController.swift in Sources */,
B1098C0D21ED07E4000DDA48 /* NavigationRouter.swift in Sources */,
B110872321F098F0003554A5 /* ActivityIndicatorPresenterType.swift in Sources */,
B1DE860A249A5C4B006454AF /* SecretsSetupRecoveryKeyCoordinator.swift in Sources */,
B139C22321FF01B200BB68EC /* KeyBackupRecoverFromPassphraseCoordinatorType.swift in Sources */,
B14084CE23BFA0990010F692 /* KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift in Sources */,
B14F143222144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinator.swift in Sources */,
@ -5527,6 +5667,7 @@
B1CE83E02422817200D07506 /* KeyVerificationVerifyBySASViewController.swift in Sources */,
B19EFA3921F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift in Sources */,
B1C3360322F1ED600021BA8D /* MediaPickerCoordinator.swift in Sources */,
B15F076D24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewState.swift in Sources */,
B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */,
B1963B3822933BC800CBA17F /* AutosizedCollectionView.swift in Sources */,
B12D79FB23E2462200FACEDC /* UserVerificationStartCoordinator.swift in Sources */,
@ -5590,6 +5731,7 @@
B1CE83DA2422817200D07506 /* KeyVerificationVerifyByScanningViewModel.swift in Sources */,
32242F0921E8B05F00725742 /* UIColor.swift in Sources */,
B16932E720F3C37100746532 /* HomeMessagesSearchDataSource.m in Sources */,
B1DE85EC249A5819006454AF /* SecureKeyBackupSetupIntroViewController.swift in Sources */,
B12D79FF23E2462200FACEDC /* UserVerificationStartViewState.swift in Sources */,
B1B558CE20EF768F00210D55 /* RoomOutgoingEncryptedAttachmentBubbleCell.m in Sources */,
B14B17672462C69000C2751E /* KeyVerificationManuallyVerifyViewState.swift in Sources */,
@ -5608,11 +5750,13 @@
B1B9DEEE22EB34EF0065E677 /* ReactionHistoryViewAction.swift in Sources */,
B1C543A4239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift in Sources */,
B1CE83B62422812100D07506 /* KeyVerificationCoordinatorBridgePresenter.swift in Sources */,
B15F076F24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewModelType.swift in Sources */,
32B94DFA228EC26400716A26 /* ReactionsMenuButton.swift in Sources */,
B1B9DEEC22EB34EF0065E677 /* ReactionHistoryViewModelType.swift in Sources */,
B157FAA523264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift in Sources */,
B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */,
B14F143022144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift in Sources */,
B15F076A24A0FBA7005E26A1 /* SecretsSetupRecoveryPassphraseViewController.swift in Sources */,
B1E5368921FB1E20001F3AFF /* UIButton.swift in Sources */,
B1DCC63422E72C1B00625807 /* UISearchBar.swift in Sources */,
32A6001622C661100042C1D9 /* EditHistoryViewState.swift in Sources */,

View file

@ -2962,7 +2962,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
};
[mxSession canEnableE2EByDefaultInNewRoomWithUsers:invite success:^(BOOL canEnableE2E) {
[mxSession riot_canEnableE2EByDefaultInNewRoomWithUsers:invite success:^(BOOL canEnableE2E) {
MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters new];
roomCreationParameters.visibility = kMXRoomDirectoryVisibilityPrivate;

View file

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "secrets_setup_key.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "secrets_setup_key@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "secrets_setup_key@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "secrets_setup_passphrase.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "secrets_setup_passphrase@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "secrets_setup_passphrase@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -381,7 +381,7 @@
"room_details_advanced_enable_e2e_encryption" = "Включване на шифроване (не може да се изключи в последствие!)";
"room_details_advanced_e2e_encryption_enabled" = "Шифроването е включено в тази стая";
"room_details_advanced_e2e_encryption_disabled" = "Шифроването не е включено в тази стая.";
"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Шифроване само за потвърдени устройства";
"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Шифроване само за потвърдени сесии";
"room_details_advanced_e2e_encryption_prompt_message" = "Шифроване от край до край е експериментално и може да не е надеждно.\n\nВсе още не трябва да се доверявате на това, че ще защити Вашите данни.\n\nУстройства все още не могат да разшифроват история от преди присъединяването към стая.\n\nВеднъж включено, шифроването в стаята не може да бъде изключено (за сега).\n\nШифровани съобщения не са видими за клиенти, които все още не поддържат шифроване.";
"room_details_fail_to_update_avatar" = "Неуспешно обновяване на снимката на стаята";
"room_details_fail_to_update_room_name" = "Неуспешно обновяване на името на стаята";
@ -457,8 +457,8 @@
// Call
"call_incoming_voice_prompt" = "Входящо гласово повикване от %@";
"call_incoming_video_prompt" = "Входящо видео повикване от %@";
"call_incoming_voice" = "Входящо повикване...";
"call_incoming_video" = "Входящо видео повикване...";
"call_incoming_voice" = "Входящо повикване";
"call_incoming_video" = "Входящо видео повикване";
"call_already_displayed" = "В момента тече разговор.";
"call_jitsi_error" = "Неуспешно присъединяване към групов разговор.";
// No VoIP support
@ -477,7 +477,7 @@
"google_analytics_use_prompt" = "Искате ли да помогнете за подобрението на %@ като анонимно изпращате съобщения за грешки и данни за използване?";
// Crypto
"e2e_enabling_on_app_update" = "Riot поддържа шифроване от край до край, но за да го включите трябва да влезете в профила си отново.\n\nМоже да го направите сега или по-късно от настройките на приложението.";
"e2e_need_log_in_again" = "Трябва да влезете обратно в профила си, за да се създадат ключове за шифроване от край до край за това устройство и да се изпрати публичния ключ към Home сървъра.\nТова е еднократно. Извинете за неудобството.";
"e2e_need_log_in_again" = "Трябва да влезете обратно в профила си, за да се създадат ключове за шифроване от-край-до-край за тази сесия и да се изпрати публичния ключ към Home сървъра.\nТова е еднократно. Извинете за неудобството.";
"bug_crash_report_description" = "Моля, опишете какво правихте преди да възникне грешката:";
"bug_report_logs_description" = "За да се диагностицират проблемите, логовете от този клиент ще бъдат изпратени с този доклад за грешки. Ако предпочитате да изпратите само текста по-горе, моля, премахнете отметката:";
// Widget
@ -499,9 +499,9 @@
"share_extension_failed_to_encrypt" = "Неуспешно изпращане. Проверете ключовете за шифроване за тази стая в главното приложение";
// Room key request dialog
"e2e_room_key_request_title" = "Заявка за ключ за шифроване";
"e2e_room_key_request_message_new_device" = "Добавихте ново устройство '%@', което изисква ключове за шифроване.";
"e2e_room_key_request_message" = "Вашето непотвърдено устройство '%@' изисква ключове за шифроване.";
"e2e_room_key_request_start_verification" = "Започни потвърждението...";
"e2e_room_key_request_message_new_device" = "Добавихте нова сесия '%@', която изисква ключове за шифроване.";
"e2e_room_key_request_message" = "Вашата непотвърдена сесия '%@' изисква ключове за шифроване.";
"e2e_room_key_request_start_verification" = "Започни потвърждението";
"e2e_room_key_request_share_without_verifying" = "Сподели без потвърждение";
"e2e_room_key_request_ignore_request" = "Игнорирай поканата";
"room_warning_about_encryption" = "Шифроване от край до край е в бета версия и може да не е надеждно.\n\nВсе още не трябва да се доверявате на това, че ще защити Вашите данни.\n\nУстройства все още не могат да разшифроват история от преди присъединяването към стая.\n\nШифровани съобщения не са видими за клиенти, които все още не поддържат шифроване.";
@ -532,10 +532,10 @@
"deactivate_account_password_alert_title" = "Деактивиране на акаунт";
"deactivate_account_password_alert_message" = "За да продължите, моля въведете паролата си";
"event_formatter_rerequest_keys_part1_link" = "Изисквай повторно ключове за шифроване";
"event_formatter_rerequest_keys_part2" = " от другите ми устройства.";
"event_formatter_rerequest_keys_part2" = " от другите ми сесии.";
// Re-request confirmation dialog
"rerequest_keys_alert_title" = "Заявката е изпратена";
"rerequest_keys_alert_message" = "Моля стартирайте Riot на друго устройство можещо да разшифрова съобщението, за да може то да изпрати ключовете до това устройство.";
"rerequest_keys_alert_message" = "Моля стартирайте Riot на друго устройство можещо да разшифрова съобщението, за да може то да изпрати ключовете до тази сесия.";
"room_message_reply_to_placeholder" = "Изпрати отговор (нешифрован)…";
"encrypted_room_message_reply_to_placeholder" = "Изпрати шифрован отговор…";
"room_message_reply_to_short_placeholder" = "Изпрати отговор…";
@ -684,27 +684,27 @@
"settings_labs_message_reaction" = "Реагирай на съобщения с емоджи";
"settings_key_backup_button_connect" = "Свържи сесията към резервно копие на ключове";
"key_backup_setup_intro_setup_connect_action_with_existing_backup" = "Свържи устройството към резервно копие на ключове";
"key_backup_recover_connent_banner_subtitle" = "Свържи устройството към резервно копие на ключове";
"key_backup_recover_connent_banner_subtitle" = "Свържи сесията към резервно копие на ключове";
// MARK: - Device Verification
"device_verification_title" = "Потвърждение на устройство";
"device_verification_security_advice" = "За максимална сигурност, препоръчваме да правите това на живо или използвайки друг защитен начин за комуникация";
"device_verification_cancelled" = "Отсрещната страна отказа потвърждението.";
"device_verification_cancelled_by_me" = "Потвърждението беше отказано. Причина: %@";
"device_verification_error_cannot_load_device" = "Неуспешно зареждане на информация за устройството.";
"device_verification_error_cannot_load_device" = "Неуспешно зареждане на информация за сесията.";
// Mark: Incoming
"device_verification_incoming_title" = "Входяща заявка за потвърждение";
"device_verification_incoming_description_1" = "Потвърдете това устройство за да го маркирате като доверено. Доверяването на устройства на партньори Ви дава допълнително спокойствие когато използвате шифроване от-край-до-край.";
"device_verification_incoming_description_2" = "Потвърждаването на устройството ще го маркира като доверено и ще маркира Вашето като доверено при партньора.";
"device_verification_incoming_description_1" = "Потвърдете тази сесия за да я маркирате като доверена. Доверяването на сесии на партньори ви дава допълнително спокойствие когато използвате шифроване от-край-до-край.";
"device_verification_incoming_description_2" = "Потвърждаването на сесията ще я маркира като доверена и ще маркира вашето като доверена при партньора.";
// MARK: Start
"device_verification_start_title" = "Потвърждение чрез сравняване на кратък текст";
"device_verification_start_wait_partner" = "Изчакване на партньора да приеме...";
"device_verification_start_wait_partner" = "Изчакване на партньора да приеме";
"device_verification_start_use_legacy" = "Не се показва нищо? Засега не всички клиенти поддържат интерактивно потвърждение. Използвайте стария метод за потвърждение.";
"device_verification_start_verify_button" = "Започни потвърждение";
"device_verification_start_use_legacy_action" = "Потвърди по стария метод";
// MARK: Verify
"device_verification_verify_title_emoji" = "Потвърдете това устройство като се уверите че следните емоджита се повяват на екрана на партньора";
"device_verification_verify_title_number" = "Потвърдете това устройство като се уверите че следните числа се повяват на екрана на партньора";
"device_verification_verify_wait_partner" = "Изчакване на потвърждение от партньора...";
"device_verification_verify_wait_partner" = "Изчакване на потвърждение от партньора";
// MARK: Verified
"device_verification_verified_title" = "Потвърдено!";
"device_verification_verified_description_1" = "Успешно потвърдихте това устройство.";
@ -927,7 +927,7 @@
"accessibility_checkbox_label" = "отметка";
"settings_labs_dm_key_verification" = "Потвърждение на ключ чрез директно съобщение";
"settings_labs_cross_signing" = "Кръстосано-подписване";
"widget_picker_manage_integrations" = "Управление на интеграциите...";
"widget_picker_manage_integrations" = "Управление на интеграциите";
// Room widget permissions
"room_widget_permission_title" = "Зареждане на приспособление";
"room_widget_permission_creator_info_title" = "Приспособлението беше добавено от:";
@ -966,3 +966,151 @@
"room_member_power_level_short_admin" = "Админ";
"room_member_power_level_short_moderator" = "Модератор";
"room_member_power_level_short_custom" = "Собствен";
"room_participants_action_security_status_complete_security" = "Завършете сигурността";
"security_settings_crypto_sessions_description" = "Доверете се на сесии за да им дадете достъп до съобщенията шифровани от-край-до-край. Ако не разпознавате дадена сесия, променете паролата си и нулирайте паролата за съобщения използваща се за резервни копия на съобщенията.";
"security_settings_backup" = "РЕЗЕРВНИ КОПИЯ НА СЪОБЩЕНИЯ";
"security_settings_crosssigning" = "КРЪСТОСАНО-ПОДПИСВАНЕ";
"security_settings_crosssigning_info_not_bootstrapped" = "Кръстосаното-подписване все още не е настроено.";
"security_settings_crosssigning_info_exists" = "Профилът ви има идентичност за кръстосано-подписване, но все още не е доверена от тази сесия. Завършете сигурността за тази сесия.";
"security_settings_crosssigning_info_trusted" = "Кръстосаното-подписване е включено. Можете да се доверявате на други потребители и други сесии на базата на кръстосано-подписване, но не можете да подписвате от тази сесия, защото нямате частни ключове за кръстосано подписване. Завършете сигурността за тази сесия.";
"security_settings_crosssigning_info_ok" = "Кръстосаното-подписване е включено.";
"security_settings_crosssigning_bootstrap" = "Настрой кръстосано-подписване";
"security_settings_crosssigning_reset" = "Нулирай кръстосаното-подписване";
"security_settings_crosssigning_complete_security" = "Завърши сигурността";
"security_settings_cryptography" = "КРИПТОГРАФИЯ";
"security_settings_export_keys_manually" = "Експортирай ключовете ръчно";
"security_settings_advanced" = "РАЗШИРЕНИ";
"security_settings_blacklist_unverified_devices" = "Никога не изпращай съобщения към недоверени сесии";
"security_settings_blacklist_unverified_devices_description" = "Потвърждаване на всички потребителски сесии за да бъдат маркирани като доверени и да се изпращат съобщения до тях.";
"security_settings_complete_security_alert_title" = "Завършване на сигурността";
"security_settings_complete_security_alert_message" = "Първо трябва да завършите сигурността на текущата си сесия.";
"security_settings_coming_soon" = "Извинете. Това действие все още не е налично в Riot-iOS. Моля използвайте друг Matrix клиент за да го настройте. Riot-iOS ще го използва след това.";
// Manage session
"manage_session_title" = "Управление на сесията";
"manage_session_info" = "СЕСИЙНА ИНФОРМАЦИЯ";
"manage_session_name" = "Име на сесия";
"manage_session_trusted" = "Доверена от вас";
"manage_session_not_trusted" = "Недоверена";
"manage_session_sign_out" = "Излез от тази сесия";
// Recover from private key
"key_backup_recover_from_private_key_info" = "Възстановяване на резервно копие…";
// MARK: - Device Verification
"key_verification_other_session_title" = "Потвърждаване на сесия";
"key_verification_new_session_title" = "Потвърждаване на новата ви сесия";
"key_verification_this_session_title" = "Потвърждаване на тази сесия";
"key_verification_user_title" = "Потвърждение";
"device_verification_security_advice_emoji" = "Сравнете уникалните емоджита, подсигурявайки, че се появяват в същата последователност.";
"device_verification_security_advice_number" = "Сравнете числата, подсигурявайки, че се появяват в същата последователност.";
// New login
"device_verification_self_verify_alert_title" = "Нов вход. Вие ли бяхте?";
"device_verification_self_verify_alert_message" = "Потвърдете входа достъпващ профила ви: %@";
"device_verification_self_verify_alert_validate_action" = "Потвърди";
"device_verification_self_verify_start_verify_action" = "Започни потвърждение";
"device_verification_self_verify_start_information" = "Използвайте тази сесия за да потвърдите новата, давайки й достъп до шифрованите съобщения.";
"device_verification_self_verify_start_waiting" = "Изчакване…";
"key_verification_self_verify_current_session_alert_title" = "Потвърждение на тази сесия";
"key_verification_self_verify_current_session_alert_message" = "Други потребители може да не й се доверяват.";
"key_verification_self_verify_current_session_alert_validate_action" = "Потвърди";
"key_verification_self_verify_unverified_sessions_alert_title" = "Преглед на входовете";
"key_verification_self_verify_unverified_sessions_alert_message" = "Потвърдете всичките си сесии за да подсигурите че профила и съобщенията ви са защитени.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Прегледай";
"device_verification_self_verify_wait_title" = "Завършване на сигурността";
"device_verification_self_verify_wait_new_sign_in_title" = "Потвърждение на вход";
"device_verification_self_verify_wait_information" = "Потвърдете тази сесия от някоя от другите ви сесии, така че да й дадете достъп до шифрованите съобщения.\n\nИзползвайте най-новия Riot на другите си устройства:";
"device_verification_self_verify_wait_additional_information" = "или друг Matrix клиент поддържащ кръстосано-подписване";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Използвай ключ за възстановяване";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Използвай парола или ключ за възстановяване";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Ако не можете да достъпите съществуваща сесия";
"key_verification_verify_sas_title_emoji" = "Сравнение на емоджита";
"key_verification_verify_sas_title_number" = "Сравнение на числа";
"key_verification_verify_sas_cancel_action" = "Не съвпадат";
"key_verification_verify_sas_validate_action" = "Съвпадат";
"key_verification_verify_sas_additional_information" = "За най-добра сигурност, използвайте друг доверен начин за комуникация или направете това на живо.";
"key_verification_manually_verify_device_title" = "Ръчно потвърждение чрез текстово съобщение";
"key_verification_manually_verify_device_instruction" = "Потвърдете, чрез сравнение на следното в Настройки в другата ви сесия:";
"key_verification_manually_verify_device_name_title" = "Име на сесия";
"key_verification_manually_verify_device_id_title" = "Идентификатор на сесия";
"key_verification_manually_verify_device_key_title" = "Ключ на сесия";
"key_verification_manually_verify_device_additional_information" = "Ако не съвпадат, сигурността на комуникацията ви може да е компрометирана.";
"key_verification_manually_verify_device_validate_action" = "Потвърди";
"key_verification_verified_new_session_title" = "Новата сесия беше потвърдена!";
"key_verification_verified_other_session_information" = "Вече може да четете защитени съобщения в другата сесия, а други потребители ще знаят да й се доверяват.";
"key_verification_verified_new_session_information" = "Вече може да четете защитени съобщения на новото си устройство, а други потребители ще знаят да му се доверяват.";
"key_verification_verified_this_session_information" = "Вече може да четете защитени съобщения на това устройство, а други потребители ще знаят да му се доверяват.";
"key_verification_verified_user_information" = "Съобщенията с този потребител са шифровани от-край-до-край и не могат да бъдат прочетени от трети страни.";
"key_verification_bootstrap_not_setup_title" = "Грешка";
"key_verification_bootstrap_not_setup_message" = "Първо трябва да настройте кръстосано-подписване.";
"key_verification_tile_request_incoming_title" = "Заявка за потвърждение";
"key_verification_tile_request_outgoing_title" = "Потвърждението беше изпратено";
"key_verification_tile_request_status_data_loading" = "Зареждане на данни…";
"key_verification_tile_request_status_waiting" = "Изчакване…";
"key_verification_tile_request_status_expired" = "Изтекло";
"key_verification_tile_request_status_cancelled_by_me" = "Отказахте";
"key_verification_tile_request_status_cancelled" = "%@ отказа";
"key_verification_tile_request_status_accepted" = "Приехте";
"key_verification_tile_request_incoming_approval_accept" = "Приеми";
"key_verification_tile_request_incoming_approval_decline" = "Откажи";
"key_verification_tile_conclusion_done_title" = "Потвърдено";
"key_verification_tile_conclusion_warning_title" = "Недоверен вход";
"key_verification_incoming_request_incoming_alert_message" = "%@ иска да извърши потвърждение";
"key_verification_verify_qr_code_title" = "Потвърждение чрез сканиране";
"key_verification_verify_qr_code_information" = "Сканирайте този код за да потвърдите по сигурен начин един друг.";
"key_verification_verify_qr_code_information_other_device" = "Сканирайте кода по-долу за да потвърдите:";
"key_verification_verify_qr_code_emoji_information" = "Потвърждение чрез сравняване на уникални емоджита.";
"key_verification_verify_qr_code_scan_code_action" = "Сканирайте кода им";
"key_verification_verify_qr_code_cannot_scan_action" = "Не можете да сканирате?";
"key_verification_verify_qr_code_start_emoji_action" = "Потвърждение чрез емоджи";
"key_verification_verify_qr_code_other_scan_my_code_title" = "Другия потребител сканира ли успешно QR кода?";
"key_verification_verify_qr_code_scan_other_code_success_title" = "Кодът беше валидиран!";
"key_verification_verify_qr_code_scan_other_code_success_message" = "QR кодът беше валидиран успешно.";
// Scanning
"key_verification_scan_confirmation_scanning_title" = "Почти приключихте! Изчакване на потвърждение…";
"key_verification_scan_confirmation_scanning_user_waiting_other" = "Изчакване на %@…";
"key_verification_scan_confirmation_scanning_device_waiting_other" = "Изчакване на другото устройство…";
// Scanned
"key_verification_scan_confirmation_scanned_title" = "Почти приключихте!";
"key_verification_scan_confirmation_scanned_user_information" = "Показва ли се същия щит при %@?";
"key_verification_scan_confirmation_scanned_device_information" = "Показва ли се същия щит на другото устройство?";
"user_verification_start_verify_action" = "Започнете потвърждение";
"user_verification_start_information_part1" = "За допълнителна сигурност, потвърдете ";
"user_verification_start_information_part2" = " чрез проверяване на еднократен код на двете устройства.";
"user_verification_start_waiting_partner" = "Изчакване на %@…";
"user_verification_start_additional_information" = "За да е сигурно, направете това на живо или чрез използване на друг начин за комуникация.";
"user_verification_sessions_list_user_trust_level_trusted_title" = "Доверено";
"user_verification_sessions_list_user_trust_level_warning_title" = "Внимание";
"user_verification_sessions_list_user_trust_level_unknown_title" = "Непознато";
"user_verification_sessions_list_information" = "Съобщенията с този потребител в тази стая са шифровани от-край-до-край и не могат да бъдат прочетени от трети страни.";
"user_verification_sessions_list_table_title" = "Сесии";
"user_verification_sessions_list_session_trusted" = "Доверена";
"user_verification_sessions_list_session_untrusted" = "Недоверена";
"user_verification_session_details_trusted_title" = "Доверена";
"user_verification_session_details_untrusted_title" = "Недоверена";
"user_verification_session_details_information_trusted_current_user" = "Тази сесия е доверена за сигурна комуникация, защото сте я потвърдили:";
"user_verification_session_details_information_trusted_other_user_part1" = "Тази сесия е доверена за сигурна комуникация, защото ";
"user_verification_session_details_information_trusted_other_user_part2" = " я е потвърдил:";
"user_verification_session_details_information_untrusted_current_user" = "Потвърдете тази сесия за да я маркирате като доверена и да й дадете достъп до шифрованите съобщения:";
"user_verification_session_details_information_untrusted_other_user" = " влезе използвайки нова сесия:";
"user_verification_session_details_additional_information_untrusted_other_user" = "Докато този потребител се довери на тази сесия, съобщенията изпратени от и към нея ще бъдат маркирани с предупреждения. Друго решение е да я потвърдите ръчно.";
"user_verification_session_details_additional_information_untrusted_current_user" = "Ако не сте се вписвали в тази сесия, профилът ви може да е бил компрометиран.";
"user_verification_session_details_verify_action_current_user" = "Потвърди интерактивно";
"user_verification_session_details_verify_action_current_user_manually" = "Потвърди ръчно чрез текстово съобщение";
"user_verification_session_details_verify_action_other_user" = "Потвърди ръчно";
"secrets_recovery_with_passphrase_title" = "Парола за възстановяване";
"secrets_recovery_with_passphrase_information_default" = "Достъпете защитената история на съобщенията и идентичността си за кръстосано-подписване (за потвърждение на други сесии), чрез въвеждане на паролата за възстановяване.";
"secrets_recovery_with_passphrase_information_verify_device" = "Използвайте паролата за възстановяване за да потвърдите това устройство.";
"secrets_recovery_with_passphrase_passphrase_title" = "Въвеждане";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Въведете паролата за възстановяване";
"secrets_recovery_with_passphrase_recover_action" = "Използвай парола";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Не знаете паролата си за възстановяване? Можете да ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "използвате ключа за възстановяване";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Неуспешен достъп до секретното складиране";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Потвърдете, че сте въвели правилната парола за възстановяване.";
"secrets_recovery_with_key_title" = "Ключ за възстановяване";
"secrets_recovery_with_key_information_default" = "Достъпете защитената история на съобщенията и самоличността за кръстосано-подписване (за потвърждение на други сесии), чрез въвеждане на ключа за възстановяване.";
"secrets_recovery_with_key_information_verify_device" = "Използвайте ключа за възстановяване за потвърждение на това устройство.";
"secrets_recovery_with_key_recovery_key_title" = "Въвеждане";
"secrets_recovery_with_key_recovery_key_placeholder" = "Въвеждане на ключ за възстановяване";
"secrets_recovery_with_key_recover_action" = "Използвай ключа";
"secrets_recovery_with_key_invalid_recovery_key_title" = "Неуспешно достъпване на секретното складиране";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Потвърдете, че сте въвели правилния ключ за възстановяване.";

View file

@ -961,7 +961,7 @@
"key_verification_tile_request_status_waiting" = "Warten…";
"key_verification_tile_request_status_expired" = "Abgelaufen";
"key_verification_tile_request_status_cancelled_by_me" = "Du hast abgebrochen";
"key_verification_tile_request_status_cancelled" = "%s brach ab";
"key_verification_tile_request_status_cancelled" = "%@ brach ab";
"key_verification_tile_request_status_accepted" = "Du hast akzeptiert";
"key_verification_tile_request_incoming_approval_accept" = "Akzeptieren";
"key_verification_tile_request_incoming_approval_decline" = "Ablehnen";

View file

@ -919,6 +919,25 @@
"rerequest_keys_alert_title" = "Request Sent";
"rerequest_keys_alert_message" = "Please launch Riot on another device that can decrypt the message so it can send the keys to this session.";
// MARK: Secure Key backup setup
// Intro
"secure_key_backup_setup_intro_title" = "Secure Backup";
"secure_key_backup_setup_intro_info" = "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.";
"secure_key_backup_setup_intro_use_security_key_title" = "Use a Security Key";
"secure_key_backup_setup_intro_use_security_key_info" = "Generate a security key to store somewhere safe like a password manager or a safe.";
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Use a Security Passphrase";
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Enter a secret phrase only you know, and generate a key for backup.";
// Cancel
"secure_key_backup_setup_cancel_alert_title" = "Are your sure?";
"secure_key_backup_setup_cancel_alert_message" = "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.\n\nYou can also set up Secure Backup & manage your keys in Settings.";
// MARK: Key backup setup
"key_backup_setup_title" = "Key Backup";
@ -1342,3 +1361,31 @@
"secrets_recovery_with_key_invalid_recovery_key_title" = "Unable to access secret storage";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Please verify that you entered the correct recovery key.";
// MARK: - Secrets set up
// Recovery Key
"secrets_setup_recovery_key_title" = "Save your Security Key";
"secrets_setup_recovery_key_information" = "Store your Recovery Key somewhere safe. It can be used to unlock your encrypted messages & data.";
"secrets_setup_recovery_key_loading" = "Loading…";
"secrets_setup_recovery_key_export_action" = "Save";
"secrets_setup_recovery_key_done_action" = "Done";
"secrets_setup_recovery_key_storage_alert_title" = "Keep it safe";
"secrets_setup_recovery_key_storage_alert_message" = "✓ Print it and store it somewhere safe\n✓ Save it on a USB key or backup drive\n✓ Copy it to your personal cloud storage";
// Recovery passphrase
"secrets_setup_recovery_passphrase_title" = "Set a Security Phrase";
"secrets_setup_recovery_passphrase_information" = "Enter a security phrase only you know, used to secure secrets on your server.";
"secrets_setup_recovery_passphrase_additional_information" = "Don't use your account password.";
"secrets_setup_recovery_passphrase_validate_action" = "Done";
"secrets_setup_recovery_passphrase_confirm_information" = "Enter your Security Phrase again to confirm it.";
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Confirm";
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Confirm passphrase";
"key_backup_setup_passphrase_confirm_passphrase_valid" = "Great!";
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Passphrase doesnt match";

View file

@ -1086,3 +1086,25 @@
"key_verification_verify_qr_code_emoji_information" = "Egiaztatu emoji bakanak konparatuz.";
"key_verification_verify_qr_code_start_emoji_action" = "Egiaztatu emoji bidez";
"user_verification_session_details_verify_action_current_user_manually" = "Egiaztatu eskuz testu bidez";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Erabili berreskuratze gakoa";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Erabili berreskuratze pasa-esaldia edo gakoa";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Ezin baduzu dagoen saio bat erabili";
"secrets_recovery_with_passphrase_title" = "Berreskuratze pasa-esaldia";
"secrets_recovery_with_passphrase_information_default" = "Atzitu zure mezu seguruen historiala eta zeharkako sinatzerako identitatea beste saioak egiaztatzeko zure berreskuratze pasa-esaldia sartuz.";
"secrets_recovery_with_passphrase_information_verify_device" = "Erabili berreskuratze pasa-esaldia gailu hau egiaztatzeko.";
"secrets_recovery_with_passphrase_passphrase_title" = "Sartu";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Sartu berreskuratze pasa-esaldia";
"secrets_recovery_with_passphrase_recover_action" = "Erabili pasa-esaldia";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Ez duzu berreskuratze pasa-esaldia gogoratzen? ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "erabili berreskuratze-gakoa";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Ezin izan da biltegi sekretua atzitu";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Egiaztatu berreskuratze pasa-esaldi zuzena sartu duzula.";
"secrets_recovery_with_key_title" = "Berreskuratze gakoa";
"secrets_recovery_with_key_information_default" = "Atzitu zure mezu seguruen historiala eta zeharkako sinatzerako identitatea beste saioak egiaztatzeko zure berreskuratze gakoa sartuz.";
"secrets_recovery_with_key_information_verify_device" = "Erabili berreskuratze gakoa gailu hau egiaztatzeko.";
"secrets_recovery_with_key_recovery_key_title" = "Sartu";
"secrets_recovery_with_key_recovery_key_placeholder" = "Sartu berreskuratze-gakoa";
"secrets_recovery_with_key_recover_action" = "Erabili gakoa";
"secrets_recovery_with_key_invalid_recovery_key_title" = "Ezin izan da biltegi sekretua atzitu";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Egiaztatu berreskuratze gako zuzena sartu duzula.";

View file

@ -1101,3 +1101,25 @@
"key_verification_manually_verify_device_additional_information" = "Sils ne correspondent pas, la sécurité de vos communications est peut-être compromise.";
"key_verification_manually_verify_device_validate_action" = "Vérifier";
"user_verification_session_details_verify_action_current_user_manually" = "Vérifier manuellement avec un texte";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Utiliser la clé de récupération";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Utiliser la phrase secrète ou la clé de récupération";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Si vous ne pouvez pas accéder à une session existante";
"secrets_recovery_with_passphrase_title" = "Phrase secrète de récupération";
"secrets_recovery_with_passphrase_information_default" = "Accédez à lhistorique de vos messages sécurisés et à votre identité de signature croisée pour vérifier dautres sessions en saisissant votre phrase secrète de récupération.";
"secrets_recovery_with_passphrase_information_verify_device" = "Utilisez votre phrase secrète de récupération pour vérifier cet appareil.";
"secrets_recovery_with_passphrase_passphrase_title" = "Saisir";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Saisir la phrase secrète de récupération";
"secrets_recovery_with_passphrase_recover_action" = "Utiliser la phrase secrète";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Vous ne connaissez pas votre phrase secrète de récupération ? Vous pouvez ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "utiliser votre clé de récupération";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Impossible daccéder au coffre secret";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Vérifiez que vous avez saisi la bonne phrase secrète de récupération.";
"secrets_recovery_with_key_title" = "Clé de récupération";
"secrets_recovery_with_key_information_default" = "Accédez à lhistorique de vos messages sécurisés et à votre identité de signature croisée pour vérifier dautres sessions en renseignant votre clé de récupération.";
"secrets_recovery_with_key_information_verify_device" = "Utilisez votre clé de récupération pour vérifier cet appareil.";
"secrets_recovery_with_key_recovery_key_title" = "Saisir";
"secrets_recovery_with_key_recovery_key_placeholder" = "Saisir la clé de récupération";
"secrets_recovery_with_key_recover_action" = "Utiliser la clé";
"secrets_recovery_with_key_invalid_recovery_key_title" = "Impossible daccéder au coffre secret";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Vérifiez que vous avez saisi la bonne clé de récupération.";

View file

@ -1103,3 +1103,25 @@
"key_verification_manually_verify_device_additional_information" = "Ha nem egyeznek akkor a kommunikációtok biztonsága veszélyben lehet.";
"key_verification_manually_verify_device_validate_action" = "Ellenőriz";
"user_verification_session_details_verify_action_current_user_manually" = "Manuális szöveges ellenőrzés";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Használd a Visszaállítási Kulcsot";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Használd a Visszaállítási Jelmondatot vagy Kulcsot";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Ha nem érsz el létező munkamenetet";
"secrets_recovery_with_passphrase_title" = "Visszaállítási Jelmondat";
"secrets_recovery_with_passphrase_information_default" = "A visszaállítási jelmondat megadásával hozzáférhetsz a titkosított üzeneteidhez és az eszközök közötti aláírásnál használt személyazonosságodhoz hogy más munkameneteket ellenőrizhess.";
"secrets_recovery_with_passphrase_information_verify_device" = "Használd a visszaállítási jelmondatot az eszköz ellenőrzésére.";
"secrets_recovery_with_passphrase_passphrase_title" = "Bevitel";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Visszaállítási jelmondat megadása";
"secrets_recovery_with_passphrase_recover_action" = "Használd a jelmondatot";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Nem emlékszel a visszaállítási jelmondatodra? Használhatod a ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "visszaállítási kulcs használata";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "A biztonsági tárolót nem sikerült elérni";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Kérlek ellenőrizd, hogy a visszaállítási jelmondatot helyesen írtad be.";
"secrets_recovery_with_key_title" = "Visszaállítási Kulcs";
"secrets_recovery_with_key_information_default" = "A visszaállítási kulcs megadásával hozzáférhetsz a biztonságos üzeneteidhez és az eszközök közötti hitelesítéshez használt személyazonosságodhoz, hogy más munkameneteket hitelesíthess.";
"secrets_recovery_with_key_information_verify_device" = "Használd a visszaállítási kulcsot az eszköz ellenőrzésére.";
"secrets_recovery_with_key_recovery_key_title" = "Bevitel";
"secrets_recovery_with_key_recovery_key_placeholder" = "Visszaállítási Kulcs megadása";
"secrets_recovery_with_key_recover_action" = "Használd a kulcsot";
"secrets_recovery_with_key_invalid_recovery_key_title" = "A biztonsági tárolót nem sikerült elérni";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Kérlek ellenőrizd, hogy a visszaállítási kulcsot helyesen írtad be.";

View file

@ -1075,3 +1075,25 @@
"key_verification_manually_verify_device_additional_information" = "Se non corrispondono, la sicurezza delle tue comunicazioni potrebbe essere compromessa.";
"key_verification_manually_verify_device_validate_action" = "Verifica";
"user_verification_session_details_verify_action_current_user_manually" = "Verifica manualmente con testo";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Usa chiave di recupero";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Usa password o chiave di recupero";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Se non puoi accedere a una sessione esistente";
"secrets_recovery_with_passphrase_title" = "Password di recupero";
"secrets_recovery_with_passphrase_information_default" = "Accedi alla tua cronologia dei messaggi sicuri e all'identità della firma incrociata per verificare altre sessioni inserendo la password di recupero.";
"secrets_recovery_with_passphrase_information_verify_device" = "Usa la password di recupero per verificare questo dispositivo.";
"secrets_recovery_with_passphrase_passphrase_title" = "Inserisci";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Inserisci la password di recupero";
"secrets_recovery_with_passphrase_recover_action" = "Usa password";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Non conosci la tua password di recupero? Puoi ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "usare la chiave di recupero";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Impossibile accedere all'archivio segreto";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Controlla di avere inserito la password di recupero corretta.";
"secrets_recovery_with_key_title" = "Chiave di recupero";
"secrets_recovery_with_key_information_default" = "Accedi alla tua cronologia dei messaggi sicuri e all'identità della firma incrociata per verificare altre sessioni inserendo la chiave di recupero.";
"secrets_recovery_with_key_information_verify_device" = "Usa la chiave di recupero per verificare questo dispositivo.";
"secrets_recovery_with_key_recovery_key_title" = "Inserisci";
"secrets_recovery_with_key_recovery_key_placeholder" = "Inserisci chiave di recupero";
"secrets_recovery_with_key_recover_action" = "Usa chiave";
"secrets_recovery_with_key_invalid_recovery_key_title" = "Impossibile accedere all'archivio segreto";
"secrets_recovery_with_key_invalid_recovery_key_message" = "Controlla di avere inserito la chiave di recupero corretta.";

View file

@ -1091,3 +1091,17 @@
"key_verification_manually_verify_device_additional_information" = "Nëse spërputhen, siguria e komunikimeve tuaja mund të jetë komprometuar.";
"key_verification_manually_verify_device_validate_action" = "Verifikoje";
"user_verification_session_details_verify_action_current_user_manually" = "Verifikojeni Dorazi përmes Teksti";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Përdor Kyç Rimarrjesh";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Përdor Frazëkalim ose Kyç Rimarrjesh";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Nëse shyni dot në një sesion ekzistues";
"secrets_recovery_with_passphrase_title" = "Frazëkalim Rimarrjesh";
"secrets_recovery_with_passphrase_information_default" = "Hyni në historikun tuaj të mesazheve të sigurt dhe përdorni identitetin tuaj “cross-signing” për të verifikuar sesione të tjerë duke dhënë frazëkalimin tuaj të rimarrjeve.";
"secrets_recovery_with_passphrase_information_verify_device" = "Që të verifikoni këtë pajisje, përdorni Frazëkalimin tuaj të Rimarrjeve.";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Jepni Frazëkalim Rimarrjesh";
"secrets_recovery_with_passphrase_recover_action" = "Përdor Frazëkalim";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Se din frazëkalimin tuaj të rimarrjeve? Mundeni të ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "përdorni kyçin tuaj të rimarrjeve";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Sarrihet të hyhet në depo të fshehtë";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Ju lutemi, verifikoni që keni dhënë frazëkalimin e saktë të rimarrjeve.";
"secrets_recovery_with_key_title" = "Kyç Rimarrjesh";

View file

@ -298,7 +298,7 @@
"settings_password_updated" = "您的密码已经更新";
"settings_crypto_device_name" = "会话名称: ";
"settings_crypto_device_id" = "\n会话ID ";
"settings_crypto_device_key" = "\n会话密钥\n";
"settings_crypto_device_key" = "\n会话密钥:\n";
"settings_crypto_export" = "导出密钥";
"settings_crypto_blacklist_unverified_devices" = "只加密到已验证的会话";
// Room Details
@ -841,7 +841,7 @@
"key_backup_recover_connent_banner_subtitle" = "关联此会话到“密钥备份”";
// MARK: - Device Verification
"device_verification_title" = "验证会话";
"key_verification_user_title" = "验证用户";
"key_verification_user_title" = "验证它们";
"device_verification_security_advice" = "为了最大化安全性,我们建议你们当面或者使用其他可信任的通讯手段来进行此操作";
"device_verification_cancelled" = "另一方取消了验证。";
"device_verification_cancelled_by_me" = "此验证被取消。原因:%@";
@ -976,7 +976,7 @@
"user_verification_sessions_list_session_trusted" = "已信任";
"user_verification_sessions_list_session_untrusted" = "不信任";
"user_verification_session_details_trusted_title" = "已信任";
"user_verification_session_details_untrusted_title" = "警告";
"user_verification_session_details_untrusted_title" = "不受信任";
"user_verification_session_details_information_trusted_current_user" = "此会话已被信任用于安全消息,因为你已经验证过它:";
"user_verification_session_details_information_trusted_other_user_part1" = "此会话已被信任用于安全消息,因为: ";
"user_verification_session_details_information_trusted_other_user_part2" = " 已验证过它:";
@ -984,7 +984,7 @@
"user_verification_session_details_information_untrusted_other_user" = " 用新会话登录:";
"user_verification_session_details_additional_information_untrusted_other_user" = "在此用户信任这个会话之前,发往和收到它的消息会有警告标签。或者,你可以手动验证它。";
"user_verification_session_details_additional_information_untrusted_current_user" = "如果你没有登录到这个会话,你的账号可能在被盗用。";
"user_verification_session_details_verify_action_current_user" = "验证";
"user_verification_session_details_verify_action_current_user" = "交互式验证";
"user_verification_session_details_verify_action_other_user" = "手动验证";
// MARK: Clients
"client_desktop_name" = "Riot 桌面版";
@ -1000,3 +1000,100 @@
"security_settings_crosssigning" = "交叉签名";
"security_settings_crosssigning_info_not_bootstrapped" = "交叉签名还没有被设置。";
"security_settings_crosssigning_info_exists" = "您的帐户有一个交叉签名身份,但是还没有被这个会话信任。完全安全的会话。";
"skip" = "跳过";
"room_member_power_level_custom_in" = "自定义(%@) 到%@";
"room_member_power_level_short_custom" = "自定义";
"security_settings_crosssigning_info_trusted" = "已启用交叉签名。您可以基于交叉签名信任其他用户和其他会话,但不能从此会话交叉签名,因为它没有交叉签名私钥。此会话完全安全。";
"security_settings_crosssigning_info_ok" = "交叉签名还没有被设置。";
"security_settings_crosssigning_bootstrap" = "引导交叉签名";
"security_settings_crosssigning_reset" = "重置交叉签名";
"security_settings_crosssigning_complete_security" = "完整安全性";
"security_settings_cryptography" = "加密";
"security_settings_complete_security_alert_title" = "绝对安全";
"security_settings_complete_security_alert_message" = "您应该先完成当前会话的安全防护。";
"security_settings_coming_soon" = "抱歉的。Riot-iOS上尚未提供此操作。请使用其他Matrix客户端进行设置。Riot-iOS将使用它。";
// Recover from private key
"key_backup_recover_from_private_key_info" = "备份恢复中…";
// MARK: - Device Verification
"key_verification_other_session_title" = "验证会话";
"key_verification_new_session_title" = "验证你的新会话";
"key_verification_this_session_title" = "验证此会话";
"device_verification_security_advice_emoji" = "比较独特的emoji确保它们以相同的顺序出现。";
"device_verification_security_advice_number" = "比较数字,确保它们以相同的顺序出现。";
// New login
"device_verification_self_verify_alert_title" = "新登录。这是你吗?";
"device_verification_self_verify_alert_message" = "验证访问您的帐户的新登录名:%@";
"device_verification_self_verify_alert_validate_action" = "验证";
"device_verification_self_verify_start_verify_action" = "开始验证";
"device_verification_self_verify_start_information" = "使用此会话验证您的新会话,并授予其访问加密信息的权限。";
"device_verification_self_verify_start_waiting" = "等待中……";
"key_verification_self_verify_current_session_alert_title" = "验证此会话";
"key_verification_self_verify_current_session_alert_message" = "其他用户可能不信任它。";
"key_verification_self_verify_current_session_alert_validate_action" = "验证";
"key_verification_self_verify_unverified_sessions_alert_title" = "查看您的登陆位置";
"key_verification_self_verify_unverified_sessions_alert_message" = "验证您的所有会话以确保您的帐户和消息的安全。";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "检查";
"device_verification_self_verify_wait_title" = "绝对安全";
"device_verification_self_verify_wait_new_sign_in_title" = "验证此登录名";
"device_verification_self_verify_wait_information" = "从您的其他会话之一验证此会话,并授予其对加密信息的访问权限。\n\n在您的其他设备上使用最新的Riot";
"device_verification_self_verify_wait_additional_information" = "或另一个支持交叉签名的Matrix客户端";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "使用恢复密钥";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "使用恢复密码或密钥";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "如果您无法访问现有会话";
"key_verification_verify_sas_title_emoji" = "比较emoji";
"key_verification_verify_sas_title_number" = "比较数字";
"key_verification_verify_sas_cancel_action" = "它们不相配";
"key_verification_verify_sas_validate_action" = "它们相配";
"key_verification_verify_sas_additional_information" = "为了最终的安全,请使用另一种可信的通信方式或亲自执行此操作。";
"key_verification_manually_verify_device_title" = "通过文本手动验证";
"key_verification_manually_verify_device_instruction" = "通过将以下设置与其他会话中的用户设置进行比较来确认:";
"key_verification_manually_verify_device_name_title" = "会话名称";
"key_verification_manually_verify_device_id_title" = "会话 ID";
"key_verification_manually_verify_device_key_title" = "会话密钥";
"key_verification_manually_verify_device_additional_information" = "如果它们不匹配,您的通信安全可能会受到威胁。";
"key_verification_manually_verify_device_validate_action" = "验证";
"key_verification_verified_new_session_title" = "新会话已验证!";
"key_verification_verified_other_session_information" = "您现在可以阅读其他会话上的安全信息,其他用户将知道他们可以信任它。";
"key_verification_verified_new_session_information" = "您现在可以在新设备上阅读安全信息,其他用户将知道他们可以信任它。";
"key_verification_verified_this_session_information" = "您现在可以在此设备上阅读安全信息,其他用户将知道他们可以信任它。";
"key_verification_verified_user_information" = "此用户的信息是端到端加密的,第三方无法读取。";
"key_verification_bootstrap_not_setup_title" = "错误";
"key_verification_bootstrap_not_setup_message" = "您需要先启动交叉签名。";
"key_verification_verify_qr_code_title" = "通过扫描进行验证";
"key_verification_verify_qr_code_information" = "扫描代码以安全地相互验证。";
"key_verification_verify_qr_code_information_other_device" = "扫描以下代码以验证:";
"key_verification_verify_qr_code_emoji_information" = "通过比较唯一的表情符号进行验证。";
"key_verification_verify_qr_code_scan_code_action" = "扫描他们的代码";
"key_verification_verify_qr_code_cannot_scan_action" = "不能扫描吗?";
"key_verification_verify_qr_code_start_emoji_action" = "通过表情符号验证";
"key_verification_verify_qr_code_other_scan_my_code_title" = "其他用户是否成功扫描了二维码?";
"key_verification_verify_qr_code_scan_other_code_success_title" = "代码已验证!";
"key_verification_verify_qr_code_scan_other_code_success_message" = "二维码已成功验证。";
// Scanning
"key_verification_scan_confirmation_scanning_title" = "快到了!\n正在等待确认…";
"key_verification_scan_confirmation_scanning_user_waiting_other" = "等待中%@…";
"key_verification_scan_confirmation_scanning_device_waiting_other" = "正在等待其他设备…";
// Scanned
"key_verification_scan_confirmation_scanned_title" = "快到了!";
"key_verification_scan_confirmation_scanned_user_information" = "是否%@显示相同的盾牌?";
"key_verification_scan_confirmation_scanned_device_information" = "另一台设备是否显示相同的盾牌?";
"user_verification_session_details_verify_action_current_user_manually" = "通过文本手动验证";
"secrets_recovery_with_passphrase_title" = "恢复密码";
"secrets_recovery_with_passphrase_information_default" = "通过输入恢复密码,访问您的安全信息历史记录和交叉签名身份,以验证其他会话。";
"secrets_recovery_with_passphrase_information_verify_device" = "使用您的恢复密码验证此设备。";
"secrets_recovery_with_passphrase_passphrase_title" = "输入";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "输入恢复密码";
"secrets_recovery_with_passphrase_recover_action" = "使用密码短语";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "忘记了您的恢复密码?您可以 ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "使用您的恢复密钥";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "无法访问机密存储";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "请验证您输入的恢复密码是否正确。";
"secrets_recovery_with_key_title" = "恢复密钥";
"secrets_recovery_with_key_information_default" = "通过输入恢复密钥访问安全信息历史记录和交叉签名身份,以验证其他会话。";
"secrets_recovery_with_key_information_verify_device" = "使用您的恢复密码验证此设备。";
"secrets_recovery_with_key_recovery_key_title" = "输入";
"secrets_recovery_with_key_recovery_key_placeholder" = "输入恢复密钥";
"secrets_recovery_with_key_recover_action" = "使用密钥";
"secrets_recovery_with_key_invalid_recovery_key_title" = "无法访问机密存储";
"secrets_recovery_with_key_invalid_recovery_key_message" = "请验证您输入的恢复密钥是否正确。";

View file

@ -25,4 +25,22 @@
*/
- (NSUInteger)riot_missedDiscussionsCount;
/**
Check if E2E by default is welcomed on the user's HS.
The default value is YES.
HS admins can disable it in /.well-known/matrix/client by returning:
"im.vector.riot.e2ee": {
"default": false
}
*/
- (BOOL)riot_isE2EByDefaultEnabledByHSAdmin;
/**
Riot version of [MXSession canEnableE2EByDefaultInNewRoomWithUsers:]
*/
- (MXHTTPOperation*)riot_canEnableE2EByDefaultInNewRoomWithUsers:(NSArray<NSString*>*)userIds
success:(void (^)(BOOL canEnableE2E))success
failure:(void (^)(NSError *error))failure;
@end

View file

@ -49,4 +49,33 @@
return missedDiscussionsCount;
}
- (BOOL)riot_isE2EByDefaultEnabledByHSAdmin
{
BOOL isE2EByDefaultEnabledByHSAdmin = YES;
MXWellKnown *wellKnown = self.homeserverWellknown;
if (wellKnown.JSONDictionary[@"im.vector.riot.e2ee"][@"default"])
{
MXJSONModelSetBoolean(isE2EByDefaultEnabledByHSAdmin, wellKnown.JSONDictionary[@"im.vector.riot.e2ee"][@"default"]);
}
return isE2EByDefaultEnabledByHSAdmin;
}
- (MXHTTPOperation*)riot_canEnableE2EByDefaultInNewRoomWithUsers:(NSArray<NSString*>*)userIds
success:(void (^)(BOOL canEnableE2E))success
failure:(void (^)(NSError *error))failure;
{
if (self.riot_isE2EByDefaultEnabledByHSAdmin)
{
return [self canEnableE2EByDefaultInNewRoomWithUsers:userIds success:success failure:failure];
}
else
{
success(NO);
return [MXHTTPOperation new];
}
}
@end

View file

@ -47,5 +47,13 @@ extension UIImage {
let tintedImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return tintedImage
}
}
func vc_withAlpha(_ alpha: CGFloat) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
draw(at: .zero, blendMode: .normal, alpha: alpha)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}

View file

@ -106,6 +106,8 @@ internal enum Asset {
internal static let searchIcon = ImageAsset(name: "search_icon")
internal static let secretsRecoveryKey = ImageAsset(name: "secrets_recovery_key")
internal static let secretsRecoveryPassphrase = ImageAsset(name: "secrets_recovery_passphrase")
internal static let secretsSetupKey = ImageAsset(name: "secrets_setup_key")
internal static let secretsSetupPassphrase = ImageAsset(name: "secrets_setup_passphrase")
internal static let removeIconPink = ImageAsset(name: "remove_icon_pink")
internal static let settingsIcon = ImageAsset(name: "settings_icon")
internal static let tabFavourites = ImageAsset(name: "tab_favourites")

View file

@ -137,6 +137,21 @@ internal enum StoryboardScene {
internal static let initialScene = InitialSceneType<Riot.SecretsRecoveryWithPassphraseViewController>(storyboard: SecretsRecoveryWithPassphraseViewController.self)
}
internal enum SecretsSetupRecoveryKeyViewController: StoryboardType {
internal static let storyboardName = "SecretsSetupRecoveryKeyViewController"
internal static let initialScene = InitialSceneType<Riot.SecretsSetupRecoveryKeyViewController>(storyboard: SecretsSetupRecoveryKeyViewController.self)
}
internal enum SecretsSetupRecoveryPassphraseViewController: StoryboardType {
internal static let storyboardName = "SecretsSetupRecoveryPassphraseViewController"
internal static let initialScene = InitialSceneType<Riot.SecretsSetupRecoveryPassphraseViewController>(storyboard: SecretsSetupRecoveryPassphraseViewController.self)
}
internal enum SecureKeyBackupSetupIntroViewController: StoryboardType {
internal static let storyboardName = "SecureKeyBackupSetupIntroViewController"
internal static let initialScene = InitialSceneType<Riot.SecureKeyBackupSetupIntroViewController>(storyboard: SecureKeyBackupSetupIntroViewController.self)
}
internal enum ServiceTermsModalScreenViewController: StoryboardType {
internal static let storyboardName = "ServiceTermsModalScreenViewController"

View file

@ -1394,7 +1394,7 @@ internal enum VectorL10n {
internal static var keyBackupRecoverTitle: String {
return VectorL10n.tr("Vector", "key_backup_recover_title")
}
/// Start using Key Backup
/// Safeguard against losing access to encrypted messages & data
internal static var keyBackupSetupBannerSubtitle: String {
return VectorL10n.tr("Vector", "key_backup_setup_banner_subtitle")
}
@ -3002,6 +3002,94 @@ internal enum VectorL10n {
internal static var secretsRecoveryWithPassphraseTitle: String {
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_title")
}
/// Done
internal static var secretsSetupRecoveryKeyDoneAction: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_done_action")
}
/// Save
internal static var secretsSetupRecoveryKeyExportAction: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_export_action")
}
/// Store your Recovery Key somewhere safe. It can be used to unlock your encrypted messages & data.
internal static var secretsSetupRecoveryKeyInformation: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_information")
}
/// Loading
internal static var secretsSetupRecoveryKeyLoading: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_loading")
}
/// Print it and store it somewhere safe\n Save it on a USB key or backup drive\n Copy it to your personal cloud storage
internal static var secretsSetupRecoveryKeyStorageAlertMessage: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_storage_alert_message")
}
/// Keep it safe
internal static var secretsSetupRecoveryKeyStorageAlertTitle: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_storage_alert_title")
}
/// Save your Security Key
internal static var secretsSetupRecoveryKeyTitle: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_title")
}
/// Don't use your account password.
internal static var secretsSetupRecoveryPassphraseAdditionalInformation: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_additional_information")
}
/// Enter your Security Phrase again to confirm it.
internal static var secretsSetupRecoveryPassphraseConfirmInformation: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_confirm_information")
}
/// Confirm passphrase
internal static var secretsSetupRecoveryPassphraseConfirmPassphrasePlaceholder: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_confirm_passphrase_placeholder")
}
/// Confirm
internal static var secretsSetupRecoveryPassphraseConfirmPassphraseTitle: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_confirm_passphrase_title")
}
/// Enter a security phrase only you know, used to secure secrets on your server.
internal static var secretsSetupRecoveryPassphraseInformation: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_information")
}
/// Set a Security Phrase
internal static var secretsSetupRecoveryPassphraseTitle: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_title")
}
/// Done
internal static var secretsSetupRecoveryPassphraseValidateAction: String {
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_validate_action")
}
/// If you cancel now, you may lose encrypted messages & data if you lose access to your logins.\n\nYou can also set up Secure Backup & manage your keys in Settings.
internal static var secureKeyBackupSetupCancelAlertMessage: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_cancel_alert_message")
}
/// Are your sure?
internal static var secureKeyBackupSetupCancelAlertTitle: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_cancel_alert_title")
}
/// Safe guard against losing access to encrypted messages & data by backing up encryption keys on your server.
internal static var secureKeyBackupSetupIntroInfo: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_info")
}
/// Secure Backup
internal static var secureKeyBackupSetupIntroTitle: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_title")
}
/// Generate a security key to store somewhere safe like a password manager or a safe.
internal static var secureKeyBackupSetupIntroUseSecurityKeyInfo: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_use_security_key_info")
}
/// Use a Security Key
internal static var secureKeyBackupSetupIntroUseSecurityKeyTitle: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_use_security_key_title")
}
/// Enter a secret phrase only you know, and generate a key for backup.
internal static var secureKeyBackupSetupIntroUseSecurityPassphraseInfo: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_use_security_passphrase_info")
}
/// Use a Security Passphrase
internal static var secureKeyBackupSetupIntroUseSecurityPassphraseTitle: String {
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_use_security_passphrase_title")
}
/// ADVANCED
internal static var securitySettingsAdvanced: String {
return VectorL10n.tr("Vector", "security_settings_advanced")

View file

@ -20,6 +20,7 @@
#import "AppDelegate.h"
#import "Riot-Swift.h"
#import "MXSession+Riot.h"
#import "AuthInputsView.h"
#import "ForgotPasswordInputsView.h"
@ -1154,32 +1155,42 @@
case MXCrossSigningStateNotBootstrapped:
{
#ifdef NEW_CROSS_SIGNING_FLOW
// Bootstrap cross-signing on user's account
// We do it for both registration and new login as long as cross-signing does not exist yet
if (self.authInputsView.password.length)
// TODO: This is still not sure we want to disable the automatic cross-signing bootstrap
// if the admin disabled e2e by default.
// Do like riot-web for the moment
if (session.riot_isE2EByDefaultEnabledByHSAdmin)
#else
if (0)
#endif
{
NSLog(@"[AuthenticationVC] sessionStateDidChange: Bootstrap with password");
[session.crypto.crossSigning bootstrapWithPassword:self.authInputsView.password success:^{
NSLog(@"[AuthenticationVC] sessionStateDidChange: Bootstrap succeeded");
[self dismiss];
} failure:^(NSError * _Nonnull error) {
NSLog(@"[AuthenticationVC] sessionStateDidChange: Bootstrap failed. Error: %@", error);
// Bootstrap cross-signing on user's account
// We do it for both registration and new login as long as cross-signing does not exist yet
if (self.authInputsView.password.length)
{
NSLog(@"[AuthenticationVC] sessionStateDidChange: Bootstrap with password");
[session.crypto.crossSigning bootstrapWithPassword:self.authInputsView.password success:^{
NSLog(@"[AuthenticationVC] sessionStateDidChange: Bootstrap succeeded");
[self dismiss];
} failure:^(NSError * _Nonnull error) {
NSLog(@"[AuthenticationVC] sessionStateDidChange: Bootstrap failed. Error: %@", error);
[session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
[self dismiss];
}];
}
else
{
NSLog(@"[AuthenticationVC] sessionStateDidChange: Do not know how to bootstrap cross-signing. Skip it.");
[session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
[self dismiss];
}];
}
}
else
{
NSLog(@"[AuthenticationVC] sessionStateDidChange: Do not know how to bootstrap cross-signing. Skip it.");
[session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
[self dismiss];
}
#else
[session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
[self dismiss];
#endif
break;
}
case MXCrossSigningStateCrossSigningExists:

View file

@ -1058,7 +1058,7 @@
// Create a new room
[self.mainSession canEnableE2EByDefaultInNewRoomWithUsers:inviteArray success:^(BOOL canEnableE2E) {
[self.mainSession riot_canEnableE2EByDefaultInNewRoomWithUsers:inviteArray success:^(BOOL canEnableE2E) {
MXStrongifyAndReturnIfNil(self);
MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters new];

View file

@ -0,0 +1,157 @@
/*
Copyright 2020 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 UIKit
import Reusable
final class SecureKeyBackupSetupIntroCell: UIView, NibOwnerLoadable, Themable {
// MARK: - Constants
private enum ImageAlpha {
static let highlighted: CGFloat = 0.3
}
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var backgroundView: UIView!
@IBOutlet private weak var imageView: UIImageView!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var accessoryImageView: UIImageView!
@IBOutlet private weak var separatorView: UIView!
// MARK: Private
private var theme: Theme?
private var isHighlighted: Bool = false {
didSet {
self.updateView()
}
}
// MARK: Public
var action: (() -> Void)?
// MARK: Setup
private func commonInit() {
self.setupGestureRecognizer()
let accessoryTemplateImage = Asset.Images.disclosureIcon.image.withRenderingMode(.alwaysTemplate)
self.accessoryImageView.image = accessoryTemplateImage
self.accessoryImageView.highlightedImage = accessoryTemplateImage.vc_withAlpha(ImageAlpha.highlighted)
}
convenience init() {
self.init(frame: CGRect.zero)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.loadNibContent()
self.commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.loadNibContent()
self.commonInit()
}
// MARK: - Public
func update(theme: Theme) {
self.theme = theme
self.backgroundView.backgroundColor = theme.backgroundColor
self.imageView.tintColor = theme.textPrimaryColor
self.titleLabel.textColor = theme.tintColor
self.informationLabel.textColor = theme.textSecondaryColor
self.accessoryImageView.tintColor = theme.textSecondaryColor
self.separatorView.backgroundColor = theme.lineBreakColor
self.updateView()
}
func fill(title: String, information: String, image: UIImage) {
let templateImage = image.withRenderingMode(.alwaysTemplate)
self.imageView.image = templateImage
self.imageView.highlightedImage = templateImage.vc_withAlpha(ImageAlpha.highlighted)
self.titleLabel.text = title
self.informationLabel.text = information
self.setupAccessibility(title: title, isEnabled: true)
self.updateView()
}
// MARK: - Private
private func setupAccessibility(title: String, isEnabled: Bool) {
self.isAccessibilityElement = true
self.accessibilityLabel = title
self.accessibilityTraits = .button
if !isEnabled {
self.accessibilityTraits.insert(.notEnabled)
}
}
private func setupGestureRecognizer() {
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(buttonAction(_:)))
gestureRecognizer.minimumPressDuration = 0
self.addGestureRecognizer(gestureRecognizer)
}
private func updateView() {
if let theme = self.theme {
self.backgroundView.backgroundColor = self.isHighlighted ? theme.overlayBackgroundColor : theme.backgroundColor
}
self.imageView.isHighlighted = self.isHighlighted
self.accessoryImageView.isHighlighted = self.isHighlighted
}
// MARK: - Actions
@objc private func buttonAction(_ sender: UILongPressGestureRecognizer) {
let isBackgroundViewTouched = sender.vc_isTouchingInside()
switch sender.state {
case .began, .changed:
self.isHighlighted = isBackgroundViewTouched
case .ended:
self.isHighlighted = false
if isBackgroundViewTouched {
self.action?()
}
case .cancelled:
self.isHighlighted = false
default:
break
}
}
}

View file

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SecureKeyBackupSetupIntroCell" customModule="Riot" customModuleProvider="target">
<connections>
<outlet property="accessoryImageView" destination="N76-Fa-onz" id="nYX-r6-t7R"/>
<outlet property="backgroundView" destination="WrK-Wq-nzz" id="kgB-Zb-g9N"/>
<outlet property="imageView" destination="PfY-xb-Psn" id="qgq-7B-nSS"/>
<outlet property="informationLabel" destination="q9X-wE-MwV" id="a4J-ZK-teU"/>
<outlet property="separatorView" destination="eKS-Ze-zhB" id="TF5-27-XFD"/>
<outlet property="titleLabel" destination="eGd-jn-myj" id="MyG-x1-33i"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="426" height="122"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WrK-Wq-nzz">
<rect key="frame" x="0.0" y="0.0" width="426" height="122"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="secrets_setup_key" translatesAutoresizingMaskIntoConstraints="NO" id="PfY-xb-Psn">
<rect key="frame" x="19" y="18" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" secondItem="PfY-xb-Psn" secondAttribute="height" multiplier="1:1" id="71S-sH-VTt"/>
<constraint firstAttribute="width" constant="24" id="Shz-Df-UoM"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="252" text="Use a Security Key" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eGd-jn-myj">
<rect key="frame" x="63" y="20" width="317" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.01176470588" green="0.70196078429999997" blue="0.50588235290000005" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Generate a security key to store somewhere safe like a password manager or a safe." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="q9X-wE-MwV">
<rect key="frame" x="63" y="49.5" width="317" height="52.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="disclosure_icon" translatesAutoresizingMaskIntoConstraints="NO" id="N76-Fa-onz">
<rect key="frame" x="400" y="55" width="6" height="12"/>
<constraints>
<constraint firstAttribute="width" constant="6" id="23d-HN-WiD"/>
<constraint firstAttribute="height" constant="12" id="4Yt-I6-2YL"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eKS-Ze-zhB" userLabel="separatorView">
<rect key="frame" x="0.0" y="121" width="426" height="1"/>
<color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="5hw-tO-Dw9"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="PfY-xb-Psn" firstAttribute="centerY" secondItem="eGd-jn-myj" secondAttribute="centerY" id="3Ha-I2-24v"/>
<constraint firstAttribute="trailing" secondItem="N76-Fa-onz" secondAttribute="trailing" constant="20" id="9C0-mv-gaL"/>
<constraint firstAttribute="trailing" secondItem="eKS-Ze-zhB" secondAttribute="trailing" id="BlW-zS-HoC"/>
<constraint firstItem="N76-Fa-onz" firstAttribute="leading" secondItem="eGd-jn-myj" secondAttribute="trailing" constant="20" id="CKw-l3-vdY"/>
<constraint firstItem="PfY-xb-Psn" firstAttribute="leading" secondItem="WrK-Wq-nzz" secondAttribute="leading" constant="19" id="NXM-42-myZ"/>
<constraint firstItem="q9X-wE-MwV" firstAttribute="leading" secondItem="eGd-jn-myj" secondAttribute="leading" id="Ovd-Xd-S7O"/>
<constraint firstAttribute="bottom" secondItem="q9X-wE-MwV" secondAttribute="bottom" constant="20" id="S9M-i1-KQ6"/>
<constraint firstItem="q9X-wE-MwV" firstAttribute="trailing" secondItem="eGd-jn-myj" secondAttribute="trailing" id="YU0-XX-vAU"/>
<constraint firstItem="eGd-jn-myj" firstAttribute="top" secondItem="WrK-Wq-nzz" secondAttribute="top" constant="20" id="cAQ-R0-bco"/>
<constraint firstAttribute="bottom" secondItem="eKS-Ze-zhB" secondAttribute="bottom" id="cnI-2n-T2c"/>
<constraint firstItem="q9X-wE-MwV" firstAttribute="top" secondItem="eGd-jn-myj" secondAttribute="bottom" constant="10" id="kYI-mK-UC1"/>
<constraint firstItem="N76-Fa-onz" firstAttribute="centerY" secondItem="WrK-Wq-nzz" secondAttribute="centerY" id="rG1-iI-v3T"/>
<constraint firstItem="eKS-Ze-zhB" firstAttribute="leading" secondItem="WrK-Wq-nzz" secondAttribute="leading" id="raL-7N-TKN"/>
<constraint firstItem="eGd-jn-myj" firstAttribute="leading" secondItem="PfY-xb-Psn" secondAttribute="trailing" constant="20" id="zi9-PT-A2O"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="WrK-Wq-nzz" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="dAF-lS-uGD"/>
<constraint firstItem="WrK-Wq-nzz" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="fAW-fz-tYP"/>
<constraint firstAttribute="bottom" secondItem="WrK-Wq-nzz" secondAttribute="bottom" id="lU3-Jc-aUe"/>
<constraint firstAttribute="trailing" secondItem="WrK-Wq-nzz" secondAttribute="trailing" id="lUt-K8-wV9"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="146.37681159420291" y="-122.54464285714285"/>
</view>
</objects>
<resources>
<image name="disclosure_icon" width="6" height="12"/>
<image name="secrets_setup_key" width="48" height="48"/>
</resources>
</document>

View file

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="LSX-Vb-DIu">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Secure Key Backup Setup Intro View Controller-->
<scene sceneID="srP-wo-sRp">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="LSX-Vb-DIu" customClass="SecureKeyBackupSetupIntroViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="pmD-eJ-G3m">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mvC-lc-ylT">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Fub-g4-o4o">
<rect key="frame" x="0.0" y="0.0" width="414" height="391"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="79w-lw-B8z">
<rect key="frame" x="0.0" y="0.0" width="414" height="391"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Safe guard against losing access to encrypted messages &amp; data by backing up encryption keys on your server." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DZf-di-JcI">
<rect key="frame" x="20" y="30" width="374" height="54"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tul-b1-7gY">
<rect key="frame" x="0.0" y="114" width="414" height="257"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Jc9-fc-Vwh">
<rect key="frame" x="0.0" y="0.0" width="414" height="257"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="d77-sQ-Uio">
<rect key="frame" x="0.0" y="0.0" width="414" height="1"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="Gwq-JQ-4Zj"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RQF-pm-g37" customClass="SecureKeyBackupSetupIntroCell" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="1" width="414" height="128"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="128" placeholder="YES" id="dOF-Du-P3S"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Yps-bc-ruH" customClass="SecureKeyBackupSetupIntroCell" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="129" width="414" height="128"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="128" placeholder="YES" id="Gpk-nd-3G2"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="d77-sQ-Uio" firstAttribute="width" secondItem="Jc9-fc-Vwh" secondAttribute="width" id="S3Q-F0-nwW"/>
<constraint firstItem="RQF-pm-g37" firstAttribute="width" secondItem="Jc9-fc-Vwh" secondAttribute="width" id="fZs-9s-jUW"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Jc9-fc-Vwh" firstAttribute="top" secondItem="tul-b1-7gY" secondAttribute="top" id="1Vr-Y3-t2r"/>
<constraint firstItem="Jc9-fc-Vwh" firstAttribute="leading" secondItem="tul-b1-7gY" secondAttribute="leading" id="4op-QY-3vL"/>
<constraint firstAttribute="bottom" secondItem="Jc9-fc-Vwh" secondAttribute="bottom" id="FqW-Rc-K1T"/>
<constraint firstAttribute="trailing" secondItem="Jc9-fc-Vwh" secondAttribute="trailing" id="QcB-wY-lCT"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="tul-b1-7gY" secondAttribute="trailing" id="TFD-iw-7y4"/>
<constraint firstItem="tul-b1-7gY" firstAttribute="top" secondItem="DZf-di-JcI" secondAttribute="bottom" constant="30" id="Ury-rf-0xS"/>
<constraint firstAttribute="trailing" secondItem="DZf-di-JcI" secondAttribute="trailing" constant="20" id="bS3-Gc-DyD"/>
<constraint firstAttribute="width" priority="750" constant="500" id="fuc-5G-HCd"/>
<constraint firstItem="tul-b1-7gY" firstAttribute="leading" secondItem="79w-lw-B8z" secondAttribute="leading" id="gYj-LZ-esB"/>
<constraint firstItem="DZf-di-JcI" firstAttribute="leading" secondItem="79w-lw-B8z" secondAttribute="leading" constant="20" id="nPo-3g-WcD"/>
<constraint firstAttribute="bottom" secondItem="tul-b1-7gY" secondAttribute="bottom" constant="20" id="qYa-0L-wrp"/>
<constraint firstItem="DZf-di-JcI" firstAttribute="top" secondItem="79w-lw-B8z" secondAttribute="top" constant="30" id="t80-aS-JzH"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="79w-lw-B8z" firstAttribute="centerX" secondItem="Fub-g4-o4o" secondAttribute="centerX" id="5Az-52-cbQ"/>
<constraint firstItem="79w-lw-B8z" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Fub-g4-o4o" secondAttribute="leading" id="Aei-Nr-Wzb"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="79w-lw-B8z" secondAttribute="trailing" id="CBG-M0-Uqd"/>
<constraint firstAttribute="bottom" secondItem="79w-lw-B8z" secondAttribute="bottom" id="JbI-yr-iot"/>
<constraint firstItem="79w-lw-B8z" firstAttribute="top" secondItem="Fub-g4-o4o" secondAttribute="top" id="s6B-HO-iVd"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="Fub-g4-o4o" secondAttribute="trailing" id="N9B-1U-3j7"/>
<constraint firstItem="Fub-g4-o4o" firstAttribute="width" secondItem="mvC-lc-ylT" secondAttribute="width" id="NzH-5s-nuz"/>
<constraint firstAttribute="bottom" secondItem="Fub-g4-o4o" secondAttribute="bottom" id="gYj-V0-rlA"/>
<constraint firstItem="Fub-g4-o4o" firstAttribute="leading" secondItem="mvC-lc-ylT" secondAttribute="leading" id="jHU-W6-8Ny"/>
<constraint firstItem="Fub-g4-o4o" firstAttribute="top" secondItem="mvC-lc-ylT" secondAttribute="top" id="nFB-Af-IUw"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="JkH-9M-Qql" firstAttribute="top" secondItem="mvC-lc-ylT" secondAttribute="top" id="5Vc-aR-jAF"/>
<constraint firstItem="mvC-lc-ylT" firstAttribute="leading" secondItem="JkH-9M-Qql" secondAttribute="leading" id="HBB-YL-5P5"/>
<constraint firstAttribute="bottom" secondItem="mvC-lc-ylT" secondAttribute="bottom" id="dn5-CG-87P"/>
<constraint firstItem="JkH-9M-Qql" firstAttribute="trailing" secondItem="mvC-lc-ylT" secondAttribute="trailing" id="xj4-xF-VEA"/>
</constraints>
<viewLayoutGuide key="safeArea" id="JkH-9M-Qql"/>
</view>
<connections>
<outlet property="informationLabel" destination="DZf-di-JcI" id="czR-MT-Ipb"/>
<outlet property="secureKeyCell" destination="RQF-pm-g37" id="5dK-h1-N6t"/>
<outlet property="securePassphraseCell" destination="Yps-bc-ruH" id="56B-9H-MOh"/>
<outlet property="topSeparatorView" destination="d77-sQ-Uio" id="TPp-kq-cFq"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="WpU-UP-qtu" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3772.4637681159425" y="-774.10714285714278"/>
</scene>
</scenes>
</document>

View file

@ -0,0 +1,133 @@
/*
Copyright 2020 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 UIKit
protocol SecureKeyBackupSetupIntroViewControllerDelegate: class {
func secureKeyBackupSetupIntroViewControllerDidTapUseKey(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController)
func secureKeyBackupSetupIntroViewControllerDidTapUsePassphrase(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController)
func secureKeyBackupSetupIntroViewControllerDidCancel(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController)
}
@objcMembers
final class SecureKeyBackupSetupIntroViewController: UIViewController {
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var topSeparatorView: UIView!
@IBOutlet private weak var secureKeyCell: SecureKeyBackupSetupIntroCell!
@IBOutlet private weak var securePassphraseCell: SecureKeyBackupSetupIntroCell!
// MARK: Private
private var theme: Theme!
// MARK: Public
weak var delegate: SecureKeyBackupSetupIntroViewControllerDelegate?
// MARK: - Setup
class func instantiate() -> SecureKeyBackupSetupIntroViewController {
let viewController = StoryboardScene.SecureKeyBackupSetupIntroViewController.initialScene.instantiate()
viewController.theme = ThemeService.shared().theme
return viewController
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.vc_removeBackTitle()
self.setupViews()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func setupViews() {
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
guard let self = self else {
return
}
self.delegate?.secureKeyBackupSetupIntroViewControllerDidCancel(self)
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.title = VectorL10n.secureKeyBackupSetupIntroTitle
self.informationLabel.text = VectorL10n.secureKeyBackupSetupIntroInfo
self.secureKeyCell.fill(title: VectorL10n.secureKeyBackupSetupIntroUseSecurityKeyTitle,
information: VectorL10n.secureKeyBackupSetupIntroUseSecurityKeyInfo,
image: Asset.Images.secretsSetupKey.image)
self.secureKeyCell.action = { [weak self] in
guard let self = self else {
return
}
self.delegate?.secureKeyBackupSetupIntroViewControllerDidTapUseKey(self)
}
self.securePassphraseCell.fill(title: VectorL10n.secureKeyBackupSetupIntroUseSecurityPassphraseTitle,
information: VectorL10n.secureKeyBackupSetupIntroUseSecurityPassphraseInfo,
image: Asset.Images.secretsSetupPassphrase.image)
self.securePassphraseCell.action = { [weak self] in
guard let self = self else {
return
}
self.delegate?.secureKeyBackupSetupIntroViewControllerDidTapUsePassphrase(self)
}
}
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.informationLabel.textColor = theme.textPrimaryColor
self.topSeparatorView.backgroundColor = theme.lineBreakColor
self.secureKeyCell.update(theme: theme)
self.securePassphraseCell.update(theme: theme)
}
private func registerThemeServiceDidChangeThemeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
}
@objc private func themeDidChange() {
self.update(theme: ThemeService.shared().theme)
}
}

View file

@ -0,0 +1,171 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup
/*
Copyright 2020 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 UIKit
@objcMembers
final class SecureKeyBackupSetupCoordinator: SecureKeyBackupSetupCoordinatorType {
// MARK: - Properties
// MARK: Private
private let navigationRouter: NavigationRouterType
private let recoveryService: MXRecoveryService
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: SecureKeyBackupSetupCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession) {
self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController())
self.recoveryService = session.crypto.recoveryService
}
// MARK: - Public methods
func start() {
let rootViewController = self.createIntro()
self.navigationRouter.setRootModule(rootViewController)
}
func toPresentable() -> UIViewController {
return self.navigationRouter.toPresentable()
}
// MARK: - Private methods
private func createIntro() -> SecureKeyBackupSetupIntroViewController {
let introViewController = SecureKeyBackupSetupIntroViewController.instantiate()
introViewController.delegate = self
return introViewController
}
private func showSetupKey(passphrase: String? = nil) {
let coordinator = SecretsSetupRecoveryKeyCoordinator(recoveryService: self.recoveryService, passphrase: passphrase)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.push(coordinator, animated: true) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showSetupPassphrase() {
let coordinator = SecretsSetupRecoveryPassphraseCoordinator(passphraseInput: .new)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.push(coordinator, animated: true) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showSetupPassphraseConfirmation(with passphrase: String) {
let coordinator = SecretsSetupRecoveryPassphraseCoordinator(passphraseInput: .confirm(passphrase))
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.push(coordinator, animated: true) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showCancelAlert() {
let alertController = UIAlertController(title: VectorL10n.secureKeyBackupSetupCancelAlertTitle,
message: VectorL10n.secureKeyBackupSetupCancelAlertMessage,
preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: VectorL10n.continue, style: .cancel, handler: { action in
}))
alertController.addAction(UIAlertAction(title: VectorL10n.keyBackupSetupSkipAlertSkipAction, style: .default, handler: { action in
self.delegate?.secureKeyBackupSetupCoordinatorDidCancel(self)
}))
self.navigationRouter.present(alertController, animated: true)
}
private func didCancel(showSkipAlert: Bool = true) {
if showSkipAlert {
self.showCancelAlert()
} else {
self.delegate?.secureKeyBackupSetupCoordinatorDidCancel(self)
}
}
private func didComplete() {
self.delegate?.secureKeyBackupSetupCoordinatorDidComplete(self)
}
}
// MARK: - SecureKeyBackupSetupIntroViewControllerDelegate
extension SecureKeyBackupSetupCoordinator: SecureKeyBackupSetupIntroViewControllerDelegate {
func secureKeyBackupSetupIntroViewControllerDidTapUseKey(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) {
self.showSetupKey()
}
func secureKeyBackupSetupIntroViewControllerDidTapUsePassphrase(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) {
self.showSetupPassphrase()
}
func secureKeyBackupSetupIntroViewControllerDidCancel(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) {
self.didCancel()
}
}
// MARK: - SecretsSetupRecoveryKeyCoordinatorDelegate
extension SecureKeyBackupSetupCoordinator: SecretsSetupRecoveryKeyCoordinatorDelegate {
func secretsSetupRecoveryKeyCoordinatorDidComplete(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) {
self.didComplete()
}
func secretsSetupRecoveryKeyCoordinatorDidFailed(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) {
self.didCancel(showSkipAlert: false)
}
func secretsSetupRecoveryKeyCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) {
self.didCancel()
}
}
// MARK: - SecretsSetupRecoveryPassphraseCoordinatorDelegate
extension SecureKeyBackupSetupCoordinator: SecretsSetupRecoveryPassphraseCoordinatorDelegate {
func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didEnterNewPassphrase passphrase: String) {
self.showSetupPassphraseConfirmation(with: passphrase)
}
func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didConfirmPassphrase passphrase: String) {
self.showSetupKey(passphrase: passphrase)
}
func secretsSetupRecoveryPassphraseCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType) {
self.didCancel()
}
}

View file

@ -0,0 +1,88 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup
/*
Copyright 2020 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
@objc protocol SecureKeyBackupSetupCoordinatorBridgePresenterDelegate {
func secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorBridgePresenter)
func secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidCancel(_ coordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorBridgePresenter)
}
/// SecureKeyBackupSetupCoordinatorBridgePresenter enables to start SecureKeyBackupSetupCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
@objcMembers
final class SecureKeyBackupSetupCoordinatorBridgePresenter: NSObject {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var coordinator: SecureKeyBackupSetupCoordinator?
// MARK: Public
weak var delegate: SecureKeyBackupSetupCoordinatorBridgePresenterDelegate?
// MARK: - Setup
init(session: MXSession) {
self.session = session
super.init()
}
// MARK: - Public
// NOTE: Default value feature is not compatible with Objective-C.
// func present(from viewController: UIViewController, animated: Bool) {
// self.present(from: viewController, animated: animated)
// }
func present(from viewController: UIViewController, animated: Bool) {
let secureKeyBackupSetupCoordinator = SecureKeyBackupSetupCoordinator(session: self.session)
secureKeyBackupSetupCoordinator.delegate = self
viewController.present(secureKeyBackupSetupCoordinator.toPresentable(), animated: animated, completion: nil)
secureKeyBackupSetupCoordinator.start()
self.coordinator = secureKeyBackupSetupCoordinator
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let coordinator = self.coordinator else {
return
}
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
if let completion = completion {
completion()
}
}
}
}
// MARK: - SecureKeyBackupSetupCoordinatorDelegate
extension SecureKeyBackupSetupCoordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorDelegate {
func secureKeyBackupSetupCoordinatorDidComplete(_ coordinator: SecureKeyBackupSetupCoordinatorType) {
self.delegate?.secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidComplete(self)
}
func secureKeyBackupSetupCoordinatorDidCancel(_ coordinator: SecureKeyBackupSetupCoordinatorType) {
self.delegate?.secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidCancel(self)
}
}

View file

@ -0,0 +1,29 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup
/*
Copyright 2020 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
protocol SecureKeyBackupSetupCoordinatorDelegate: class {
func secureKeyBackupSetupCoordinatorDidComplete(_ coordinator: SecureKeyBackupSetupCoordinatorType)
func secureKeyBackupSetupCoordinatorDidCancel(_ coordinator: SecureKeyBackupSetupCoordinatorType)
}
/// `SecureKeyBackupSetupCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow.
protocol SecureKeyBackupSetupCoordinatorType: Coordinator, Presentable {
var delegate: SecureKeyBackupSetupCoordinatorDelegate? { get }
}

View file

@ -0,0 +1,72 @@
// File created from ScreenTemplate
// $ createScreen.sh SecretsSetupRecoveryKey SecretsSetupRecoveryKey
/*
Copyright 2020 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
import UIKit
final class SecretsSetupRecoveryKeyCoordinator: SecretsSetupRecoveryKeyCoordinatorType {
// MARK: - Properties
// MARK: Private
private var secretsSetupRecoveryKeyViewModel: SecretsSetupRecoveryKeyViewModelType
private let secretsSetupRecoveryKeyViewController: SecretsSetupRecoveryKeyViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: SecretsSetupRecoveryKeyCoordinatorDelegate?
// MARK: - Setup
init(recoveryService: MXRecoveryService, passphrase: String?) {
let secretsSetupRecoveryKeyViewModel = SecretsSetupRecoveryKeyViewModel(recoveryService: recoveryService, passphrase: passphrase)
let secretsSetupRecoveryKeyViewController = SecretsSetupRecoveryKeyViewController.instantiate(with: secretsSetupRecoveryKeyViewModel)
self.secretsSetupRecoveryKeyViewModel = secretsSetupRecoveryKeyViewModel
self.secretsSetupRecoveryKeyViewController = secretsSetupRecoveryKeyViewController
}
// MARK: - Public methods
func start() {
self.secretsSetupRecoveryKeyViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.secretsSetupRecoveryKeyViewController
}
}
// MARK: - SecretsSetupRecoveryKeyViewModelCoordinatorDelegate
extension SecretsSetupRecoveryKeyCoordinator: SecretsSetupRecoveryKeyViewModelCoordinatorDelegate {
func secretsSetupRecoveryKeyViewModelDidComplete(_ viewModel: SecretsSetupRecoveryKeyViewModelType) {
self.delegate?.secretsSetupRecoveryKeyCoordinatorDidComplete(self)
}
func secretsSetupRecoveryKeyViewModelDidFailed(_ viewModel: SecretsSetupRecoveryKeyViewModelType) {
self.delegate?.secretsSetupRecoveryKeyCoordinatorDidFailed(self)
}
func secretsSetupRecoveryKeyViewModelDidCancel(_ viewModel: SecretsSetupRecoveryKeyViewModelType) {
self.delegate?.secretsSetupRecoveryKeyCoordinatorDidCancel(self)
}
}

View file

@ -0,0 +1,30 @@
// File created from ScreenTemplate
// $ createScreen.sh SecretsSetupRecoveryKey SecretsSetupRecoveryKey
/*
Copyright 2020 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
protocol SecretsSetupRecoveryKeyCoordinatorDelegate: class {
func secretsSetupRecoveryKeyCoordinatorDidComplete(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType)
func secretsSetupRecoveryKeyCoordinatorDidFailed(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType)
func secretsSetupRecoveryKeyCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType)
}
/// `SecretsSetupRecoveryKeyCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
protocol SecretsSetupRecoveryKeyCoordinatorType: Coordinator, Presentable {
var delegate: SecretsSetupRecoveryKeyCoordinatorDelegate? { get }
}

View file

@ -0,0 +1,27 @@
// File created from ScreenTemplate
// $ createScreen.sh SecretsSetupRecoveryKey SecretsSetupRecoveryKey
/*
Copyright 2020 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
/// SecretsSetupRecoveryKeyViewController view actions exposed to view model
enum SecretsSetupRecoveryKeyViewAction {
case loadData
case done
case errorAlertOk
case cancel
}

View file

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EoE-Pl-I63">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Secrets Setup Recovery Key View Controller-->
<scene sceneID="x3I-nC-qtU">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="EoE-Pl-I63" customClass="SecretsSetupRecoveryKeyViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="EZ7-Nb-xmk">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ahz-9d-sce">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Rs5-uo-2W5">
<rect key="frame" x="0.0" y="0.0" width="414" height="382"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="K9F-ti-0rB">
<rect key="frame" x="0.0" y="0.0" width="414" height="382"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="secrets_setup_key" translatesAutoresizingMaskIntoConstraints="NO" id="JwH-yj-Gj8">
<rect key="frame" x="183" y="35" width="48" height="48"/>
<constraints>
<constraint firstAttribute="width" secondItem="JwH-yj-Gj8" secondAttribute="height" multiplier="1:1" id="DTn-tC-iTc"/>
<constraint firstAttribute="width" constant="48" id="uXl-gX-etQ"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Store your Recovery Key somewhere safe. It can be used to unlock your encrypted messages &amp; data." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="csL-ru-oas">
<rect key="frame" x="20" y="113" width="374" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Loading…" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aDh-9M-4UN">
<rect key="frame" x="20" y="184" width="374" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zgt-AN-9EH">
<rect key="frame" x="0.0" y="242" width="414" height="120"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cju-9A-6Ns" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="20" y="0.0" width="374" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="ywR-tU-0tp"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal" title="Export">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="exportButtonAction:" destination="EoE-Pl-I63" eventType="touchUpInside" id="8Sv-N4-mhU"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="v3h-dA-xvr" userLabel="Continue" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="20" y="70" width="374" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="efg-jS-vMe"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal" title="Continue">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="doneButtonAction:" destination="EoE-Pl-I63" eventType="touchUpInside" id="NO6-2J-vWo"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="v3h-dA-xvr" firstAttribute="top" secondItem="cju-9A-6Ns" secondAttribute="bottom" constant="20" id="CVl-bR-ZyK"/>
<constraint firstAttribute="bottom" secondItem="v3h-dA-xvr" secondAttribute="bottom" id="PPw-gM-JID"/>
<constraint firstItem="v3h-dA-xvr" firstAttribute="leading" secondItem="cju-9A-6Ns" secondAttribute="leading" id="THe-E7-SvT"/>
<constraint firstItem="v3h-dA-xvr" firstAttribute="trailing" secondItem="cju-9A-6Ns" secondAttribute="trailing" id="W5O-7M-cF3"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="cju-9A-6Ns" secondAttribute="trailing" constant="20" id="X0c-Z0-KGn"/>
<constraint firstItem="cju-9A-6Ns" firstAttribute="top" secondItem="zgt-AN-9EH" secondAttribute="top" id="dPj-uh-WWa"/>
<constraint firstItem="cju-9A-6Ns" firstAttribute="centerX" secondItem="zgt-AN-9EH" secondAttribute="centerX" id="iuh-Zf-BZM"/>
<constraint firstItem="cju-9A-6Ns" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="zgt-AN-9EH" secondAttribute="leading" constant="20" id="iyq-Bv-kvf"/>
<constraint firstItem="cju-9A-6Ns" firstAttribute="width" secondItem="zgt-AN-9EH" secondAttribute="width" priority="750" id="t3e-c6-wSf"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="csL-ru-oas" secondAttribute="trailing" constant="20" id="4ZO-ii-ENI"/>
<constraint firstAttribute="width" priority="750" constant="500" id="G40-eF-Vmb"/>
<constraint firstItem="csL-ru-oas" firstAttribute="leading" secondItem="K9F-ti-0rB" secondAttribute="leading" constant="20" id="GaH-AP-bZ1"/>
<constraint firstItem="aDh-9M-4UN" firstAttribute="leading" secondItem="csL-ru-oas" secondAttribute="leading" id="J0Y-Fl-1Lm"/>
<constraint firstAttribute="bottom" secondItem="zgt-AN-9EH" secondAttribute="bottom" constant="20" id="NNI-yY-2gw"/>
<constraint firstItem="aDh-9M-4UN" firstAttribute="trailing" secondItem="csL-ru-oas" secondAttribute="trailing" id="QAS-cx-4zF"/>
<constraint firstItem="zgt-AN-9EH" firstAttribute="top" secondItem="aDh-9M-4UN" secondAttribute="bottom" constant="40" id="WQw-uJ-5v6"/>
<constraint firstItem="zgt-AN-9EH" firstAttribute="leading" secondItem="K9F-ti-0rB" secondAttribute="leading" id="dKH-aq-rWl"/>
<constraint firstAttribute="trailing" secondItem="zgt-AN-9EH" secondAttribute="trailing" id="dRS-cB-t6V"/>
<constraint firstItem="aDh-9M-4UN" firstAttribute="top" secondItem="csL-ru-oas" secondAttribute="bottom" constant="35" id="fB9-8Q-Fee"/>
<constraint firstItem="csL-ru-oas" firstAttribute="top" secondItem="JwH-yj-Gj8" secondAttribute="bottom" constant="30" id="pKd-Oy-PNV"/>
<constraint firstItem="JwH-yj-Gj8" firstAttribute="centerX" secondItem="K9F-ti-0rB" secondAttribute="centerX" id="qYR-oP-1zH"/>
<constraint firstItem="JwH-yj-Gj8" firstAttribute="top" secondItem="K9F-ti-0rB" secondAttribute="top" constant="35" id="sae-bb-nrs"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="K9F-ti-0rB" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Rs5-uo-2W5" secondAttribute="leading" id="4rN-tv-wkb"/>
<constraint firstItem="K9F-ti-0rB" firstAttribute="centerX" secondItem="Rs5-uo-2W5" secondAttribute="centerX" id="PIo-oO-BbD"/>
<constraint firstItem="K9F-ti-0rB" firstAttribute="top" secondItem="Rs5-uo-2W5" secondAttribute="top" id="nB3-uX-q4J"/>
<constraint firstAttribute="bottom" secondItem="K9F-ti-0rB" secondAttribute="bottom" id="t4Y-vr-8c6"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="K9F-ti-0rB" secondAttribute="trailing" id="txe-zb-TiV"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="Rs5-uo-2W5" secondAttribute="bottom" id="Fai-XD-wYZ"/>
<constraint firstItem="Rs5-uo-2W5" firstAttribute="leading" secondItem="Ahz-9d-sce" secondAttribute="leading" id="Fv4-4B-T6y"/>
<constraint firstAttribute="trailing" secondItem="Rs5-uo-2W5" secondAttribute="trailing" id="lUM-5U-R9B"/>
<constraint firstItem="Rs5-uo-2W5" firstAttribute="top" secondItem="Ahz-9d-sce" secondAttribute="top" id="s95-pV-QYC"/>
<constraint firstItem="Rs5-uo-2W5" firstAttribute="width" secondItem="Ahz-9d-sce" secondAttribute="width" id="whx-pE-t67"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" red="0.94509803920000002" green="0.96078431369999995" blue="0.97254901959999995" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="R4q-cd-DVX" firstAttribute="top" secondItem="Ahz-9d-sce" secondAttribute="top" id="233-gk-CKV"/>
<constraint firstItem="R4q-cd-DVX" firstAttribute="trailing" secondItem="Ahz-9d-sce" secondAttribute="trailing" id="Rc0-Sf-qtU"/>
<constraint firstAttribute="bottom" secondItem="Ahz-9d-sce" secondAttribute="bottom" id="V3e-5C-fSc"/>
<constraint firstItem="Ahz-9d-sce" firstAttribute="leading" secondItem="R4q-cd-DVX" secondAttribute="leading" id="kow-MO-5hW"/>
</constraints>
<viewLayoutGuide key="safeArea" id="R4q-cd-DVX"/>
</view>
<connections>
<outlet property="doneButton" destination="v3h-dA-xvr" id="YEi-d4-sUs"/>
<outlet property="exportButton" destination="cju-9A-6Ns" id="TU9-kQ-MbV"/>
<outlet property="informationLabel" destination="csL-ru-oas" id="tkl-2J-VDB"/>
<outlet property="recoveryKeyLabel" destination="aDh-9M-4UN" id="yai-aZ-7uj"/>
<outlet property="secureKeyImageView" destination="JwH-yj-Gj8" id="H1W-pB-CN1"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ekR-Lh-PNe" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3772" y="-774"/>
</scene>
</scenes>
<resources>
<image name="secrets_setup_key" width="48" height="48"/>
</resources>
</document>

View file

@ -0,0 +1,225 @@
// File created from ScreenTemplate
// $ createScreen.sh SecretsSetupRecoveryKey SecretsSetupRecoveryKey
/*
Copyright 2020 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 UIKit
final class SecretsSetupRecoveryKeyViewController: UIViewController {
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var secureKeyImageView: UIImageView!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var recoveryKeyLabel: UILabel!
@IBOutlet private weak var exportButton: RoundedButton!
@IBOutlet private weak var doneButton: RoundedButton!
// MARK: Private
private var viewModel: SecretsSetupRecoveryKeyViewModelType!
private var theme: Theme!
private var errorPresenter: MXKErrorPresentation!
private var activityPresenter: ActivityIndicatorPresenter!
private var recoveryKey: String?
private var hasSavedRecoveryKey: Bool = false
// MARK: - Setup
class func instantiate(with viewModel: SecretsSetupRecoveryKeyViewModelType) -> SecretsSetupRecoveryKeyViewController {
let viewController = StoryboardScene.SecretsSetupRecoveryKeyViewController.initialScene.instantiate()
viewController.viewModel = viewModel
viewController.theme = ThemeService.shared().theme
return viewController
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.setupViews()
self.activityPresenter = ActivityIndicatorPresenter()
self.errorPresenter = MXKErrorAlertPresentation()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
self.viewModel.viewDelegate = self
self.viewModel.process(viewAction: .loadData)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Hide back button
self.navigationItem.setHidesBackButton(true, animated: animated)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.secureKeyImageView.tintColor = theme.textPrimaryColor
self.informationLabel.textColor = theme.textPrimaryColor
self.recoveryKeyLabel.textColor = theme.textSecondaryColor
self.exportButton.update(theme: theme)
self.doneButton.update(theme: theme)
}
private func registerThemeServiceDidChangeThemeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
}
@objc private func themeDidChange() {
self.update(theme: ThemeService.shared().theme)
}
private func setupViews() {
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
self?.cancelButtonAction()
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.vc_removeBackTitle()
self.title = VectorL10n.secretsSetupRecoveryKeyTitle
self.secureKeyImageView.image = Asset.Images.secretsSetupKey.image.withRenderingMode(.alwaysTemplate)
self.informationLabel.text = VectorL10n.secretsSetupRecoveryKeyInformation
self.recoveryKeyLabel.text = VectorL10n.secretsSetupRecoveryKeyLoading
self.exportButton.setTitle(VectorL10n.secretsSetupRecoveryKeyExportAction, for: .normal)
self.exportButton.isEnabled = false
self.doneButton.setTitle(VectorL10n.continue, for: .normal)
self.updateDoneButton()
}
private func render(viewState: SecretsSetupRecoveryKeyViewState) {
switch viewState {
case .loading:
self.renderLoading()
case .loaded(let recoveryKey):
self.renderLoaded(recoveryKey: recoveryKey)
case .error(let error):
self.render(error: error)
}
}
private func renderLoading() {
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
}
private func renderLoaded(recoveryKey: String) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.exportButton.isEnabled = true
self.recoveryKey = recoveryKey
self.recoveryKeyLabel.text = recoveryKey
}
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true) {
self.viewModel.process(viewAction: .errorAlertOk)
}
}
private func updateDoneButton() {
self.doneButton.isEnabled = self.hasSavedRecoveryKey
}
private func presentKeepSafeAlert() {
let alertController = UIAlertController(title: VectorL10n.secretsSetupRecoveryKeyStorageAlertTitle,
message: VectorL10n.secretsSetupRecoveryKeyStorageAlertMessage,
preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: VectorL10n.continue, style: .cancel, handler: { action in
self.viewModel.process(viewAction: .done)
}))
self.present(alertController, animated: true, completion: nil)
}
private func shareRecoveryKey() {
guard let recoveryKey = self.recoveryKey else {
return
}
// Set up activity view controller
let activityItems: [Any] = [ recoveryKey ]
let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
activityViewController.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
// Enable made copy button only if user has selected an activity item and has setup recovery key without passphrase
if completed {
self.hasSavedRecoveryKey = true
self.updateDoneButton()
}
}
// Configure source view when activity view controller is presented with a popover
if let popoverPresentationController = activityViewController.popoverPresentationController {
popoverPresentationController.sourceView = self.exportButton
popoverPresentationController.sourceRect = self.exportButton.bounds
popoverPresentationController.permittedArrowDirections = [.down, .up]
}
self.present(activityViewController, animated: true)
}
// MARK: - Actions
@IBAction private func exportButtonAction(_ sender: Any) {
self.shareRecoveryKey()
}
@IBAction private func doneButtonAction(_ sender: Any) {
self.presentKeepSafeAlert()
}
private func cancelButtonAction() {
self.viewModel.process(viewAction: .cancel)
}
}
// MARK: - SecretsSetupRecoveryKeyViewModelViewDelegate
extension SecretsSetupRecoveryKeyViewController: SecretsSetupRecoveryKeyViewModelViewDelegate {
func secretsSetupRecoveryKeyViewModel(_ viewModel: SecretsSetupRecoveryKeyViewModelType, didUpdateViewState viewSate: SecretsSetupRecoveryKeyViewState) {
self.render(viewState: viewSate)
}
}

View file

@ -0,0 +1,72 @@
// File created from ScreenTemplate
// $ createScreen.sh SecretsSetupRecoveryKey SecretsSetupRecoveryKey
/*
Copyright 2020 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
final class SecretsSetupRecoveryKeyViewModel: SecretsSetupRecoveryKeyViewModelType {
// MARK: - Properties
// MARK: Private
private let recoveryService: MXRecoveryService
private let passphrase: String?
// MARK: Public
weak var viewDelegate: SecretsSetupRecoveryKeyViewModelViewDelegate?
weak var coordinatorDelegate: SecretsSetupRecoveryKeyViewModelCoordinatorDelegate?
// MARK: - Setup
init(recoveryService: MXRecoveryService, passphrase: String?) {
self.recoveryService = recoveryService
self.passphrase = passphrase
}
// MARK: - Public
func process(viewAction: SecretsSetupRecoveryKeyViewAction) {
switch viewAction {
case .loadData:
self.createSecureKey()
case .done:
self.coordinatorDelegate?.secretsSetupRecoveryKeyViewModelDidComplete(self)
case .errorAlertOk:
self.coordinatorDelegate?.secretsSetupRecoveryKeyViewModelDidFailed(self)
case .cancel:
self.coordinatorDelegate?.secretsSetupRecoveryKeyViewModelDidCancel(self)
}
}
// MARK: - Private
private func createSecureKey() {
self.update(viewState: .loading)
self.recoveryService.createRecovery(forSecrets: nil, withPassphrase: self.passphrase, success: { secretStorageKeyCreationInfo in
self.update(viewState: .loaded(secretStorageKeyCreationInfo.recoveryKey))
}, failure: { error in
self.update(viewState: .error(error))
})
}
private func update(viewState: SecretsSetupRecoveryKeyViewState) {
self.viewDelegate?.secretsSetupRecoveryKeyViewModel(self, didUpdateViewState: viewState)
}
}

View file

@ -0,0 +1,38 @@
// File created from ScreenTemplate
// $ createScreen.sh SecretsSetupRecoveryKey SecretsSetupRecoveryKey
/*
Copyright 2020 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
protocol SecretsSetupRecoveryKeyViewModelViewDelegate: class {
func secretsSetupRecoveryKeyViewModel(_ viewModel: SecretsSetupRecoveryKeyViewModelType, didUpdateViewState viewSate: SecretsSetupRecoveryKeyViewState)
}
protocol SecretsSetupRecoveryKeyViewModelCoordinatorDelegate: class {
func secretsSetupRecoveryKeyViewModelDidComplete(_ viewModel: SecretsSetupRecoveryKeyViewModelType)
func secretsSetupRecoveryKeyViewModelDidFailed(_ viewModel: SecretsSetupRecoveryKeyViewModelType)
func secretsSetupRecoveryKeyViewModelDidCancel(_ viewModel: SecretsSetupRecoveryKeyViewModelType)
}
/// Protocol describing the view model used by `SecretsSetupRecoveryKeyViewController`
protocol SecretsSetupRecoveryKeyViewModelType {
var viewDelegate: SecretsSetupRecoveryKeyViewModelViewDelegate? { get set }
var coordinatorDelegate: SecretsSetupRecoveryKeyViewModelCoordinatorDelegate? { get set }
func process(viewAction: SecretsSetupRecoveryKeyViewAction)
}

View file

@ -0,0 +1,26 @@
// File created from ScreenTemplate
// $ createScreen.sh SecretsSetupRecoveryKey SecretsSetupRecoveryKey
/*
Copyright 2020 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
/// SecretsSetupRecoveryKeyViewController view state
enum SecretsSetupRecoveryKeyViewState {
case loading
case loaded(_ recoveryKey: String)
case error(Error)
}

View file

@ -0,0 +1,73 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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
import UIKit
final class SecretsSetupRecoveryPassphraseCoordinator: SecretsSetupRecoveryPassphraseCoordinatorType {
// MARK: - Properties
// MARK: Private
private var secretsSetupRecoveryPassphraseViewModel: SecretsSetupRecoveryPassphraseViewModelType
private let secretsSetupRecoveryPassphraseViewController: SecretsSetupRecoveryPassphraseViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: SecretsSetupRecoveryPassphraseCoordinatorDelegate?
// MARK: - Setup
init(passphraseInput: SecretsSetupRecoveryPassphraseInput) {
let secretsSetupRecoveryPassphraseViewModel = SecretsSetupRecoveryPassphraseViewModel(passphraseInput: passphraseInput)
let secretsSetupRecoveryPassphraseViewController = SecretsSetupRecoveryPassphraseViewController.instantiate(with: secretsSetupRecoveryPassphraseViewModel)
self.secretsSetupRecoveryPassphraseViewModel = secretsSetupRecoveryPassphraseViewModel
self.secretsSetupRecoveryPassphraseViewController = secretsSetupRecoveryPassphraseViewController
}
// MARK: - Public methods
func start() {
self.secretsSetupRecoveryPassphraseViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.secretsSetupRecoveryPassphraseViewController
}
}
// MARK: - SecretsSetupRecoveryPassphraseViewModelCoordinatorDelegate
extension SecretsSetupRecoveryPassphraseCoordinator: SecretsSetupRecoveryPassphraseViewModelCoordinatorDelegate {
func secretsSetupRecoveryPassphraseViewModel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType, didEnterNewPassphrase passphrase: String) {
self.delegate?.secretsSetupRecoveryPassphraseCoordinator(self, didEnterNewPassphrase: passphrase)
}
func secretsSetupRecoveryPassphraseViewModel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType, didConfirmPassphrase passphrase: String) {
self.delegate?.secretsSetupRecoveryPassphraseCoordinator(self, didConfirmPassphrase: passphrase)
}
func secretsSetupRecoveryPassphraseViewModelDidCancel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType) {
self.delegate?.secretsSetupRecoveryPassphraseCoordinatorDidCancel(self)
}
}

View file

@ -0,0 +1,30 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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
protocol SecretsSetupRecoveryPassphraseCoordinatorDelegate: class {
func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didEnterNewPassphrase passphrase: String)
func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didConfirmPassphrase passphrase: String)
func secretsSetupRecoveryPassphraseCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType)
}
/// `SecretsSetupRecoveryPassphraseCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
protocol SecretsSetupRecoveryPassphraseCoordinatorType: Coordinator, Presentable {
var delegate: SecretsSetupRecoveryPassphraseCoordinatorDelegate? { get }
}

View file

@ -0,0 +1,24 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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 SecretsSetupRecoveryPassphraseInput {
case new
case confirm(_ passphrase: String)
}

View file

@ -0,0 +1,27 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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
/// SecretsSetupRecoveryPassphraseViewController view actions exposed to view model
enum SecretsSetupRecoveryPassphraseViewAction {
case loadData
case updatePassphrase(_ passphrase: String?)
case validate
case cancel
}

View file

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="bIB-0i-ukm">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Secrets Setup Recovery Passphrase View Controller-->
<scene sceneID="etY-7t-lyY">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="bIB-0i-ukm" customClass="SecretsSetupRecoveryPassphraseViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="D8T-l5-mMj">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="o4q-2F-ezk">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dME-t7-qZD">
<rect key="frame" x="0.0" y="0.0" width="414" height="598"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NHb-J1-L5X">
<rect key="frame" x="0.0" y="0.0" width="414" height="598"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="secrets_setup_passphrase" translatesAutoresizingMaskIntoConstraints="NO" id="ZX3-oS-5DJ">
<rect key="frame" x="185" y="35" width="44" height="48"/>
<constraints>
<constraint firstAttribute="height" constant="48" id="380-Pr-HJO"/>
<constraint firstAttribute="width" constant="44" id="Ypb-bz-jVe"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ecv-l3-ryP">
<rect key="frame" x="20" y="113" width="374" height="54"/>
<string key="text">Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery passphrase.</string>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5eP-6U-QZi">
<rect key="frame" x="0.0" y="207" width="414" height="251.5"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="bottom" translatesAutoresizingMaskIntoConstraints="NO" id="mPf-Xv-wqH">
<rect key="frame" x="0.0" y="0.0" width="414" height="251.5"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4z6-DU-d2T">
<rect key="frame" x="0.0" y="0.0" width="414" height="78.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="enter" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iM1-le-WDv">
<rect key="frame" x="20" y="10" width="39.5" height="58.5"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Enter passphrase" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="wuc-Sr-qja">
<rect key="frame" x="79.5" y="14.5" width="280.5" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="oeq-kq-s6b"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="next" secureTextEntry="YES"/>
<connections>
<outlet property="delegate" destination="bIB-0i-ukm" id="ZTp-o9-59m"/>
</connections>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="H1x-SK-Bsn">
<rect key="frame" x="360" y="17.5" width="44" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="qC3-Mk-XiH"/>
<constraint firstAttribute="height" constant="44" id="uwx-Uv-7kY"/>
</constraints>
<state key="normal" image="reveal_password_button"/>
<connections>
<action selector="passphraseVisibilityButtonAction:" destination="bIB-0i-ukm" eventType="touchUpInside" id="cic-gC-Lfl"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="iM1-le-WDv" firstAttribute="leading" secondItem="4z6-DU-d2T" secondAttribute="leading" constant="20" id="5Qr-ay-AD3"/>
<constraint firstAttribute="trailing" secondItem="H1x-SK-Bsn" secondAttribute="trailing" constant="10" id="9bF-iX-wf7"/>
<constraint firstItem="iM1-le-WDv" firstAttribute="centerY" secondItem="4z6-DU-d2T" secondAttribute="centerY" id="E3g-fR-guv"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="wuc-Sr-qja" secondAttribute="bottom" constant="5" id="EF3-tn-aHa"/>
<constraint firstItem="H1x-SK-Bsn" firstAttribute="centerY" secondItem="wuc-Sr-qja" secondAttribute="centerY" id="QWg-IV-bRt"/>
<constraint firstAttribute="bottom" secondItem="iM1-le-WDv" secondAttribute="bottom" constant="10" id="VIu-zS-irW"/>
<constraint firstItem="wuc-Sr-qja" firstAttribute="top" relation="greaterThanOrEqual" secondItem="4z6-DU-d2T" secondAttribute="top" constant="5" id="WEZ-WG-H3c"/>
<constraint firstItem="wuc-Sr-qja" firstAttribute="leading" secondItem="iM1-le-WDv" secondAttribute="trailing" priority="750" constant="10" id="XG2-GF-pwv"/>
<constraint firstItem="H1x-SK-Bsn" firstAttribute="leading" secondItem="wuc-Sr-qja" secondAttribute="trailing" id="g2t-e4-oKl"/>
<constraint firstItem="iM1-le-WDv" firstAttribute="top" secondItem="4z6-DU-d2T" secondAttribute="top" constant="10" id="iKt-i6-jnP"/>
<constraint firstItem="iM1-le-WDv" firstAttribute="centerY" secondItem="wuc-Sr-qja" secondAttribute="centerY" id="tkC-ad-yyK"/>
<constraint firstItem="wuc-Sr-qja" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="iM1-le-WDv" secondAttribute="trailing" constant="20" id="uOM-mT-X0Z"/>
</constraints>
</view>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pQ6-Ke-kTc">
<rect key="frame" x="0.0" y="78.5" width="414" height="173"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="XEQ-L8-Tbl">
<rect key="frame" x="0.0" y="5" width="414" height="153"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="O4X-SY-HCD">
<rect key="frame" x="0.0" y="0.0" width="414" height="5"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7Ur-Gj-5yT" customClass="PasswordStrengthView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="20" y="0.0" width="374" height="5"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="5" id="LGA-bA-pUr"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="7Ur-Gj-5yT" firstAttribute="top" secondItem="O4X-SY-HCD" secondAttribute="top" id="hAi-DD-d7R"/>
<constraint firstItem="7Ur-Gj-5yT" firstAttribute="leading" secondItem="O4X-SY-HCD" secondAttribute="leading" constant="20" id="qLK-02-VvY"/>
<constraint firstAttribute="bottom" secondItem="7Ur-Gj-5yT" secondAttribute="bottom" id="sye-7J-VNw"/>
<constraint firstAttribute="trailing" secondItem="7Ur-Gj-5yT" secondAttribute="trailing" constant="20" id="uYv-z7-RLE"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Yd2-sG-uwh">
<rect key="frame" x="0.0" y="20" width="414" height="133"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Try adding a word" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="A2u-5W-L5q">
<rect key="frame" x="20" y="0.0" width="374" height="133"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" priority="250" id="I6i-Jg-mZ3"/>
<constraint firstItem="A2u-5W-L5q" firstAttribute="top" secondItem="Yd2-sG-uwh" secondAttribute="top" id="Qib-J0-MO4"/>
<constraint firstAttribute="bottom" secondItem="A2u-5W-L5q" secondAttribute="bottom" id="UZc-rg-rAc"/>
<constraint firstAttribute="trailing" secondItem="A2u-5W-L5q" secondAttribute="trailing" constant="20" id="YYn-et-fHT"/>
<constraint firstItem="A2u-5W-L5q" firstAttribute="leading" secondItem="Yd2-sG-uwh" secondAttribute="leading" constant="20" id="bLx-1L-c23"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="O4X-SY-HCD" firstAttribute="width" secondItem="XEQ-L8-Tbl" secondAttribute="width" id="NRY-zi-9gP"/>
<constraint firstItem="Yd2-sG-uwh" firstAttribute="width" secondItem="XEQ-L8-Tbl" secondAttribute="width" id="Wxj-rm-tK6"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="XEQ-L8-Tbl" firstAttribute="leading" secondItem="pQ6-Ke-kTc" secondAttribute="leading" id="aVG-9g-4t9"/>
<constraint firstItem="XEQ-L8-Tbl" firstAttribute="top" secondItem="pQ6-Ke-kTc" secondAttribute="top" constant="5" id="qz3-J5-Jc0"/>
<constraint firstAttribute="bottom" secondItem="XEQ-L8-Tbl" secondAttribute="bottom" constant="15" id="tG9-Jd-R6N"/>
<constraint firstAttribute="trailing" secondItem="XEQ-L8-Tbl" secondAttribute="trailing" id="vAD-HS-KZy"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="pQ6-Ke-kTc" firstAttribute="width" secondItem="mPf-Xv-wqH" secondAttribute="width" id="FJz-yd-QPP"/>
<constraint firstItem="4z6-DU-d2T" firstAttribute="width" secondItem="mPf-Xv-wqH" secondAttribute="width" id="Tjm-Zw-JKh"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="mPf-Xv-wqH" firstAttribute="top" secondItem="5eP-6U-QZi" secondAttribute="top" id="1fu-vG-gQo"/>
<constraint firstAttribute="trailing" secondItem="mPf-Xv-wqH" secondAttribute="trailing" id="3aT-0u-Dqp"/>
<constraint firstAttribute="bottom" secondItem="mPf-Xv-wqH" secondAttribute="bottom" id="QyV-Wc-l5Z"/>
<constraint firstItem="mPf-Xv-wqH" firstAttribute="leading" secondItem="5eP-6U-QZi" secondAttribute="leading" id="czh-ku-UT4"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Don't use your account password." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2LW-AX-yzs">
<rect key="frame" x="20" y="473.5" width="374" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2kp-HO-dRr">
<rect key="frame" x="0.0" y="528" width="414" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Ow-Ba-bLe" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="20" y="0.0" width="374" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="aYo-rF-vZL"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal" title="Validate">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="validateButtonAction:" destination="bIB-0i-ukm" eventType="touchUpInside" id="CRT-SQ-iBx"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="5Ow-Ba-bLe" secondAttribute="bottom" id="Ey4-nH-44x"/>
<constraint firstItem="5Ow-Ba-bLe" firstAttribute="width" secondItem="2kp-HO-dRr" secondAttribute="width" priority="750" id="d9G-hg-c38"/>
<constraint firstItem="5Ow-Ba-bLe" firstAttribute="top" secondItem="2kp-HO-dRr" secondAttribute="top" id="p83-Ml-a6D"/>
<constraint firstItem="5Ow-Ba-bLe" firstAttribute="centerX" secondItem="2kp-HO-dRr" secondAttribute="centerX" id="taR-rx-sJn"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="5eP-6U-QZi" secondAttribute="trailing" id="0ve-ds-mJr"/>
<constraint firstItem="ecv-l3-ryP" firstAttribute="leading" secondItem="NHb-J1-L5X" secondAttribute="leading" constant="20" id="1Wo-9r-ycH"/>
<constraint firstItem="2LW-AX-yzs" firstAttribute="leading" secondItem="NHb-J1-L5X" secondAttribute="leading" constant="20" id="6je-oq-7RI"/>
<constraint firstItem="2LW-AX-yzs" firstAttribute="top" secondItem="5eP-6U-QZi" secondAttribute="bottom" constant="15" id="7ul-hJ-K6H"/>
<constraint firstAttribute="trailing" secondItem="ecv-l3-ryP" secondAttribute="trailing" constant="20" id="9jK-Nm-ExO"/>
<constraint firstAttribute="width" priority="750" constant="500" id="Gg8-aF-YB1"/>
<constraint firstAttribute="trailing" secondItem="2LW-AX-yzs" secondAttribute="trailing" constant="20" id="HxK-zm-30M"/>
<constraint firstItem="ecv-l3-ryP" firstAttribute="top" secondItem="ZX3-oS-5DJ" secondAttribute="bottom" constant="30" id="Sgu-ux-Ec9"/>
<constraint firstAttribute="trailing" secondItem="2kp-HO-dRr" secondAttribute="trailing" id="TQA-Lg-F8a"/>
<constraint firstItem="2kp-HO-dRr" firstAttribute="leading" secondItem="NHb-J1-L5X" secondAttribute="leading" id="Yqh-Ug-xoQ"/>
<constraint firstItem="ZX3-oS-5DJ" firstAttribute="centerX" secondItem="NHb-J1-L5X" secondAttribute="centerX" id="dhm-uO-9qa"/>
<constraint firstItem="5eP-6U-QZi" firstAttribute="leading" secondItem="NHb-J1-L5X" secondAttribute="leading" id="em6-Xe-8LR"/>
<constraint firstItem="ZX3-oS-5DJ" firstAttribute="top" secondItem="NHb-J1-L5X" secondAttribute="top" constant="35" id="gxm-Dc-zzj"/>
<constraint firstItem="2kp-HO-dRr" firstAttribute="top" secondItem="2LW-AX-yzs" secondAttribute="bottom" constant="40" id="hMN-TD-hYF"/>
<constraint firstAttribute="bottom" secondItem="2kp-HO-dRr" secondAttribute="bottom" constant="20" id="svg-Pb-ME3"/>
<constraint firstItem="5eP-6U-QZi" firstAttribute="top" secondItem="ecv-l3-ryP" secondAttribute="bottom" constant="40" id="vDP-O1-IhH"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="NHb-J1-L5X" secondAttribute="bottom" id="53C-6L-LrF"/>
<constraint firstItem="NHb-J1-L5X" firstAttribute="top" secondItem="dME-t7-qZD" secondAttribute="top" id="ZlU-kl-Rzq"/>
<constraint firstItem="5Ow-Ba-bLe" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="dME-t7-qZD" secondAttribute="leading" constant="20" id="ZmL-F4-HZY"/>
<constraint firstItem="NHb-J1-L5X" firstAttribute="centerX" secondItem="dME-t7-qZD" secondAttribute="centerX" id="cUL-iD-JJv"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="NHb-J1-L5X" secondAttribute="trailing" id="eLO-V9-4WS"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="5Ow-Ba-bLe" secondAttribute="trailing" constant="20" id="lAb-bG-jNQ"/>
<constraint firstItem="NHb-J1-L5X" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="dME-t7-qZD" secondAttribute="leading" id="qix-Tx-bKx"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="dME-t7-qZD" firstAttribute="leading" secondItem="o4q-2F-ezk" secondAttribute="leading" id="Eqv-Ts-WXt"/>
<constraint firstItem="dME-t7-qZD" firstAttribute="width" secondItem="o4q-2F-ezk" secondAttribute="width" id="PLv-tO-F3G"/>
<constraint firstAttribute="trailing" secondItem="dME-t7-qZD" secondAttribute="trailing" id="WWJ-PK-ihX"/>
<constraint firstItem="dME-t7-qZD" firstAttribute="top" secondItem="o4q-2F-ezk" secondAttribute="top" id="Wqq-0l-F66"/>
<constraint firstAttribute="bottom" secondItem="dME-t7-qZD" secondAttribute="bottom" id="itF-04-4ea"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" red="0.94509803920000002" green="0.96078431369999995" blue="0.97254901959999995" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="o4q-2F-ezk" firstAttribute="leading" secondItem="dKy-p2-wAx" secondAttribute="leading" id="Jje-qL-QFy"/>
<constraint firstItem="dKy-p2-wAx" firstAttribute="trailing" secondItem="o4q-2F-ezk" secondAttribute="trailing" id="Jow-ri-Vds"/>
<constraint firstAttribute="bottom" secondItem="o4q-2F-ezk" secondAttribute="bottom" id="flc-Xx-pJR"/>
<constraint firstItem="dKy-p2-wAx" firstAttribute="top" secondItem="o4q-2F-ezk" secondAttribute="top" id="rly-LW-com"/>
</constraints>
<viewLayoutGuide key="safeArea" id="dKy-p2-wAx"/>
</view>
<connections>
<outlet property="additionalInformationLabel" destination="2LW-AX-yzs" id="sSr-zi-cYk"/>
<outlet property="formBackgroundView" destination="5eP-6U-QZi" id="DSp-VW-aQt"/>
<outlet property="informationLabel" destination="ecv-l3-ryP" id="cJ6-CH-05z"/>
<outlet property="passphraseAdditionalInfoView" destination="pQ6-Ke-kTc" id="0tj-vn-lWG"/>
<outlet property="passphraseAdditionalLabel" destination="A2u-5W-L5q" id="OI1-F7-Rsm"/>
<outlet property="passphraseStrengthContainerView" destination="O4X-SY-HCD" id="Ibs-aY-NAO"/>
<outlet property="passphraseStrengthView" destination="7Ur-Gj-5yT" id="4um-Bj-28E"/>
<outlet property="passphraseTextField" destination="wuc-Sr-qja" id="FPu-mI-s69"/>
<outlet property="passphraseTitleLabel" destination="iM1-le-WDv" id="MXH-F1-72q"/>
<outlet property="passphraseVisibilityButton" destination="H1x-SK-Bsn" id="hJB-hW-7Jk"/>
<outlet property="scrollView" destination="o4q-2F-ezk" id="yWy-nx-irL"/>
<outlet property="securePassphraseImageView" destination="ZX3-oS-5DJ" id="wi7-vp-rvG"/>
<outlet property="validateButton" destination="5Ow-Ba-bLe" id="Ugv-xk-l5i"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Lob-0d-tfH" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3772.4637681159425" y="-774.10714285714278"/>
</scene>
</scenes>
<resources>
<image name="reveal_password_button" width="24" height="18"/>
<image name="secrets_setup_passphrase" width="48" height="48"/>
</resources>
</document>

View file

@ -0,0 +1,323 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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 UIKit
final class SecretsSetupRecoveryPassphraseViewController: UIViewController {
// MARK: - Constants
private enum Constants {
static let animationDuration: TimeInterval = 0.3
}
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var scrollView: UIScrollView!
@IBOutlet private weak var securePassphraseImageView: UIImageView!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var formBackgroundView: UIView!
@IBOutlet private weak var passphraseTitleLabel: UILabel!
@IBOutlet private weak var passphraseTextField: UITextField!
@IBOutlet private weak var passphraseVisibilityButton: UIButton!
@IBOutlet private weak var passphraseAdditionalInfoView: UIView!
@IBOutlet private weak var passphraseStrengthContainerView: UIView!
@IBOutlet private weak var passphraseStrengthView: PasswordStrengthView!
@IBOutlet private weak var passphraseAdditionalLabel: UILabel!
@IBOutlet private weak var additionalInformationLabel: UILabel!
@IBOutlet private weak var validateButton: RoundedButton!
// MARK: Private
private var viewModel: SecretsSetupRecoveryPassphraseViewModelType!
private var theme: Theme!
private var keyboardAvoider: KeyboardAvoider?
private var errorPresenter: MXKErrorPresentation!
private var activityPresenter: ActivityIndicatorPresenter!
private var isFirstViewAppearing: Bool = true
private var isPassphraseTextFieldEditedOnce: Bool = false
private var currentViewData: SecretsSetupRecoveryPassphraseViewData?
// MARK: - Setup
class func instantiate(with viewModel: SecretsSetupRecoveryPassphraseViewModelType) -> SecretsSetupRecoveryPassphraseViewController {
let viewController = StoryboardScene.SecretsSetupRecoveryPassphraseViewController.initialScene.instantiate()
viewController.viewModel = viewModel
viewController.theme = ThemeService.shared().theme
return viewController
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.setupViews()
self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView)
self.activityPresenter = ActivityIndicatorPresenter()
self.errorPresenter = MXKErrorAlertPresentation()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
self.viewModel.viewDelegate = self
self.viewModel.process(viewAction: .loadData)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.keyboardAvoider?.startAvoiding()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if self.isFirstViewAppearing {
self.isFirstViewAppearing = false
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.view.endEditing(true)
self.keyboardAvoider?.stopAvoiding()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func setupViews() {
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
self?.cancelButtonAction()
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.vc_removeBackTitle()
self.title = VectorL10n.secretsSetupRecoveryPassphraseTitle
self.scrollView.keyboardDismissMode = .interactive
self.securePassphraseImageView.image = Asset.Images.secretsSetupPassphrase.image.withRenderingMode(.alwaysTemplate)
self.passphraseTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
self.passphraseAdditionalInfoView.isHidden = true
let visibilityImage = Asset.Images.revealPasswordButton.image.withRenderingMode(.alwaysTemplate)
self.passphraseVisibilityButton.setImage(visibilityImage, for: .normal)
self.additionalInformationLabel.text = VectorL10n.secretsSetupRecoveryPassphraseAdditionalInformation
self.validateButton.setTitle(VectorL10n.continue, for: .normal)
}
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.securePassphraseImageView.tintColor = theme.textPrimaryColor
self.informationLabel.textColor = theme.textPrimaryColor
self.formBackgroundView.backgroundColor = theme.backgroundColor
self.passphraseTitleLabel.textColor = theme.textPrimaryColor
theme.applyStyle(onTextField: self.passphraseTextField)
let passphraseTitle: String
if let viewData = self.currentViewData, case .confimPassphrase = viewData.mode {
passphraseTitle = VectorL10n.secretsSetupRecoveryPassphraseConfirmPassphrasePlaceholder
} else {
passphraseTitle = VectorL10n.keyBackupSetupPassphrasePassphrasePlaceholder
}
self.passphraseTextField.attributedPlaceholder = NSAttributedString(string: passphraseTitle,
attributes: [.foregroundColor: theme.placeholderTextColor])
self.passphraseVisibilityButton.tintColor = theme.tintColor
self.additionalInformationLabel.textColor = theme.textSecondaryColor
self.validateButton.update(theme: theme)
}
private func registerThemeServiceDidChangeThemeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
}
@objc private func themeDidChange() {
self.update(theme: ThemeService.shared().theme)
}
private func render(viewState: SecretsSetupRecoveryPassphraseViewState) {
switch viewState {
case .loaded(let viewData):
self.renderLoaded(viewData: viewData)
case .formUpdated(let viewData):
self.renderFormUpdated(viewData: viewData)
case .error(let error):
self.render(error: error)
}
}
private func renderLoaded(viewData: SecretsSetupRecoveryPassphraseViewData) {
self.currentViewData = viewData
let informationText: String
let passphraseTitle: String
let showPasswordStrength: Bool
switch viewData.mode {
case .newPassphrase(strength: let strength):
informationText = VectorL10n.secretsSetupRecoveryPassphraseInformation
passphraseTitle = VectorL10n.keyBackupSetupPassphrasePassphraseTitle
showPasswordStrength = true
self.passphraseStrengthView.strength = strength
case .confimPassphrase:
informationText = VectorL10n.secretsSetupRecoveryPassphraseConfirmInformation
passphraseTitle = VectorL10n.secretsSetupRecoveryPassphraseConfirmPassphraseTitle
showPasswordStrength = false
}
self.informationLabel.text = informationText
self.passphraseTitleLabel.text = passphraseTitle
self.passphraseStrengthContainerView.isHidden = !showPasswordStrength
self.update(theme: self.theme)
}
private func renderFormUpdated(viewData: SecretsSetupRecoveryPassphraseViewData) {
self.currentViewData = viewData
if case .newPassphrase(strength: let strength) = viewData.mode {
self.passphraseStrengthView.strength = strength
}
self.validateButton.isEnabled = viewData.isFormValid
self.updatePassphraseAdditionalLabel(viewData: viewData)
// Show passphrase additional info at first character entered
if self.isPassphraseTextFieldEditedOnce == false, self.passphraseTextField.text?.isEmpty == false {
self.isPassphraseTextFieldEditedOnce = true
self.showPassphraseAdditionalInfo(animated: true)
}
}
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
}
private func showPassphraseAdditionalInfo(animated: Bool) {
guard self.passphraseAdditionalInfoView.isHidden else {
return
}
// Workaround to layout passphraseStrengthView corner radius
self.passphraseStrengthView.setNeedsLayout()
UIView.animate(withDuration: Constants.animationDuration) {
self.passphraseAdditionalInfoView.isHidden = false
}
}
private func updatePassphraseAdditionalLabel(viewData: SecretsSetupRecoveryPassphraseViewData) {
let text: String
let textColor: UIColor
if viewData.isFormValid {
switch viewData.mode {
case .newPassphrase:
text = VectorL10n.keyBackupSetupPassphrasePassphraseValid
case .confimPassphrase:
text = VectorL10n.keyBackupSetupPassphraseConfirmPassphraseValid
}
textColor = self.theme.tintColor
} else {
switch viewData.mode {
case .newPassphrase:
text = VectorL10n.keyBackupSetupPassphrasePassphraseInvalid
case .confimPassphrase:
text = VectorL10n.keyBackupSetupPassphraseConfirmPassphraseInvalid
}
textColor = self.theme.noticeColor
}
self.passphraseAdditionalLabel.text = text
self.passphraseAdditionalLabel.textColor = textColor
}
// MARK: - Actions
@IBAction private func passphraseVisibilityButtonAction(_ sender: Any) {
guard self.isPassphraseTextFieldEditedOnce else {
return
}
self.passphraseTextField.isSecureTextEntry.toggle()
}
@objc private func textFieldDidChange(_ textField: UITextField) {
guard textField == self.passphraseTextField else {
return
}
self.viewModel.process(viewAction: .updatePassphrase(textField.text))
}
@IBAction private func validateButtonAction(_ sender: Any) {
self.viewModel.process(viewAction: .validate)
}
private func cancelButtonAction() {
self.viewModel.process(viewAction: .cancel)
}
}
// MARK: - SecretsSetupRecoveryPassphraseViewModelViewDelegate
extension SecretsSetupRecoveryPassphraseViewController: SecretsSetupRecoveryPassphraseViewModelViewDelegate {
func secretsSetupRecoveryPassphraseViewModel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType, didUpdateViewState viewSate: SecretsSetupRecoveryPassphraseViewState) {
self.render(viewState: viewSate)
}
}

View file

@ -0,0 +1,126 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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
final class SecretsSetupRecoveryPassphraseViewModel: SecretsSetupRecoveryPassphraseViewModelType {
// MARK: - Properties
// MARK: Private
private let passphraseInput: SecretsSetupRecoveryPassphraseInput
private let passwordStrengthManager: PasswordStrengthManager
private var currentViewData: SecretsSetupRecoveryPassphraseViewData?
private var passphrase: String?
// MARK: Public
weak var viewDelegate: SecretsSetupRecoveryPassphraseViewModelViewDelegate?
weak var coordinatorDelegate: SecretsSetupRecoveryPassphraseViewModelCoordinatorDelegate?
// MARK: - Setup
init(passphraseInput: SecretsSetupRecoveryPassphraseInput) {
self.passphraseInput = passphraseInput
self.passwordStrengthManager = PasswordStrengthManager()
}
// MARK: - Public
func process(viewAction: SecretsSetupRecoveryPassphraseViewAction) {
switch viewAction {
case .loadData:
self.loadData()
case .updatePassphrase(let passphrase):
self.updatePassphrase(passphrase)
case .validate:
self.validate()
case .cancel:
self.coordinatorDelegate?.secretsSetupRecoveryPassphraseViewModelDidCancel(self)
}
}
// MARK: - Private
private func loadData() {
let viewDataMode: SecretsSetupRecoveryPassphraseViewDataMode
switch self.passphraseInput {
case .new:
viewDataMode = .newPassphrase(strength: .tooGuessable)
case .confirm:
viewDataMode = .confimPassphrase
}
let viewData = SecretsSetupRecoveryPassphraseViewData(mode: viewDataMode, isFormValid: false)
self.update(viewState: .loaded(viewData))
}
private func update(viewState: SecretsSetupRecoveryPassphraseViewState) {
self.viewDelegate?.secretsSetupRecoveryPassphraseViewModel(self, didUpdateViewState: viewState)
}
private func updatePassphrase(_ passphrase: String?) {
let viewDataMode: SecretsSetupRecoveryPassphraseViewDataMode
let isFormValid: Bool
switch self.passphraseInput {
case .new:
let passphraseStrength = self.passwordStrength(for: passphrase)
viewDataMode = .newPassphrase(strength: passphraseStrength)
isFormValid = passphraseStrength == .veryUnguessable
case .confirm(let passphraseToConfirm):
viewDataMode = .confimPassphrase
isFormValid = passphrase == passphraseToConfirm
}
let viewData = SecretsSetupRecoveryPassphraseViewData(mode: viewDataMode, isFormValid: isFormValid)
self.passphrase = passphrase
self.currentViewData = viewData
self.update(viewState: .formUpdated(viewData))
}
private func validate() {
guard let viewData = self.currentViewData,
viewData.isFormValid,
let passphrase = self.passphrase else {
return
}
switch self.passphraseInput {
case .new:
self.coordinatorDelegate?.secretsSetupRecoveryPassphraseViewModel(self, didEnterNewPassphrase: passphrase)
case .confirm:
self.coordinatorDelegate?.secretsSetupRecoveryPassphraseViewModel(self, didConfirmPassphrase: passphrase)
}
}
private func passwordStrength(for password: String?) -> PasswordStrength {
guard let password = password else {
return .tooGuessable
}
return self.passwordStrengthManager.passwordStrength(for: password)
}
}

View file

@ -0,0 +1,38 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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
protocol SecretsSetupRecoveryPassphraseViewModelViewDelegate: class {
func secretsSetupRecoveryPassphraseViewModel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType, didUpdateViewState viewSate: SecretsSetupRecoveryPassphraseViewState)
}
protocol SecretsSetupRecoveryPassphraseViewModelCoordinatorDelegate: class {
func secretsSetupRecoveryPassphraseViewModel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType, didEnterNewPassphrase passphrase: String)
func secretsSetupRecoveryPassphraseViewModel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType, didConfirmPassphrase passphrase: String)
func secretsSetupRecoveryPassphraseViewModelDidCancel(_ viewModel: SecretsSetupRecoveryPassphraseViewModelType)
}
/// Protocol describing the view model used by `SecretsSetupRecoveryPassphraseViewController`
protocol SecretsSetupRecoveryPassphraseViewModelType {
var viewDelegate: SecretsSetupRecoveryPassphraseViewModelViewDelegate? { get set }
var coordinatorDelegate: SecretsSetupRecoveryPassphraseViewModelCoordinatorDelegate? { get set }
func process(viewAction: SecretsSetupRecoveryPassphraseViewAction)
}

View file

@ -0,0 +1,36 @@
// File created from ScreenTemplate
// $ createScreen.sh Test SecretsSetupRecoveryPassphrase
/*
Copyright 2020 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 SecretsSetupRecoveryPassphraseViewDataMode {
case newPassphrase(strength: PasswordStrength)
case confimPassphrase
}
struct SecretsSetupRecoveryPassphraseViewData {
let mode: SecretsSetupRecoveryPassphraseViewDataMode
let isFormValid: Bool
}
/// SecretsSetupRecoveryPassphraseViewController view state
enum SecretsSetupRecoveryPassphraseViewState {
case loaded(_ viewData: SecretsSetupRecoveryPassphraseViewData)
case formUpdated(_ viewData: SecretsSetupRecoveryPassphraseViewData)
case error(Error)
}

View file

@ -564,7 +564,7 @@
[[AppDelegate theDelegate] showErrorAsAlert:error];
};
[self.mainSession canEnableE2EByDefaultInNewRoomWithUsers:inviteArray success:^(BOOL canEnableE2E) {
[self.mainSession riot_canEnableE2EByDefaultInNewRoomWithUsers:inviteArray success:^(BOOL canEnableE2E) {
MXStrongifyAndReturnIfNil(self);
// Create new room

View file

@ -0,0 +1,25 @@
#!/bin/sh
# ./getlogs.sh https://riot.im/bugreports/listing/2020-06-07/104229/
if [ ! $# -eq 1 ]; then
echo "Usage: ./getLogs.sh [http link]"
exit 1
fi
LOGS_URL=$1
ID=$( basename $LOGS_URL )
echo $ID
mkdir $ID
cd $ID
wget -r -nd --user=matrix --password=a^njerkoo=les $LOGS_URL
for f in *.log.gz; do
mv -- "$f" "${f%.log.gz}.log"
done
rm *.html