// // LaunchScreenIPAD.swift // PrivadoVPN // // Created by Lizaveta Malinouskaya on 6/22/21. // Copyright © 2021 Privado LLC. All rights reserved. // import Foundation import UIKit final class LaunchScreenControllerIPAD: UIViewController, UITextViewDelegate { private enum Constants { enum Color { static let backGradientTop = Colors.SystemBackgrounds.GradientActive.top.color static let backGradientBottom = Colors.SystemBackgrounds.GradientActive.bottom.color static let title = Colors.basicText.color static let createButtonBackground = Colors.Button.background.color static let createButtonText = Colors.Button.text.color static let loginButtonText = Colors.Button.text.color static let errorText = Colors.TextField.error.color static let scrollBarColor = Colors.Base.primaryLightGrey.color } enum Geometry { enum Shared { static let buttonTop: CGFloat = 50 static let labelBottom: CGFloat = 50 static let labelHeight: CGFloat = 30 static let labelWidth: CGFloat = 340 static let buttonHeight: CGFloat = 50 static let buttonWidth: CGFloat = 344 static let scrollViewHeight: CGFloat = 537 } enum Portrait { static let scrollViewInset: CGFloat = (UIScreen.main.bounds.width - 586) / 2 } enum Landscape { static let scrollViewInset: CGFloat = (UIScreen.main.bounds.width - 670) / 2 } } enum LocalizedString { static let button = "launch.button" static let content = "launch.content" static let label = "launch.top" } enum Font { static let title = UIFont.primary(size: 27, weight: .semibold) static let button = UIFont.primary(size: 16, weight: .bold) static let content = UIFont.primary(size: 19, weight: .semibold) } } private let output: LaunchScreenControllerOutput private var compactConstraints = [NSLayoutConstraint]() private var regularConstraints = [NSLayoutConstraint]() private var sharedConstraints = [NSLayoutConstraint]() private let isLandscapeModeEmitter = Emitter() private var textView: UITextView? // MARK: - Init init(output: LaunchScreenControllerOutput) { self.output = output super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Lyfecycle override func loadView() { let view = UIView(frame: .zero) view.autoresizesSubviews = true view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .black self.view = view } override func viewDidLoad() { super.viewDidLoad() self.configureUI() self.isLandscapeModeEmitter.addReaction { [weak self] isLandscape -> ShouldContinueReceiveNotifications in self?.activateLayoutFor(landscape: isLandscape) return self.isExist } self.output.viewIsReady() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if let superview = self.view.superview { NSLayoutConstraint.activate([ self.view.topAnchor.constraint(equalTo: superview.topAnchor), self.view.leadingAnchor.constraint(equalTo: superview.leadingAnchor), self.view.trailingAnchor.constraint(equalTo: superview.trailingAnchor), self.view.bottomAnchor.constraint(equalTo: superview.bottomAnchor) ]) } } override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent // .default } // MARK: - UI private func configureUI() { self.view.translatesAutoresizingMaskIntoConstraints = false let gradientView = self.initializeBackgroundGradient(using: self.view) let circleLeft = self.initializeFadedCircles(using: self.view) let circleRight = self.initializeFadedCircles(using: self.view) let logoTitle = self.initializeTitleLabel(using: self.view) let agreeButton = self.initializeAgreeButton(using: self.view) let scrollView = self.initializeScrollView(using: self) // MARK: - Shared constraints self.sharedConstraints = [ // Circles circleLeft.centerXAnchor.constraint(equalTo: self.view.leadingAnchor), circleRight.centerXAnchor.constraint(equalTo: self.view.trailingAnchor), circleRight.centerYAnchor.constraint(equalTo: self.view.bottomAnchor), // Gradient view gradientView.topAnchor.constraint(equalTo: self.view.topAnchor), gradientView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), gradientView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), gradientView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), // Logo title logoTitle.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), logoTitle.widthAnchor.constraint(equalToConstant: Constants.Geometry.Shared.labelWidth), logoTitle.heightAnchor.constraint(equalToConstant: Constants.Geometry.Shared.labelHeight), logoTitle.bottomAnchor.constraint(equalTo: scrollView.topAnchor, constant: -Constants.Geometry.Shared.labelBottom), // Scroll view scrollView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), scrollView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor), scrollView.heightAnchor.constraint(equalToConstant: Constants.Geometry.Shared.scrollViewHeight), // Create button agreeButton.topAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: Constants.Geometry.Shared.buttonTop), agreeButton.heightAnchor.constraint(equalToConstant: Constants.Geometry.Shared.buttonHeight), agreeButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), agreeButton.widthAnchor.constraint(equalToConstant: Constants.Geometry.Shared.buttonWidth) ] // MARK: - Portrait constraints self.compactConstraints = [ // Scroll view scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: Constants.Geometry.Portrait.scrollViewInset), scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -Constants.Geometry.Portrait.scrollViewInset) ] // MARK: - Landscape constraints self.regularConstraints = [ // Scroll view scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: Constants.Geometry.Landscape.scrollViewInset), scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -Constants.Geometry.Landscape.scrollViewInset) ] let landscape = DeviceInfoProvider.isLandscapeOrienation && self.traitCollection.horizontalSizeClass == .regular self.activateLayoutFor(landscape: landscape) } private func activateLayoutFor(landscape: Bool) { if landscape { NSLayoutConstraint.deactivate(self.compactConstraints) NSLayoutConstraint.activate(self.regularConstraints) } else { NSLayoutConstraint.deactivate(self.regularConstraints) NSLayoutConstraint.activate(self.compactConstraints) } NSLayoutConstraint.activate(self.sharedConstraints) } private func initializeBackgroundGradient(using container: UIView) -> UIView { let gradientView = GradientView() gradientView.translatesAutoresizingMaskIntoConstraints = false gradientView.horizontalMode = false gradientView.stops = [ .init(color: Constants.Color.backGradientTop, location: 0), .init(color: Constants.Color.backGradientBottom, location: 1) ] container.addSubview(gradientView) return gradientView } private func initializeTitleLabel(using container: UIView) -> UILabel { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.text = NSLocalizedString(Constants.LocalizedString.label, comment: "Fast and Secure VPN You Can Trust") label.font = Constants.Font.title label.textColor = Constants.Color.title label.numberOfLines = 0 label.textAlignment = .center container.addSubview(label) return label } private func initializeAgreeButton(using container: UIView) -> UIButton { let button = UIButton(frame: .zero) button.translatesAutoresizingMaskIntoConstraints = false button.layer.cornerRadius = Constants.Geometry.Shared.buttonHeight / 2 button.clipsToBounds = true button.backgroundColor = Constants.Color.createButtonBackground button.setTitleColor(Constants.Color.createButtonText, for: .normal) button.titleLabel?.font = Constants.Font.button button.setTitle(NSLocalizedString(Constants.LocalizedString.button, comment: "Agree & Continue"), for: .normal) button.addTarget(self, action: #selector(self.buttonClick), for: .touchUpInside) container.addSubview(button) return button } private func initializeFadedCircles(using container: UIView) -> UIView { let circles = BackgroundCircles() circles.translatesAutoresizingMaskIntoConstraints = false container.addSubview(circles) return circles } private func initializeScrollView(using container: (UIViewController & UITextViewDelegate)) -> UITextView { let view = LaunchScreenScrollView() view.delegate = container container.view.addSubview(view) return view } @objc func buttonClick() { self.output.agreeClick() } // MARK: Scroll view delegate func scrollViewDidScroll(_ scrollView: UIScrollView) { guard let verticalIndicator = (scrollView.subviews[safe: (scrollView.subviews.count - 1)]?.subviews[safe: 0]) else { return } verticalIndicator.backgroundColor = Constants.Color.scrollBarColor } }