Swiftgram/TelegramUI/GalleryControllerNode.swift
2016-08-23 16:21:34 +03:00

167 lines
7.3 KiB
Swift

import Foundation
import AsyncDisplayKit
import Display
class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate {
var statusBar: StatusBar?
var navigationBar: NavigationBar?
var transitionNodeForCentralItem: (() -> ASDisplayNode?)?
var dismiss: (() -> Void)?
var containerLayout: ContainerViewLayout?
var scrollView: UIScrollView
var pager: GalleryPagerNode
var areControlsHidden = false
override init() {
self.scrollView = UIScrollView()
self.pager = GalleryPagerNode()
super.init(viewBlock: {
return UITracingLayerView()
}, didLoad: nil)
self.pager.toggleControlsVisibility = { [weak self] in
if let strongSelf = self {
strongSelf.areControlsHidden = !strongSelf.areControlsHidden
UIView.animate(withDuration: 0.3, animations: {
let alpha: CGFloat = strongSelf.areControlsHidden ? 0.0 : 1.0
strongSelf.navigationBar?.alpha = alpha
strongSelf.statusBar?.alpha = alpha
})
}
}
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.alwaysBounceHorizontal = false
self.scrollView.alwaysBounceVertical = false
self.scrollView.clipsToBounds = false
self.scrollView.delegate = self
self.scrollView.scrollsToTop = false
self.view.addSubview(self.scrollView)
self.scrollView.addSubview(self.pager.view)
self.backgroundColor = UIColor.black
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
self.containerLayout = layout
let previousContentHeight = self.scrollView.contentSize.height
let previousVerticalOffset = self.scrollView.contentOffset.y
self.scrollView.frame = CGRect(origin: CGPoint(), size: layout.size)
self.scrollView.contentSize = CGSize(width: 0.0, height: layout.size.height * 3.0)
if previousContentHeight.isEqual(to: 0.0) {
self.scrollView.contentOffset = CGPoint(x: 0.0, y: self.scrollView.contentSize.height / 3.0)
} else {
self.scrollView.contentOffset = CGPoint(x: 0.0, y: previousVerticalOffset * self.scrollView.contentSize.height / previousContentHeight)
}
self.pager.frame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: layout.size)
self.pager.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
}
func animateIn(animateContent: Bool) {
self.backgroundColor = self.backgroundColor?.withAlphaComponent(0.0)
self.statusBar?.alpha = 0.0
self.navigationBar?.alpha = 0.0
UIView.animate(withDuration: 0.2, animations: {
self.backgroundColor = self.backgroundColor?.withAlphaComponent(1.0)
self.statusBar?.alpha = 1.0
self.navigationBar?.alpha = 1.0
})
if animateContent {
self.scrollView.layer.animateBounds(from: self.scrollView.layer.bounds.offsetBy(dx: 0.0, dy: -self.scrollView.layer.bounds.size.height), to: self.scrollView.layer.bounds, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring)
}
}
func animateOut(animateContent: Bool, completion: @escaping () -> Void) {
var contentAnimationCompleted = true
var interfaceAnimationCompleted = false
let intermediateCompletion = {
if contentAnimationCompleted && interfaceAnimationCompleted {
completion()
}
}
UIView.animate(withDuration: 0.25, animations: {
self.backgroundColor = self.backgroundColor?.withAlphaComponent(0.0)
self.statusBar?.alpha = 0.0
self.navigationBar?.alpha = 0.0
}, completion: { _ in
interfaceAnimationCompleted = true
intermediateCompletion()
})
if animateContent {
contentAnimationCompleted = false
self.scrollView.layer.animateBounds(from: self.scrollView.layer.bounds, to: self.scrollView.layer.bounds.offsetBy(dx: 0.0, dy: -self.scrollView.layer.bounds.size.height), duration: 0.25, timingFunction: kCAMediaTimingFunctionLinear, removeOnCompletion: false, completion: { _ in
contentAnimationCompleted = true
intermediateCompletion()
})
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0
let transition = 1.0 - min(1.0, max(0.0, abs(distanceFromEquilibrium) / 50.0))
let backgroundTransition = 1.0 - min(1.0, max(0.0, abs(distanceFromEquilibrium) / 80.0))
self.backgroundColor = self.backgroundColor?.withAlphaComponent(backgroundTransition)
if !self.areControlsHidden {
self.statusBar?.alpha = transition
self.navigationBar?.alpha = transition
}
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
targetContentOffset.pointee = scrollView.contentOffset
if abs(velocity.y) > 1.0 {
self.layer.animate(from: self.layer.backgroundColor!, to: UIColor(white: 0.0, alpha: 0.0).cgColor, keyPath: "backgroundColor", timingFunction: kCAMediaTimingFunctionLinear, duration: 0.2, removeOnCompletion: false)
var interfaceAnimationCompleted = false
var contentAnimationCompleted = true
let completion = { [weak self] in
if interfaceAnimationCompleted && contentAnimationCompleted {
if let dismiss = self?.dismiss {
dismiss()
}
}
}
if let centralItemNode = self.pager.centralItemNode(), let transitionNodeForCentralItem = self.transitionNodeForCentralItem, let node = transitionNodeForCentralItem() {
contentAnimationCompleted = false
centralItemNode.animateOut(to: node, completion: {
contentAnimationCompleted = true
completion()
})
}
self.animateOut(animateContent: false, completion: {
interfaceAnimationCompleted = true
completion()
})
if contentAnimationCompleted {
contentAnimationCompleted = false
self.scrollView.layer.animateBounds(from: self.scrollView.layer.bounds, to: self.scrollView.layer.bounds.offsetBy(dx: 0.0, dy: self.scrollView.layer.bounds.size.height * (velocity.y < 0.0 ? -1.0 : 1.0)), duration: 0.2, timingFunction: kCAMediaTimingFunctionLinear, removeOnCompletion: false, completion: { _ in
contentAnimationCompleted = true
completion()
})
}
} else {
self.scrollView.setContentOffset(CGPoint(x: 0.0, y: self.scrollView.contentSize.height / 3.0), animated: true)
}
}
}