mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-02 12:48:45 +00:00
Pinch dismiss with scrolling
This commit is contained in:
parent
cee549cb2a
commit
bfcb7e6e10
@ -239,6 +239,7 @@ private final class PinchControllerNode: ViewControllerTracingNode {
|
|||||||
private var initialSourceFrame: CGRect?
|
private var initialSourceFrame: CGRect?
|
||||||
|
|
||||||
private let clippingNode: ASDisplayNode
|
private let clippingNode: ASDisplayNode
|
||||||
|
private let scrollingContainer: ASDisplayNode
|
||||||
|
|
||||||
private let sourceNode: PinchSourceContainerNode
|
private let sourceNode: PinchSourceContainerNode
|
||||||
private let getContentAreaInScreenSpace: () -> CGRect
|
private let getContentAreaInScreenSpace: () -> CGRect
|
||||||
@ -262,10 +263,13 @@ private final class PinchControllerNode: ViewControllerTracingNode {
|
|||||||
self.clippingNode = ASDisplayNode()
|
self.clippingNode = ASDisplayNode()
|
||||||
self.clippingNode.clipsToBounds = true
|
self.clippingNode.clipsToBounds = true
|
||||||
|
|
||||||
|
self.scrollingContainer = ASDisplayNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.dimNode)
|
self.addSubnode(self.dimNode)
|
||||||
self.addSubnode(self.clippingNode)
|
self.addSubnode(self.clippingNode)
|
||||||
|
self.clippingNode.addSubnode(self.scrollingContainer)
|
||||||
|
|
||||||
self.sourceNode.deactivate = { [weak self] in
|
self.sourceNode.deactivate = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -312,10 +316,10 @@ private final class PinchControllerNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateIn() {
|
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.sourceNode.contentNode.frame = convertedFrame
|
||||||
self.initialSourceFrame = convertedFrame
|
self.initialSourceFrame = convertedFrame
|
||||||
self.clippingNode.addSubnode(self.sourceNode.contentNode)
|
self.scrollingContainer.addSubnode(self.sourceNode.contentNode)
|
||||||
|
|
||||||
var updatedContentAreaInScreenSpace = self.getContentAreaInScreenSpace()
|
var updatedContentAreaInScreenSpace = self.getContentAreaInScreenSpace()
|
||||||
updatedContentAreaInScreenSpace.origin.x = 0.0
|
updatedContentAreaInScreenSpace.origin.x = 0.0
|
||||||
@ -326,17 +330,25 @@ private final class PinchControllerNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateOut(completion: @escaping () -> Void) {
|
func animateOut(completion: @escaping () -> Void) {
|
||||||
|
self.isAnimatingOut = true
|
||||||
|
|
||||||
let performCompletion: () -> Void = { [weak self] in
|
let performCompletion: () -> Void = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.isAnimatingOut = false
|
||||||
|
|
||||||
strongSelf.sourceNode.restoreToNaturalSize()
|
strongSelf.sourceNode.restoreToNaturalSize()
|
||||||
strongSelf.sourceNode.addSubnode(strongSelf.sourceNode.contentNode)
|
strongSelf.sourceNode.addSubnode(strongSelf.sourceNode.contentNode)
|
||||||
|
|
||||||
completion()
|
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 {
|
if let (scale, pinchLocation, offset) = self.sourceNode.gesture.currentTransform, let initialSourceFrame = self.initialSourceFrame {
|
||||||
let duration = 0.3
|
let duration = 0.3
|
||||||
let transitionCurve: ContainedViewLayoutTransitionCurve = .easeInOut
|
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? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
return nil
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -356,6 +356,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
private weak var sendMessageActionsController: ChatSendMessageActionSheetController?
|
private weak var sendMessageActionsController: ChatSendMessageActionSheetController?
|
||||||
private var searchResultsController: ChatSearchResultsController?
|
private var searchResultsController: ChatSearchResultsController?
|
||||||
|
|
||||||
|
private weak var currentPinchController: PinchController?
|
||||||
|
private weak var currentPinchSourceItemNode: ListViewItemNode?
|
||||||
|
|
||||||
private var screenCaptureManager: ScreenCaptureDetectionManager?
|
private var screenCaptureManager: ScreenCaptureDetectionManager?
|
||||||
private let chatAdditionalDataDisposable = MetaDisposable()
|
private let chatAdditionalDataDisposable = MetaDisposable()
|
||||||
@ -920,6 +923,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
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: {
|
let pinchController = PinchController(sourceNode: sourceNode, getContentAreaInScreenSpace: {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return CGRect()
|
return CGRect()
|
||||||
@ -927,6 +941,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
return strongSelf.chatDisplayNode.view.convert(strongSelf.chatDisplayNode.frameForVisibleArea(), to: nil)
|
return strongSelf.chatDisplayNode.view.convert(strongSelf.chatDisplayNode.frameForVisibleArea(), to: nil)
|
||||||
})
|
})
|
||||||
|
strongSelf.currentPinchController = pinchController
|
||||||
|
strongSelf.currentPinchSourceItemNode = sourceItemNode
|
||||||
strongSelf.window?.presentInGlobalOverlay(pinchController)
|
strongSelf.window?.presentInGlobalOverlay(pinchController)
|
||||||
}, openMessageContextActions: { message, node, rect, gesture in
|
}, openMessageContextActions: { message, node, rect, gesture in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
@ -4017,21 +4033,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
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 offset > 0.0 {
|
||||||
if var scrolledToMessageIdValue = strongSelf.scrolledToMessageIdValue {
|
if var scrolledToMessageIdValue = strongSelf.scrolledToMessageIdValue {
|
||||||
@ -4041,6 +4042,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
} else if offset < 0.0 {
|
} else if offset < 0.0 {
|
||||||
strongSelf.scrolledToMessageIdValue = nil
|
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 {
|
if case .pinnedMessages = self.presentationInterfaceState.subject {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user