diff --git a/Display/ContainableController.swift b/Display/ContainableController.swift index 9417b2afee..4ed6f3296e 100644 --- a/Display/ContainableController.swift +++ b/Display/ContainableController.swift @@ -32,38 +32,46 @@ public enum ContainedViewLayoutTransition { public extension ContainedViewLayoutTransition { func updateFrame(node: ASDisplayNode, frame: CGRect, completion: ((Bool) -> Void)? = nil) { - switch self { - case .immediate: - node.frame = frame - if let completion = completion { - completion(true) - } - case let .animated(duration, curve): - let previousFrame = node.frame - node.frame = frame - node.layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, completion: { result in + if node.frame.equalTo(frame) { + completion?(true) + } else { + switch self { + case .immediate: + node.frame = frame if let completion = completion { - completion(result) + completion(true) } - }) + case let .animated(duration, curve): + let previousFrame = node.frame + node.frame = frame + node.layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, completion: { result in + if let completion = completion { + completion(result) + } + }) + } } } func updatePosition(node: ASDisplayNode, position: CGPoint, completion: ((Bool) -> Void)? = nil) { - switch self { - case .immediate: - node.position = position - if let completion = completion { - completion(true) - } - case let .animated(duration, curve): - let previousPosition = node.position - node.position = position - node.layer.animatePosition(from: previousPosition, to: position, duration: duration, timingFunction: curve.timingFunction, completion: { result in + if node.position.equalTo(position) { + completion?(true) + } else { + switch self { + case .immediate: + node.position = position if let completion = completion { - completion(result) + completion(true) } - }) + case let .animated(duration, curve): + let previousPosition = node.position + node.position = position + node.layer.animatePosition(from: previousPosition, to: position, duration: duration, timingFunction: curve.timingFunction, completion: { result in + if let completion = completion { + completion(result) + } + }) + } } } @@ -83,17 +91,21 @@ public extension ContainedViewLayoutTransition { } func animatePosition(node: ASDisplayNode, to position: CGPoint, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) { - switch self { - case .immediate: - if let completion = completion { - completion(true) + if node.position.equalTo(position) { + completion?(true) + } else { + switch self { + case .immediate: + if let completion = completion { + completion(true) + } + case let .animated(duration, curve): + node.layer.animatePosition(from: node.position, to: position, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: removeOnCompletion, completion: { result in + if let completion = completion { + completion(result) + } + }) } - case let .animated(duration, curve): - node.layer.animatePosition(from: node.position, to: position, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: removeOnCompletion, completion: { result in - if let completion = completion { - completion(result) - } - }) } } @@ -115,20 +127,24 @@ public extension ContainedViewLayoutTransition { } func updateFrame(layer: CALayer, frame: CGRect, completion: ((Bool) -> Void)? = nil) { - switch self { - case .immediate: - layer.frame = frame - if let completion = completion { - completion(true) - } - case let .animated(duration, curve): - let previousFrame = layer.frame - layer.frame = frame - layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, completion: { result in + if layer.frame.equalTo(frame) { + completion?(true) + } else { + switch self { + case .immediate: + layer.frame = frame if let completion = completion { - completion(result) + completion(true) } - }) + case let .animated(duration, curve): + let previousFrame = layer.frame + layer.frame = frame + layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, completion: { result in + if let completion = completion { + completion(result) + } + }) + } } } diff --git a/Display/Font.swift b/Display/Font.swift index 295dd1e4f2..99372d913d 100644 --- a/Display/Font.swift +++ b/Display/Font.swift @@ -13,6 +13,18 @@ public struct Font { return CTFontCreateWithName("HelveticaNeue-Medium" as CFString, size, nil) } } + + public static func bold(_ size: CGFloat) -> UIFont { + if #available(iOS 8.2, *) { + return UIFont.systemFont(ofSize: size, weight: UIFontWeightBold) + } else { + return CTFontCreateWithName("HelveticaNeue-Bold" as CFString, size, nil) + } + } + + public static func italic(_ size: CGFloat) -> UIFont { + return UIFont.italicSystemFont(ofSize: size) + } } public extension NSAttributedString { diff --git a/Display/GenerateImage.swift b/Display/GenerateImage.swift index f64d202553..220e7cf83b 100644 --- a/Display/GenerateImage.swift +++ b/Display/GenerateImage.swift @@ -87,7 +87,16 @@ public func generateStretchableFilledCircleImage(radius: CGFloat, color: UIColor public func generateStretchableFilledCircleImage(diameter: CGFloat, color: UIColor?, backgroundColor: UIColor? = nil) -> UIImage? { let intRadius = Int(diameter / 2.0) - let cap = intRadius == 1 ? 2 : intRadius + let intDiameter = Int(diameter) + let cap: Int + if intDiameter == 3 { + cap = 1 + } else if intRadius == 1 { + cap = 2 + } else { + cap = intRadius + } + return generateFilledCircleImage(diameter: diameter, color: color, backgroundColor: backgroundColor)?.stretchableImage(withLeftCapWidth: cap, topCapHeight: cap) } diff --git a/Display/GridNodeScroller.swift b/Display/GridNodeScroller.swift index 6ad5e93348..b4a8c5e6fb 100644 --- a/Display/GridNodeScroller.swift +++ b/Display/GridNodeScroller.swift @@ -1,6 +1,15 @@ import UIKit +private class GridNodeScrollerLayer: CALayer { + override func setNeedsDisplay() { + } +} + private class GridNodeScrollerView: UIScrollView { + override class var layerClass: AnyClass { + return GridNodeScrollerLayer.self + } + override func touchesShouldCancel(in view: UIView) -> Bool { return true } diff --git a/Display/ListView.swift b/Display/ListView.swift index a4f35b25f3..30b036fef6 100644 --- a/Display/ListView.swift +++ b/Display/ListView.swift @@ -14,6 +14,9 @@ private final class ListViewBackingLayer: CALayer { override func layoutSublayers() { } + + override func setNeedsDisplay() { + } } final class ListViewBackingView: UIView { @@ -146,6 +149,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel private var flashNodesDelayTimer: Foundation.Timer? private var highlightedItemIndex: Int? + private let waitingForNodesDisposable = MetaDisposable() + public func reportDurationInMS(duration: Int, smallDropEvent: Double, largeDropEvent: Double) { print("reportDurationInMS duration: \(duration), smallDropEvent: \(smallDropEvent), largeDropEvent: \(largeDropEvent)") } @@ -241,6 +246,15 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel deinit { self.pauseAnimations() self.displayLink.invalidate() + + for itemNode in self.itemNodes { + ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemNode) + } + for itemHeaderNode in self.itemHeaderNodes { + ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemHeaderNode) + } + + self.waitingForNodesDisposable.dispose() } @objc func frictionSliderChanged(_ slider: UISlider) { @@ -738,7 +752,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel DispatchQueue.global().async(execute: f) } - private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: ListViewItemNode?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, width: CGFloat, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNode, ListViewItemNodeLayout, @escaping () -> Void) -> Void) { + private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: ListViewItemNode?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, width: CGFloat, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNode, ListViewItemNodeLayout, @escaping () -> (Signal?, () -> Void)) -> Void) { if let previousNode = previousNode { item.updateNode(async: { f in if synchronous { @@ -750,21 +764,27 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if Thread.isMainThread { if synchronous { completion(previousNode, layout, { - previousNode.index = index - apply() + return (nil, { + previousNode.index = index + apply() + }) }) } else { self.async { completion(previousNode, layout, { - previousNode.index = index - apply() + return (nil, { + previousNode.index = index + apply() + }) }) } } } else { completion(previousNode, layout, { - previousNode.index = index - apply() + return (nil, { + previousNode.index = index + apply() + }) }) } }) @@ -1068,7 +1088,53 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel let stationaryItemIndex = updatedState.stationaryOffset?.0 let next = { - self.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateTopItemVerticalOrigin: options.contains(.AnimateTopItemPosition), operations: updatedOperations, requestItemInsertionAnimationsIndices: options.contains(.RequestItemInsertionAnimations) ? insertedIndexSet : Set(), scrollToItem: scrollToItem, updateSizeAndInsets: updateSizeAndInsets, stationaryItemIndex: stationaryItemIndex, updateOpaqueState: updateOpaqueState, completion: completion) + var updatedOperations = updatedOperations + + var readySignals: [Signal]? + + if options.contains(.PreferSynchronousResourceLoading) { + var currentReadySignals: [Signal] = [] + for i in 0 ..< updatedOperations.count { + if case let .InsertNode(index, offsetDirection, node, layout, apply) = updatedOperations[i] { + let (ready, commitApply) = apply() + updatedOperations[i] = .InsertNode(index: index, offsetDirection: offsetDirection, node: node, layout: layout, apply: { + return (nil, commitApply) + }) + if let ready = ready { + currentReadySignals.append(ready) + } + } + } + readySignals = currentReadySignals + } + + let beginReplay = { [weak self] in + if let strongSelf = self { + strongSelf.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateTopItemVerticalOrigin: options.contains(.AnimateTopItemPosition), operations: updatedOperations, requestItemInsertionAnimationsIndices: options.contains(.RequestItemInsertionAnimations) ? insertedIndexSet : Set(), scrollToItem: scrollToItem, updateSizeAndInsets: updateSizeAndInsets, stationaryItemIndex: stationaryItemIndex, updateOpaqueState: updateOpaqueState, completion: { + if options.contains(.PreferSynchronousResourceLoading) { + let startTime = CACurrentMediaTime() + self?.recursivelyEnsureDisplaySynchronously(true) + let deltaTime = CACurrentMediaTime() - startTime + print("ListView: waited \(deltaTime * 1000.0) ms for nodes to display") + } + completion() + }) + } + } + + if let readySignals = readySignals, !readySignals.isEmpty && false { + let readyWithTimeout = combineLatest(readySignals) + |> deliverOnMainQueue + |> timeout(0.2, queue: Queue.mainQueue(), alternate: .single([])) + let startTime = CACurrentMediaTime() + self.waitingForNodesDisposable.set(readyWithTimeout.start(completed: { + let deltaTime = CACurrentMediaTime() - startTime + print("ListView: waited \(deltaTime * 1000.0) ms for nodes to load") + beginReplay() + })) + } else { + beginReplay() + } } if options.contains(.LowLatency) || options.contains(.Synchronous) { @@ -1123,7 +1189,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel let heightDelta = layout.size.height - updatedState.nodes[i].frame.size.height - updatedOperations.append(.UpdateLayout(index: i, layout: layout, apply: apply)) + updatedOperations.append(.UpdateLayout(index: i, layout: layout, apply: { + return (nil, apply) + })) if !animated { let previousFrame = updatedState.nodes[i].frame @@ -1252,7 +1320,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } } - private func insertNodeAtIndex(animated: Bool, animateAlpha: Bool, forceAnimateInsertion: Bool, previousFrame: CGRect?, nodeIndex: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (), timestamp: Double) { + private func insertNodeAtIndex(animated: Bool, animateAlpha: Bool, forceAnimateInsertion: Bool, previousFrame: CGRect?, nodeIndex: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (Signal?, () -> Void), timestamp: Double) { let insertionOrigin = self.referencePointForInsertionAtIndex(nodeIndex) let nodeOrigin: CGPoint @@ -1272,7 +1340,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel node.insets = layout.insets node.apparentHeight = animated ? 0.0 : layout.size.height node.frame = nodeFrame - apply() + apply().1() self.itemNodes.insert(node, at: nodeIndex) if useDynamicTuning { @@ -1514,10 +1582,10 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if let height = height, let previousLayout = previousLayout { if takenPreviousNodes.contains(referenceNode) { - self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: ListViewItemNode(layerBacked: true), layout: ListViewItemNodeLayout(contentSize: CGSize(width: self.visibleSize.width, height: height), insets: UIEdgeInsets()), apply: { }, timestamp: timestamp) + self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: ListViewItemNode(layerBacked: true), layout: ListViewItemNodeLayout(contentSize: CGSize(width: self.visibleSize.width, height: height), insets: UIEdgeInsets()), apply: { return (nil, {}) }, timestamp: timestamp) } else { referenceNode.index = nil - self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: referenceNode, layout: previousLayout, apply: { }, timestamp: timestamp) + self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: referenceNode, layout: previousLayout, apply: { return (nil, {}) }, timestamp: timestamp) self.addSubnode(referenceNode) } } else { @@ -1562,7 +1630,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel node.contentSize = layout.contentSize node.insets = layout.insets - apply() + apply().1() let updatedApparentHeight = node.bounds.size.height let updatedInsets = node.insets @@ -1893,7 +1961,6 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel let lowestHeaderNode = self.lowestHeaderNode() for itemNode in temporaryPreviousNodes { itemNode.frame = itemNode.frame.offsetBy(dx: 0.0, dy: offset) - temporaryPreviousNodes.append(itemNode) if let lowestHeaderNode = lowestHeaderNode { self.insertSubnode(itemNode, belowSubnode: lowestHeaderNode) } else { @@ -1942,12 +2009,18 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel animation.completion = { _ in for itemNode in temporaryPreviousNodes { itemNode.removeFromSupernode() + ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemNode) } for headerNode in temporaryHeaderNodes { headerNode.removeFromSupernode() + ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: headerNode) } } self.layer.add(animation, forKey: nil) + } else { + for itemNode in temporaryPreviousNodes { + ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemNode) + } } } @@ -1977,6 +2050,12 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel //print("replayOperations \(delta * 1000.0) ms") } + for (previousNode, _) in previousApparentFrames { + if previousNode.supernode == nil { + ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: previousNode) + } + } + completion() } }) @@ -2306,6 +2385,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel let node = self.itemNodes[i] if node.index == nil && node.apparentHeight <= CGFloat(FLT_EPSILON) { self.removeItemNodeAtIndex(i) + ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: node) } else { i += 1 } @@ -2507,6 +2587,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if true { //!(itemNode.hitTest(CGPoint(x: strongSelf.touchesPosition.x - itemNode.frame.minX, y: strongSelf.touchesPosition.y - itemNode.frame.minY), with: event) is UIControl) { if !itemNode.isLayerBacked { strongSelf.view.bringSubview(toFront: itemNode.view) + for (_, headerNode) in strongSelf.itemHeaderNodes { + strongSelf.view.bringSubview(toFront: headerNode.view) + } } itemNode.setHighlighted(true, animated: false) } @@ -2594,6 +2677,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if itemNode.index == index { if !itemNode.isLayerBacked { self.view.bringSubview(toFront: itemNode.view) + for (_, headerNode) in self.itemHeaderNodes { + self.view.bringSubview(toFront: headerNode.view) + } } itemNode.setHighlighted(true, animated: false) break diff --git a/Display/ListViewIntermediateState.swift b/Display/ListViewIntermediateState.swift index 083efe4612..bac1aa5eb7 100644 --- a/Display/ListViewIntermediateState.swift +++ b/Display/ListViewIntermediateState.swift @@ -1,4 +1,5 @@ import Foundation +import SwiftSignalKit public enum ListViewCenterScrollPositionOverflow { case Top @@ -121,6 +122,7 @@ public struct ListViewDeleteAndInsertOptions: OptionSet { public static let Synchronous = ListViewDeleteAndInsertOptions(rawValue: 8) public static let RequestItemInsertionAnimations = ListViewDeleteAndInsertOptions(rawValue: 16) public static let AnimateTopItemPosition = ListViewDeleteAndInsertOptions(rawValue: 32) + public static let PreferSynchronousResourceLoading = ListViewDeleteAndInsertOptions(rawValue: 64) } public struct ListViewUpdateSizeAndInsets { @@ -222,7 +224,7 @@ struct TransactionState { struct PendingNode { let index: Int let node: ListViewItemNode - let apply: () -> () + let apply: () -> (Signal?, () -> Void) let frame: CGRect let apparentHeight: CGFloat } @@ -701,7 +703,7 @@ struct ListViewState { return height } - mutating func insertNode(_ itemIndex: Int, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: @escaping () -> (), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) { + mutating func insertNode(_ itemIndex: Int, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: @escaping () -> (Signal?, () -> Void), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) { let (insertionOrigin, insertionIndex) = self.nodeInsertionPointAndIndex(itemIndex) let nodeOrigin: CGPoint @@ -806,7 +808,7 @@ struct ListViewState { } } - mutating func updateNodeAtItemIndex(_ itemIndex: Int, layout: ListViewItemNodeLayout, direction: ListViewItemOperationDirectionHint?, animation: ListViewItemUpdateAnimation, apply: @escaping () -> Void, operations: inout [ListViewStateOperation]) { + mutating func updateNodeAtItemIndex(_ itemIndex: Int, layout: ListViewItemNodeLayout, direction: ListViewItemOperationDirectionHint?, animation: ListViewItemUpdateAnimation, apply: @escaping () -> (Signal?, () -> Void), operations: inout [ListViewStateOperation]) { var i = -1 for node in self.nodes { i += 1 @@ -862,9 +864,9 @@ struct ListViewState { } enum ListViewStateOperation { - case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> ()) + case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (Signal?, () -> Void)) case InsertDisappearingPlaceholder(index: Int, referenceNode: ListViewItemNode, offsetDirection: ListViewInsertionOffsetDirection) case Remove(index: Int, offsetDirection: ListViewInsertionOffsetDirection) case Remap([Int: Int]) - case UpdateLayout(index: Int, layout: ListViewItemNodeLayout, apply: () -> ()) + case UpdateLayout(index: Int, layout: ListViewItemNodeLayout, apply: () -> (Signal?, () -> Void)) } diff --git a/Display/ListViewItem.swift b/Display/ListViewItem.swift index cd9278fe2d..153847d2ad 100644 --- a/Display/ListViewItem.swift +++ b/Display/ListViewItem.swift @@ -6,8 +6,22 @@ public enum ListViewItemUpdateAnimation { case System(duration: Double) } +public struct ListViewItemConfigureNodeFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let preferSynchronousResourceLoading = ListViewItemConfigureNodeFlags(rawValue: 1 << 0) +} + public protocol ListViewItem { - func nodeConfiguredForWidth(async: @escaping (@escaping () -> Void) -> Void, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> Void) -> Void) + func nodeConfiguredForWidth(async: @escaping (@escaping () -> Void) -> Void, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> Void) -> Void) var accessoryItem: ListViewAccessoryItem? { get } @@ -37,8 +51,4 @@ public extension ListViewItem { func selected(listView: ListView) { } - - func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> Void) -> Void) { - completion(ListViewItemNodeLayout(contentSize: node.contentSize, insets: node.insets), {}) - } } diff --git a/Display/ListViewItemNode.swift b/Display/ListViewItemNode.swift index 15912c8c1f..8c97ec0400 100644 --- a/Display/ListViewItemNode.swift +++ b/Display/ListViewItemNode.swift @@ -1,5 +1,6 @@ import Foundation import AsyncDisplayKit +import SwiftSignalKit var testSpringFrictionLimits: (CGFloat, CGFloat) = (3.0, 60.0) var testSpringFriction: CGFloat = 31.8211269378662 @@ -133,6 +134,10 @@ open class ListViewItemNode: ASDisplayNode { return ListViewItemNodeLayout(contentSize: contentSize, insets: insets) } + public var displayResourcesReady: Signal { + return .complete() + } + public init(layerBacked: Bool, dynamicBounce: Bool = true, rotated: Bool = false) { if true { if dynamicBounce { @@ -163,6 +168,12 @@ open class ListViewItemNode: ASDisplayNode { self.isLayerBacked = layerBacked } + /*deinit { + if Thread.isMainThread { + print("deallocating on main thread") + } + }*/ + var apparentHeight: CGFloat = 0.0 private var _bounds: CGRect = CGRect() private var _position: CGPoint = CGPoint() diff --git a/Display/NavigationTransitionCoordinator.swift b/Display/NavigationTransitionCoordinator.swift index 26858c75ee..d1fe4b5e0c 100644 --- a/Display/NavigationTransitionCoordinator.swift +++ b/Display/NavigationTransitionCoordinator.swift @@ -56,7 +56,7 @@ class NavigationTransitionCoordinator { self.dimView.backgroundColor = UIColor.black self.shadowView = UIImageView(image: shadowImage) - if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar { + if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar, !topNavigationBar.isHidden, !bottomNavigationBar.isHidden { var topFrame = topNavigationBar.view.convert(topNavigationBar.bounds, to: container) var bottomFrame = bottomNavigationBar.view.convert(bottomNavigationBar.bounds, to: container) topFrame.origin.x = 0.0 @@ -111,7 +111,7 @@ class NavigationTransitionCoordinator { } func updateNavigationBarTransition() { - if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar { + if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition { let position: CGFloat switch self.transition { case .Push: @@ -126,7 +126,7 @@ class NavigationTransitionCoordinator { } func maybeCreateNavigationBarTransition() { - if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar { + if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition { let position: CGFloat switch self.transition { case .Push: @@ -141,7 +141,7 @@ class NavigationTransitionCoordinator { } func endNavigationBarTransition() { - if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar { + if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition { topNavigationBar.transitionState = nil bottomNavigationBar.transitionState = nil }