|  |  |  | 
 | 
					
						
							|  |  |  | final class SeedVC : BaseVC { | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private let mnemonic: String = { | 
					
						
							|  |  |  |         let identityManager = OWSIdentityManager.shared() | 
					
						
							|  |  |  |         let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection | 
					
						
							|  |  |  |         var hexEncodedSeed: String! = databaseConnection.object(forKey: "LKLokiSeed", inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) as! String? | 
					
						
							|  |  |  |         if hexEncodedSeed == nil { | 
					
						
							|  |  |  |             hexEncodedSeed = identityManager.identityKeyPair()!.hexEncodedPrivateKey // Legacy account | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return Mnemonic.encode(hexEncodedString: hexEncodedSeed) | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private lazy var redactedMnemonic: String = { | 
					
						
							|  |  |  |         if isIPhone5OrSmaller { | 
					
						
							|  |  |  |             return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆" | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆ ▆▆▆▆▆▆▆▆ ▆▆ ▆▆▆ ▆▆▆▆▆▆▆" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: Components | 
					
						
							|  |  |  |     private lazy var seedReminderView: SeedReminderView = { | 
					
						
							|  |  |  |         let result = SeedReminderView(hasContinueButton: false) | 
					
						
							|  |  |  |         let title = "You're almost finished! 90%" | 
					
						
							|  |  |  |         let attributedTitle = NSMutableAttributedString(string: title) | 
					
						
							|  |  |  |         attributedTitle.addAttribute(.foregroundColor, value: Colors.accent, range: (title as NSString).range(of: "90%")) | 
					
						
							|  |  |  |         result.title = attributedTitle | 
					
						
							|  |  |  |         result.subtitle = NSLocalizedString("view_seed_reminder_subtitle_2", comment: "") | 
					
						
							|  |  |  |         result.setProgress(0.9, animated: false) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private lazy var mnemonicLabel: UILabel = { | 
					
						
							|  |  |  |         let result = UILabel() | 
					
						
							|  |  |  |         result.textColor = Colors.accent | 
					
						
							|  |  |  |         result.font = Fonts.spaceMono(ofSize: Values.mediumFontSize) | 
					
						
							|  |  |  |         result.numberOfLines = 0 | 
					
						
							|  |  |  |         result.textAlignment = .center | 
					
						
							|  |  |  |         result.lineBreakMode = .byWordWrapping | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private lazy var copyButton: Button = { | 
					
						
							|  |  |  |         let result = Button(style: .prominentOutline, size: .large) | 
					
						
							|  |  |  |         result.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal) | 
					
						
							|  |  |  |         result.addTarget(self, action: #selector(copyMnemonic), for: UIControl.Event.touchUpInside) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: Lifecycle | 
					
						
							|  |  |  |     override func viewDidLoad() { | 
					
						
							|  |  |  |         super.viewDidLoad() | 
					
						
							|  |  |  |         setUpGradientBackground() | 
					
						
							|  |  |  |         setUpNavBarStyle() | 
					
						
							|  |  |  |         setNavBarTitle(NSLocalizedString("vc_seed_title", comment: "")) | 
					
						
							|  |  |  |         // Set up navigation bar buttons | 
					
						
							|  |  |  |         let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) | 
					
						
							|  |  |  |         closeButton.tintColor = Colors.text | 
					
						
							|  |  |  |         navigationItem.leftBarButtonItem = closeButton | 
					
						
							|  |  |  |         // Set up title label | 
					
						
							|  |  |  |         let titleLabel = UILabel() | 
					
						
							|  |  |  |         titleLabel.textColor = Colors.text | 
					
						
							|  |  |  |         titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize) | 
					
						
							|  |  |  |         titleLabel.text = NSLocalizedString("vc_seed_title_2", comment: "") | 
					
						
							|  |  |  |         titleLabel.numberOfLines = 0 | 
					
						
							|  |  |  |         titleLabel.lineBreakMode = .byWordWrapping | 
					
						
							|  |  |  |         // Set up explanation label | 
					
						
							|  |  |  |         let explanationLabel = UILabel() | 
					
						
							|  |  |  |         explanationLabel.textColor = Colors.text | 
					
						
							|  |  |  |         explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) | 
					
						
							|  |  |  |         explanationLabel.text = NSLocalizedString("vc_seed_explanation", comment: "") | 
					
						
							|  |  |  |         explanationLabel.numberOfLines = 0 | 
					
						
							|  |  |  |         explanationLabel.lineBreakMode = .byWordWrapping | 
					
						
							|  |  |  |         // Set up mnemonic label | 
					
						
							|  |  |  |         mnemonicLabel.text = redactedMnemonic | 
					
						
							|  |  |  |         let mnemonicLabelGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(revealMnemonic)) | 
					
						
							|  |  |  |         mnemonicLabel.addGestureRecognizer(mnemonicLabelGestureRecognizer) | 
					
						
							|  |  |  |         mnemonicLabel.isUserInteractionEnabled = true | 
					
						
							|  |  |  |         mnemonicLabel.isEnabled = true | 
					
						
							|  |  |  |         // Set up mnemonic label container | 
					
						
							|  |  |  |         let mnemonicLabelContainer = UIView() | 
					
						
							|  |  |  |         mnemonicLabelContainer.addSubview(mnemonicLabel) | 
					
						
							|  |  |  |         mnemonicLabel.pin(to: mnemonicLabelContainer, withInset: isIPhone6OrSmaller ? Values.smallSpacing : Values.mediumSpacing) | 
					
						
							|  |  |  |         mnemonicLabelContainer.layer.cornerRadius = TextField.cornerRadius | 
					
						
							|  |  |  |         mnemonicLabelContainer.layer.borderWidth = 1 | 
					
						
							|  |  |  |         mnemonicLabelContainer.layer.borderColor = Colors.text.cgColor | 
					
						
							|  |  |  |         // Set up call to action label | 
					
						
							|  |  |  |         let callToActionLabel = UILabel() | 
					
						
							|  |  |  |         callToActionLabel.textColor = Colors.text.withAlphaComponent(Values.mediumOpacity) | 
					
						
							|  |  |  |         callToActionLabel.font = .systemFont(ofSize: isIPhone5OrSmaller ? Values.smallFontSize : Values.mediumFontSize) | 
					
						
							|  |  |  |         callToActionLabel.text = NSLocalizedString("vc_seed_reveal_button_title", comment: "") | 
					
						
							|  |  |  |         callToActionLabel.textAlignment = .center | 
					
						
							|  |  |  |         let callToActionLabelGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(revealMnemonic)) | 
					
						
							|  |  |  |         callToActionLabel.addGestureRecognizer(callToActionLabelGestureRecognizer) | 
					
						
							|  |  |  |         callToActionLabel.isUserInteractionEnabled = true | 
					
						
							|  |  |  |         callToActionLabel.isEnabled = true | 
					
						
							|  |  |  |         // Set up spacers | 
					
						
							|  |  |  |         let topSpacer = UIView.vStretchingSpacer() | 
					
						
							|  |  |  |         let bottomSpacer = UIView.vStretchingSpacer() | 
					
						
							|  |  |  |         // Set up copy button container | 
					
						
							|  |  |  |         let copyButtonContainer = UIView() | 
					
						
							|  |  |  |         copyButtonContainer.addSubview(copyButton) | 
					
						
							|  |  |  |         copyButton.pin(.leading, to: .leading, of: copyButtonContainer, withInset: Values.massiveSpacing) | 
					
						
							|  |  |  |         copyButton.pin(.top, to: .top, of: copyButtonContainer) | 
					
						
							|  |  |  |         copyButtonContainer.pin(.trailing, to: .trailing, of: copyButton, withInset: Values.massiveSpacing) | 
					
						
							|  |  |  |         copyButtonContainer.pin(.bottom, to: .bottom, of: copyButton) | 
					
						
							|  |  |  |         // Set up top stack view | 
					
						
							|  |  |  |         let topStackView = UIStackView(arrangedSubviews: [ titleLabel, UIView.spacer(withHeight: isIPhone6OrSmaller ? Values.smallSpacing : Values.largeSpacing), explanationLabel, | 
					
						
							|  |  |  |             UIView.spacer(withHeight: isIPhone6OrSmaller ? Values.smallSpacing + 2 : Values.largeSpacing), mnemonicLabelContainer ]) | 
					
						
							|  |  |  |         if !isIPhone5OrSmaller { | 
					
						
							|  |  |  |             topStackView.addArrangedSubview(UIView.spacer(withHeight: Values.smallSpacing)) | 
					
						
							|  |  |  |             topStackView.addArrangedSubview(callToActionLabel) // Not that important and it really gets in the way on small screens | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         topStackView.axis = .vertical | 
					
						
							|  |  |  |         topStackView.alignment = .fill | 
					
						
							|  |  |  |         // Set up top stack view container | 
					
						
							|  |  |  |         let topStackViewContainer = UIView() | 
					
						
							|  |  |  |         topStackViewContainer.addSubview(topStackView) | 
					
						
							|  |  |  |         topStackView.pin(.leading, to: .leading, of: topStackViewContainer, withInset: Values.veryLargeSpacing) | 
					
						
							|  |  |  |         topStackView.pin(.top, to: .top, of: topStackViewContainer) | 
					
						
							|  |  |  |         topStackViewContainer.pin(.trailing, to: .trailing, of: topStackView, withInset: Values.veryLargeSpacing) | 
					
						
							|  |  |  |         topStackViewContainer.pin(.bottom, to: .bottom, of: topStackView) | 
					
						
							|  |  |  |         // Set up seed reminder view | 
					
						
							|  |  |  |         view.addSubview(seedReminderView) | 
					
						
							|  |  |  |         seedReminderView.pin(.leading, to: .leading, of: view) | 
					
						
							|  |  |  |         seedReminderView.pin(.top, to: .top, of: view) | 
					
						
							|  |  |  |         seedReminderView.pin(.trailing, to: .trailing, of: view) | 
					
						
							|  |  |  |         // Set up main stack view | 
					
						
							|  |  |  |         let mainStackView = UIStackView(arrangedSubviews: [ topSpacer, topStackViewContainer, bottomSpacer, copyButtonContainer ]) | 
					
						
							|  |  |  |         mainStackView.axis = .vertical | 
					
						
							|  |  |  |         mainStackView.alignment = .fill | 
					
						
							|  |  |  |         mainStackView.layoutMargins = UIEdgeInsets(top: 0, leading: 0, bottom: Values.mediumSpacing, trailing: 0) | 
					
						
							|  |  |  |         mainStackView.isLayoutMarginsRelativeArrangement = true | 
					
						
							|  |  |  |         view.addSubview(mainStackView) | 
					
						
							|  |  |  |         mainStackView.pin(.leading, to: .leading, of: view) | 
					
						
							|  |  |  |         mainStackView.pin(.top, to: .bottom, of: seedReminderView) | 
					
						
							|  |  |  |         mainStackView.pin(.trailing, to: .trailing, of: view) | 
					
						
							|  |  |  |         mainStackView.pin(.bottom, to: .bottom, of: view) | 
					
						
							|  |  |  |         topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: General | 
					
						
							|  |  |  |     @objc private func enableCopyButton() { | 
					
						
							|  |  |  |         copyButton.isUserInteractionEnabled = true | 
					
						
							|  |  |  |         UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { | 
					
						
							|  |  |  |             self.copyButton.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal) | 
					
						
							|  |  |  |         }, completion: nil) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: Interaction | 
					
						
							|  |  |  |     @objc private func close() { | 
					
						
							|  |  |  |         dismiss(animated: true, completion: nil) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @objc private func revealMnemonic() { | 
					
						
							|  |  |  |         UIView.transition(with: mnemonicLabel, duration: 0.25, options: .transitionCrossDissolve, animations: { | 
					
						
							|  |  |  |             self.mnemonicLabel.text = self.mnemonic | 
					
						
							|  |  |  |             self.mnemonicLabel.textColor = Colors.text | 
					
						
							|  |  |  |         }, completion: nil) | 
					
						
							|  |  |  |         UIView.transition(with: seedReminderView.titleLabel, duration: 0.25, options: .transitionCrossDissolve, animations: { | 
					
						
							|  |  |  |             let title = "Account Secured! 100%" | 
					
						
							|  |  |  |             let attributedTitle = NSMutableAttributedString(string: title) | 
					
						
							|  |  |  |             attributedTitle.addAttribute(.foregroundColor, value: Colors.accent, range: (title as NSString).range(of: "100%")) | 
					
						
							|  |  |  |             self.seedReminderView.title = attributedTitle | 
					
						
							|  |  |  |         }, completion: nil) | 
					
						
							|  |  |  |         UIView.transition(with: seedReminderView.subtitleLabel, duration: 1, options: .transitionCrossDissolve, animations: { | 
					
						
							|  |  |  |             self.seedReminderView.subtitle = NSLocalizedString("view_seed_reminder_subtitle_3", comment: "") | 
					
						
							|  |  |  |         }, completion: nil) | 
					
						
							|  |  |  |         seedReminderView.setProgress(1, animated: true) | 
					
						
							|  |  |  |         UserDefaults.standard[.hasViewedSeed] = true | 
					
						
							|  |  |  |         NotificationCenter.default.post(name: .seedViewed, object: nil) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @objc private func copyMnemonic() { | 
					
						
							|  |  |  |         revealMnemonic() | 
					
						
							|  |  |  |         UIPasteboard.general.string = mnemonic | 
					
						
							|  |  |  |         copyButton.isUserInteractionEnabled = false | 
					
						
							|  |  |  |         UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { | 
					
						
							|  |  |  |             self.copyButton.setTitle(NSLocalizedString("copied", comment: ""), for: UIControl.State.normal) | 
					
						
							|  |  |  |         }, completion: nil) | 
					
						
							|  |  |  |         Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |