@ -1,9 +1,24 @@
final class OnboardingKeyPairViewController : OnboardingBaseViewController {
private var mode : Mode = . register { didSet { if mode != oldValue { handleModeChanged ( ) } } }
private var keyPair : ECKeyPair ! { didSet { updateMnemonic ( ) } }
private var mnemonic : String ! { didSet { mnemonicLabel. text = mnemonic } }
private var mnemonic : String ! { didSet { handleMnemonicChanged( ) } }
private var userName : String ?
// MARK: C o m p o n e n t s
private lazy var registerStackView : UIStackView = {
let result = UIStackView ( arrangedSubviews : [ explanationLabel , UIView . spacer ( withHeight : 32 ) , mnemonicLabel , UIView . spacer ( withHeight : 24 ) , copyButton , UIView . spacer ( withHeight : 8 ) , restoreButton ] )
result . accessibilityIdentifier = " onboarding.keyPairStep.registerStackView "
result . axis = . vertical
return result
} ( )
private lazy var explanationLabel : UILabel = {
let result = createExplanationLabel ( text : NSLocalizedString ( " Please save the seed below in a safe location. It can be used to restore your account if you lose access, or to migrate to a new device. " , comment : " " ) )
result . accessibilityIdentifier = " onboarding.keyPairStep.explanationLabel "
return result
} ( )
private lazy var mnemonicLabel : UILabel = {
let result = createExplanationLabel ( text : " " )
result . accessibilityIdentifier = " onboarding.keyPairStep.mnemonicLabel "
@ -20,6 +35,43 @@ final class OnboardingKeyPairViewController : OnboardingBaseViewController {
return result
} ( )
private lazy var restoreButton : OWSFlatButton = {
let result = createLinkButton ( title : NSLocalizedString ( " Restore Using Mnemonic " , comment : " " ) , selector : #selector ( switchMode ) )
result . accessibilityIdentifier = " onboarding.keyPairStep.restoreButton "
return result
} ( )
private lazy var restoreStackView : UIStackView = {
let result = UIStackView ( arrangedSubviews : [ mnemonicTextField , UIView . spacer ( withHeight : 24 ) , registerButton ] )
result . accessibilityIdentifier = " onboarding.keyPairStep.restoreStackView "
result . axis = . vertical
return result
} ( )
private lazy var mnemonicTextField : UITextField = {
let result = UITextField ( frame : CGRect . zero )
result . accessibilityIdentifier = " onboarding.keyPairStep.mnemonicTextField "
result . textAlignment = . center
result . placeholder = NSLocalizedString ( " Enter Your Mnemonic " , comment : " " )
return result
} ( )
private lazy var registerButton : OWSFlatButton = {
let result = createLinkButton ( title : NSLocalizedString ( " Register a New Account " , comment : " " ) , selector : #selector ( switchMode ) )
result . accessibilityIdentifier = " onboarding.keyPairStep.registerButton "
return result
} ( )
private lazy var registerOrRestoreButton : OWSFlatButton = {
let result = createButton ( title : " " , selector : #selector ( registerOrRestore ) )
result . accessibilityIdentifier = " onboarding.keyPairStep.registerOrRestoreButton "
return result
} ( )
// MARK: T y p e s
enum Mode { case register , restore }
// MARK: L i f e c y c l e
init ( onboardingController : OnboardingController , userName : String ? ) {
super . init ( onboardingController : onboardingController )
self . userName = userName
@ -28,6 +80,7 @@ final class OnboardingKeyPairViewController : OnboardingBaseViewController {
override public func viewDidLoad ( ) {
super . loadView ( )
setUpViewHierarchy ( )
handleModeChanged ( ) // P e r f o r m i n i t i a l u p d a t e
updateKeyPair ( )
// T e s t
// = = = = = = = = = = = = = = = =
@ -43,36 +96,50 @@ final class OnboardingKeyPairViewController : OnboardingBaseViewController {
}
private func setUpViewHierarchy ( ) {
// P r e p a r e
view . backgroundColor = Theme . backgroundColor
view . layoutMargins = . zero
// S e t u p v i e w h i e r a r c h y
let titleLabel = createTitleLabel ( text : NSLocalizedString ( " Create Your Loki Messenger Account " , comment : " " ) )
titleLabel . accessibilityIdentifier = " onboarding.keyPairStep.titleLabel "
let topSpacer = UIView . vStretchingSpacer ( )
let explanationLabel = createExplanationLabel ( text : NSLocalizedString ( " Please save the seed below in a safe location. It can be used to restore your account if you lose access, or to migrate to a new device. " , comment : " " ) )
explanationLabel . accessibilityIdentifier = " onboarding.keyPairStep.explanationLabel "
let bottomSpacer = UIView . vStretchingSpacer ( )
let registerButton = createButton ( title : NSLocalizedString ( " Register " , comment : " " ) , selector : #selector ( register ) )
registerButton . accessibilityIdentifier = " onboarding.keyPairStep.registerButton "
let stackView = UIStackView ( arrangedSubviews : [
titleLabel ,
topSpacer ,
explanationLabel ,
UIView . spacer ( withHeight : 32 ) ,
mnemonicLabel ,
UIView . spacer ( withHeight : 24 ) ,
copyButton ,
bottomSpacer ,
registerButton
] )
stackView . axis = . vertical
stackView . alignment = . fill
stackView . layoutMargins = UIEdgeInsets ( top : 32 , left : 32 , bottom : 32 , right : 32 )
stackView . isLayoutMarginsRelativeArrangement = true
view . addSubview ( stackView )
stackView . autoPinWidthToSuperview ( )
stackView . autoPin ( toTopLayoutGuideOf : self , withInset : 0 )
autoPinView ( toBottomOfViewControllerOrKeyboard : stackView , avoidNotch : true )
topSpacer . autoMatch ( . height , to : . height , of : bottomSpacer )
titleLabel . setContentHuggingPriority ( . required , for : NSLayoutConstraint . Axis . vertical )
let mainView = UIView ( frame : CGRect . zero )
mainView . addSubview ( restoreStackView )
mainView . addSubview ( registerStackView )
let mainStackView = UIStackView ( arrangedSubviews : [ titleLabel , mainView , registerOrRestoreButton ] )
mainStackView . axis = . vertical
mainStackView . layoutMargins = UIEdgeInsets ( top : 32 , left : 32 , bottom : 32 , right : 32 )
mainStackView . isLayoutMarginsRelativeArrangement = true
view . addSubview ( mainStackView )
// S e t u p c o n s t r a i n t s
mainStackView . autoPinWidthToSuperview ( )
mainStackView . autoPin ( toTopLayoutGuideOf : self , withInset : 0 )
autoPinView ( toBottomOfViewControllerOrKeyboard : mainStackView , avoidNotch : true )
registerStackView . autoPinWidthToSuperview ( )
registerStackView . autoVCenterInSuperview ( )
restoreStackView . autoPinWidthToSuperview ( )
restoreStackView . autoVCenterInSuperview ( )
}
// MARK: G e n e r a l
@objc private func enableCopyButton ( ) {
copyButton . isUserInteractionEnabled = true
copyButton . setTitle ( NSLocalizedString ( " Copy " , comment : " " ) )
}
// MARK: U p d a t i n g
private func handleModeChanged ( ) {
let registerOrRestoreButtonTitle : String = {
switch mode {
case . register : return NSLocalizedString ( " Register " , comment : " " )
case . restore : return NSLocalizedString ( " Restore " , comment : " " )
}
} ( )
UIView . animate ( withDuration : 0.25 ) {
self . registerStackView . alpha = ( self . mode = = . register ? 1 : 0 )
self . restoreStackView . alpha = ( self . mode = = . restore ? 1 : 0 )
}
self . registerOrRestoreButton . setTitle ( registerOrRestoreButtonTitle )
}
private func updateKeyPair ( ) {
@ -84,33 +151,50 @@ final class OnboardingKeyPairViewController : OnboardingBaseViewController {
private func updateMnemonic ( ) {
mnemonic = Mnemonic . encode ( hexEncodedString : keyPair . hexEncodedPrivateKey )
}
private func handleMnemonicChanged ( ) {
mnemonicLabel . text = mnemonic
}
// MARK: I n t e r a c t i o n
@objc private func copyMnemonic ( ) {
UIPasteboard . general . string = mnemonic
copyButton . isUserInteractionEnabled = false
copyButton . setTitle ( NSLocalizedString ( " Copied ✓ " , comment : " " ) )
Timer . scheduledTimer ( timeInterval : 4 , target : self , selector : #selector ( enableCopyButton ) , userInfo : nil , repeats : false )
}
@objc private func enableCopyButton ( ) {
copyButton . isUserInteractionEnabled = true
copyButton . setTitle ( NSLocalizedString ( " Copy " , comment : " " ) )
@objc private func switchMode ( ) {
switch mode {
case . register : mode = . restore
case . restore : mode = . register
}
}
@objc private func register ( ) {
@objc private func registerOrRestore ( ) {
let hexEncodedPublicKey : String
switch mode {
case . register : hexEncodedPublicKey = keyPair . hexEncodedPublicKey
case . restore :
let mnemonic = mnemonicTextField . text !
do {
let hexEncodedPrivateKey = try Mnemonic . decode ( mnemonic : mnemonic )
let keyPair = ECKeyPair . generate ( withHexEncodedPrivateKey : hexEncodedPrivateKey )
// TODO: S t o r e k e y p a i r
hexEncodedPublicKey = keyPair . hexEncodedPublicKey
} catch let error {
fatalError ( error . localizedDescription ) // TODO: H a n d l e
}
}
let accountManager = TSAccountManager . sharedInstance ( )
accountManager . phoneNumberAwaitingVerification = keyPair . hexEncodedPublicKey
accountManager . phoneNumberAwaitingVerification = hexEncodedPublicKey
accountManager . didRegister ( )
let onSuccess : ( ) -> Void = { [ weak self ] in
let onSuccess = { [ weak self ] in
guard let strongSelf = self else { return }
strongSelf . onboardingController . verificationDidComplete ( fromView : strongSelf )
}
if let userName = userName {
// T r y t o s a v e t h e u s e r n a m e
OWSProfileManager . shared ( ) . updateLocalProfileName ( userName , avatarImage : nil , success : onSuccess , failure : {
Logger . warn ( " Failed to set user name " )
onSuccess ( )
} )
OWSProfileManager . shared ( ) . updateLocalProfileName ( userName , avatarImage : nil , success : onSuccess , failure : onSuccess ) // T r y t o s a v e t h e u s e r n a m e b u t i g n o r e t h e r e s u l t
} else {
onSuccess ( )
}