Swiftgram/Display/Window.swift
2016-03-28 17:13:25 +03:00

188 lines
6.9 KiB
Swift

import Foundation
import AsyncDisplayKit
public class WindowRootViewController: UIViewController {
public override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .Default
}
public override func prefersStatusBarHidden() -> Bool {
return false
}
}
public struct ViewControllerLayout: Equatable {
public let size: CGSize
public let insets: UIEdgeInsets
public let inputViewHeight: CGFloat
public let statusBarHeight: CGFloat
}
public protocol WindowContentController {
func setParentLayout(layout: ViewControllerLayout, duration: NSTimeInterval, curve: UInt)
var view: UIView! { get }
}
public func animateRotation(view: UIView?, toFrame: CGRect, duration: NSTimeInterval) {
if let view = view {
UIView.animateWithDuration(duration, animations: { () -> Void in
view.frame = toFrame
})
}
}
public func animateRotation(view: ASDisplayNode?, toFrame: CGRect, duration: NSTimeInterval) {
if let view = view {
CALayer.beginRecordingChanges()
UIView.animateWithDuration(duration, animations: { () -> Void in
view.frame = toFrame
})
view.layout()
let states = CALayer.endRecordingChanges() as! [CALayerAnimation]
let k = Float(UIView.animationDurationFactor())
var speed: Float = 1.0
if k != 0 && k != 1 {
speed = Float(1.0) / k
}
for state in states {
if let layer = state.layer {
if !CGRectEqualToRect(state.startBounds, state.endBounds) {
let boundsAnimation = CABasicAnimation(keyPath: "bounds")
boundsAnimation.fromValue = NSValue(CGRect: state.startBounds)
boundsAnimation.toValue = NSValue(CGRect: state.endBounds)
boundsAnimation.duration = duration
boundsAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
boundsAnimation.removedOnCompletion = true
boundsAnimation.fillMode = kCAFillModeForwards
boundsAnimation.speed = speed
layer.addAnimation(boundsAnimation, forKey: "_rotationBounds")
}
if !CGPointEqualToPoint(state.startPosition, state.endPosition) {
let positionAnimation = CABasicAnimation(keyPath: "position")
positionAnimation.fromValue = NSValue(CGPoint: state.startPosition)
positionAnimation.toValue = NSValue(CGPoint: state.endPosition)
positionAnimation.duration = duration
positionAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
positionAnimation.removedOnCompletion = true
positionAnimation.fillMode = kCAFillModeForwards
positionAnimation.speed = speed
layer.addAnimation(positionAnimation, forKey: "_rotationPosition")
}
}
}
}
}
public class Window: UIWindow {
private let statusBarManager: StatusBarManager
private var updateViewSizeOnLayout: (Bool, NSTimeInterval) = (false, 0.0)
public var isUpdatingOrientationLayout = false
private let orientationChangeDuration: NSTimeInterval = {
UIDevice.currentDevice().userInterfaceIdiom == .Pad ? 0.4 : 0.3
}()
public convenience init() {
self.init(frame: UIScreen.mainScreen().bounds)
}
public override init(frame: CGRect) {
self.statusBarManager = StatusBarManager()
super.init(frame: frame)
super.rootViewController = WindowRootViewController()
}
public required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
return self.viewController?.view.hitTest(point, withEvent: event)
}
public override var frame: CGRect {
get {
return super.frame
}
set(value) {
let sizeUpdated = super.frame.size != value.size
super.frame = value
if sizeUpdated {
self.updateViewSizeOnLayout = (true, self.isRotating() ? self.orientationChangeDuration : 0.0)
self.setNeedsLayout()
}
}
}
public override var bounds: CGRect {
get {
return super.frame
}
set(value) {
let sizeUpdated = super.bounds.size != value.size
super.bounds = value
if sizeUpdated {
self.updateViewSizeOnLayout = (true, self.isRotating() ? self.orientationChangeDuration : 0.0)
self.setNeedsLayout()
}
}
}
private var _rootViewController: WindowContentController?
public var viewController: WindowContentController? {
get {
return _rootViewController
}
set(value) {
self._rootViewController?.view.removeFromSuperview()
self._rootViewController = value
self._rootViewController?.view.frame = self.bounds
self._rootViewController?.setParentLayout(ViewControllerLayout(size: self.bounds.size, insets: UIEdgeInsets(), inputViewHeight: 0.0, statusBarHeight: 0.0), duration: 0.0, curve: 0)
if let view = self._rootViewController?.view {
self.addSubview(view)
}
self.updateStatusBars()
}
}
override public func layoutSubviews() {
super.layoutSubviews()
if self.updateViewSizeOnLayout.0 {
self.updateViewSizeOnLayout.0 = false
self._rootViewController?.setParentLayout(ViewControllerLayout(size: self.bounds.size, insets: UIEdgeInsets(), inputViewHeight: 0.0, statusBarHeight: 0.0), duration: updateViewSizeOnLayout.1, curve: 0)
}
}
var postUpdateToInterfaceOrientationBlocks: [Void -> Void] = []
override public func _updateToInterfaceOrientation(arg1: Int32, duration arg2: Double, force arg3: Bool) {
self.isUpdatingOrientationLayout = true
super._updateToInterfaceOrientation(arg1, duration: arg2, force: arg3)
self.isUpdatingOrientationLayout = false
let blocks = self.postUpdateToInterfaceOrientationBlocks
self.postUpdateToInterfaceOrientationBlocks = []
for f in blocks {
f()
}
}
public func addPostUpdateToInterfaceOrientationBlock(f: Void -> Void) {
postUpdateToInterfaceOrientationBlocks.append(f)
}
func updateStatusBars() {
self.statusBarManager.surfaces = (self._rootViewController as? StatusBarSurfaceProvider)?.statusBarSurfaces() ?? []
}
}