mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-03 22:38:41 +09:00
437 lines
22 KiB
Swift
437 lines
22 KiB
Swift
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|||
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|||
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|||
|
|
|
|||
|
|
import UIKit
|
|||
|
|
import SnapKit
|
|||
|
|
|
|||
|
|
struct IntroViewControllerUX {
|
|||
|
|
static let Width = 375
|
|||
|
|
static let Height = 667
|
|||
|
|
static let SyncButtonTopPadding = 5
|
|||
|
|
static let MinimumFontScale: CGFloat = 0.5
|
|||
|
|
|
|||
|
|
static let CardSlides = ["tour-Welcome", "tour-Search", "tour-Private", "tour-Mail", "tour-Sync"]
|
|||
|
|
static let NumberOfCards = CardSlides.count
|
|||
|
|
|
|||
|
|
static let PagerCenterOffsetFromScrollViewBottom = UIScreen.main.bounds.width <= 320 ? 20 : 30
|
|||
|
|
|
|||
|
|
static let StartBrowsingButtonTitle = NSLocalizedString("Start Browsing", tableName: "Intro", comment: "See http://mzl.la/1T8gxwo")
|
|||
|
|
static let StartBrowsingButtonColor = UIColor(rgb: 0x4990E2)
|
|||
|
|
static let StartBrowsingButtonHeight = 56
|
|||
|
|
static let SignInButtonTitle = NSLocalizedString("Sign in to Firefox", tableName: "Intro", comment: "See http://mzl.la/1T8gxwo")
|
|||
|
|
static let SignInButtonColor = UIColor(rgb: 0x45A1FF)
|
|||
|
|
static let SignInButtonHeight = 60
|
|||
|
|
static let SignInButtonWidth = 290
|
|||
|
|
|
|||
|
|
static let CardTextLineHeight = UIScreen.main.bounds.width <= 320 ? CGFloat(2) : CGFloat(6)
|
|||
|
|
static let CardTextWidth = UIScreen.main.bounds.width <= 320 ? 240 : 280
|
|||
|
|
static let CardTitleHeight = 50
|
|||
|
|
|
|||
|
|
static let CardTitleWelcome = NSLocalizedString("Intro.Slides.Welcome.Title", tableName: "Intro", value: "Thanks for choosing Firefox!", comment: "Title for the first panel 'Welcome' in the First Run tour.")
|
|||
|
|
static let CardTitleSearch = NSLocalizedString("Intro.Slides.Search.Title", tableName: "Intro", value: "Your search, your way", comment: "Title for the second panel 'Search' in the First Run tour.")
|
|||
|
|
static let CardTitlePrivate = NSLocalizedString("Intro.Slides.Private.Title", tableName: "Intro", value: "Browse like no one’s watching", comment: "Title for the third panel 'Private Browsing' in the First Run tour.")
|
|||
|
|
static let CardTitleMail = NSLocalizedString("Intro.Slides.Mail.Title", tableName: "Intro", value: "You’ve got mail… options", comment: "Title for the fourth panel 'Mail' in the First Run tour.")
|
|||
|
|
static let CardTitleSync = NSLocalizedString("Intro.Slides.Sync.Title", tableName: "Intro", value: "Pick up where you left off", comment: "Title for the fifth panel 'Sync' in the First Run tour.")
|
|||
|
|
|
|||
|
|
static let CardTextWelcome = NSLocalizedString("Intro.Slides.Welcome.Description", tableName: "Intro", value: "A modern mobile browser from Mozilla, the non-profit committed to a free and open web.", comment: "Description for the 'Welcome' panel in the First Run tour.")
|
|||
|
|
static let CardTextSearch = NSLocalizedString("Intro.Slides.Search.Description", tableName: "Intro", value: "Searching for something different? Choose another default search engine (or add your own) in Settings.", comment: "Description for the 'Favorite Search Engine' panel in the First Run tour.")
|
|||
|
|
static let CardTextPrivate = NSLocalizedString("Intro.Slides.Private.Description", tableName: "Intro", value: "Tap the mask icon to slip into Private Browsing mode.", comment: "Description for the 'Private Browsing' panel in the First Run tour.")
|
|||
|
|
static let CardTextMail = NSLocalizedString("Intro.Slides.Mail.Description", tableName: "Intro", value: "Use any email app — not just Mail — with Firefox.", comment: "Description for the 'Mail' panel in the First Run tour.")
|
|||
|
|
static let CardTextSync = NSLocalizedString("Intro.Slides.Sync.Description", tableName: "Intro", value: "Use Sync to find the bookmarks, passwords, and other things you save to Firefox on all your devices.", comment: "Description for the 'Sync' panel in the First Run tour.")
|
|||
|
|
|
|||
|
|
static let FadeDuration = 0.25
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let IntroViewControllerSeenProfileKey = "IntroViewControllerSeen"
|
|||
|
|
|
|||
|
|
protocol IntroViewControllerDelegate: class {
|
|||
|
|
func introViewControllerDidFinish(_ introViewController: IntroViewController, requestToLogin: Bool)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class IntroViewController: UIViewController, UIScrollViewDelegate {
|
|||
|
|
weak var delegate: IntroViewControllerDelegate?
|
|||
|
|
|
|||
|
|
var slides = [UIImage]()
|
|||
|
|
var cards = [UIImageView]()
|
|||
|
|
var introViews = [UIView]()
|
|||
|
|
var titleLabels = [UILabel]()
|
|||
|
|
var textLabels = [UILabel]()
|
|||
|
|
|
|||
|
|
var startBrowsingButton: UIButton!
|
|||
|
|
var introView: UIView?
|
|||
|
|
var slideContainer: UIView!
|
|||
|
|
var pageControl: UIPageControl!
|
|||
|
|
var backButton: UIButton!
|
|||
|
|
var forwardButton: UIButton!
|
|||
|
|
var signInButton: UIButton!
|
|||
|
|
|
|||
|
|
fileprivate var scrollView: IntroOverlayScrollView!
|
|||
|
|
|
|||
|
|
var slideVerticalScaleFactor: CGFloat = 1.0
|
|||
|
|
|
|||
|
|
override func viewDidLoad() {
|
|||
|
|
view.backgroundColor = UIColor.white
|
|||
|
|
|
|||
|
|
// scale the slides down for iPhone 4S
|
|||
|
|
if view.frame.height <= 480 {
|
|||
|
|
slideVerticalScaleFactor = 1.33
|
|||
|
|
slideVerticalScaleFactor = 1.33 //4S
|
|||
|
|
} else if view.frame.height <= 568 {
|
|||
|
|
slideVerticalScaleFactor = 1.15 //SE
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for slideName in IntroViewControllerUX.CardSlides {
|
|||
|
|
slides.append(UIImage(named: slideName)!)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
startBrowsingButton = UIButton()
|
|||
|
|
startBrowsingButton.backgroundColor = UIColor.clear
|
|||
|
|
startBrowsingButton.setTitle(IntroViewControllerUX.StartBrowsingButtonTitle, for: UIControlState())
|
|||
|
|
startBrowsingButton.setTitleColor(IntroViewControllerUX.StartBrowsingButtonColor, for: UIControlState())
|
|||
|
|
startBrowsingButton.addTarget(self, action: #selector(IntroViewController.SELstartBrowsing), for: UIControlEvents.touchUpInside)
|
|||
|
|
startBrowsingButton.accessibilityIdentifier = "IntroViewController.startBrowsingButton"
|
|||
|
|
|
|||
|
|
view.addSubview(startBrowsingButton)
|
|||
|
|
startBrowsingButton.snp.makeConstraints { (make) -> Void in
|
|||
|
|
if #available(iOS 11.0, *) {
|
|||
|
|
make.left.right.bottom.equalTo(self.view.safeAreaLayoutGuide)
|
|||
|
|
} else {
|
|||
|
|
make.left.right.bottom.equalTo(self.view)
|
|||
|
|
}
|
|||
|
|
make.height.equalTo(IntroViewControllerUX.StartBrowsingButtonHeight)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
scrollView = IntroOverlayScrollView()
|
|||
|
|
scrollView.backgroundColor = UIColor.clear
|
|||
|
|
scrollView.accessibilityLabel = NSLocalizedString("Intro Tour Carousel", comment: "Accessibility label for the introduction tour carousel")
|
|||
|
|
scrollView.delegate = self
|
|||
|
|
scrollView.bounces = false
|
|||
|
|
scrollView.isPagingEnabled = true
|
|||
|
|
scrollView.showsHorizontalScrollIndicator = false
|
|||
|
|
scrollView.contentSize = CGSize(width: scaledWidthOfSlide * CGFloat(IntroViewControllerUX.NumberOfCards), height: scaledHeightOfSlide)
|
|||
|
|
scrollView.accessibilityIdentifier = "IntroViewController.scrollView"
|
|||
|
|
view.addSubview(scrollView)
|
|||
|
|
|
|||
|
|
slideContainer = UIView()
|
|||
|
|
for i in 0..<IntroViewControllerUX.NumberOfCards {
|
|||
|
|
let imageView = UIImageView(frame: CGRect(x: CGFloat(i)*scaledWidthOfSlide, y: 0, width: scaledWidthOfSlide, height: scaledHeightOfSlide))
|
|||
|
|
imageView.image = slides[i]
|
|||
|
|
slideContainer.addSubview(imageView)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
scrollView.addSubview(slideContainer)
|
|||
|
|
scrollView.snp.makeConstraints { (make) -> Void in
|
|||
|
|
make.left.right.top.equalTo(self.view)
|
|||
|
|
make.bottom.equalTo(startBrowsingButton.snp.top)
|
|||
|
|
}
|
|||
|
|
self.view.layoutIfNeeded()
|
|||
|
|
self.scrollView.layoutIfNeeded()
|
|||
|
|
|
|||
|
|
pageControl = UIPageControl()
|
|||
|
|
pageControl.pageIndicatorTintColor = UIColor.black.withAlphaComponent(0.3)
|
|||
|
|
pageControl.currentPageIndicatorTintColor = UIColor.black
|
|||
|
|
pageControl.numberOfPages = IntroViewControllerUX.NumberOfCards
|
|||
|
|
pageControl.accessibilityIdentifier = "IntroViewController.pageControl"
|
|||
|
|
pageControl.addTarget(self, action: #selector(IntroViewController.changePage), for: UIControlEvents.valueChanged)
|
|||
|
|
|
|||
|
|
view.addSubview(pageControl)
|
|||
|
|
pageControl.snp.makeConstraints { (make) -> Void in
|
|||
|
|
make.centerX.equalTo(self.scrollView)
|
|||
|
|
make.centerY.equalTo(self.startBrowsingButton.snp.top).offset(-IntroViewControllerUX.PagerCenterOffsetFromScrollViewBottom)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func addCard(title: String, text: String, introView: UIView) {
|
|||
|
|
self.introViews.append(introView)
|
|||
|
|
|
|||
|
|
let titleLabel = UILabel()
|
|||
|
|
titleLabel.numberOfLines = 2
|
|||
|
|
titleLabel.adjustsFontSizeToFitWidth = true
|
|||
|
|
titleLabel.minimumScaleFactor = IntroViewControllerUX.MinimumFontScale
|
|||
|
|
titleLabel.textAlignment = NSTextAlignment.center
|
|||
|
|
titleLabel.text = title
|
|||
|
|
titleLabels.append(titleLabel)
|
|||
|
|
introView.addSubview(titleLabel)
|
|||
|
|
titleLabel.snp.makeConstraints { (make ) -> Void in
|
|||
|
|
make.top.equalTo(introView).offset(20)
|
|||
|
|
make.centerX.equalTo(introView)
|
|||
|
|
make.height.equalTo(IntroViewControllerUX.CardTitleHeight)
|
|||
|
|
make.width.equalTo(IntroViewControllerUX.CardTextWidth)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let textLabel = UILabel()
|
|||
|
|
textLabel.numberOfLines = 5
|
|||
|
|
textLabel.attributedText = attributedStringForLabel(text)
|
|||
|
|
textLabel.adjustsFontSizeToFitWidth = true
|
|||
|
|
textLabel.minimumScaleFactor = IntroViewControllerUX.MinimumFontScale
|
|||
|
|
textLabel.lineBreakMode = .byTruncatingTail
|
|||
|
|
textLabels.append(textLabel)
|
|||
|
|
introView.addSubview(textLabel)
|
|||
|
|
textLabel.snp.makeConstraints({ (make) -> Void in
|
|||
|
|
make.top.equalTo(titleLabel.snp.bottom).offset(20)
|
|||
|
|
make.centerX.equalTo(introView)
|
|||
|
|
make.width.equalTo(IntroViewControllerUX.CardTextWidth)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
addCard(title: IntroViewControllerUX.CardTitleWelcome, text: IntroViewControllerUX.CardTextWelcome, introView: UIView())
|
|||
|
|
addCard(title: IntroViewControllerUX.CardTitleSearch, text: IntroViewControllerUX.CardTextSearch, introView: UIView())
|
|||
|
|
addCard(title: IntroViewControllerUX.CardTitlePrivate, text: IntroViewControllerUX.CardTextPrivate, introView: UIView())
|
|||
|
|
addCard(title: IntroViewControllerUX.CardTitleMail, text: IntroViewControllerUX.CardTextMail, introView: UIView())
|
|||
|
|
|
|||
|
|
// Sync card, with sign in to sync button.
|
|||
|
|
signInButton = UIButton()
|
|||
|
|
signInButton.backgroundColor = IntroViewControllerUX.SignInButtonColor
|
|||
|
|
signInButton.setTitle(IntroViewControllerUX.SignInButtonTitle, for: UIControlState())
|
|||
|
|
signInButton.setTitleColor(UIColor.white, for: UIControlState())
|
|||
|
|
signInButton.clipsToBounds = true
|
|||
|
|
signInButton.addTarget(self, action: #selector(IntroViewController.SELlogin), for: UIControlEvents.touchUpInside)
|
|||
|
|
signInButton.snp.makeConstraints { (make) -> Void in
|
|||
|
|
make.height.equalTo(IntroViewControllerUX.SignInButtonHeight)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let syncCardView = UIView()
|
|||
|
|
// introViews.append(syncCardView)
|
|||
|
|
addCard(title: IntroViewControllerUX.CardTitleSync, text: IntroViewControllerUX.CardTextSync, introView: syncCardView)
|
|||
|
|
|
|||
|
|
syncCardView.addSubview(signInButton)
|
|||
|
|
syncCardView.bringSubview(toFront: signInButton)
|
|||
|
|
signInButton.snp.makeConstraints { (make) -> Void in
|
|||
|
|
make.centerX.equalTo(syncCardView)
|
|||
|
|
make.width.equalTo(IntroViewControllerUX.CardTextWidth) // TODO Talk to UX about small screen sizes
|
|||
|
|
make.bottom.equalTo(syncCardView)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// We need a reference to the sync pages textlabel so we can adjust the constraints
|
|||
|
|
if let index = introViews.index(of: syncCardView), index < textLabels.count {
|
|||
|
|
let syncTextLabel = textLabels[index]
|
|||
|
|
syncTextLabel.snp.makeConstraints { make in
|
|||
|
|
make.bottom.equalTo(signInButton.snp.top).offset(-IntroViewControllerUX.SyncButtonTopPadding)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// Add all the cards to the view, make them invisible with zero alpha
|
|||
|
|
for introView in introViews {
|
|||
|
|
introView.alpha = 0
|
|||
|
|
self.view.addSubview(introView)
|
|||
|
|
introView.snp.makeConstraints { (make) -> Void in
|
|||
|
|
make.top.equalTo(self.slideContainer.snp.bottom)
|
|||
|
|
make.bottom.equalTo(self.startBrowsingButton.snp.top)
|
|||
|
|
make.left.right.equalTo(self.view)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Make whole screen scrollable by bringing the scrollview to the top
|
|||
|
|
view.bringSubview(toFront: scrollView)
|
|||
|
|
view.sendSubview(toBack: pageControl)
|
|||
|
|
scrollView?.bringSubview(toFront: syncCardView)
|
|||
|
|
signInButton.superview?.bringSubview(toFront: signInButton)
|
|||
|
|
|
|||
|
|
// Activate the first card
|
|||
|
|
setActiveIntroView(introViews[0], forPage: 0)
|
|||
|
|
setupDynamicFonts()
|
|||
|
|
}
|
|||
|
|
override func viewWillAppear(_ animated: Bool) {
|
|||
|
|
super.viewWillAppear(animated)
|
|||
|
|
NotificationCenter.default.addObserver(self, selector: #selector(SELDynamicFontChanged(_:)), name: NotificationDynamicFontChanged, object: nil)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override func viewWillDisappear(_ animated: Bool) {
|
|||
|
|
super.viewWillDisappear(animated)
|
|||
|
|
NotificationCenter.default.removeObserver(self, name: NotificationDynamicFontChanged, object: nil)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func SELDynamicFontChanged(_ notification: Notification) {
|
|||
|
|
guard notification.name == NotificationDynamicFontChanged else { return }
|
|||
|
|
setupDynamicFonts()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override func viewDidLayoutSubviews() {
|
|||
|
|
super.viewDidLayoutSubviews()
|
|||
|
|
|
|||
|
|
scrollView.snp.remakeConstraints { (make) -> Void in
|
|||
|
|
make.left.right.top.equalTo(self.view)
|
|||
|
|
make.bottom.equalTo(self.startBrowsingButton.snp.top)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for i in 0..<IntroViewControllerUX.NumberOfCards {
|
|||
|
|
if let imageView = slideContainer.subviews[i] as? UIImageView {
|
|||
|
|
imageView.frame = CGRect(x: CGFloat(i)*scaledWidthOfSlide, y: 0, width: scaledWidthOfSlide, height: scaledHeightOfSlide)
|
|||
|
|
imageView.contentMode = UIViewContentMode.scaleAspectFit
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
slideContainer.frame = CGRect(x: 0, y: 0, width: scaledWidthOfSlide * CGFloat(IntroViewControllerUX.NumberOfCards), height: scaledHeightOfSlide)
|
|||
|
|
scrollView.contentSize = CGSize(width: slideContainer.frame.width, height: slideContainer.frame.height)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override var prefersStatusBarHidden: Bool {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override var shouldAutorotate: Bool {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
|||
|
|
// This actually does the right thing on iPad where the modally
|
|||
|
|
// presented version happily rotates with the iPad orientation.
|
|||
|
|
return UIInterfaceOrientationMask.portrait
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func SELstartBrowsing() {
|
|||
|
|
LeanPlumClient.shared.track(event: .dismissedOnboarding)
|
|||
|
|
delegate?.introViewControllerDidFinish(self, requestToLogin: false)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func SELback() {
|
|||
|
|
if introView == introViews[1] {
|
|||
|
|
setActiveIntroView(introViews[0], forPage: 0)
|
|||
|
|
scrollView.scrollRectToVisible(scrollView.subviews[0].frame, animated: true)
|
|||
|
|
pageControl.currentPage = 0
|
|||
|
|
} else if introView == introViews[2] {
|
|||
|
|
setActiveIntroView(introViews[1], forPage: 1)
|
|||
|
|
scrollView.scrollRectToVisible(scrollView.subviews[1].frame, animated: true)
|
|||
|
|
pageControl.currentPage = 1
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func SELforward() {
|
|||
|
|
if introView == introViews[0] {
|
|||
|
|
setActiveIntroView(introViews[1], forPage: 1)
|
|||
|
|
scrollView.scrollRectToVisible(scrollView.subviews[1].frame, animated: true)
|
|||
|
|
pageControl.currentPage = 1
|
|||
|
|
} else if introView == introViews[1] {
|
|||
|
|
setActiveIntroView(introViews[2], forPage: 2)
|
|||
|
|
scrollView.scrollRectToVisible(scrollView.subviews[2].frame, animated: true)
|
|||
|
|
pageControl.currentPage = 2
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func SELlogin() {
|
|||
|
|
delegate?.introViewControllerDidFinish(self, requestToLogin: true)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileprivate var accessibilityScrollStatus: String {
|
|||
|
|
let number = NSNumber(value: pageControl.currentPage + 1)
|
|||
|
|
return String(format: NSLocalizedString("Introductory slide %@ of %@", tableName: "Intro", comment: "String spoken by assistive technology (like VoiceOver) stating on which page of the intro wizard we currently are. E.g. Introductory slide 1 of 3"), NumberFormatter.localizedString(from: number, number: .decimal), NumberFormatter.localizedString(from: NSNumber(value: IntroViewControllerUX.NumberOfCards), number: .decimal))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func changePage() {
|
|||
|
|
let swipeCoordinate = CGFloat(pageControl.currentPage) * scrollView.frame.size.width
|
|||
|
|
scrollView.setContentOffset(CGPoint(x: swipeCoordinate, y: 0), animated: true)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
|||
|
|
// Need to add this method so that when forcibly dragging, instead of letting deceleration happen, should also calculate what card it's on.
|
|||
|
|
// This especially affects sliding to the last or first slides.
|
|||
|
|
if !decelerate {
|
|||
|
|
scrollViewDidEndDecelerating(scrollView)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
|||
|
|
// Need to add this method so that tapping the pageControl will also change the card texts.
|
|||
|
|
// scrollViewDidEndDecelerating waits until the end of the animation to calculate what card it's on.
|
|||
|
|
scrollViewDidEndDecelerating(scrollView)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
|||
|
|
let page = Int(scrollView.contentOffset.x / scrollView.frame.size.width)
|
|||
|
|
setActiveIntroView(introViews[page], forPage: page)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|||
|
|
let maximumHorizontalOffset = scrollView.frame.width
|
|||
|
|
let currentHorizontalOffset = scrollView.contentOffset.x
|
|||
|
|
|
|||
|
|
var percentageOfScroll = currentHorizontalOffset / maximumHorizontalOffset
|
|||
|
|
percentageOfScroll = percentageOfScroll > 1.0 ? 1.0 : percentageOfScroll
|
|||
|
|
let whiteComponent = UIColor.white.components
|
|||
|
|
let grayComponent = UIColor(rgb: 0xF2F2F2).components
|
|||
|
|
|
|||
|
|
let page = Int(scrollView.contentOffset.x / scrollView.frame.size.width)
|
|||
|
|
pageControl.currentPage = page
|
|||
|
|
|
|||
|
|
let newRed = (1.0 - percentageOfScroll) * whiteComponent.red + percentageOfScroll * grayComponent.red
|
|||
|
|
let newGreen = (1.0 - percentageOfScroll) * whiteComponent.green + percentageOfScroll * grayComponent.green
|
|||
|
|
let newBlue = (1.0 - percentageOfScroll) * whiteComponent.blue + percentageOfScroll * grayComponent.blue
|
|||
|
|
let newColor = UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: 1.0)
|
|||
|
|
slideContainer.backgroundColor = newColor
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileprivate func setActiveIntroView(_ newIntroView: UIView, forPage page: Int) {
|
|||
|
|
if introView != newIntroView {
|
|||
|
|
UIView.animate(withDuration: IntroViewControllerUX.FadeDuration, animations: { () -> Void in
|
|||
|
|
self.introView?.alpha = 0
|
|||
|
|
self.introView = newIntroView
|
|||
|
|
newIntroView.alpha = 1.0
|
|||
|
|
if page == 0 {
|
|||
|
|
self.startBrowsingButton.alpha = 0
|
|||
|
|
} else {
|
|||
|
|
self.startBrowsingButton.alpha = 1
|
|||
|
|
}
|
|||
|
|
}, completion: { _ in
|
|||
|
|
if page == (IntroViewControllerUX.NumberOfCards - 1) {
|
|||
|
|
self.scrollView.signinButton = self.signInButton
|
|||
|
|
} else {
|
|||
|
|
self.scrollView.signinButton = nil
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileprivate var scaledWidthOfSlide: CGFloat {
|
|||
|
|
return view.frame.width
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileprivate var scaledHeightOfSlide: CGFloat {
|
|||
|
|
return (view.frame.width / slides[0].size.width) * slides[0].size.height / slideVerticalScaleFactor
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileprivate func attributedStringForLabel(_ text: String) -> NSMutableAttributedString {
|
|||
|
|
let paragraphStyle = NSMutableParagraphStyle()
|
|||
|
|
paragraphStyle.lineSpacing = IntroViewControllerUX.CardTextLineHeight
|
|||
|
|
paragraphStyle.alignment = .center
|
|||
|
|
|
|||
|
|
let string = NSMutableAttributedString(string: text)
|
|||
|
|
string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: string.length))
|
|||
|
|
return string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileprivate func setupDynamicFonts() {
|
|||
|
|
startBrowsingButton.titleLabel?.font = UIFont(name: "FiraSans-Regular", size: DynamicFontHelper.defaultHelper.IntroStandardFontSize)
|
|||
|
|
signInButton.titleLabel?.font = UIFont(name: "FiraSans-Regular", size: DynamicFontHelper.defaultHelper.IntroBigFontSize)
|
|||
|
|
|
|||
|
|
for titleLabel in titleLabels {
|
|||
|
|
titleLabel.font = UIFont(name: "FiraSans-Medium", size: DynamicFontHelper.defaultHelper.IntroBigFontSize)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for label in textLabels {
|
|||
|
|
label.font = UIFont(name: "FiraSans-UltraLight", size: DynamicFontHelper.defaultHelper.IntroStandardFontSize)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileprivate class IntroOverlayScrollView: UIScrollView {
|
|||
|
|
weak var signinButton: UIButton?
|
|||
|
|
|
|||
|
|
fileprivate override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
|||
|
|
if let signinFrame = signinButton?.frame {
|
|||
|
|
let convertedFrame = convert(signinFrame, from: signinButton?.superview)
|
|||
|
|
if convertedFrame.contains(point) {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return CGRect(origin: self.frame.origin, size: CGSize(width: self.contentSize.width, height: self.frame.size.height)).contains(point)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
extension UIColor {
|
|||
|
|
var components:(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
|
|||
|
|
var r: CGFloat = 0
|
|||
|
|
var g: CGFloat = 0
|
|||
|
|
var b: CGFloat = 0
|
|||
|
|
var a: CGFloat = 0
|
|||
|
|
getRed(&r, green: &g, blue: &b, alpha: &a)
|
|||
|
|
return (r, g, b, a)
|
|||
|
|
}
|
|||
|
|
}
|