From 7dbc5b2e78119a24f26c2888030d861e6ff07d45 Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Mon, 3 Dec 2018 05:04:45 +0400 Subject: [PATCH] Collection API updates --- Display/GridItemNode.swift | 3 +++ Display/GridNode.swift | 3 +++ Display/ListView.swift | 32 +++++++++++++++---------- Display/ListViewIntermediateState.swift | 8 +++---- Display/ListViewItem.swift | 12 ++++++++-- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Display/GridItemNode.swift b/Display/GridItemNode.swift index 5acb7a1aa4..613a6b168c 100644 --- a/Display/GridItemNode.swift +++ b/Display/GridItemNode.swift @@ -14,4 +14,7 @@ open class GridItemNode: ASDisplayNode { super.frame = value } } + + open func updateLayout(item: GridItem, size: CGSize, isVisible: Bool, synchronousLoads: Bool) { + } } diff --git a/Display/GridNode.swift b/Display/GridNode.swift index 921450bce7..f967cde388 100644 --- a/Display/GridNode.swift +++ b/Display/GridNode.swift @@ -799,6 +799,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { let lowestSectionNode: ASDisplayNode? = self.lowestSectionNode() + let bounds = self.bounds var existingItemIndices = Set() for item in presentationLayoutTransition.layout.items { existingItemIndices.insert(item.index) @@ -807,10 +808,12 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { if itemNode.frame != item.frame { itemNode.frame = item.frame } + itemNode.updateLayout(item: self.items[item.index], size: item.frame.size, isVisible: bounds.intersects(item.frame), synchronousLoads: synchronousLoads) } else { let itemNode = self.items[item.index].node(layout: presentationLayoutTransition.layout.layout, synchronousLoad: synchronousLoads) itemNode.frame = item.frame self.addItemNode(index: item.index, itemNode: itemNode, lowestSectionNode: lowestSectionNode) + itemNode.updateLayout(item: self.items[item.index], size: item.frame.size, isVisible: bounds.intersects(item.frame), synchronousLoads: synchronousLoads) } } diff --git a/Display/ListView.swift b/Display/ListView.swift index 42971a3df8..95874b094f 100644 --- a/Display/ListView.swift +++ b/Display/ListView.swift @@ -1165,7 +1165,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel DispatchQueue.global().async(execute: f) } - private func nodeForItem(synchronous: Bool, synchronousLoads: Bool, item: ListViewItem, previousNode: QueueLocalObject?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, params: ListViewItemLayoutParams, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (QueueLocalObject, ListViewItemNodeLayout, @escaping () -> (Signal?, () -> Void)) -> Void) { + private func nodeForItem(synchronous: Bool, synchronousLoads: Bool, item: ListViewItem, previousNode: QueueLocalObject?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, params: ListViewItemLayoutParams, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (QueueLocalObject, ListViewItemNodeLayout, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { if let previousNode = previousNode { item.updateNode(async: { f in if synchronous { @@ -1180,29 +1180,29 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if Thread.isMainThread { if synchronous { completion(previousNode, layout, { - return (nil, { + return (nil, { info in assert(Queue.mainQueue().isCurrent()) previousNode.with({ $0.index = index }) - apply() + apply(info) }) }) } else { self.async { completion(previousNode, layout, { - return (nil, { + return (nil, { info in assert(Queue.mainQueue().isCurrent()) previousNode.with({ $0.index = index }) - apply() + apply(info) }) }) } } } else { completion(previousNode, layout, { - return (nil, { + return (nil, { info in assert(Queue.mainQueue().isCurrent()) previousNode.with({ $0.index = index }) - apply() + apply(info) }) }) } @@ -1759,7 +1759,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: () -> (Signal?, () -> Void), timestamp: Double, listInsets: UIEdgeInsets) { + private func insertNodeAtIndex(animated: Bool, animateAlpha: Bool, forceAnimateInsertion: Bool, previousFrame: CGRect?, nodeIndex: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (Signal?, (ListViewItemApply) -> Void), timestamp: Double, listInsets: UIEdgeInsets, visibleBounds: CGRect) { let insertionOrigin = self.referencePointForInsertionAtIndex(nodeIndex) let nodeOrigin: CGPoint @@ -1782,7 +1782,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if let accessoryItemNode = node.accessoryItemNode { node.layoutAccessoryItemNode(accessoryItemNode, leftInset: listInsets.left, rightInset: listInsets.right) } - apply().1() + apply().1(ListViewItemApply(isOnScreen: visibleBounds.intersects(nodeFrame))) self.itemNodes.insert(node, at: nodeIndex) var offsetHeight = node.apparentHeight @@ -2025,6 +2025,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel let lowestNodeToInsertBelow = self.lowestNodeToInsertBelow() var hadInserts = false + let visibleBounds = CGRect(origin: CGPoint(), size: self.visibleSize) + for operation in operations { switch operation { case let .InsertNode(index, offsetDirection, nodeAnimated, nodeObject, layout, apply): @@ -2045,7 +2047,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel updatedPreviousFrame = nil } - self.insertNodeAtIndex(animated: nodeAnimated, animateAlpha: animateAlpha, forceAnimateInsertion: forceAnimateInsertion, previousFrame: updatedPreviousFrame, nodeIndex: index, offsetDirection: offsetDirection, node: node, layout: layout, apply: apply, timestamp: timestamp, listInsets: listInsets) + self.insertNodeAtIndex(animated: nodeAnimated, animateAlpha: animateAlpha, forceAnimateInsertion: forceAnimateInsertion, previousFrame: updatedPreviousFrame, nodeIndex: index, offsetDirection: offsetDirection, node: node, layout: layout, apply: apply, timestamp: timestamp, listInsets: listInsets, visibleBounds: visibleBounds) hadInserts = true if let _ = updatedPreviousFrame { if let itemNode = self.reorderNode?.itemNode, itemNode.supernode == self { @@ -2093,10 +2095,10 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if let height = height, let previousLayout = previousLayout { if takenPreviousNodes.contains(referenceNode) { let tempNode = ListViewTempItemNode(layerBacked: true) - self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: tempNode, layout: ListViewItemNodeLayout(contentSize: CGSize(width: self.visibleSize.width, height: height), insets: UIEdgeInsets()), apply: { return (nil, {}) }, timestamp: timestamp, listInsets: listInsets) + self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: tempNode, layout: ListViewItemNodeLayout(contentSize: CGSize(width: self.visibleSize.width, height: height), insets: UIEdgeInsets()), apply: { return (nil, { _ in }) }, timestamp: timestamp, listInsets: listInsets, visibleBounds: visibleBounds) } else { referenceNode.index = nil - self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: referenceNode, layout: previousLayout, apply: { return (nil, {}) }, timestamp: timestamp, listInsets: listInsets) + self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: referenceNode, layout: previousLayout, apply: { return (nil, { _ in }) }, timestamp: timestamp, listInsets: listInsets, visibleBounds: visibleBounds) if let verticalScrollIndicator = self.verticalScrollIndicator { self.insertSubnode(referenceNode, belowSubnode: verticalScrollIndicator) } else { @@ -2151,11 +2153,15 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel node.contentSize = layout.contentSize node.insets = layout.insets - apply().1() let updatedApparentHeight = node.bounds.size.height let updatedInsets = node.insets + var apparentFrame = node.apparentFrame + apparentFrame.size.height = updatedApparentHeight + + apply().1(ListViewItemApply(isOnScreen: visibleBounds.intersects(apparentFrame))) + var offsetRanges = OffsetRanges() if animated { diff --git a/Display/ListViewIntermediateState.swift b/Display/ListViewIntermediateState.swift index 8e91b0c723..4fc0f49409 100644 --- a/Display/ListViewIntermediateState.swift +++ b/Display/ListViewIntermediateState.swift @@ -689,7 +689,7 @@ struct ListViewState { return height } - mutating func insertNode(_ itemIndex: Int, node: QueueLocalObject, layout: ListViewItemNodeLayout, apply: @escaping () -> (Signal?, () -> Void), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) { + mutating func insertNode(_ itemIndex: Int, node: QueueLocalObject, layout: ListViewItemNodeLayout, apply: @escaping () -> (Signal?, (ListViewItemApply) -> Void), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) { let (insertionOrigin, insertionIndex) = self.nodeInsertionPointAndIndex(itemIndex) let nodeOrigin: CGPoint @@ -794,7 +794,7 @@ struct ListViewState { } } - mutating func updateNodeAtItemIndex(_ itemIndex: Int, layout: ListViewItemNodeLayout, direction: ListViewItemOperationDirectionHint?, animation: ListViewItemUpdateAnimation, apply: @escaping () -> (Signal?, () -> Void), operations: inout [ListViewStateOperation]) { + mutating func updateNodeAtItemIndex(_ itemIndex: Int, layout: ListViewItemNodeLayout, direction: ListViewItemOperationDirectionHint?, animation: ListViewItemUpdateAnimation, apply: @escaping () -> (Signal?, (ListViewItemApply) -> Void), operations: inout [ListViewStateOperation]) { var i = -1 for node in self.nodes { i += 1 @@ -850,9 +850,9 @@ struct ListViewState { } enum ListViewStateOperation { - case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, node: QueueLocalObject, layout: ListViewItemNodeLayout, apply: () -> (Signal?, () -> Void)) + case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, node: QueueLocalObject, layout: ListViewItemNodeLayout, apply: () -> (Signal?, (ListViewItemApply) -> Void)) case InsertDisappearingPlaceholder(index: Int, referenceNode: QueueLocalObject, offsetDirection: ListViewInsertionOffsetDirection) case Remove(index: Int, offsetDirection: ListViewInsertionOffsetDirection) case Remap([Int: Int]) - case UpdateLayout(index: Int, layout: ListViewItemNodeLayout, apply: () -> (Signal?, () -> Void)) + case UpdateLayout(index: Int, layout: ListViewItemNodeLayout, apply: () -> (Signal?, (ListViewItemApply) -> Void)) } diff --git a/Display/ListViewItem.swift b/Display/ListViewItem.swift index 7072657ee6..bc8e15dc55 100644 --- a/Display/ListViewItem.swift +++ b/Display/ListViewItem.swift @@ -32,9 +32,17 @@ public struct ListViewItemConfigureNodeFlags: OptionSet { public static let preferSynchronousResourceLoading = ListViewItemConfigureNodeFlags(rawValue: 1 << 0) } +public struct ListViewItemApply { + public let isOnScreen: Bool + + public init(isOnScreen: Bool) { + self.isOnScreen = isOnScreen + } +} + public protocol ListViewItem { - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) - func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> Void) -> Void) + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) var accessoryItem: ListViewAccessoryItem? { get } var headerAccessoryItem: ListViewAccessoryItem? { get }