session-ios/Signal/src/Loki/View Controllers/RegisterVC.swift

183 lines
9.8 KiB
Swift

final class RegisterVC : UIViewController {
private var seed: Data! { didSet { updateKeyPair() } }
private var keyPair: ECKeyPair! { didSet { updatePublicKeyLabel() } }
// MARK: Components
private lazy var publicKeyLabel: UILabel = {
let result = UILabel()
result.textColor = Colors.text
result.font = Fonts.spaceMono(ofSize: Values.largeFontSize)
result.numberOfLines = 0
result.textAlignment = .center
result.lineBreakMode = .byCharWrapping
return result
}()
private lazy var copyPublicKeyButton: Button = {
let result = Button(style: .prominentOutline, size: .large)
result.setTitle(NSLocalizedString("Copy", comment: ""), for: UIControl.State.normal)
result.addTarget(self, action: #selector(copyPublicKey), for: UIControl.Event.touchUpInside)
return result
}()
private lazy var legalLabel: UILabel = {
let result = UILabel()
result.textColor = Colors.text
result.font = .systemFont(ofSize: Values.verySmallFontSize)
let text = "By using this service, you agree to our Terms and Conditions and Privacy Statement"
let attributedText = NSMutableAttributedString(string: text)
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms and Conditions"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Statement"))
result.attributedText = attributedText
result.numberOfLines = 0
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
return result
}()
// MARK: Settings
override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent }
// MARK: Lifecycle
override func viewDidLoad() {
// Set gradient background
view.backgroundColor = .clear
let gradient = Gradients.defaultLokiBackground
view.setGradient(gradient)
// Set up navigation bar
let navigationBar = navigationController!.navigationBar
navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationBar.shadowImage = UIImage()
navigationBar.isTranslucent = false
navigationBar.barTintColor = Colors.navigationBarBackground
// Set up logo image view
let logoImageView = UIImageView()
logoImageView.image = #imageLiteral(resourceName: "Session")
logoImageView.contentMode = .scaleAspectFit
logoImageView.set(.width, to: 32)
logoImageView.set(.height, to: 32)
navigationItem.titleView = logoImageView
// Set up title label
let titleLabel = UILabel()
titleLabel.textColor = Colors.text
titleLabel.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
titleLabel.text = NSLocalizedString("Say hello to your Session ID", 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("Your Session ID is the unique address that people can use to contact you on Session. With no connection to your real identity, your Session ID is totally anonymous and private by design.", comment: "")
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
// Set up public key label container
let publicKeyLabelContainer = UIView()
publicKeyLabelContainer.addSubview(publicKeyLabel)
publicKeyLabel.pin(to: publicKeyLabelContainer, withInset: Values.mediumSpacing)
publicKeyLabelContainer.layer.cornerRadius = Values.textFieldCornerRadius
publicKeyLabelContainer.layer.borderWidth = Values.borderThickness
publicKeyLabelContainer.layer.borderColor = Colors.text.cgColor
// Set up spacers
let topSpacer = UIView.vStretchingSpacer()
let bottomSpacer = UIView.vStretchingSpacer()
// Set up register button
let registerButton = Button(style: .prominentFilled, size: .large)
registerButton.setTitle(NSLocalizedString("Continue", comment: ""), for: UIControl.State.normal)
registerButton.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize)
registerButton.addTarget(self, action: #selector(register), for: UIControl.Event.touchUpInside)
// Set up button stack view
let buttonStackView = UIStackView(arrangedSubviews: [ registerButton, copyPublicKeyButton ])
buttonStackView.axis = .vertical
buttonStackView.spacing = Values.mediumSpacing
buttonStackView.alignment = .fill
// Set up button stack view container
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)
// Set up legal label
legalLabel.isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleLegalLabelTapped))
legalLabel.addGestureRecognizer(tapGestureRecognizer)
// Set up legal label container
let legalLabelContainer = UIView()
legalLabelContainer.set(.height, to: Values.onboardingButtonBottomOffset)
legalLabelContainer.addSubview(legalLabel)
legalLabel.pin(.leading, to: .leading, of: legalLabelContainer, withInset: Values.massiveSpacing)
legalLabel.pin(.top, to: .top, of: legalLabelContainer)
legalLabelContainer.pin(.trailing, to: .trailing, of: legalLabel, withInset: Values.massiveSpacing)
legalLabelContainer.pin(.bottom, to: .bottom, of: legalLabel, withInset: 10)
// Set up top stack view
let topStackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel, publicKeyLabelContainer ])
topStackView.axis = .vertical
topStackView.spacing = Values.veryLargeSpacing
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 main stack view
let mainStackView = UIStackView(arrangedSubviews: [ topSpacer, topStackViewContainer, bottomSpacer, buttonStackViewContainer, legalLabelContainer ])
mainStackView.axis = .vertical
mainStackView.alignment = .fill
view.addSubview(mainStackView)
mainStackView.pin(to: view)
topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true
// Peform initial seed update
updateSeed()
}
// MARK: General
@objc private func enableCopyButton() {
copyPublicKeyButton.isUserInteractionEnabled = true
UIView.transition(with: copyPublicKeyButton, duration: 0.25, options: .transitionCrossDissolve, animations: {
self.copyPublicKeyButton.setTitle(NSLocalizedString("Copy", comment: ""), for: UIControl.State.normal)
}, completion: nil)
}
// MARK: Updating
private func updateSeed() {
seed = Randomness.generateRandomBytes(16)
}
private func updateKeyPair() {
keyPair = Curve25519.generateKeyPair(fromSeed: seed + seed)
}
private func updatePublicKeyLabel() {
publicKeyLabel.text = keyPair.hexEncodedPublicKey
}
// MARK: Interaction
@objc private func register() {
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
let displayNameVC = DisplayNameVC()
navigationController!.pushViewController(displayNameVC, animated: true)
}
@objc private func copyPublicKey() {
UIPasteboard.general.string = keyPair.hexEncodedPublicKey
copyPublicKeyButton.isUserInteractionEnabled = false
UIView.transition(with: copyPublicKeyButton, duration: 0.25, options: .transitionCrossDissolve, animations: {
self.copyPublicKeyButton.setTitle(NSLocalizedString("Copied", comment: ""), for: UIControl.State.normal)
}, completion: nil)
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false)
}
@objc private func handleLegalLabelTapped(_ tapGestureRecognizer: UITapGestureRecognizer) {
let url = URL(string: "https://github.com/loki-project/loki-messenger-ios/blob/master/privacy-policy.md")!
UIApplication.shared.open(url)
}
}