final class LandingVC : BaseVC , LinkDeviceVCDelegate , DeviceLinkingModalDelegate {
private var fakeChatViewContentOffset : CGPoint !
// MARK: C o m p o n e n t s
private lazy var fakeChatView : FakeChatView = {
let result = FakeChatView ( )
result . set ( . height , to : Values . fakeChatViewHeight )
return result
} ( )
private lazy var registerButton : Button = {
let result = Button ( style : . prominentFilled , size : . large )
result . setTitle ( NSLocalizedString ( " Create Session ID " , comment : " " ) , for : UIControl . State . normal )
result . titleLabel ! . font = . boldSystemFont ( ofSize : Values . mediumFontSize )
result . addTarget ( self , action : #selector ( register ) , for : UIControl . Event . touchUpInside )
return result
} ( )
private lazy var restoreButton : Button = {
let result = Button ( style : . prominentOutline , size : . large )
result . setTitle ( NSLocalizedString ( " Continue your Session " , comment : " " ) , for : UIControl . State . normal )
result . titleLabel ! . font = . boldSystemFont ( ofSize : Values . mediumFontSize )
result . addTarget ( self , action : #selector ( restore ) , for : UIControl . Event . touchUpInside )
return result
} ( )
private lazy var linkButton : Button = {
let result = Button ( style : . regularBorderless , size : . small )
result . setTitle ( NSLocalizedString ( " Link to an existing account " , comment : " " ) , for : UIControl . State . normal )
result . titleLabel ! . font = . systemFont ( ofSize : Values . smallFontSize )
result . addTarget ( self , action : #selector ( linkDevice ) , for : UIControl . Event . touchUpInside )
return result
} ( )
// MARK: L i f e c y c l e
override func viewDidLoad ( ) {
super . viewDidLoad ( )
// S e t g r a d i e n t b a c k g r o u n d
view . backgroundColor = . clear
let gradient = Gradients . defaultLokiBackground
view . setGradient ( gradient )
// S e t u p n a v i g a t i o n b a r
let navigationBar = navigationController ! . navigationBar
navigationBar . setBackgroundImage ( UIImage ( ) , for : UIBarMetrics . default )
navigationBar . shadowImage = UIImage ( )
navigationBar . isTranslucent = false
navigationBar . barTintColor = Colors . navigationBarBackground
// S e t u p l o g o i m a g e v i e w
let logoImageView = UIImageView ( )
logoImageView . image = # imageLiteral ( resourceName : " SessionGreen32 " )
logoImageView . contentMode = . scaleAspectFit
logoImageView . set ( . width , to : 32 )
logoImageView . set ( . height , to : 32 )
navigationItem . titleView = logoImageView
// S e t u p t i t l e l a b e l
let titleLabel = UILabel ( )
titleLabel . textColor = Colors . text
titleLabel . font = . boldSystemFont ( ofSize : isSmallScreen ? Values . largeFontSize : Values . veryLargeFontSize )
titleLabel . text = NSLocalizedString ( " Your Session begins here... " , comment : " " )
titleLabel . numberOfLines = 0
titleLabel . lineBreakMode = . byWordWrapping
// S e t u p t i t l e l a b e l c o n t a i n e r
let titleLabelContainer = UIView ( )
titleLabelContainer . addSubview ( titleLabel )
titleLabel . pin ( . leading , to : . leading , of : titleLabelContainer , withInset : Values . veryLargeSpacing )
titleLabel . pin ( . top , to : . top , of : titleLabelContainer )
titleLabelContainer . pin ( . trailing , to : . trailing , of : titleLabel , withInset : Values . veryLargeSpacing )
titleLabelContainer . pin ( . bottom , to : . bottom , of : titleLabel )
// S e t u p s p a c e r s
let topSpacer = UIView . vStretchingSpacer ( )
let bottomSpacer = UIView . vStretchingSpacer ( )
// S e t u p l i n k b u t t o n c o n t a i n e r
let linkButtonContainer = UIView ( )
linkButtonContainer . set ( . height , to : Values . onboardingButtonBottomOffset )
linkButtonContainer . addSubview ( linkButton )
linkButton . pin ( . leading , to : . leading , of : linkButtonContainer , withInset : Values . massiveSpacing )
linkButton . pin ( . top , to : . top , of : linkButtonContainer )
linkButtonContainer . pin ( . trailing , to : . trailing , of : linkButton , withInset : Values . massiveSpacing )
linkButtonContainer . pin ( . bottom , to : . bottom , of : linkButton , withInset : isSmallScreen ? 6 : 10 )
// S e t u p b u t t o n s t a c k v i e w
let buttonStackView = UIStackView ( arrangedSubviews : [ registerButton , restoreButton ] )
buttonStackView . axis = . vertical
buttonStackView . spacing = isSmallScreen ? Values . smallSpacing : Values . mediumSpacing
buttonStackView . alignment = . fill
// S e t u p b u t t o n s t a c k v i e w c o n t a i n e r
let buttonStackViewContainer = UIView ( )
buttonStackViewContainer . addSubview ( buttonStackView )
buttonStackView . pin ( . leading , to : . leading , of : buttonStackViewContainer , withInset : Values . massiveSpacing )
buttonStackView . pin ( . top , to : . top , of : buttonStackViewContainer )
buttonStackViewContainer . pin ( . trailing , to : . trailing , of : buttonStackView , withInset : Values . massiveSpacing )
buttonStackViewContainer . pin ( . bottom , to : . bottom , of : buttonStackView )
// S e t u p m a i n s t a c k v i e w
let mainStackView = UIStackView ( arrangedSubviews : [ topSpacer , titleLabelContainer , UIView . spacer ( withHeight : isSmallScreen ? Values . smallSpacing : Values . mediumSpacing ) , fakeChatView , bottomSpacer , buttonStackViewContainer , linkButtonContainer ] )
mainStackView . axis = . vertical
mainStackView . alignment = . fill
view . addSubview ( mainStackView )
mainStackView . pin ( to : view )
topSpacer . heightAnchor . constraint ( equalTo : bottomSpacer . heightAnchor , multiplier : 1 ) . isActive = true
// S h o w d e v i c e u n l i n k e d a l e r t i f n e e d e d
if UserDefaults . standard [ . wasUnlinked ] {
let alert = UIAlertController ( title : NSLocalizedString ( " Device Unlinked " , comment : " " ) , message : NSLocalizedString ( " Your device was unlinked successfully " , comment : " " ) , preferredStyle : . alert )
alert . addAction ( UIAlertAction ( title : NSLocalizedString ( " OK " , comment : " " ) , accessibilityIdentifier : nil , style : . default , handler : nil ) )
present ( alert , animated : true , completion : nil )
UserDefaults . removeAll ( )
}
}
override func viewDidDisappear ( _ animated : Bool ) {
super . viewDidAppear ( animated )
if let fakeChatViewContentOffset = fakeChatViewContentOffset {
fakeChatView . contentOffset = fakeChatViewContentOffset
}
}
// MARK: I n t e r a c t i o n
@objc private func register ( ) {
fakeChatViewContentOffset = fakeChatView . contentOffset
DispatchQueue . main . async {
self . fakeChatView . contentOffset = self . fakeChatViewContentOffset
}
let registerVC = RegisterVC ( )
navigationController ! . pushViewController ( registerVC , animated : true )
}
@objc private func restore ( ) {
fakeChatViewContentOffset = fakeChatView . contentOffset
DispatchQueue . main . async {
self . fakeChatView . contentOffset = self . fakeChatViewContentOffset
}
let restoreVC = RestoreVC ( )
navigationController ! . pushViewController ( restoreVC , animated : true )
}
@objc private func linkDevice ( ) {
let linkDeviceVC = LinkDeviceVC ( )
linkDeviceVC . delegate = self
let navigationController = OWSNavigationController ( rootViewController : linkDeviceVC )
present ( navigationController , animated : true , completion : nil )
}
// MARK: D e v i c e L i n k i n g
func requestDeviceLink ( with hexEncodedPublicKey : String ) {
guard ECKeyPair . isValidHexEncodedPublicKey ( candidate : hexEncodedPublicKey ) else {
let alert = UIAlertController ( title : NSLocalizedString ( " Invalid Session ID " , comment : " " ) , message : NSLocalizedString ( " Please make sure the Session ID you entered is correct and try again. " , comment : " " ) , preferredStyle : . alert )
alert . addAction ( UIAlertAction ( title : NSLocalizedString ( " OK " , comment : " " ) , accessibilityIdentifier : nil , style : . default , handler : nil ) )
return present ( alert , animated : true , completion : nil )
}
let seed = Randomness . generateRandomBytes ( 16 ) !
let keyPair = Curve25519 . generateKeyPair ( fromSeed : seed + seed )
let identityManager = OWSIdentityManager . shared ( )
let databaseConnection = identityManager . value ( forKey : " dbConnection " ) as ! YapDatabaseConnection
databaseConnection . setObject ( seed . toHexString ( ) , forKey : " LKLokiSeed " , inCollection : OWSPrimaryStorageIdentityKeyStoreCollection )
databaseConnection . setObject ( keyPair , forKey : OWSPrimaryStorageIdentityKeyStoreIdentityKey , inCollection : OWSPrimaryStorageIdentityKeyStoreCollection )
TSAccountManager . sharedInstance ( ) . phoneNumberAwaitingVerification = keyPair . hexEncodedPublicKey
TSAccountManager . sharedInstance ( ) . didRegister ( )
let appDelegate = UIApplication . shared . delegate as ! AppDelegate
appDelegate . startPollerIfNeeded ( )
let deviceLinkingModal = DeviceLinkingModal ( mode : . slave , delegate : self )
deviceLinkingModal . modalPresentationStyle = . overFullScreen
deviceLinkingModal . modalTransitionStyle = . crossDissolve
self . present ( deviceLinkingModal , animated : true , completion : nil )
let linkingRequestMessage = DeviceLinkingUtilities . getLinkingRequestMessage ( for : hexEncodedPublicKey )
ThreadUtil . enqueue ( linkingRequestMessage )
}
func handleDeviceLinkAuthorized ( _ deviceLink : DeviceLink ) {
UserDefaults . standard [ . masterHexEncodedPublicKey ] = deviceLink . master . hexEncodedPublicKey
fakeChatViewContentOffset = fakeChatView . contentOffset
DispatchQueue . main . async {
self . fakeChatView . contentOffset = self . fakeChatViewContentOffset
}
let homeVC = HomeVC ( )
navigationController ! . setViewControllers ( [ homeVC ] , animated : true )
}
func handleDeviceLinkingModalDismissed ( ) {
let appDelegate = UIApplication . shared . delegate as ! AppDelegate
appDelegate . stopPollerIfNeeded ( )
TSAccountManager . sharedInstance ( ) . resetForReregistration ( )
}
// MARK: C o n v e n i e n c e
private func setUserInteractionEnabled ( _ isEnabled : Bool ) {
[ registerButton , restoreButton , linkButton ] . forEach {
$0 . isUserInteractionEnabled = isEnabled
}
}
}