diff --git a/submodules/ContextUI/Sources/PinchController.swift b/submodules/ContextUI/Sources/PinchController.swift index c08bd4a6b1..997498b4d5 100644 --- a/submodules/ContextUI/Sources/PinchController.swift +++ b/submodules/ContextUI/Sources/PinchController.swift @@ -239,6 +239,7 @@ private final class PinchControllerNode: ViewControllerTracingNode { private var initialSourceFrame: CGRect? private let clippingNode: ASDisplayNode + private let scrollingContainer: ASDisplayNode private let sourceNode: PinchSourceContainerNode private let getContentAreaInScreenSpace: () -> CGRect @@ -262,10 +263,13 @@ private final class PinchControllerNode: ViewControllerTracingNode { self.clippingNode = ASDisplayNode() self.clippingNode.clipsToBounds = true + self.scrollingContainer = ASDisplayNode() + super.init() self.addSubnode(self.dimNode) self.addSubnode(self.clippingNode) + self.clippingNode.addSubnode(self.scrollingContainer) self.sourceNode.deactivate = { [weak self] in guard let strongSelf = self else { @@ -312,10 +316,10 @@ private final class PinchControllerNode: ViewControllerTracingNode { } func animateIn() { - let convertedFrame = convertFrame(self.sourceNode.contentNode.frame, from: self.sourceNode.view, to: self.view) + let convertedFrame = convertFrame(self.sourceNode.bounds, from: self.sourceNode.view, to: self.view) self.sourceNode.contentNode.frame = convertedFrame self.initialSourceFrame = convertedFrame - self.clippingNode.addSubnode(self.sourceNode.contentNode) + self.scrollingContainer.addSubnode(self.sourceNode.contentNode) var updatedContentAreaInScreenSpace = self.getContentAreaInScreenSpace() updatedContentAreaInScreenSpace.origin.x = 0.0 @@ -326,17 +330,25 @@ private final class PinchControllerNode: ViewControllerTracingNode { } func animateOut(completion: @escaping () -> Void) { + self.isAnimatingOut = true + let performCompletion: () -> Void = { [weak self] in guard let strongSelf = self else { return } + strongSelf.isAnimatingOut = false + strongSelf.sourceNode.restoreToNaturalSize() strongSelf.sourceNode.addSubnode(strongSelf.sourceNode.contentNode) completion() } + let convertedFrame = convertFrame(self.sourceNode.bounds, from: self.sourceNode.view, to: self.view) + self.sourceNode.contentNode.frame = convertedFrame + self.initialSourceFrame = convertedFrame + if let (scale, pinchLocation, offset) = self.sourceNode.gesture.currentTransform, let initialSourceFrame = self.initialSourceFrame { let duration = 0.3 let transitionCurve: ContainedViewLayoutTransitionCurve = .easeInOut @@ -379,6 +391,13 @@ private final class PinchControllerNode: ViewControllerTracingNode { } } + func addRelativeContentOffset(_ offset: CGPoint, transition: ContainedViewLayoutTransition) { + if self.isAnimatingOut { + self.scrollingContainer.bounds = self.scrollingContainer.bounds.offsetBy(dx: 0.0, dy: offset.y) + transition.animateOffsetAdditive(node: self.scrollingContainer, offset: -offset.y) + } + } + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { return nil } @@ -450,4 +469,8 @@ public final class PinchController: ViewController, StandalonePresentableControl }) } } + + public func addRelativeContentOffset(_ offset: CGPoint, transition: ContainedViewLayoutTransition) { + self.controllerNode.addRelativeContentOffset(offset, transition: transition) + } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index db0430b55c..cc7cb5115d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -356,6 +356,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private weak var sendMessageActionsController: ChatSendMessageActionSheetController? private var searchResultsController: ChatSearchResultsController? + + private weak var currentPinchController: PinchController? + private weak var currentPinchSourceItemNode: ListViewItemNode? private var screenCaptureManager: ScreenCaptureDetectionManager? private let chatAdditionalDataDisposable = MetaDisposable() @@ -920,6 +923,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } + + var sourceItemNode: ListViewItemNode? + strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in + guard let itemNode = itemNode as? ListViewItemNode else { + return + } + if sourceNode.view.isDescendant(of: itemNode.view) { + sourceItemNode = itemNode + } + } + let pinchController = PinchController(sourceNode: sourceNode, getContentAreaInScreenSpace: { guard let strongSelf = self else { return CGRect() @@ -927,6 +941,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return strongSelf.chatDisplayNode.view.convert(strongSelf.chatDisplayNode.frameForVisibleArea(), to: nil) }) + strongSelf.currentPinchController = pinchController + strongSelf.currentPinchSourceItemNode = sourceItemNode strongSelf.window?.presentInGlobalOverlay(pinchController) }, openMessageContextActions: { message, node, rect, gesture in gesture?.cancel() @@ -4017,21 +4033,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } - for (tooltipScreen, tooltipItemNode) in strongSelf.currentMessageTooltipScreens { - if let itemNode = itemNode { - if itemNode === tooltipItemNode { - tooltipScreen.addRelativeScrollingOffset(-offset, transition: transition) - } - } else { - tooltipScreen.addRelativeScrollingOffset(-offset, transition: transition) - } - } - } - - self.chatDisplayNode.historyNode.didScrollWithOffset = { [weak self] offset, _, _ in - guard let strongSelf = self else { - return - } if offset > 0.0 { if var scrolledToMessageIdValue = strongSelf.scrolledToMessageIdValue { @@ -4041,6 +4042,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else if offset < 0.0 { strongSelf.scrolledToMessageIdValue = nil } + + if let currentPinchSourceItemNode = strongSelf.currentPinchSourceItemNode { + if let itemNode = itemNode { + if itemNode === currentPinchSourceItemNode { + strongSelf.currentPinchController?.addRelativeContentOffset(CGPoint(x: 0.0, y: -offset), transition: transition) + } + } else { + strongSelf.currentPinchController?.addRelativeContentOffset(CGPoint(x: 0.0, y: -offset), transition: transition) + } + } } if case .pinnedMessages = self.presentationInterfaceState.subject {