2022-04-01 08:22:45 +02:00
// C o p y r i g h t © 2 0 2 2 R a n g e p r o o f P t y L t d . A l l r i g h t s r e s e r v e d .
2019-12-09 02:33:40 +01:00
2022-04-01 08:22:45 +02:00
import UIKit
2022-08-12 05:35:17 +02:00
import SessionUIKit
2022-04-01 08:22:45 +02:00
import SessionUtilitiesKit
2022-09-20 08:06:01 +02:00
import SignalUtilitiesKit
2022-04-01 08:22:45 +02:00
final class RestoreVC : BaseVC {
2019-12-09 02:33:40 +01:00
private var spacer1HeightConstraint : NSLayoutConstraint !
private var spacer2HeightConstraint : NSLayoutConstraint !
2019-12-09 03:24:03 +01:00
private var spacer3HeightConstraint : NSLayoutConstraint !
2019-12-09 02:33:40 +01:00
private var restoreButtonBottomOffsetConstraint : NSLayoutConstraint !
private var bottomConstraint : NSLayoutConstraint !
2022-09-20 08:06:01 +02:00
// MARK: - C o m p o n e n t s
2020-10-21 00:41:28 +02:00
private lazy var mnemonicTextView : TextView = {
2022-08-12 05:35:17 +02:00
let result = TextView ( placeholder : " vc_restore_seed_text_field_hint " . localized ( ) )
2022-05-12 09:28:27 +02:00
result . autocapitalizationType = . none
2022-09-20 08:06:01 +02:00
result . themeBorderColor = . textPrimary
2020-12-17 01:37:53 +01:00
result . accessibilityLabel = " Recovery phrase text view "
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
return result
} ( )
2019-12-09 03:24:03 +01:00
private lazy var legalLabel : UILabel = {
let result = UILabel ( )
result . font = . systemFont ( ofSize : Values . verySmallFontSize )
2020-02-06 03:31:07 +01:00
let text = " By using this service, you agree to our Terms of Service, End User License Agreement (EULA) and Privacy Policy "
2022-08-12 05:35:17 +02:00
let attributedText = NSMutableAttributedString (
string : text ,
attributes : [
. font : UIFont . systemFont ( ofSize : Values . verySmallFontSize )
]
)
2020-02-06 03:31:07 +01:00
attributedText . addAttribute ( . font , value : UIFont . boldSystemFont ( ofSize : Values . verySmallFontSize ) , range : ( text as NSString ) . range ( of : " Terms of Service " ) )
attributedText . addAttribute ( . font , value : UIFont . boldSystemFont ( ofSize : Values . verySmallFontSize ) , range : ( text as NSString ) . range ( of : " End User License Agreement (EULA) " ) )
attributedText . addAttribute ( . font , value : UIFont . boldSystemFont ( ofSize : Values . verySmallFontSize ) , range : ( text as NSString ) . range ( of : " Privacy Policy " ) )
2022-09-20 08:06:01 +02:00
result . themeTextColor = . textPrimary
2019-12-09 03:24:03 +01:00
result . attributedText = attributedText
result . textAlignment = . center
result . lineBreakMode = . byWordWrapping
2022-08-12 05:35:17 +02:00
result . numberOfLines = 0
2019-12-09 03:24:03 +01:00
return result
} ( )
2022-08-12 05:35:17 +02:00
// MARK: - L i f e c y c l e
2019-12-09 02:33:40 +01:00
override func viewDidLoad ( ) {
2020-02-20 04:37:17 +01:00
super . viewDidLoad ( )
2022-08-31 09:44:44 +02:00
2020-05-30 00:20:30 +02:00
setUpNavBarSessionIcon ( )
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// S e t u p t i t l e l a b e l
let titleLabel = UILabel ( )
2020-06-18 06:41:02 +02:00
titleLabel . font = . boldSystemFont ( ofSize : isIPhone5OrSmaller ? Values . largeFontSize : Values . veryLargeFontSize )
2022-08-12 05:35:17 +02:00
titleLabel . text = " vc_restore_title " . localized ( )
2022-09-20 08:06:01 +02:00
titleLabel . themeTextColor = . textPrimary
2019-12-09 02:33:40 +01:00
titleLabel . lineBreakMode = . byWordWrapping
2022-08-12 05:35:17 +02:00
titleLabel . numberOfLines = 0
2019-12-09 02:33:40 +01:00
// S e t u p e x p l a n a t i o n l a b e l
let explanationLabel = UILabel ( )
explanationLabel . font = . systemFont ( ofSize : Values . smallFontSize )
2022-08-12 05:35:17 +02:00
explanationLabel . text = " vc_restore_explanation " . localized ( )
2022-09-20 08:06:01 +02:00
explanationLabel . themeTextColor = . textPrimary
2019-12-09 02:33:40 +01:00
explanationLabel . lineBreakMode = . byWordWrapping
2022-08-12 05:35:17 +02:00
explanationLabel . numberOfLines = 0
2019-12-09 03:24:03 +01:00
// S e t u p l e g a l l a b e l
legalLabel . isUserInteractionEnabled = true
let legalLabelTapGestureRecognizer = UITapGestureRecognizer ( target : self , action : #selector ( handleLegalLabelTapped ) )
legalLabel . addGestureRecognizer ( legalLabelTapGestureRecognizer )
2022-09-20 08:06:01 +02:00
2019-12-09 02:33:40 +01:00
// S e t u p s p a c e r s
let topSpacer = UIView . vStretchingSpacer ( )
let spacer1 = UIView ( )
2020-06-18 06:41:02 +02:00
spacer1HeightConstraint = spacer1 . set ( . height , to : isIPhone5OrSmaller ? Values . smallSpacing : Values . veryLargeSpacing )
2019-12-09 02:33:40 +01:00
let spacer2 = UIView ( )
2020-06-18 06:41:02 +02:00
spacer2HeightConstraint = spacer2 . set ( . height , to : isIPhone5OrSmaller ? Values . smallSpacing : Values . veryLargeSpacing )
2019-12-09 03:24:03 +01:00
let spacer3 = UIView ( )
2020-06-18 06:41:02 +02:00
spacer3HeightConstraint = spacer3 . set ( . height , to : isIPhone5OrSmaller ? Values . smallSpacing : Values . veryLargeSpacing )
2019-12-09 02:33:40 +01:00
let bottomSpacer = UIView . vStretchingSpacer ( )
let restoreButtonBottomOffsetSpacer = UIView ( )
restoreButtonBottomOffsetConstraint = restoreButtonBottomOffsetSpacer . set ( . height , to : Values . onboardingButtonBottomOffset )
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// S e t u p r e s t o r e b u t t o n
2022-08-12 05:35:17 +02:00
let restoreButton = OutlineButton ( style : . filled , size : . large )
restoreButton . setTitle ( " continue_2 " . localized ( ) , for : UIControl . State . normal )
2019-12-09 02:33:40 +01:00
restoreButton . addTarget ( self , action : #selector ( restore ) , for : UIControl . Event . touchUpInside )
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// S e t u p r e s t o r e b u t t o n c o n t a i n e r
2022-03-03 04:31:18 +01:00
let restoreButtonContainer = UIView ( wrapping : restoreButton , withInsets : UIEdgeInsets ( top : 0 , leading : Values . massiveSpacing , bottom : 0 , trailing : Values . massiveSpacing ) , shouldAdaptForIPadWithWidth : Values . iPadButtonWidth )
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// S e t u p t o p s t a c k v i e w
2020-10-21 00:41:28 +02:00
let topStackView = UIStackView ( arrangedSubviews : [ titleLabel , spacer1 , explanationLabel , spacer2 , mnemonicTextView , spacer3 , legalLabel ] )
2019-12-09 02:33:40 +01:00
topStackView . axis = . vertical
topStackView . alignment = . fill
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// S e t u p t o p s t a c k v i e w c o n t a i n e r
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 )
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// S e t u p m a i n s t a c k v i e w
let mainStackView = UIStackView ( arrangedSubviews : [ topSpacer , topStackViewContainer , bottomSpacer , restoreButtonContainer , restoreButtonBottomOffsetSpacer ] )
mainStackView . axis = . vertical
mainStackView . alignment = . fill
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
view . addSubview ( mainStackView )
mainStackView . pin ( . leading , to : . leading , of : view )
mainStackView . pin ( . top , to : . top , of : view )
mainStackView . pin ( . trailing , to : . trailing , of : view )
bottomConstraint = mainStackView . pin ( . bottom , to : . bottom , of : view )
topSpacer . heightAnchor . constraint ( equalTo : bottomSpacer . heightAnchor , multiplier : 1 ) . isActive = true
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// D i s m i s s k e y b o a r d o n t a p
let tapGestureRecognizer = UITapGestureRecognizer ( target : self , action : #selector ( dismissKeyboard ) )
view . addGestureRecognizer ( tapGestureRecognizer )
2022-08-12 05:35:17 +02:00
2019-12-09 02:33:40 +01:00
// L i s t e n t o k e y b o a r d n o t i f i c a t i o n s
let notificationCenter = NotificationCenter . default
notificationCenter . addObserver ( self , selector : #selector ( handleKeyboardWillChangeFrameNotification ( _ : ) ) , name : UIResponder . keyboardWillChangeFrameNotification , object : nil )
notificationCenter . addObserver ( self , selector : #selector ( handleKeyboardWillHideNotification ( _ : ) ) , name : UIResponder . keyboardWillHideNotification , object : nil )
}
override func viewDidAppear ( _ animated : Bool ) {
super . viewDidAppear ( animated )
2020-07-29 05:32:51 +02:00
// O n s m a l l s c r e e n s w e h i d e t h e l e g a l l a b e l w h e n t h e k e y b o a r d i s u p , b u t i t ' s i m p o r t a n t t h a t t h e u s e r s e e s i t s o
// i n t h o s e i n s t a n c e s w e d o n ' t m a k e t h e k e y b o a r d c o m e u p a u t o m a t i c a l l y
if ! isIPhone5OrSmaller {
2020-10-21 00:41:28 +02:00
mnemonicTextView . becomeFirstResponder ( )
2020-07-29 05:32:51 +02:00
}
2019-12-09 02:33:40 +01:00
}
deinit {
NotificationCenter . default . removeObserver ( self )
}
// MARK: G e n e r a l
@objc private func dismissKeyboard ( ) {
2020-10-21 00:41:28 +02:00
mnemonicTextView . resignFirstResponder ( )
2019-12-09 02:33:40 +01:00
}
// MARK: U p d a t i n g
@objc private func handleKeyboardWillChangeFrameNotification ( _ notification : Notification ) {
guard let newHeight = ( notification . userInfo ? [ UIResponder . keyboardFrameEndUserInfoKey ] as ? NSValue ) ? . cgRectValue . size . height else { return }
2022-09-20 08:06:01 +02:00
2019-12-09 02:33:40 +01:00
bottomConstraint . constant = - newHeight // N e g a t i v e d u e t o h o w t h e c o n s t r a i n t i s s e t u p
2020-07-27 05:35:00 +02:00
restoreButtonBottomOffsetConstraint . constant = isIPhone6OrSmaller ? Values . smallSpacing : Values . largeSpacing
spacer1HeightConstraint . constant = isIPhone6OrSmaller ? Values . smallSpacing : Values . mediumSpacing
spacer2HeightConstraint . constant = isIPhone6OrSmaller ? Values . smallSpacing : Values . mediumSpacing
spacer3HeightConstraint . constant = isIPhone6OrSmaller ? Values . smallSpacing : Values . mediumSpacing
2022-09-20 08:06:01 +02:00
2020-07-29 05:32:51 +02:00
if isIPhone5OrSmaller { legalLabel . isUserInteractionEnabled = false }
2022-09-20 08:06:01 +02:00
2019-12-09 02:33:40 +01:00
UIView . animate ( withDuration : 0.25 ) {
2020-07-29 05:32:51 +02:00
if isIPhone5OrSmaller { self . legalLabel . alpha = 0 }
2019-12-09 02:33:40 +01:00
self . view . layoutIfNeeded ( )
}
}
@objc private func handleKeyboardWillHideNotification ( _ notification : Notification ) {
bottomConstraint . constant = 0
restoreButtonBottomOffsetConstraint . constant = Values . onboardingButtonBottomOffset
2020-06-18 06:41:02 +02:00
spacer1HeightConstraint . constant = isIPhone5OrSmaller ? Values . smallSpacing : Values . veryLargeSpacing
spacer2HeightConstraint . constant = isIPhone5OrSmaller ? Values . smallSpacing : Values . veryLargeSpacing
spacer3HeightConstraint . constant = isIPhone5OrSmaller ? Values . smallSpacing : Values . veryLargeSpacing
2022-09-20 08:06:01 +02:00
2020-07-29 05:32:51 +02:00
if isIPhone5OrSmaller { legalLabel . isUserInteractionEnabled = true }
2022-09-20 08:06:01 +02:00
2019-12-09 02:33:40 +01:00
UIView . animate ( withDuration : 0.25 ) {
2020-07-29 05:32:51 +02:00
if isIPhone5OrSmaller { self . legalLabel . alpha = 1 }
2019-12-09 02:33:40 +01:00
self . view . layoutIfNeeded ( )
}
}
2022-09-20 08:06:01 +02:00
// MARK: - I n t e r a c t i o n
2019-12-09 02:33:40 +01:00
@objc private func restore ( ) {
func showError ( title : String , message : String = " " ) {
2022-09-20 08:06:01 +02:00
let modal : ConfirmationModal = ConfirmationModal (
info : ConfirmationModal . Info (
title : title ,
explanation : message ,
cancelTitle : " BUTTON_OK " . localized ( ) ,
cancelStyle : . textPrimary
)
)
present ( modal , animated : true )
2019-12-09 02:33:40 +01:00
}
2022-09-20 08:06:01 +02:00
2021-03-04 00:04:16 +01:00
let mnemonic = mnemonicTextView . text ! . lowercased ( )
2019-12-09 02:33:40 +01:00
do {
let hexEncodedSeed = try Mnemonic . decode ( mnemonic : mnemonic )
let seed = Data ( hex : hexEncodedSeed )
2022-04-01 08:22:45 +02:00
let ( ed25519KeyPair , x25519KeyPair ) = try ! Identity . generate ( from : seed )
2021-02-23 03:53:30 +01:00
Onboarding . Flow . recover . preregister ( with : seed , ed25519KeyPair : ed25519KeyPair , x25519KeyPair : x25519KeyPair )
2020-10-21 00:41:28 +02:00
mnemonicTextView . resignFirstResponder ( )
2022-09-20 08:06:01 +02:00
2019-12-09 02:33:40 +01:00
Timer . scheduledTimer ( withTimeInterval : 0.25 , repeats : false ) { _ in
let displayNameVC = DisplayNameVC ( )
self . navigationController ! . pushViewController ( displayNameVC , animated : true )
}
} catch let error {
let error = error as ? Mnemonic . DecodingError ? ? Mnemonic . DecodingError . generic
showError ( title : error . errorDescription ! )
}
}
2019-12-09 03:24:03 +01:00
@objc private func handleLegalLabelTapped ( _ tapGestureRecognizer : UITapGestureRecognizer ) {
2020-02-06 03:31:07 +01:00
let urlAsString : String ?
let tosRange = ( legalLabel . text ! as NSString ) . range ( of : " Terms of Service " )
let eulaRange = ( legalLabel . text ! as NSString ) . range ( of : " End User License Agreement (EULA) " )
let ppRange = ( legalLabel . text ! as NSString ) . range ( of : " Privacy Policy " )
let touchInLegalLabelCoordinates = tapGestureRecognizer . location ( in : legalLabel )
let characterIndex = legalLabel . characterIndex ( for : touchInLegalLabelCoordinates )
2022-09-20 08:06:01 +02:00
2020-02-06 03:31:07 +01:00
if tosRange . contains ( characterIndex ) {
2020-05-28 06:38:33 +02:00
urlAsString = " https://getsession.org/terms-of-service/ "
2020-02-06 03:31:07 +01:00
} else if eulaRange . contains ( characterIndex ) {
2020-05-28 06:38:33 +02:00
urlAsString = " https://getsession.org/terms-of-service/#eula "
2020-02-06 03:31:07 +01:00
} else if ppRange . contains ( characterIndex ) {
2020-05-28 06:38:33 +02:00
urlAsString = " https://getsession.org/privacy-policy/ "
2020-02-06 03:31:07 +01:00
} else {
urlAsString = nil
}
2022-09-20 08:06:01 +02:00
2020-02-06 03:31:07 +01:00
if let urlAsString = urlAsString {
let url = URL ( string : urlAsString ) !
UIApplication . shared . open ( url )
}
2019-12-09 03:24:03 +01:00
}
2019-12-09 02:33:40 +01:00
}