From bffb8eb8ca39b9be2fcd161ae1c876adbe5b0fec Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 17 Sep 2018 19:15:29 +0100 Subject: [PATCH] no message --- Display/ListView.swift | 75 ++++++++++++++++--------- Display/ListViewIntermediateState.swift | 10 ++-- Display/ListViewItem.swift | 2 +- Display/NativeWindowHostView.swift | 16 +++--- 4 files changed, 63 insertions(+), 40 deletions(-) diff --git a/Display/ListView.swift b/Display/ListView.swift index 5b7ad477cc..999db10275 100644 --- a/Display/ListView.swift +++ b/Display/ListView.swift @@ -199,7 +199,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel public final var beganInteractiveDragging: () -> Void = { } public final var didEndScrolling: (() -> Void)? - public final var reorderItem: (Int, Int, Any?) -> Void = { _, _, _ in } + public final var reorderItem: (Int, Int, Any?) -> Signal = { _, _, _ in return .single(false) } private final var animations: [ListViewAnimation] = [] private final var actionsForVSync: [() -> ()] = [] @@ -216,16 +216,10 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel private var flashNodesDelayTimer: Foundation.Timer? private var highlightedItemIndex: Int? private var reorderNode: ListViewReorderingItemNode? + private var reorderFeedback: HapticFeedback? + private var reorderFeedbackDisposable: MetaDisposable? private let waitingForNodesDisposable = MetaDisposable() - - public func reportDurationInMS(duration: Int, smallDropEvent: Double, largeDropEvent: Double) { - print("reportDurationInMS duration: \(duration), smallDropEvent: \(smallDropEvent), largeDropEvent: \(largeDropEvent)") - } - - public func reportStackTrace(stack: String!, withSlide slide: String!) { - NSLog("reportStackTrace stack: \(stack)\n\nslide: \(slide)") - } override public init() { class DisplayLinkProxy: NSObject { @@ -331,6 +325,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } self.waitingForNodesDisposable.dispose() + self.reorderFeedbackDisposable?.dispose() } private func displayLinkEvent() { @@ -435,7 +430,19 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if reorderNode.currentState?.0 != reorderItemIndex || reorderNode.currentState?.1 != toIndex { reorderNode.currentState = (reorderItemIndex, toIndex) //print("reorder \(reorderItemIndex) to \(toIndex) offset \(offset)") - self.reorderItem(reorderItemIndex, toIndex, self.opaqueTransactionState) + if self.reorderFeedbackDisposable == nil { + self.reorderFeedbackDisposable = MetaDisposable() + } + self.reorderFeedbackDisposable?.set((self.reorderItem(reorderItemIndex, toIndex, self.opaqueTransactionState) + |> deliverOnMainQueue).start(next: { [weak self] value in + guard let strongSelf = self, value else { + return + } + if strongSelf.reorderFeedback == nil { + strongSelf.reorderFeedback = HapticFeedback() + } + strongSelf.reorderFeedback?.tap() + })) } } } @@ -1098,7 +1105,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?, params: ListViewItemLayoutParams, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNode, ListViewItemNodeLayout, @escaping () -> (Signal?, () -> Void)) -> Void) { + private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: QueueLocalObject?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, params: ListViewItemLayoutParams, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (QueueLocalObject, ListViewItemNodeLayout, @escaping () -> (Signal?, () -> Void)) -> Void) { if let previousNode = previousNode { item.updateNode(async: { f in if synchronous { @@ -1106,12 +1113,16 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } else { self.async(f) } - }, node: previousNode, params: params, previousItem: previousItem, nextItem: nextItem, animation: updateAnimation, completion: { (layout, apply) in + }, 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, { - previousNode.index = index + assert(Queue.mainQueue().isCurrent()) + previousNode.with({ $0.index = index }) apply() }) }) @@ -1119,7 +1130,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel self.async { completion(previousNode, layout, { return (nil, { - previousNode.index = index + assert(Queue.mainQueue().isCurrent()) + previousNode.with({ $0.index = index }) apply() }) }) @@ -1128,7 +1140,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } else { completion(previousNode, layout, { return (nil, { - previousNode.index = index + assert(Queue.mainQueue().isCurrent()) + previousNode.with({ $0.index = index }) apply() }) }) @@ -1142,8 +1155,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel self.async(f) } }, params: params, previousItem: previousItem, nextItem: nextItem, completion: { itemNode, apply in + //assert(Queue.mainQueue().isCurrent()) itemNode.index = index - completion(itemNode, ListViewItemNodeLayout(contentSize: itemNode.contentSize, insets: itemNode.insets), apply) + completion(QueueLocalObject(queue: Queue.mainQueue(), generate: { return itemNode }), ListViewItemNodeLayout(contentSize: itemNode.contentSize, insets: itemNode.insets), apply) }) } } @@ -1153,7 +1167,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel nodes.reserveCapacity(self.itemNodes.count) for node in self.itemNodes { if let index = node.index { - nodes.append(.Node(index: index, frame: node.apparentFrame, referenceNode: node)) + nodes.append(.Node(index: index, frame: node.apparentFrame, referenceNode: QueueLocalObject(queue: Queue.mainQueue(), generate: { + return node + }))) } else { nodes.append(.Placeholder(frame: node.apparentFrame)) } @@ -1226,13 +1242,13 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } } - var previousNodes: [Int: ListViewItemNode] = [:] + var previousNodes: [Int: QueueLocalObject] = [:] for insertedItem in sortedIndicesAndItems { self.items.insert(insertedItem.item, at: insertedItem.index) if let previousIndex = insertedItem.previousIndex { for itemNode in self.itemNodes { if itemNode.index == previousIndex { - previousNodes[insertedItem.index] = itemNode + previousNodes[insertedItem.index] = QueueLocalObject(queue: Queue.mainQueue(), generate: { return itemNode }) } } } @@ -1242,7 +1258,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel self.items[updatedItem.index] = updatedItem.item for itemNode in self.itemNodes { if itemNode.index == updatedItem.previousIndex { - previousNodes[updatedItem.index] = itemNode + previousNodes[updatedItem.index] = QueueLocalObject(queue: Queue.mainQueue(), generate: { return itemNode }) break } } @@ -1539,7 +1555,10 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } else { self.async(f) } - }, node: referenceNode, params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), previousItem: index == 0 ? nil : self.items[index - 1], nextItem: index == self.items.count - 1 ? nil : self.items[index + 1], animation: updateAnimation, completion: { layout, apply in + }, node: { + assert(Queue.mainQueue().isCurrent()) + return referenceNode.syncWith({ $0 })! + }, params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), previousItem: index == 0 ? nil : self.items[index - 1], nextItem: index == self.items.count - 1 ? nil : self.items[index + 1], animation: updateAnimation, completion: { layout, apply in var updatedState = state var updatedOperations = operations @@ -1579,7 +1598,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } } - private func fillMissingNodes(synchronous: Bool, animated: Bool, inputAnimatedInsertIndices: Set, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: ListViewItemNode], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) { + private func fillMissingNodes(synchronous: Bool, animated: Bool, inputAnimatedInsertIndices: Set, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: QueueLocalObject], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) { let animatedInsertIndices = inputAnimatedInsertIndices var state = inputState var previousNodes = inputPreviousNodes @@ -1638,7 +1657,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } } - private func updateNodes(synchronous: Bool, animated: Bool, updateIndicesAndItems: [ListViewUpdateItem], inputState: ListViewState, previousNodes: [Int: ListViewItemNode], inputOperations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) { + private func updateNodes(synchronous: Bool, animated: Bool, updateIndicesAndItems: [ListViewUpdateItem], inputState: ListViewState, previousNodes: [Int: QueueLocalObject], inputOperations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) { var state = inputState var operations = inputOperations var updateIndicesAndItems = updateIndicesAndItems @@ -1938,7 +1957,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel var takenPreviousNodes = Set() for operation in operations { if case let .InsertNode(_, _, _, node, _, _) = operation { - takenPreviousNodes.insert(node) + takenPreviousNodes.insert(node.syncWith({ $0 })!) } } @@ -1946,7 +1965,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel for operation in operations { switch operation { - case let .InsertNode(index, offsetDirection, nodeAnimated, node, layout, apply): + case let .InsertNode(index, offsetDirection, nodeAnimated, nodeObject, layout, apply): + let node = nodeObject.syncWith({ $0 })! var previousFrame: CGRect? for (previousNode, frame) in previousApparentFrames { if previousNode === node { @@ -1989,10 +2009,12 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel } } } - case let .InsertDisappearingPlaceholder(index, referenceNode, offsetDirection): + case let .InsertDisappearingPlaceholder(index, referenceNodeObject, offsetDirection): var height: CGFloat? var previousLayout: ListViewItemNodeLayout? + let referenceNode = referenceNodeObject.syncWith({ $0 })! + for (node, previousFrame) in previousApparentFrames { if node === referenceNode { height = previousFrame.size.height @@ -2004,7 +2026,6 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel if let height = height, let previousLayout = previousLayout { if takenPreviousNodes.contains(referenceNode) { let tempNode = ListViewTempItemNode(layerBacked: true) - //referenceNode.copyHeightAndApparentHeightAnimations(to: tempNode) 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) } else { referenceNode.index = nil diff --git a/Display/ListViewIntermediateState.swift b/Display/ListViewIntermediateState.swift index b8f48c166f..184160ffcb 100644 --- a/Display/ListViewIntermediateState.swift +++ b/Display/ListViewIntermediateState.swift @@ -203,14 +203,14 @@ struct TransactionState { struct PendingNode { let index: Int - let node: ListViewItemNode + let node: QueueLocalObject let apply: () -> (Signal?, () -> Void) let frame: CGRect let apparentHeight: CGFloat } enum ListViewStateNode { - case Node(index: Int, frame: CGRect, referenceNode: ListViewItemNode?) + case Node(index: Int, frame: CGRect, referenceNode: QueueLocalObject?) case Placeholder(frame: CGRect) var index: Int? { @@ -687,7 +687,7 @@ struct ListViewState { return height } - mutating func insertNode(_ itemIndex: Int, node: ListViewItemNode, 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?, () -> Void), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) { let (insertionOrigin, insertionIndex) = self.nodeInsertionPointAndIndex(itemIndex) let nodeOrigin: CGPoint @@ -848,8 +848,8 @@ struct ListViewState { } enum ListViewStateOperation { - case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (Signal?, () -> Void)) - case InsertDisappearingPlaceholder(index: Int, referenceNode: ListViewItemNode, offsetDirection: ListViewInsertionOffsetDirection) + case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, node: QueueLocalObject, layout: ListViewItemNodeLayout, apply: () -> (Signal?, () -> 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)) diff --git a/Display/ListViewItem.swift b/Display/ListViewItem.swift index 3e83961725..dead8c13c0 100644 --- a/Display/ListViewItem.swift +++ b/Display/ListViewItem.swift @@ -34,7 +34,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)) -> Void) - func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> 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 } var headerAccessoryItem: ListViewAccessoryItem? { get } diff --git a/Display/NativeWindowHostView.swift b/Display/NativeWindowHostView.swift index 8c4871553d..9ab58e2eeb 100644 --- a/Display/NativeWindowHostView.swift +++ b/Display/NativeWindowHostView.swift @@ -92,14 +92,20 @@ private final class NativeWindow: UIWindow, WindowHost { var cancelInteractiveKeyboardGesturesImpl: (() -> Void)? var forEachControllerImpl: (((ViewController) -> Void) -> Void)? - private var frameTransition: ContainedViewLayoutTransition? - override var frame: CGRect { get { return super.frame } set(value) { let sizeUpdated = super.frame.size != value.size - if sizeUpdated, let transition = self.frameTransition, case let .animated(duration, curve) = transition { + + var frameTransition: ContainedViewLayoutTransition = .immediate + if #available(iOSApplicationExtension 9.0, *) { + let duration = UIView.inheritedAnimationDuration + if !duration.isZero { + frameTransition = .animated(duration: duration, curve: .easeInOut) + } + } + if sizeUpdated, case let .animated(duration, curve) = frameTransition { let previousFrame = super.frame super.frame = value self.layer.animateFrame(from: previousFrame, to: value, duration: duration, timingFunction: curve.timingFunction) @@ -149,11 +155,7 @@ private final class NativeWindow: UIWindow, WindowHost { override func _update(toInterfaceOrientation arg1: Int32, duration arg2: Double, force arg3: Bool) { self.updateIsUpdatingOrientationLayout?(true) - if !arg2.isZero { - self.frameTransition = .animated(duration: arg2, curve: .easeInOut) - } super._update(toInterfaceOrientation: arg1, duration: arg2, force: arg3) - self.frameTransition = nil self.updateIsUpdatingOrientationLayout?(false) self.updateToInterfaceOrientation?()