Home telegram - listView
Post
Cancel

telegram - listView

node for item

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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>?, (ListViewItemApply) -> Void)) -> Void) {
    if let previousNode = previousNode {
      // alreay initialized
      // updateNode
        item.updateNode(async: { f in
            if synchronous {
                f()
            } else {
                self.async(f)
            }
        }, node: {
            assert(Queue.mainQueue().isCurrent())
            return previousNode.syncWith({ $0 })!
        }, params: params, previousItem: previousItem, nextItem: nextItem, animation: updateAnimation, completion: { (layout, apply) in
            if Thread.isMainThread {
                if synchronous {
                    completion(previousNode, layout, {
                        return (nil, { info in
                            assert(Queue.mainQueue().isCurrent())
                            previousNode.with({ $0.index = index })
                            apply(info)
                        })
                    })
                } else {
                    self.async {
                        completion(previousNode, layout, {
                            return (nil, { info in
                                assert(Queue.mainQueue().isCurrent())
                                previousNode.with({ $0.index = index })
                                apply(info)
                            })
                        })
                    }
                }
            } else {
                completion(previousNode, layout, {
                    return (nil, { info in
                        assert(Queue.mainQueue().isCurrent())
                        previousNode.with({ $0.index = index })
                        apply(info)
                    })
                })
            }
        })
    } else {
        item.nodeConfiguredForParams(async: { f in
            if synchronous {
                f()
            } else {
                self.async(f)
            }
        }, 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)
        })
    }
}

fillMissingNodes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
    var operations = inputOperations
    let completion = inputCompletion
    let updateAnimation: ListViewItemUpdateAnimation = animated ? .System(duration: insertionAnimationDuration) : .None

    if state.nodes.count > 1000 {
        print("state.nodes.count > 1000")
    }

    while true {
        if self.items.count == 0 {
            completion(state, operations)
            break
        } else {
            var insertionItemIndexAndDirection: (Int, ListViewInsertionOffsetDirection)?

            if self.debugInfo {
                assert(true)
            }

            if let insertionPoint = state.insertionPoint(insertDirectionHints, itemCount: self.items.count) {
                insertionItemIndexAndDirection = (insertionPoint.index, insertionPoint.direction)
            }

            if self.debugInfo {
                print("insertionItemIndexAndDirection \(String(describing: insertionItemIndexAndDirection))")
            }

            if let insertionItemIndexAndDirection = insertionItemIndexAndDirection {
                let index = insertionItemIndexAndDirection.0
                let threadId = pthread_self()
                var tailRecurse = false
                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
                        state.insertNode(index, node: node, layout: layout, apply: apply, offsetDirection: insertionItemIndexAndDirection.1, animated: animated && animatedInsertIndices.contains(index), operations: &operations, itemCount: self.items.count)
                    } else {
                        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, synchronousLoads: synchronousLoads, animated: animated, inputAnimatedInsertIndices: animatedInsertIndices, insertDirectionHints: insertDirectionHints, inputState: updatedState, inputPreviousNodes: previousNodes, inputOperations: updatedOperations, inputCompletion: completion)
                    }
                })
                if !tailRecurse {
                    tailRecurse = true
                    break
                }
            } else {
                completion(state, operations)
                break
            }
        }
    }
}

updateVisibleItemsTransaction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private func updateVisibleItemsTransaction(synchronous: Bool, completion: @escaping () -> Void) {
    if self.items.count == 0 && self.itemNodes.count == 0 {
        completion()
        return
    }
    var i = 0
    while i < self.itemNodes.count {
        let node = self.itemNodes[i]
        if node.index == nil && node.apparentHeight <= CGFloat.ulpOfOne {
            self.removeItemNodeAtIndex(i)
        } else {
            i += 1
        }
    }

    let state = self.currentState()

    let begin: () -> Void = {
      // fillMissingNodes based on current state
      // no `insertDirectionHints`
      // no `inputAnimatedInsertIndices`
      // no `inputPreviousNodes`
      // no `inputOperations`
        self.fillMissingNodes(synchronous: synchronous, synchronousLoads: false, animated: false, inputAnimatedInsertIndices: [], insertDirectionHints: [:], inputState: state, inputPreviousNodes: [:], inputOperations: []) { state, operations in
            var updatedState = state
            var updatedOperations = operations
            updatedState.removeInvisibleNodes(&updatedOperations)
            self.dispatchOnVSync {
                self.replayOperations(animated: false, animateAlpha: false, animateCrossfade: false, synchronous: false, animateTopItemVerticalOrigin: false, operations: updatedOperations, requestItemInsertionAnimationsIndices: Set(), scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemIndex: nil, updateOpaqueState: nil, completion: completion)
            }
        }
    }
    if synchronous {
        begin()
    } else {
        self.async {
            begin()
        }
    }
}

updateVisibleItemRange

1
2
3
4
5
6
7
8
private func updateVisibleItemRange(force: Bool = false) {
    let currentRange = self.immediateDisplayedItemRange()
    
    if currentRange != self.displayedItemRange || force {
        self.displayedItemRange = currentRange
        self.displayedItemRangeChanged(currentRange, self.opaqueTransactionState)
    }
}

immediateDisplayedItemRange

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
private func immediateDisplayedItemRange() -> ListViewDisplayedItemRange {
    var loadedRange: ListViewItemRange?
    var visibleRange: ListViewVisibleItemRange?
    if self.itemNodes.count != 0 {
        var firstIndex: (nodeIndex: Int, index: Int)?
        var lastIndex: (nodeIndex: Int, index: Int)?

      // find the first index
        var i = 0
        while i < self.itemNodes.count {
            if let index = self.itemNodes[i].index {
                firstIndex = (i, index)
                break
            }
            i += 1
        }
      
      // find the last index
        i = self.itemNodes.count - 1
        while i >= 0 {
            if let index = self.itemNodes[i].index {
                lastIndex = (i, index)
                break
            }
            i -= 1
        }
        if let firstIndex = firstIndex, let lastIndex = lastIndex {
          // find first visible index
          // frame.maxY >= self.insets.top && frame.minY < self.visibleSize.height + self.insets.bottom
            var firstVisibleIndex: (Int, Bool)?
            for i in firstIndex.nodeIndex ... lastIndex.nodeIndex {
                if let index = self.itemNodes[i].index {
                    let frame = self.itemNodes[i].apparentFrame
                    if frame.maxY >= self.insets.top && frame.minY < self.visibleSize.height + self.insets.bottom {
                        firstVisibleIndex = (index, frame.minY >= self.insets.top - 10.0)
                        break
                    }
                }
            }

            if let firstVisibleIndex = firstVisibleIndex {
              // find last visible index
              // frame.maxY >= self.insets.top && frame.minY < self.visibleSize.height - self.insets.bottom
                var lastVisibleIndex: Int?
                for i in (firstIndex.nodeIndex ... lastIndex.nodeIndex).reversed() {
                    if let index = self.itemNodes[i].index {
                        let frame = self.itemNodes[i].apparentFrame
                        if frame.maxY >= self.insets.top && frame.minY < self.visibleSize.height - self.insets.bottom {
                            lastVisibleIndex = index
                            break
                        }
                    }
                }

                if let lastVisibleIndex = lastVisibleIndex {
                  // visible range
                    visibleRange = ListViewVisibleItemRange(firstIndex: firstVisibleIndex.0, firstIndexFullyVisible: firstVisibleIndex.1, lastIndex: lastVisibleIndex)
                }
            }
// loaded range
            loadedRange = ListViewItemRange(firstIndex: firstIndex.index, lastIndex: lastIndex.index)
        }
    }

    return ListViewDisplayedItemRange(loadedRange: loadedRange, visibleRange: visibleRange)
}

displayedItemRangeChanged

1
public final var displayedItemRangeChanged: (ListViewDisplayedItemRange, Any?) -> Void = { _, _ in }

current state

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private func currentState() -> ListViewState {
    var nodes: [ListViewStateNode] = []
    nodes.reserveCapacity(self.itemNodes.count)
    for node in self.itemNodes {
        if let index = node.index {
            nodes.append(.Node(index: index, frame: node.apparentFrame, referenceNode: QueueLocalObject(queue: Queue.mainQueue(), generate: {
                return node
            })))
        } else {
            nodes.append(.Placeholder(frame: node.apparentFrame))
        }
    }
    return ListViewState(insets: self.insets, visibleSize: self.visibleSize, invisibleInset: self.invisibleInset, nodes: nodes, scrollPosition: nil, stationaryOffset: nil, stackFromBottom: self.stackFromBottom)
}
This post is licensed under CC BY 4.0 by the author.