diff --git a/Display.xcodeproj/project.pbxproj b/Display.xcodeproj/project.pbxproj index a1a3df240e..93f7294fe1 100644 --- a/Display.xcodeproj/project.pbxproj +++ b/Display.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + D02BDB021B6AC703008AFAD2 /* RuntimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02BDB011B6AC703008AFAD2 /* RuntimeUtils.swift */; }; D05CC2671B69316F00E235A3 /* Display.h in Headers */ = {isa = PBXBuildFile; fileRef = D05CC2661B69316F00E235A3 /* Display.h */; settings = {ATTRIBUTES = (Public, ); }; }; D05CC26E1B69316F00E235A3 /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D05CC2631B69316F00E235A3 /* Display.framework */; }; D05CC2731B69316F00E235A3 /* DisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2721B69316F00E235A3 /* DisplayTests.swift */; }; @@ -48,6 +49,10 @@ D05CC3251B695B0700E235A3 /* NavigationBarProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = D05CC3231B695B0700E235A3 /* NavigationBarProxy.m */; }; D05CC3271B69725400E235A3 /* NavigationBackArrowLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D05CC3261B69725400E235A3 /* NavigationBackArrowLight@2x.png */; }; D05CC3291B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC3281B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift */; }; + D05CC3651B69960300E235A3 /* AsyncDisplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D05CC3641B69960300E235A3 /* AsyncDisplayKit.framework */; }; + D06EE8451B7140FF00837186 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06EE8441B7140FF00837186 /* Font.swift */; }; + D07921A91B6FC0C0005C23D9 /* KeyboardHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */; }; + D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -61,6 +66,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + D02BDB011B6AC703008AFAD2 /* RuntimeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuntimeUtils.swift; sourceTree = ""; }; D05CC2631B69316F00E235A3 /* Display.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Display.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D05CC2661B69316F00E235A3 /* Display.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Display.h; sourceTree = ""; }; D05CC2681B69316F00E235A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -105,6 +111,10 @@ D05CC3231B695B0700E235A3 /* NavigationBarProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NavigationBarProxy.m; sourceTree = ""; }; D05CC3261B69725400E235A3 /* NavigationBackArrowLight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NavigationBackArrowLight@2x.png"; sourceTree = ""; }; D05CC3281B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractiveTransitionGestureRecognizer.swift; sourceTree = ""; }; + D05CC3641B69960300E235A3 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AsyncDisplayKit.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-gbpsmqzuwcmmxadrqcwyrluaftwp/Build/Products/Debug-iphoneos/AsyncDisplayKit.framework"; sourceTree = ""; }; + D06EE8441B7140FF00837186 /* Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = ""; }; + D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardHostWindow.swift; sourceTree = ""; }; + D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarHostWindow.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -112,6 +122,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D05CC3651B69960300E235A3 /* AsyncDisplayKit.framework in Frameworks */, D05CC29A1B69323B00E235A3 /* SwiftSignalKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -127,6 +138,13 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + D02BDAEC1B6A7053008AFAD2 /* Nodes */ = { + isa = PBXGroup; + children = ( + ); + name = Nodes; + sourceTree = ""; + }; D05CC2591B69316F00E235A3 = { isa = PBXGroup; children = ( @@ -150,7 +168,10 @@ isa = PBXGroup; children = ( D05CC3001B6955D500E235A3 /* Utils */, + D07921AA1B6FC911005C23D9 /* Status Bar */, + D07921A71B6FC0AE005C23D9 /* Keyboard */, D05CC3211B695AA600E235A3 /* Navigation */, + D02BDAEC1B6A7053008AFAD2 /* Nodes */, D05CC2A11B69326C00E235A3 /* Window.swift */, D05CC2E21B69552C00E235A3 /* ViewController.swift */, D05CC2E11B69534100E235A3 /* Supporting Files */, @@ -170,6 +191,7 @@ D05CC2A31B6932D500E235A3 /* Frameworks */ = { isa = PBXGroup; children = ( + D05CC3641B69960300E235A3 /* AsyncDisplayKit.framework */, D05CC2991B69323B00E235A3 /* SwiftSignalKit.framework */, ); name = Frameworks; @@ -212,6 +234,8 @@ D05CC3221B695B0700E235A3 /* NavigationBarProxy.h */, D05CC3231B695B0700E235A3 /* NavigationBarProxy.m */, D05CC2E41B69555800E235A3 /* CAAnimationUtils.swift */, + D02BDB011B6AC703008AFAD2 /* RuntimeUtils.swift */, + D06EE8441B7140FF00837186 /* Font.swift */, ); name = Utils; sourceTree = ""; @@ -233,6 +257,22 @@ name = Navigation; sourceTree = ""; }; + D07921A71B6FC0AE005C23D9 /* Keyboard */ = { + isa = PBXGroup; + children = ( + D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */, + ); + name = Keyboard; + sourceTree = ""; + }; + D07921AA1B6FC911005C23D9 /* Status Bar */ = { + isa = PBXGroup; + children = ( + D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.swift */, + ); + name = "Status Bar"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -354,11 +394,15 @@ buildActionMask = 2147483647; files = ( D05CC3181B695A9600E235A3 /* NavigationItemTransitionState.swift in Sources */, + D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */, D05CC2F81B6955D000E235A3 /* UIViewController+Navigation.m in Sources */, + D02BDB021B6AC703008AFAD2 /* RuntimeUtils.swift in Sources */, D05CC31F1B695A9600E235A3 /* NavigationControllerProxy.m in Sources */, D05CC3031B69568600E235A3 /* NotificationCenterUtils.m in Sources */, D05CC2E31B69552C00E235A3 /* ViewController.swift in Sources */, D05CC2A01B69326400E235A3 /* NavigationController.swift in Sources */, + D06EE8451B7140FF00837186 /* Font.swift in Sources */, + D07921A91B6FC0C0005C23D9 /* KeyboardHostWindow.swift in Sources */, D05CC3251B695B0700E235A3 /* NavigationBarProxy.m in Sources */, D05CC2F71B6955D000E235A3 /* UIKitUtils.swift in Sources */, D05CC3161B695A9600E235A3 /* NavigationBar.swift in Sources */, diff --git a/Display/BarButtonItemWrapper.swift b/Display/BarButtonItemWrapper.swift index fab8fa1752..f529094e29 100644 --- a/Display/BarButtonItemWrapper.swift +++ b/Display/BarButtonItemWrapper.swift @@ -24,7 +24,7 @@ internal class BarButtonItemWrapper { self.parentNode.addSubnode(self.buttonNode) self.setEnabledListenerKey = barButtonItem.addSetEnabledListener({ [weak self] enabled in - self?.buttonNode.enabled = enabled + self?.buttonNode.enabled = enabled.boolValue return }) diff --git a/Display/CAAnimationUtils.swift b/Display/CAAnimationUtils.swift index 6e5efec0fa..5c9b095749 100644 --- a/Display/CAAnimationUtils.swift +++ b/Display/CAAnimationUtils.swift @@ -1,7 +1,21 @@ import UIKit -extension CALayer { - internal func animate(from from: NSValue, to: NSValue, keyPath: String, timingFunction: String, duration: NSTimeInterval) { +@objc private class CALayerAnimationDelegate: NSObject { + let completion: Bool -> Void + + init(completion: Bool -> Void) { + self.completion = completion + + super.init() + } + + @objc override func animationDidStop(anim: CAAnimation, finished flag: Bool) { + self.completion(flag) + } +} + +public extension CALayer { + public func animate(from from: NSValue, to: NSValue, keyPath: String, timingFunction: String, duration: NSTimeInterval, completion: (Bool -> Void)? = nil) { let k = Float(UIView.animationDurationFactor()) var speed: Float = 1.0 if k != 0 && k != 1 { @@ -16,13 +30,16 @@ extension CALayer { animation.removedOnCompletion = true animation.fillMode = kCAFillModeForwards animation.speed = speed + if let completion = completion { + animation.delegate = CALayerAnimationDelegate(completion: completion) + } self.addAnimation(animation, forKey: keyPath) self.setValue(to, forKey: keyPath) } - internal func animateAlpha(from from: CGFloat, to: CGFloat, duration: NSTimeInterval) { + public func animateAlpha(from from: CGFloat, to: CGFloat, duration: NSTimeInterval) { self.animate(from: NSNumber(float: Float(from)), to: NSNumber(float: Float(to)), keyPath: "opacity", timingFunction: kCAMediaTimingFunctionEaseInEaseOut, duration: duration) } diff --git a/Display/Font.swift b/Display/Font.swift new file mode 100644 index 0000000000..e908fac5f8 --- /dev/null +++ b/Display/Font.swift @@ -0,0 +1,20 @@ +import Foundation +import UIKit + +public struct Font { + public static func regular(size: CGFloat) -> UIFont { + if matchMinimumSystemVersion(9) { + return UIFont(name: ".SFUIDisplay-Regular", size: size)! + } else { + return UIFont(name: "HelveticaNeue", size: size)! + } + } + + public static func medium(size: CGFloat) -> UIFont { + if matchMinimumSystemVersion(9) { + return UIFont(name: ".SFUIDisplay-Medium", size: size)! + } else { + return UIFont(name: "HelveticaNeue-Medium", size: size)! + } + } +} diff --git a/Display/InteractiveTransitionGestureRecognizer.swift b/Display/InteractiveTransitionGestureRecognizer.swift index 107d85bdf6..4526e27c41 100644 --- a/Display/InteractiveTransitionGestureRecognizer.swift +++ b/Display/InteractiveTransitionGestureRecognizer.swift @@ -28,11 +28,13 @@ class InteractiveTransitionGestureRecognizer: UIPanGestureRecognizer { let translation = CGPoint(x: location.x - firstLocation.x, y: location.y - firstLocation.y) if !validatedGesture { - if translation.x < 0.0 { + if self.firstLocation.x < 16.0 { + validatedGesture = true + } else if translation.x < 0.0 { self.state = .Failed - } else if abs(translation.y) >= 2.0 { + } else if abs(translation.y) > 2.0 && abs(translation.y) > abs(translation.x) * 2.0 { self.state = .Failed - } else if translation.x >= 3.0 && translation.x / 3.0 > translation.y { + } else if abs(translation.x) > 2.0 && abs(translation.y) * 2.0 < abs(translation.x) { validatedGesture = true } } diff --git a/Display/KeyboardHostWindow.swift b/Display/KeyboardHostWindow.swift new file mode 100644 index 0000000000..c6597c2a92 --- /dev/null +++ b/Display/KeyboardHostWindow.swift @@ -0,0 +1,28 @@ +import Foundation +import UIKit + +public class KeyboardHostWindow: UIWindow { + let textField: UITextField + + convenience public init() { + self.init(frame: CGRect()) + } + + override init(frame: CGRect) { + self.textField = UITextField(frame: CGRect(x: -110.0, y: 0.0, width: 100.0, height: 50.0)) + + super.init(frame: frame) + + self.windowLevel = 1000.0 + self.rootViewController = UIViewController() + self.addSubview(self.textField) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public func acquireFirstResponder() { + textField.becomeFirstResponder() + } +} diff --git a/Display/NavigationController.swift b/Display/NavigationController.swift index a8d88014ba..e6a852f8ba 100644 --- a/Display/NavigationController.swift +++ b/Display/NavigationController.swift @@ -1,19 +1,28 @@ import Foundation import UIKit import AsyncDisplayKit +import SwiftSignalKit public class NavigationController: NavigationControllerProxy, WindowContentController, UIGestureRecognizerDelegate { - private var _navigationBar: NavigationBar? + private var _navigationBar: NavigationBar! private var navigationTransitionCoordinator: NavigationTransitionCoordinator? + private var currentPushDisposable = MetaDisposable() + public override init() { + self._navigationBar = nil + super.init() + self._navigationBar = NavigationBar() - self._navigationBar?.frame = CGRect(x: 0.0, y: 0.0, width: 320.0, height: 44.0) - self._navigationBar?.proxy = self.navigationBar as? NavigationBarProxy - self._navigationBar?.backPressed = { [weak self] in - if self?.viewControllers.count > 1 { - self?.popViewControllerAnimated(true) + + self._navigationBar.frame = CGRect(x: 0.0, y: 0.0, width: 320.0, height: 44.0) + self._navigationBar.proxy = self.navigationBar as? NavigationBarProxy + self._navigationBar.backPressed = { [weak self] in + if let strongSelf = self { + if strongSelf.viewControllers.count > 1 { + strongSelf.popViewControllerAnimated(true) + } } return } @@ -30,12 +39,10 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr public override func loadView() { super.loadView() - if let _navigationBar = self._navigationBar { - self.navigationBar.superview?.insertSubview(_navigationBar.view, aboveSubview: self.navigationBar) - } + self.navigationBar.superview?.insertSubview(_navigationBar.view, aboveSubview: self.navigationBar) self.navigationBar.removeFromSuperview() - self._navigationBar?.frame = navigationBarFrame(self.view.frame.size) + self._navigationBar.frame = navigationBarFrame(self.view.frame.size) let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: Selector("panGesture:")) panRecognizer.delegate = self @@ -59,10 +66,10 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr bottomController.viewWillAppear(true) let bottomView = bottomController.view - let navigationTransitionCoordinator = NavigationTransitionCoordinator(container: self.view, topView: topView, bottomView: bottomView, navigationBar: self._navigationBar!) + let navigationTransitionCoordinator = NavigationTransitionCoordinator(container: self.view, topView: topView, bottomView: bottomView, navigationBar: self._navigationBar) self.navigationTransitionCoordinator = navigationTransitionCoordinator - self._navigationBar?.beginInteractivePopProgress(bottomController.navigationItem, evenMorePreviousItem: self.viewControllers.count >= 3 ? (self.viewControllers[self.viewControllers.count - 3] as UIViewController).navigationItem : nil) + self._navigationBar.beginInteractivePopProgress(bottomController.navigationItem, evenMorePreviousItem: self.viewControllers.count >= 3 ? (self.viewControllers[self.viewControllers.count - 3] as UIViewController).navigationItem : nil) } case UIGestureRecognizerState.Changed: if let navigationTransitionCoordinator = self.navigationTransitionCoordinator { @@ -77,7 +84,7 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr navigationTransitionCoordinator.animateCompletion(velocity, completion: { self.navigationTransitionCoordinator = nil - self._navigationBar?.endInteractivePopProgress() + self._navigationBar.endInteractivePopProgress() if self.viewControllers.count >= 2 && self.navigationTransitionCoordinator == nil { let topController = self.viewControllers[self.viewControllers.count - 1] as UIViewController @@ -106,7 +113,7 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr navigationTransitionCoordinator.animateCancel({ self.navigationTransitionCoordinator = nil - self._navigationBar?.endInteractivePopProgress() + self._navigationBar.endInteractivePopProgress() if self.viewControllers.count >= 2 && self.navigationTransitionCoordinator == nil { let topController = self.viewControllers[self.viewControllers.count - 1] as UIViewController @@ -145,7 +152,19 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr } } + public func pushViewController(signal: Signal) -> Disposable { + let disposable = (signal |> deliverOnMainQueue).start(next: {[weak self] controller in + if let strongSelf = self { + strongSelf.pushViewController(controller, animated: true) + } + }) + self.currentPushDisposable.set(disposable) + return disposable + } + public override func pushViewController(viewController: UIViewController, animated: Bool) { + self.currentPushDisposable.set(nil) + var controllers = self.viewControllers controllers.append(viewController) self.setViewControllers(controllers, animated: animated) @@ -167,7 +186,7 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr let topViewController = viewControllers[viewControllers.count - 1] as UIViewController if let controller = topViewController as? WindowContentController { - controller.setViewSize(self.view.bounds.size, duration: 0.0) + controller.setViewSize(self.view.bounds.size, insets: UIEdgeInsets(top: CGRectGetMaxY(self._navigationBar.frame), left: 0.0, bottom: 0.0, right: 0.0), duration: 0.0) } else { topViewController.view.frame = CGRect(origin: CGPoint(), size: self.view.bounds.size) } @@ -177,23 +196,23 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr } private func navigationBarFrame(size: CGSize) -> CGRect { - let condensedBar = (size.height < size.width || size.height <= 320.0) && size.height < 768.0 + //let condensedBar = (size.height < size.width || size.height <= 320.0) && size.height < 768.0 return CGRect(x: 0.0, y: 0.0, width: size.width, height: 20.0 + (size.height >= size.width ? 44.0 : 32.0)) } - public func setViewSize(toSize: CGSize, duration: NSTimeInterval) { + public func setViewSize(size: CGSize, insets: UIEdgeInsets, duration: NSTimeInterval) { if duration > DBL_EPSILON { - animateRotation(self.view, toFrame: CGRect(x: 0.0, y: 0.0, width: toSize.width, height: toSize.height), duration: duration) + animateRotation(self.view, toFrame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height), duration: duration) } else { - self.view.frame = CGRect(x: 0.0, y: 0.0, width: toSize.width, height: toSize.height) + self.view.frame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height) } if duration > DBL_EPSILON { - animateRotation(self._navigationBar, toFrame: self.navigationBarFrame(toSize), duration: duration) + animateRotation(self._navigationBar, toFrame: self.navigationBarFrame(size), duration: duration) } else { - self._navigationBar?.frame = self.navigationBarFrame(toSize) + self._navigationBar.frame = self.navigationBarFrame(size) } if let navigationTransitionCoordinator = self.navigationTransitionCoordinator { @@ -203,17 +222,18 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr let bottomController = self.viewControllers[self.viewControllers.count - 2] as UIViewController if let controller = bottomController as? WindowContentController { - controller.setViewSize(toSize, duration: duration) + controller.setViewSize(size, insets: UIEdgeInsets(top: CGRectGetMaxY(self._navigationBar.frame), left: 0.0, bottom: 0.0, right: 0.0), duration: duration) + } else { + bottomController.view.frame = CGRectMake(0.0, 0.0, size.width, size.height) } - bottomController.view.frame = CGRectMake(0.0, 0.0, toSize.width, toSize.height) } } if let topViewController = self.topViewController { if let controller = topViewController as? WindowContentController { - controller.setViewSize(toSize, duration: duration) + controller.setViewSize(size, insets: UIEdgeInsets(top: CGRectGetMaxY(self._navigationBar.frame), left: 0.0, bottom: 0.0, right: 0.0), duration: duration) } else { - topViewController.view.frame = CGRectMake(0.0, 0.0, toSize.width, toSize.height) + topViewController.view.frame = CGRectMake(0.0, 0.0, size.width, size.height) } } @@ -227,6 +247,6 @@ public class NavigationController: NavigationControllerProxy, WindowContentContr } public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { - return true + return otherGestureRecognizer is UIPanGestureRecognizer } } diff --git a/Display/NavigationItemWrapper.swift b/Display/NavigationItemWrapper.swift index 0ae268cc07..47ed0bcba4 100644 --- a/Display/NavigationItemWrapper.swift +++ b/Display/NavigationItemWrapper.swift @@ -50,12 +50,12 @@ internal class NavigationItemWrapper { }) self.setLeftBarButtonItemListenerKey = navigationItem.addSetLeftBarButtonItemListener({ [weak self] barButtonItem, animated in - self?.setLeftBarButtonItem(barButtonItem, animated: animated) + self?.setLeftBarButtonItem(barButtonItem, animated: animated.boolValue) return }) self.setRightBarButtonItemListenerKey = navigationItem.addSetRightBarButtonItemListener({ [weak self] barButtonItem, animated in - self?.setRightBarButtonItem(barButtonItem, animated: animated) + self?.setRightBarButtonItem(barButtonItem, animated: animated.boolValue) return }) diff --git a/Display/RuntimeUtils.swift b/Display/RuntimeUtils.swift new file mode 100644 index 0000000000..178c77d13b --- /dev/null +++ b/Display/RuntimeUtils.swift @@ -0,0 +1,23 @@ +import Foundation +import UIKit + +private let systemVersion = { () -> (Int, Int) in + let string = UIDevice.currentDevice().systemVersion as NSString + var minor = 0 + let range = string.rangeOfString(".") + if range.location != NSNotFound { + minor = Int((string.substringFromIndex(range.location + 1) as NSString).intValue) + } + return (Int(string.intValue), minor) +}() + +public func matchMinimumSystemVersion(major: Int, minor: Int = 0) -> Bool { + let version = systemVersion + if version.0 == major { + return version.1 >= minor + } else if version.0 < major { + return false + } else { + return true + } +} diff --git a/Display/StatusBarHostWindow.swift b/Display/StatusBarHostWindow.swift new file mode 100644 index 0000000000..901b24de39 --- /dev/null +++ b/Display/StatusBarHostWindow.swift @@ -0,0 +1,29 @@ +import Foundation +import UIKit + +private class StatusBarHostWindowController: UIViewController { + override func preferredStatusBarStyle() -> UIStatusBarStyle { + return UIStatusBarStyle.Default + } + + override func prefersStatusBarHidden() -> Bool { + return false + } + + override func shouldAutorotate() -> Bool { + return true + } +} + +public class StatusBarHostWindow: UIWindow { + public init() { + super.init(frame: CGRect()) + + self.windowLevel = 10000.0 + self.rootViewController = StatusBarHostWindowController() + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} \ No newline at end of file diff --git a/Display/UIKitUtils.swift b/Display/UIKitUtils.swift index 46e1fc8a89..0d6dace84b 100644 --- a/Display/UIKitUtils.swift +++ b/Display/UIKitUtils.swift @@ -29,3 +29,22 @@ private func dumpLayers(layer: CALayer, indent: String = "") { public func floorToScreenPixels(value: CGFloat) -> CGFloat { return floor(value * 2.0) / 2.0 } + +public extension UIColor { + convenience init(_ rgb: Int) { + self.init(red: CGFloat((rgb >> 16) & 0xff) / 255.0, green: CGFloat((rgb >> 8) & 0xff) / 255.0, blue: CGFloat(rgb & 0xff) / 255.0, alpha: 1.0) + } +} + +public extension CGSize { + public func fitted(size: CGSize) -> CGSize { + var fittedSize = self + if fittedSize.width > size.width { + fittedSize = CGSize(width: size.width, height: floor((fittedSize.height * size.width / max(fittedSize.width, 1.0)))) + } + if fittedSize.height > size.height { + fittedSize = CGSize(width: floor((fittedSize.width * size.height / max(fittedSize.height, 1.0))), height: size.height) + } + return fittedSize + } +} diff --git a/Display/ViewController.swift b/Display/ViewController.swift index cd2d61e3f6..fc83869639 100644 --- a/Display/ViewController.swift +++ b/Display/ViewController.swift @@ -40,12 +40,12 @@ import AsyncDisplayKit self.displayNode = ASDisplayNode() } - public func setViewSize(toSize: CGSize, duration: NSTimeInterval) { + public func setViewSize(size: CGSize, insets: UIEdgeInsets, duration: NSTimeInterval) { if duration > DBL_EPSILON { - animateRotation(self.displayNode, toFrame: CGRect(x: 0.0, y: 0.0, width: toSize.width, height: toSize.height), duration: duration) + animateRotation(self.displayNode, toFrame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height), duration: duration) } else { - self.displayNode.frame = CGRect(x: 0.0, y: 0.0, width: toSize.width, height: toSize.height) + self.displayNode.frame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height) } } } diff --git a/Display/Window.swift b/Display/Window.swift index 0b2ae25ccd..2fdf47ae8f 100644 --- a/Display/Window.swift +++ b/Display/Window.swift @@ -13,7 +13,7 @@ public class WindowRootViewController: UIViewController { @objc public protocol WindowContentController { - func setViewSize(toSize: CGSize, duration: NSTimeInterval) + func setViewSize(size: CGSize, insets: UIEdgeInsets, duration: NSTimeInterval) var view: UIView! { get } } @@ -93,7 +93,7 @@ public class Window: UIWindow { let sizeUpdated = super.frame.size != value.size super.frame = value if sizeUpdated { - self.viewController?.setViewSize(value.size, duration: self.isRotating() ? 0.3 : 0.0) + self.viewController?.setViewSize(value.size, insets: UIEdgeInsets(), duration: self.isRotating() ? 0.3 : 0.0) } } } @@ -106,7 +106,7 @@ public class Window: UIWindow { let sizeUpdated = super.bounds.size != value.size super.bounds = value if sizeUpdated { - self.viewController?.setViewSize(value.size, duration: self.isRotating() ? 0.3 : 0.0) + self.viewController?.setViewSize(value.size, insets: UIEdgeInsets(), duration: self.isRotating() ? 0.3 : 0.0) } } }