255 lines
10 KiB
Swift
255 lines
10 KiB
Swift
//
|
|
// 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<Bool>()
|
|
|
|
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
|
|
}
|
|
}
|