mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-07 23:03:35 +00:00
Various fixes
This commit is contained in:
parent
bb44454500
commit
7a58ac1bfc
@ -10,7 +10,7 @@ public protocol GridSection {
|
||||
|
||||
public protocol GridItem {
|
||||
var section: GridSection? { get }
|
||||
func node(layout: GridNodeLayout) -> GridItemNode
|
||||
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode
|
||||
func update(node: GridItemNode)
|
||||
var aspectRatio: CGFloat { get }
|
||||
var fillsRowWithHeight: CGFloat? { get }
|
||||
|
||||
@ -97,8 +97,9 @@ public struct GridNodeTransaction {
|
||||
public let stationaryItems: GridNodeStationaryItems
|
||||
public let updateFirstIndexInSectionOffset: Int?
|
||||
public let updateOpaqueState: Any?
|
||||
public let synchronousLoads: Bool
|
||||
|
||||
public init(deleteItems: [Int], insertItems: [GridNodeInsertItem], updateItems: [GridNodeUpdateItem], scrollToItem: GridNodeScrollToItem?, updateLayout: GridNodeUpdateLayout?, itemTransition: ContainedViewLayoutTransition, stationaryItems: GridNodeStationaryItems, updateFirstIndexInSectionOffset: Int?, updateOpaqueState: Any? = nil) {
|
||||
public init(deleteItems: [Int], insertItems: [GridNodeInsertItem], updateItems: [GridNodeUpdateItem], scrollToItem: GridNodeScrollToItem?, updateLayout: GridNodeUpdateLayout?, itemTransition: ContainedViewLayoutTransition, stationaryItems: GridNodeStationaryItems, updateFirstIndexInSectionOffset: Int?, updateOpaqueState: Any? = nil, synchronousLoads: Bool = false) {
|
||||
self.deleteItems = deleteItems
|
||||
self.insertItems = insertItems
|
||||
self.updateItems = updateItems
|
||||
@ -108,6 +109,7 @@ public struct GridNodeTransaction {
|
||||
self.stationaryItems = stationaryItems
|
||||
self.updateFirstIndexInSectionOffset = updateFirstIndexInSectionOffset
|
||||
self.updateOpaqueState = updateOpaqueState
|
||||
self.synchronousLoads = synchronousLoads
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,7 +348,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
||||
generatedScrollToItem = nil
|
||||
}
|
||||
|
||||
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(stationaryItems: transaction.stationaryItems, layoutTransactionOffset: layoutTransactionOffset, scrollToItem: generatedScrollToItem), removedNodes: removedNodes, updateLayoutTransition: updateLayoutTransition, customScrollToItem: transaction.scrollToItem != nil, itemTransition: transaction.itemTransition, updatingLayout: transaction.updateLayout != nil, completion: completion)
|
||||
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(stationaryItems: transaction.stationaryItems, layoutTransactionOffset: layoutTransactionOffset, scrollToItem: generatedScrollToItem), removedNodes: removedNodes, updateLayoutTransition: updateLayoutTransition, customScrollToItem: transaction.scrollToItem != nil, itemTransition: transaction.itemTransition, synchronousLoads: transaction.synchronousLoads, updatingLayout: transaction.updateLayout != nil, completion: completion)
|
||||
}
|
||||
|
||||
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||
@ -368,7 +370,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
||||
|
||||
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
if !self.applyingContentOffset {
|
||||
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(layoutTransactionOffset: 0.0), removedNodes: [], updateLayoutTransition: nil, customScrollToItem: false, itemTransition: .immediate, updatingLayout: false, completion: { _ in })
|
||||
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(layoutTransactionOffset: 0.0), removedNodes: [], updateLayoutTransition: nil, customScrollToItem: false, itemTransition: .immediate, synchronousLoads: false, updatingLayout: false, completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,7 +746,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
||||
return lowestHeaderNode
|
||||
}
|
||||
|
||||
private func applyPresentaionLayoutTransition(_ presentationLayoutTransition: GridNodePresentationLayoutTransition, removedNodes: [GridItemNode], updateLayoutTransition: ContainedViewLayoutTransition?, customScrollToItem: Bool, itemTransition: ContainedViewLayoutTransition, updatingLayout: Bool, completion: (GridNodeDisplayedItemRange) -> Void) {
|
||||
private func applyPresentaionLayoutTransition(_ presentationLayoutTransition: GridNodePresentationLayoutTransition, removedNodes: [GridItemNode], updateLayoutTransition: ContainedViewLayoutTransition?, customScrollToItem: Bool, itemTransition: ContainedViewLayoutTransition, synchronousLoads: Bool, updatingLayout: Bool, completion: (GridNodeDisplayedItemRange) -> Void) {
|
||||
let boundsTransition: ContainedViewLayoutTransition = updateLayoutTransition ?? .immediate
|
||||
|
||||
var previousItemFrames: [WrappedGridItemNode: CGRect]?
|
||||
@ -806,7 +808,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
||||
itemNode.frame = item.frame
|
||||
}
|
||||
} else {
|
||||
let itemNode = self.items[item.index].node(layout: presentationLayoutTransition.layout.layout)
|
||||
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)
|
||||
}
|
||||
|
||||
@ -116,6 +116,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
private final let scroller: ListViewScroller
|
||||
private final var visibleSize: CGSize = CGSize()
|
||||
public private(set) final var insets = UIEdgeInsets()
|
||||
public private(set) final var scrollIndicatorInsets = UIEdgeInsets()
|
||||
private final var ensureTopInsetForOverlayHighlightedItems: CGFloat?
|
||||
private final var lastContentOffset: CGPoint = CGPoint()
|
||||
private final var lastContentOffsetTimestamp: CFAbsoluteTime = 0.0
|
||||
@ -125,6 +126,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
private final var needsAnimations = false
|
||||
|
||||
public final var dynamicBounceEnabled = true
|
||||
public final var rotated = false
|
||||
|
||||
private final var invisibleInset: CGFloat = 500.0
|
||||
public var preloadPages: Bool = true {
|
||||
@ -177,6 +179,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
if let fillColor = self.verticalScrollIndicatorColor {
|
||||
if self.verticalScrollIndicator == nil {
|
||||
let verticalScrollIndicator = ASImageNode()
|
||||
verticalScrollIndicator.isUserInteractionEnabled = false
|
||||
verticalScrollIndicator.alpha = 0.0
|
||||
verticalScrollIndicator.image = generateStretchableFilledCircleImage(diameter: 3.0, color: fillColor)
|
||||
self.verticalScrollIndicator = verticalScrollIndicator
|
||||
self.addSubnode(verticalScrollIndicator)
|
||||
@ -233,6 +237,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
private var selectionTouchDelayTimer: Foundation.Timer?
|
||||
private var selectionLongTapDelayTimer: Foundation.Timer?
|
||||
private var flashNodesDelayTimer: Foundation.Timer?
|
||||
private var flashScrollIndicatorTimer: Foundation.Timer?
|
||||
private var highlightedItemIndex: Int?
|
||||
private var reorderNode: ListViewReorderingItemNode?
|
||||
private var reorderFeedback: HapticFeedback?
|
||||
@ -383,7 +388,11 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
}
|
||||
let reorderNode = ListViewReorderingItemNode(itemNode: itemNode, initialLocation: itemNode.frame.origin)
|
||||
self.reorderNode = reorderNode
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
self.insertSubnode(reorderNode, belowSubnode: verticalScrollIndicator)
|
||||
} else {
|
||||
self.addSubnode(reorderNode)
|
||||
}
|
||||
itemNode.isHidden = true
|
||||
}
|
||||
|
||||
@ -492,6 +501,31 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
}
|
||||
}
|
||||
|
||||
private func resetScrollIndicatorFlashTimer(start: Bool) {
|
||||
if let flashScrollIndicatorTimer = self.flashScrollIndicatorTimer {
|
||||
flashScrollIndicatorTimer.invalidate()
|
||||
self.flashScrollIndicatorTimer = nil
|
||||
}
|
||||
|
||||
if start {
|
||||
let timer = Timer(timeInterval: 0.1, target: ListViewTimerProxy { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let flashScrollIndicatorTimer = strongSelf.flashScrollIndicatorTimer {
|
||||
flashScrollIndicatorTimer.invalidate()
|
||||
strongSelf.flashScrollIndicatorTimer = nil
|
||||
strongSelf.verticalScrollIndicator?.alpha = 0.0
|
||||
strongSelf.verticalScrollIndicator?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
|
||||
self.flashScrollIndicatorTimer = timer
|
||||
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
|
||||
} else {
|
||||
self.verticalScrollIndicator?.layer.removeAnimation(forKey: "opacity")
|
||||
self.verticalScrollIndicator?.alpha = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
private func headerItemsAreFlashing() -> Bool {
|
||||
//print("\(self.scroller.isDragging) || (\(self.scroller.isDecelerating) && \(self.isDeceleratingAfterTracking)) || \(self.flashNodesDelayTimer != nil)")
|
||||
return self.scroller.isDragging || (self.isDeceleratingAfterTracking) || self.flashNodesDelayTimer != nil
|
||||
@ -508,6 +542,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
self.lastContentOffsetTimestamp = 0.0
|
||||
self.resetHeaderItemsFlashTimer(start: false)
|
||||
self.updateHeaderItemsFlashing(animated: true)
|
||||
self.resetScrollIndicatorFlashTimer(start: false)
|
||||
|
||||
if self.snapToBottomInsetUntilFirstInteraction {
|
||||
self.snapToBottomInsetUntilFirstInteraction = false
|
||||
@ -521,10 +556,12 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
self.lastContentOffsetTimestamp = CACurrentMediaTime()
|
||||
self.isDeceleratingAfterTracking = true
|
||||
self.updateHeaderItemsFlashing(animated: true)
|
||||
self.resetScrollIndicatorFlashTimer(start: false)
|
||||
} else {
|
||||
self.isDeceleratingAfterTracking = false
|
||||
self.resetHeaderItemsFlashTimer(start: true)
|
||||
self.updateHeaderItemsFlashing(animated: true)
|
||||
self.resetScrollIndicatorFlashTimer(start: true)
|
||||
|
||||
self.lastContentOffsetTimestamp = 0.0
|
||||
self.didEndScrolling?()
|
||||
@ -536,6 +573,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
self.isDeceleratingAfterTracking = false
|
||||
self.resetHeaderItemsFlashTimer(start: true)
|
||||
self.updateHeaderItemsFlashing(animated: true)
|
||||
self.resetScrollIndicatorFlashTimer(start: true)
|
||||
self.didEndScrolling?()
|
||||
}
|
||||
|
||||
@ -1006,6 +1044,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
if itemNode.isHighlightedInOverlay {
|
||||
lowestOverlayNode = itemNode
|
||||
itemNode.view.superview?.bringSubview(toFront: itemNode.view)
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
verticalScrollIndicator.view.superview?.bringSubview(toFront: verticalScrollIndicator.view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1030,6 +1071,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
for (_, headerNode) in self.itemHeaderNodes {
|
||||
self.view.bringSubview(toFront: headerNode.view)
|
||||
}
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
verticalScrollIndicator.view.superview?.bringSubview(toFront: verticalScrollIndicator.view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1121,7 +1165,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
DispatchQueue.global().async(execute: f)
|
||||
}
|
||||
|
||||
private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: QueueLocalObject<ListViewItemNode>?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, params: ListViewItemLayoutParams, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (QueueLocalObject<ListViewItemNode>, ListViewItemNodeLayout, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
|
||||
private func nodeForItem(synchronous: Bool, synchronousLoads: Bool, item: ListViewItem, previousNode: QueueLocalObject<ListViewItemNode>?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, params: ListViewItemLayoutParams, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (QueueLocalObject<ListViewItemNode>, ListViewItemNodeLayout, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
|
||||
if let previousNode = previousNode {
|
||||
item.updateNode(async: { f in
|
||||
if synchronous {
|
||||
@ -1170,8 +1214,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
} else {
|
||||
self.async(f)
|
||||
}
|
||||
}, params: params, previousItem: previousItem, nextItem: nextItem, completion: { itemNode, apply in
|
||||
//assert(Queue.mainQueue().isCurrent())
|
||||
}, params: params, synchronousLoads: synchronousLoads, previousItem: previousItem, nextItem: nextItem, completion: { itemNode, apply in
|
||||
itemNode.index = index
|
||||
completion(QueueLocalObject(queue: Queue.mainQueue(), generate: { return itemNode }), ListViewItemNodeLayout(contentSize: itemNode.contentSize, insets: itemNode.insets), apply)
|
||||
})
|
||||
@ -1216,6 +1259,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
if let updateSizeAndInsets = updateSizeAndInsets , (self.items.count == 0 || (updateSizeAndInsets.size == self.visibleSize && updateSizeAndInsets.insets == self.insets)) {
|
||||
self.visibleSize = updateSizeAndInsets.size
|
||||
self.insets = updateSizeAndInsets.insets
|
||||
self.scrollIndicatorInsets = updateSizeAndInsets.scrollIndicatorInsets ?? self.insets
|
||||
self.ensureTopInsetForOverlayHighlightedItems = updateSizeAndInsets.ensureTopInsetForOverlayHighlightedItems
|
||||
|
||||
let wasIgnoringScrollingEvents = self.ignoreScrollingEvents
|
||||
@ -1438,7 +1482,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
print("deleteAndInsertItemsTransaction prepare \((CACurrentMediaTime() - startTime) * 1000.0) ms")
|
||||
}
|
||||
|
||||
self.fillMissingNodes(synchronous: options.contains(.Synchronous), animated: animated, inputAnimatedInsertIndices: animated ? insertedIndexSet : Set<Int>(), insertDirectionHints: insertDirectionHints, inputState: state, inputPreviousNodes: previousNodes, inputOperations: operations, inputCompletion: { updatedState, operations in
|
||||
self.fillMissingNodes(synchronous: options.contains(.Synchronous), synchronousLoads: options.contains(.PreferSynchronousResourceLoading), animated: animated, inputAnimatedInsertIndices: animated ? insertedIndexSet : Set<Int>(), insertDirectionHints: insertDirectionHints, inputState: state, inputPreviousNodes: previousNodes, inputOperations: operations, inputCompletion: { updatedState, operations in
|
||||
|
||||
if self.debugInfo {
|
||||
print("fillMissingNodes completion \((CACurrentMediaTime() - startTime) * 1000.0) ms")
|
||||
@ -1461,7 +1505,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
|
||||
updateIndices.subtract(explicitelyUpdateIndices)
|
||||
|
||||
self.updateNodes(synchronous: options.contains(.Synchronous), animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: updatedState, previousNodes: previousNodes, inputOperations: operations, completion: { updatedState, operations in
|
||||
self.updateNodes(synchronous: options.contains(.Synchronous), synchronousLoads: options.contains(.PreferSynchronousResourceLoading), animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: updatedState, previousNodes: previousNodes, inputOperations: operations, completion: { updatedState, operations in
|
||||
self.updateAdjacent(synchronous: options.contains(.Synchronous), animated: animated, state: updatedState, updateAdjacentItemsIndices: updateIndices, operations: operations, completion: { state, operations in
|
||||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
@ -1614,7 +1658,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
}
|
||||
}
|
||||
|
||||
private func fillMissingNodes(synchronous: Bool, animated: Bool, inputAnimatedInsertIndices: Set<Int>, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
private func fillMissingNodes(synchronous: Bool, synchronousLoads: Bool, animated: Bool, inputAnimatedInsertIndices: Set<Int>, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
let animatedInsertIndices = inputAnimatedInsertIndices
|
||||
var state = inputState
|
||||
var previousNodes = inputPreviousNodes
|
||||
@ -1649,7 +1693,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
let index = insertionItemIndexAndDirection.0
|
||||
let threadId = pthread_self()
|
||||
var tailRecurse = false
|
||||
self.nodeForItem(synchronous: synchronous, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), updateAnimation: updateAnimation, completion: { (node, layout, apply) in
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), updateAnimation: updateAnimation, completion: { (node, layout, apply) in
|
||||
|
||||
if pthread_equal(pthread_self(), threadId) != 0 && !tailRecurse {
|
||||
tailRecurse = true
|
||||
@ -1658,7 +1702,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
updatedState.insertNode(index, node: node, layout: layout, apply: apply, offsetDirection: insertionItemIndexAndDirection.1, animated: animated && animatedInsertIndices.contains(index), operations: &updatedOperations, itemCount: self.items.count)
|
||||
self.fillMissingNodes(synchronous: synchronous, animated: animated, inputAnimatedInsertIndices: animatedInsertIndices, insertDirectionHints: insertDirectionHints, inputState: updatedState, inputPreviousNodes: previousNodes, inputOperations: updatedOperations, inputCompletion: completion)
|
||||
self.fillMissingNodes(synchronous: synchronous, synchronousLoads: synchronousLoads, animated: animated, inputAnimatedInsertIndices: animatedInsertIndices, insertDirectionHints: insertDirectionHints, inputState: updatedState, inputPreviousNodes: previousNodes, inputOperations: updatedOperations, inputCompletion: completion)
|
||||
}
|
||||
})
|
||||
if !tailRecurse {
|
||||
@ -1673,7 +1717,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
}
|
||||
}
|
||||
|
||||
private func updateNodes(synchronous: Bool, animated: Bool, updateIndicesAndItems: [ListViewUpdateItem], inputState: ListViewState, previousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
private func updateNodes(synchronous: Bool, synchronousLoads: Bool, animated: Bool, updateIndicesAndItems: [ListViewUpdateItem], inputState: ListViewState, previousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
var state = inputState
|
||||
var operations = inputOperations
|
||||
var updateIndicesAndItems = updateIndicesAndItems
|
||||
@ -1685,11 +1729,11 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
} else {
|
||||
let updateItem = updateIndicesAndItems[0]
|
||||
if let previousNode = previousNodes[updateItem.index] {
|
||||
self.nodeForItem(synchronous: synchronous, item: updateItem.item, previousNode: previousNode, index: updateItem.index, previousItem: updateItem.index == 0 ? nil : self.items[updateItem.index - 1], nextItem: updateItem.index == (self.items.count - 1) ? nil : self.items[updateItem.index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), updateAnimation: animated ? .System(duration: insertionAnimationDuration) : .None, completion: { _, layout, apply in
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: updateItem.item, previousNode: previousNode, index: updateItem.index, previousItem: updateItem.index == 0 ? nil : self.items[updateItem.index - 1], nextItem: updateItem.index == (self.items.count - 1) ? nil : self.items[updateItem.index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), updateAnimation: animated ? .System(duration: insertionAnimationDuration) : .None, completion: { _, layout, apply in
|
||||
state.updateNodeAtItemIndex(updateItem.index, layout: layout, direction: updateItem.directionHint, animation: animated ? .System(duration: insertionAnimationDuration) : .None, apply: apply, operations: &operations)
|
||||
|
||||
updateIndicesAndItems.remove(at: 0)
|
||||
self.updateNodes(synchronous: synchronous, animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: state, previousNodes: previousNodes, inputOperations: operations, completion: completion)
|
||||
self.updateNodes(synchronous: synchronous, synchronousLoads: synchronousLoads, animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: state, previousNodes: previousNodes, inputOperations: operations, completion: completion)
|
||||
})
|
||||
break
|
||||
} else {
|
||||
@ -2008,6 +2052,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
self.insertSubnode(node, belowSubnode: itemNode)
|
||||
} else if let lowestNodeToInsertBelow = lowestNodeToInsertBelow {
|
||||
self.insertSubnode(node, belowSubnode: lowestNodeToInsertBelow)
|
||||
} else if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
self.insertSubnode(node, belowSubnode: verticalScrollIndicator)
|
||||
} else {
|
||||
self.addSubnode(node)
|
||||
}
|
||||
@ -2023,6 +2069,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
self.insertSubnode(node, belowSubnode: itemNode)
|
||||
} else if let lowestNodeToInsertBelow = lowestNodeToInsertBelow {
|
||||
self.insertSubnode(node, belowSubnode: lowestNodeToInsertBelow)
|
||||
} else if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
self.insertSubnode(node, belowSubnode: verticalScrollIndicator)
|
||||
} else {
|
||||
self.addSubnode(node)
|
||||
}
|
||||
@ -2049,8 +2097,12 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
} 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)
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
self.insertSubnode(referenceNode, belowSubnode: verticalScrollIndicator)
|
||||
} else {
|
||||
self.addSubnode(referenceNode)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
@ -2178,6 +2230,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
|
||||
if hadInserts, let reorderNode = self.reorderNode, reorderNode.supernode != nil {
|
||||
self.view.bringSubview(toFront: reorderNode.view)
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
verticalScrollIndicator.view.superview?.bringSubview(toFront: verticalScrollIndicator.view)
|
||||
}
|
||||
}
|
||||
|
||||
if self.debugInfo {
|
||||
@ -2249,7 +2304,6 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
self.stopScrolling()
|
||||
}
|
||||
|
||||
self.insertNodesInBatches(nodes: [], completion: {
|
||||
self.debugCheckMonotonity()
|
||||
|
||||
var sizeAndInsetsOffset: CGFloat = 0.0
|
||||
@ -2273,6 +2327,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
offsetFix += additionalScrollDistance
|
||||
|
||||
self.insets = updateSizeAndInsets.insets
|
||||
self.scrollIndicatorInsets = updateSizeAndInsets.scrollIndicatorInsets ?? self.insets
|
||||
self.ensureTopInsetForOverlayHighlightedItems = updateSizeAndInsets.ensureTopInsetForOverlayHighlightedItems
|
||||
self.visibleSize = updateSizeAndInsets.size
|
||||
|
||||
@ -2474,6 +2529,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
itemNode.frame = itemNode.frame.offsetBy(dx: 0.0, dy: offset)
|
||||
if let lowestNodeToInsertBelow = lowestNodeToInsertBelow {
|
||||
self.insertSubnode(itemNode, belowSubnode: lowestNodeToInsertBelow)
|
||||
} else if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
self.insertSubnode(itemNode, belowSubnode: verticalScrollIndicator)
|
||||
} else {
|
||||
self.addSubnode(itemNode)
|
||||
}
|
||||
@ -2484,9 +2541,13 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
if headerNode.supernode == nil {
|
||||
headerNode.frame = headerNode.frame.offsetBy(dx: 0.0, dy: offset)
|
||||
temporaryHeaderNodes.append(headerNode)
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
self.insertSubnode(headerNode, belowSubnode: verticalScrollIndicator)
|
||||
} else {
|
||||
self.addSubnode(headerNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animation: CABasicAnimation
|
||||
switch scrollToItem.curve {
|
||||
@ -2613,18 +2674,6 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
}
|
||||
}
|
||||
|
||||
completion()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func insertNodesInBatches(nodes: [ASDisplayNode], completion: () -> Void) {
|
||||
if nodes.count == 0 {
|
||||
completion()
|
||||
} else {
|
||||
for node in nodes {
|
||||
self.addSubnode(node)
|
||||
}
|
||||
completion()
|
||||
}
|
||||
}
|
||||
@ -2722,7 +2771,11 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
headerNode.updateInternalStickLocationDistanceFactor(stickLocationDistanceFactor, animated: false)
|
||||
self.itemHeaderNodes[id] = headerNode
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
self.insertSubnode(headerNode, belowSubnode: verticalScrollIndicator)
|
||||
} else {
|
||||
self.addSubnode(headerNode)
|
||||
}
|
||||
if animateInsertion {
|
||||
headerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
headerNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.3)
|
||||
@ -2912,9 +2965,85 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
}
|
||||
}
|
||||
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
var topIndexAndBoundary: (Int, CGFloat, CGFloat)?
|
||||
var bottomIndexAndBoundary: (Int, CGFloat, CGFloat)?
|
||||
for itemNode in self.itemNodes {
|
||||
if itemNode.apparentFrame.maxY > 0.0, let index = itemNode.index {
|
||||
topIndexAndBoundary = (index, itemNode.apparentFrame.minY, itemNode.apparentFrame.height)
|
||||
break
|
||||
}
|
||||
}
|
||||
for itemNode in self.itemNodes.reversed() {
|
||||
if itemNode.apparentFrame.minY <= self.visibleSize.height, let index = itemNode.index {
|
||||
bottomIndexAndBoundary = (index, itemNode.apparentFrame.maxY, itemNode.apparentFrame.height)
|
||||
break
|
||||
}
|
||||
}
|
||||
if let topIndexAndBoundary = topIndexAndBoundary, let bottomIndexAndBoundary = bottomIndexAndBoundary {
|
||||
let rangeItemCount = max(1, bottomIndexAndBoundary.0 - topIndexAndBoundary.0 + 1)
|
||||
//let visibleRangeHeight = max(0.0, bottomIndexAndBoundary.1 - topIndexAndBoundary.1)
|
||||
//let averageRangeItemHeight = visibleRangeHeight / CGFloat(rangeItemCount)
|
||||
let averageRangeItemHeight: CGFloat = 44.0
|
||||
|
||||
let visibleRangeHeight = CGFloat(rangeItemCount) * averageRangeItemHeight
|
||||
let upperItemsHeight = floor(averageRangeItemHeight * CGFloat(topIndexAndBoundary.0))
|
||||
let lowerItemsHeight = floor(averageRangeItemHeight * CGFloat(self.items.count - bottomIndexAndBoundary.0))
|
||||
let approximateContentHeight = upperItemsHeight + visibleRangeHeight + lowerItemsHeight
|
||||
|
||||
let convertedTopBoundary: CGFloat
|
||||
if topIndexAndBoundary.1 < 0.0 {
|
||||
convertedTopBoundary = topIndexAndBoundary.1 * averageRangeItemHeight / topIndexAndBoundary.2
|
||||
} else {
|
||||
convertedTopBoundary = topIndexAndBoundary.1
|
||||
}
|
||||
|
||||
var convertedBottomBoundary: CGFloat = 0.0
|
||||
if bottomIndexAndBoundary.1 > self.visibleSize.height {
|
||||
convertedBottomBoundary = (bottomIndexAndBoundary.1 - self.visibleSize.height) * averageRangeItemHeight / bottomIndexAndBoundary.2
|
||||
}
|
||||
convertedBottomBoundary += convertedTopBoundary + CGFloat(rangeItemCount) * averageRangeItemHeight
|
||||
|
||||
let approximateFirstItemOffset = convertedTopBoundary - upperItemsHeight
|
||||
let approximateLastItemOffset = convertedBottomBoundary
|
||||
|
||||
let approximateOffset = -approximateFirstItemOffset + self.insets.top
|
||||
let approximateBottomOffset = -approximateLastItemOffset + self.insets.top
|
||||
let indicatorInsets: CGFloat = 3.0
|
||||
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
//print("convertedTopBoundary = \(convertedTopBoundary), topIndexAndBoundary.1 = \(topIndexAndBoundary.1), upperItemsHeight = \(upperItemsHeight), approximateOffset = \(approximateOffset), approximateBottomOffset = \(approximateBottomOffset)")
|
||||
|
||||
let visibleHeightWithoutInsets = self.visibleSize.height - self.insets.top - self.insets.bottom
|
||||
let visibleHeightWithoutIndicatorInsets = visibleHeightWithoutInsets - indicatorInsets * 2.0
|
||||
|
||||
// visibleHeightWithoutIndicatorInsets -> approximateContentHeight
|
||||
// x -> approximateOffset
|
||||
// x = visibleHeightWithoutIndicatorInsets * approximateOffset / approximateContentHeight
|
||||
|
||||
// visibleHeightWithoutIndicatorInsets -> approximateContentHeight
|
||||
// x -> visibleHeightWithoutInsets
|
||||
|
||||
let indicatorOffset = ceilToScreenPixels(visibleHeightWithoutIndicatorInsets * approximateOffset / approximateContentHeight)
|
||||
let approximateIndicatorHeight = ceilToScreenPixels(visibleHeightWithoutIndicatorInsets * visibleHeightWithoutInsets / approximateContentHeight)
|
||||
|
||||
let minHeight: CGFloat = 6.0
|
||||
let indicatorHeight = max(minHeight, approximateIndicatorHeight)
|
||||
|
||||
var indicatorFrame = CGRect(origin: CGPoint(x: self.rotated ? indicatorInsets : (self.visibleSize.width - 3.0 - indicatorInsets), y: self.scrollIndicatorInsets.top + indicatorInsets + indicatorOffset), size: CGSize(width: 3.0, height: indicatorHeight))
|
||||
if indicatorFrame.minY < self.scrollIndicatorInsets.top + indicatorInsets {
|
||||
indicatorFrame.size.height -= self.scrollIndicatorInsets.top + indicatorInsets - indicatorFrame.minY
|
||||
indicatorFrame.origin.y = self.scrollIndicatorInsets.top + indicatorInsets
|
||||
indicatorFrame.size.height = max(minHeight, indicatorFrame.height)
|
||||
}
|
||||
if verticalScrollIndicator.isHidden {
|
||||
verticalScrollIndicator.isHidden = false
|
||||
verticalScrollIndicator.frame = indicatorFrame
|
||||
} else {
|
||||
verticalScrollIndicator.frame = indicatorFrame
|
||||
}
|
||||
} else {
|
||||
verticalScrollIndicator.isHidden = true
|
||||
}
|
||||
/*let size = self.visibleSize.height
|
||||
let range = computeVerticalScrollRange()
|
||||
let extent = computeVerticalScrollExtent()
|
||||
@ -2986,7 +3115,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
|
||||
let state = self.currentState()
|
||||
self.async {
|
||||
self.fillMissingNodes(synchronous: false, animated: false, inputAnimatedInsertIndices: [], insertDirectionHints: [:], inputState: state, inputPreviousNodes: [:], inputOperations: []) { state, operations in
|
||||
self.fillMissingNodes(synchronous: false, synchronousLoads: false, animated: false, inputAnimatedInsertIndices: [], insertDirectionHints: [:], inputState: state, inputPreviousNodes: [:], inputOperations: []) { state, operations in
|
||||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
updatedState.removeInvisibleNodes(&updatedOperations)
|
||||
@ -3489,6 +3618,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
if let itemHighlightOverlayBackground = self.itemHighlightOverlayBackground {
|
||||
itemHighlightOverlayBackground.view.superview?.bringSubview(toFront: itemHighlightOverlayBackground.view)
|
||||
}
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
verticalScrollIndicator.view.superview?.bringSubview(toFront: verticalScrollIndicator.view)
|
||||
}
|
||||
}
|
||||
|
||||
private func reorderHeaderNodeToFront(_ headerNode: ListViewItemHeaderNode) {
|
||||
@ -3496,5 +3628,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
||||
if let itemHighlightOverlayBackground = self.itemHighlightOverlayBackground {
|
||||
itemHighlightOverlayBackground.view.superview?.bringSubview(toFront: itemHighlightOverlayBackground.view)
|
||||
}
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
verticalScrollIndicator.view.superview?.bringSubview(toFront: verticalScrollIndicator.view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,13 +108,15 @@ public struct ListViewDeleteAndInsertOptions: OptionSet {
|
||||
public struct ListViewUpdateSizeAndInsets {
|
||||
public let size: CGSize
|
||||
public let insets: UIEdgeInsets
|
||||
public let scrollIndicatorInsets: UIEdgeInsets?
|
||||
public let duration: Double
|
||||
public let curve: ListViewAnimationCurve
|
||||
public let ensureTopInsetForOverlayHighlightedItems: CGFloat?
|
||||
|
||||
public init(size: CGSize, insets: UIEdgeInsets, duration: Double, curve: ListViewAnimationCurve, ensureTopInsetForOverlayHighlightedItems: CGFloat? = nil) {
|
||||
public init(size: CGSize, insets: UIEdgeInsets, scrollIndicatorInsets: UIEdgeInsets? = nil, duration: Double, curve: ListViewAnimationCurve, ensureTopInsetForOverlayHighlightedItems: CGFloat? = nil) {
|
||||
self.size = size
|
||||
self.insets = insets
|
||||
self.scrollIndicatorInsets = scrollIndicatorInsets
|
||||
self.duration = duration
|
||||
self.curve = curve
|
||||
self.ensureTopInsetForOverlayHighlightedItems = ensureTopInsetForOverlayHighlightedItems
|
||||
|
||||
@ -33,7 +33,7 @@ public struct ListViewItemConfigureNodeFlags: OptionSet {
|
||||
}
|
||||
|
||||
public protocol ListViewItem {
|
||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void)
|
||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> 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)
|
||||
|
||||
var accessoryItem: ListViewAccessoryItem? { get }
|
||||
|
||||
@ -32,6 +32,9 @@ public let UIScreenScale = UIScreen.main.scale
|
||||
public func floorToScreenPixels(_ value: CGFloat) -> CGFloat {
|
||||
return floor(value * UIScreenScale) / UIScreenScale
|
||||
}
|
||||
public func ceilToScreenPixels(_ value: CGFloat) -> CGFloat {
|
||||
return ceil(value * UIScreenScale) / UIScreenScale
|
||||
}
|
||||
|
||||
public let UIScreenPixel = 1.0 / UIScreenScale
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user