diff --git a/submodules/TelegramUI/Components/Chat/ChatInputAccessoryPanel/Sources/ChatInputAccessoryPanel.swift b/submodules/TelegramUI/Components/Chat/ChatInputAccessoryPanel/Sources/ChatInputAccessoryPanel.swift index d6ac3cde01..13d7af877b 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputAccessoryPanel/Sources/ChatInputAccessoryPanel.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputAccessoryPanel/Sources/ChatInputAccessoryPanel.swift @@ -39,6 +39,22 @@ public final class ChatInputAccessoryPanelEnvironment: Equatable { } } +public final class ChatInputAccessoryPanelTransitionData { + public let titleView: UIView + public let textView: UIView + public let lineView: UIView + public let imageView: UIView? + + public init(titleView: UIView, textView: UIView, lineView: UIView, imageView: UIView?) { + self.titleView = titleView + self.textView = textView + self.lineView = lineView + self.imageView = imageView + } +} + public protocol ChatInputAccessoryPanelView: UIView { var contentTintView: UIView { get } + var storedFrameBeforeDismissed: CGRect? { get set } + var transitionData: ChatInputAccessoryPanelTransitionData? { get } } diff --git a/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift b/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift index f5488c542f..2892c5ba4a 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift @@ -276,6 +276,20 @@ public final class ChatInputMessageAccessoryPanel: Component { private var inlineTextStarImage: UIImage? private var inlineTextTonImage: (UIImage, UIColor)? + public var transitionData: ChatInputAccessoryPanelTransitionData? { + guard let textView = self.text.view else { + return nil + } + return ChatInputAccessoryPanelTransitionData( + titleView: self.titleNode.view, + textView: textView, + lineView: self.lineView, + imageView: nil + ) + } + + public var storedFrameBeforeDismissed: CGRect? + override public init(frame: CGRect) { self.contentTintView = UIView() diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift index da828f78b5..001202a781 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -3044,18 +3044,18 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } public final class AnimationTransitionReplyPanel { - public let titleNode: ASDisplayNode - public let textNode: ASDisplayNode - public let lineNode: ASDisplayNode - public let imageNode: ASDisplayNode + public let titleView: UIView + public let textView: UIView + public let lineView: UIView + public let imageView: UIView? public let relativeSourceRect: CGRect public let relativeTargetRect: CGRect - public init(titleNode: ASDisplayNode, textNode: ASDisplayNode, lineNode: ASDisplayNode, imageNode: ASDisplayNode, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { - self.titleNode = titleNode - self.textNode = textNode - self.lineNode = lineNode - self.imageNode = imageNode + public init(titleView: UIView, textView: UIView, lineView: UIView, imageView: UIView?, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { + self.titleView = titleView + self.textView = textView + self.lineView = lineView + self.imageView = imageView self.relativeSourceRect = relativeSourceRect self.relativeTargetRect = relativeTargetRect } @@ -3066,10 +3066,10 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let localRect = self.contextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view) let mappedPanel = ChatMessageReplyInfoNode.TransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 582b45a0e2..1f0ac586f8 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -1094,18 +1094,18 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI } public final class AnimationTransitionReplyPanel { - public let titleNode: ASDisplayNode - public let textNode: ASDisplayNode - public let lineNode: ASDisplayNode - public let imageNode: ASDisplayNode + public let titleView: UIView + public let textView: UIView + public let lineView: UIView + public let imageView: UIView? public let relativeSourceRect: CGRect public let relativeTargetRect: CGRect - public init(titleNode: ASDisplayNode, textNode: ASDisplayNode, lineNode: ASDisplayNode, imageNode: ASDisplayNode, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { - self.titleNode = titleNode - self.textNode = textNode - self.lineNode = lineNode - self.imageNode = imageNode + public init(titleView: UIView, textView: UIView, lineView: UIView, imageView: UIView?, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { + self.titleView = titleView + self.textView = textView + self.lineView = lineView + self.imageView = imageView self.relativeSourceRect = relativeSourceRect self.relativeTargetRect = relativeTargetRect } @@ -1115,10 +1115,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI if let replyInfoNode = self.replyInfoNode { let localRect = self.mainContextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view) let mappedPanel = ChatMessageReplyInfoNode.TransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift index ae7d338e7d..9ebecccaad 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift @@ -58,18 +58,18 @@ private let groupIcon: UIImage = { public class ChatMessageReplyInfoNode: ASDisplayNode { public final class TransitionReplyPanel { - public let titleNode: ASDisplayNode - public let textNode: ASDisplayNode - public let lineNode: ASDisplayNode - public let imageNode: ASDisplayNode + public let titleView: UIView + public let textView: UIView + public let lineView: UIView + public let imageView: UIView? public let relativeSourceRect: CGRect public let relativeTargetRect: CGRect - public init(titleNode: ASDisplayNode, textNode: ASDisplayNode, lineNode: ASDisplayNode, imageNode: ASDisplayNode, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { - self.titleNode = titleNode - self.textNode = textNode - self.lineNode = lineNode - self.imageNode = imageNode + public init(titleView: UIView, textView: UIView, lineView: UIView, imageView: UIView?, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { + self.titleView = titleView + self.textView = textView + self.lineView = lineView + self.imageView = imageView self.relativeSourceRect = relativeSourceRect self.relativeTargetRect = relativeTargetRect } @@ -971,84 +971,88 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { if let titleNode = self.titleNode { let offset = CGPoint( - x: localRect.minX + sourceReplyPanel.titleNode.frame.minX - titleNode.frame.minX, - y: localRect.minY + sourceReplyPanel.titleNode.frame.midY - titleNode.frame.midY + x: localRect.minX + sourceReplyPanel.titleView.frame.minX - titleNode.frame.minX, + y: localRect.minY + sourceReplyPanel.titleView.frame.midY - titleNode.frame.midY ) transition.horizontal.animatePositionAdditive(node: titleNode, offset: CGPoint(x: offset.x, y: 0.0)) transition.vertical.animatePositionAdditive(node: titleNode, offset: CGPoint(x: 0.0, y: offset.y)) - sourceParentNode.addSubnode(sourceReplyPanel.titleNode) + sourceParentNode.view.addSubview(sourceReplyPanel.titleView) titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) - sourceReplyPanel.titleNode.frame = sourceReplyPanel.titleNode.frame + sourceReplyPanel.titleView.frame = sourceReplyPanel.titleView.frame .offsetBy(dx: sourceParentOffset.x, dy: sourceParentOffset.y) .offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y) - transition.horizontal.animatePositionAdditive(node: sourceReplyPanel.titleNode, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) - transition.vertical.animatePositionAdditive(node: sourceReplyPanel.titleNode, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) + transition.horizontal.animatePositionAdditive(layer: sourceReplyPanel.titleView.layer, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) + transition.vertical.animatePositionAdditive(layer: sourceReplyPanel.titleView.layer, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) } if let textNode = self.textNode { let offset = CGPoint( - x: localRect.minX + sourceReplyPanel.textNode.frame.minX - textNode.textNode.frame.minX, - y: localRect.minY + sourceReplyPanel.textNode.frame.midY - textNode.textNode.frame.midY + x: localRect.minX + sourceReplyPanel.textView.frame.minX - textNode.textNode.frame.minX, + y: localRect.minY + sourceReplyPanel.textView.frame.midY - textNode.textNode.frame.midY ) transition.horizontal.animatePositionAdditive(node: textNode.textNode, offset: CGPoint(x: offset.x, y: 0.0)) transition.vertical.animatePositionAdditive(node: textNode.textNode, offset: CGPoint(x: 0.0, y: offset.y)) - sourceParentNode.addSubnode(sourceReplyPanel.textNode) + sourceParentNode.view.addSubview(sourceReplyPanel.textView) textNode.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) - sourceReplyPanel.textNode.frame = sourceReplyPanel.textNode.frame + sourceReplyPanel.textView.frame = sourceReplyPanel.textView.frame .offsetBy(dx: sourceParentOffset.x, dy: sourceParentOffset.y) .offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y) - transition.horizontal.animatePositionAdditive(node: sourceReplyPanel.textNode, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) - transition.vertical.animatePositionAdditive(node: sourceReplyPanel.textNode, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) + transition.horizontal.animatePositionAdditive(layer: sourceReplyPanel.textView.layer, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) + transition.vertical.animatePositionAdditive(layer: sourceReplyPanel.textView.layer, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) } if let imageNode = self.imageNode { - let offset = CGPoint( - x: localRect.minX + sourceReplyPanel.imageNode.frame.midX - imageNode.frame.midX, - y: localRect.minY + sourceReplyPanel.imageNode.frame.midY - imageNode.frame.midY - ) - - transition.horizontal.animatePositionAdditive(node: imageNode, offset: CGPoint(x: offset.x, y: 0.0)) - transition.vertical.animatePositionAdditive(node: imageNode, offset: CGPoint(x: 0.0, y: offset.y)) - - sourceParentNode.addSubnode(sourceReplyPanel.imageNode) - - imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) - - sourceReplyPanel.imageNode.frame = sourceReplyPanel.imageNode.frame - .offsetBy(dx: sourceParentOffset.x, dy: sourceParentOffset.y) - .offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y) - transition.horizontal.animatePositionAdditive(node: sourceReplyPanel.imageNode, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) - transition.vertical.animatePositionAdditive(node: sourceReplyPanel.imageNode, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) + if let sourceImageView = sourceReplyPanel.imageView { + let offset = CGPoint( + x: localRect.minX + sourceImageView.frame.midX - imageNode.frame.midX, + y: localRect.minY + sourceImageView.frame.midY - imageNode.frame.midY + ) + + transition.horizontal.animatePositionAdditive(node: imageNode, offset: CGPoint(x: offset.x, y: 0.0)) + transition.vertical.animatePositionAdditive(node: imageNode, offset: CGPoint(x: 0.0, y: offset.y)) + + sourceParentNode.view.addSubview(sourceImageView) + + imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) + + sourceImageView.frame = sourceImageView.frame + .offsetBy(dx: sourceParentOffset.x, dy: sourceParentOffset.y) + .offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y) + transition.horizontal.animatePositionAdditive(layer: sourceImageView.layer, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) + transition.vertical.animatePositionAdditive(layer: sourceImageView.layer, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) + } else { + imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) + } } do { let backgroundView = self.backgroundView let offset = CGPoint( - x: localRect.minX + sourceReplyPanel.lineNode.frame.minX - backgroundView.frame.minX, - y: localRect.minY + sourceReplyPanel.lineNode.frame.minY - backgroundView.frame.minY + x: localRect.minX + sourceReplyPanel.lineView.frame.minX - backgroundView.frame.minX, + y: localRect.minY + sourceReplyPanel.lineView.frame.minY - backgroundView.frame.minY ) transition.horizontal.animatePositionAdditive(layer: backgroundView.layer, offset: CGPoint(x: offset.x, y: 0.0)) transition.vertical.animatePositionAdditive(layer: backgroundView.layer, offset: CGPoint(x: 0.0, y: offset.y)) - sourceParentNode.addSubnode(sourceReplyPanel.lineNode) + sourceParentNode.view.addSubview(sourceReplyPanel.lineView) backgroundView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) - sourceReplyPanel.lineNode.frame = sourceReplyPanel.lineNode.frame + sourceReplyPanel.lineView.frame = sourceReplyPanel.lineView.frame .offsetBy(dx: sourceParentOffset.x, dy: sourceParentOffset.y) .offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y) - transition.horizontal.animatePositionAdditive(node: sourceReplyPanel.lineNode, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) - transition.vertical.animatePositionAdditive(node: sourceReplyPanel.lineNode, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) + transition.horizontal.animatePositionAdditive(layer: sourceReplyPanel.lineView.layer, offset: CGPoint(x: offset.x, y: 0.0), removeOnCompletion: false) + transition.vertical.animatePositionAdditive(layer: sourceReplyPanel.lineView.layer, offset: CGPoint(x: 0.0, y: offset.y), removeOnCompletion: false) return offset } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift index 734c5113a7..6ab149a52c 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift @@ -2160,18 +2160,18 @@ public class ChatMessageStickerItemNode: ChatMessageItemView { } public final class AnimationTransitionReplyPanel { - public let titleNode: ASDisplayNode - public let textNode: ASDisplayNode - public let lineNode: ASDisplayNode - public let imageNode: ASDisplayNode + public let titleView: UIView + public let textView: UIView + public let lineView: UIView + public let imageView: UIView? public let relativeSourceRect: CGRect public let relativeTargetRect: CGRect - public init(titleNode: ASDisplayNode, textNode: ASDisplayNode, lineNode: ASDisplayNode, imageNode: ASDisplayNode, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { - self.titleNode = titleNode - self.textNode = textNode - self.lineNode = lineNode - self.imageNode = imageNode + public init(titleView: UIView, textView: UIView, lineView: UIView, imageView: UIView?, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { + self.titleView = titleView + self.textView = textView + self.lineView = lineView + self.imageView = imageView self.relativeSourceRect = relativeSourceRect self.relativeTargetRect = relativeTargetRect } @@ -2181,10 +2181,10 @@ public class ChatMessageStickerItemNode: ChatMessageItemView { if let replyInfoNode = self.replyInfoNode { let localRect = self.contextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view) let mappedPanel = ChatMessageReplyInfoNode.TransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift index 176ef3ce7e..9561e36828 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift @@ -1633,6 +1633,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { } public func animateFrom(sourceView: UIView, scrollOffset: CGFloat, widthDifference: CGFloat, transition: CombinedTransition) { + self.containerNode.clipsToBounds = false self.containerNode.view.addSubview(sourceView) sourceView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak sourceView] _ in @@ -1645,7 +1646,12 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { y: sourceView.frame.minY - (self.textNode.textNode.frame.minY - 3.0) - scrollOffset ) - transition.vertical.animatePositionAdditive(node: self.textNode.textNode, offset: offset) + transition.vertical.animatePositionAdditive(layer: self.textNode.textNode.layer, offset: offset, completion: { [weak self] _ in + guard let self else { + return + } + self.containerNode.clipsToBounds = true + }) transition.updatePosition(layer: sourceView.layer, position: CGPoint(x: sourceView.layer.position.x - offset.x, y: sourceView.layer.position.y - offset.y)) if let statusNode = self.statusNode { diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index 5ce99b52dc..4a5ac4fd49 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -274,6 +274,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg public let recordMoreButton: ChatRecordingViewOnceButtonNode private var accessoryPanel: (component: AnyComponentWithIdentity, view: ComponentView)? + public var accessoryPanelView: ChatInputAccessoryPanelView? { + return self.accessoryPanel?.view.view as? ChatInputAccessoryPanelView + } private var contextPanel: (container: UIView, mask: UIImageView, panel: ChatInputContextPanelNode)? private var mediaPreviewPanelNode: ChatRecordingPreviewInputPanelNodeImpl? @@ -2254,10 +2257,12 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg let alphaTransitionIn: ContainedViewLayoutTransition = transition.isAnimated ? ContainedViewLayoutTransition.animated(duration: 0.15, curve: .easeInOut) : .immediate let alphaTransitionOut: ContainedViewLayoutTransition = transition.isAnimated ? ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) : .immediate - let accessoryPanelAnimationBlurRadius: CGFloat = 20.0 var removedAccessoryPanelView: UIView? if let currentAccessoryPanel = self.accessoryPanel, currentAccessoryPanel.component.id != accessoryPanel?.id { + if let panelView = currentAccessoryPanel.view.view as? ChatInputAccessoryPanelView { + panelView.storedFrameBeforeDismissed = panelView.convert(panelView.bounds, to: nil) + } self.accessoryPanel = nil if let accessoryPanelView = currentAccessoryPanel.view.view { removedAccessoryPanelView = accessoryPanelView @@ -2299,18 +2304,10 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg accessoryPanelComponentView.frame = accessoryPanelFrame.offsetBy(dx: 0.0, dy: self.textInputNodeClippingContainer.frame.minY - accessoryPanelFrame.height) accessoryPanelComponentView.alpha = 0.0 - if transition.isAnimated { - ComponentTransition(alphaTransitionIn).animateBlur(layer: accessoryPanelComponentView.layer, fromRadius: accessoryPanelAnimationBlurRadius, toRadius: 0.0) - } - if let accessoryPanelComponentView = accessoryPanelComponentView as? ChatInputAccessoryPanelView { self.textInputContainerBackgroundView.maskContentView.addSubview(accessoryPanelComponentView.contentTintView) accessoryPanelComponentView.contentTintView.frame = accessoryPanelFrame.offsetBy(dx: 0.0, dy: self.textInputNodeClippingContainer.frame.minY - accessoryPanelFrame.height) accessoryPanelComponentView.contentTintView.alpha = 0.0 - - if transition.isAnimated { - ComponentTransition(alphaTransitionIn).animateBlur(layer: accessoryPanelComponentView.contentTintView.layer, fromRadius: accessoryPanelAnimationBlurRadius, toRadius: 0.0) - } } } transition.updateFrame(view: accessoryPanelComponentView, frame: accessoryPanelFrame) @@ -2378,16 +2375,17 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg self.textInputContainerBackgroundView.update(size: textInputContainerBackgroundFrame.size, cornerRadius: floor(minimalInputHeight * 0.5), isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: ComponentTransition(transition)) + transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: textInputContainerBackgroundFrame) + transition.updateAlpha(node: self.textInputBackgroundNode, alpha: audioRecordingItemsAlpha) + if let removedAccessoryPanelView { if let removedAccessoryPanelView = removedAccessoryPanelView as? ChatInputAccessoryPanelView { let contentTintView = removedAccessoryPanelView.contentTintView - ComponentTransition(alphaTransitionOut).animateBlur(layer: contentTintView.layer, fromRadius: 0.0, toRadius: accessoryPanelAnimationBlurRadius, removeOnCompletion: false) transition.updateFrame(view: contentTintView, frame: CGRect(origin: CGPoint(x: contentTintView.frame.minX, y: textFieldTopContentOffset - contentTintView.bounds.height), size: contentTintView.bounds.size)) alphaTransitionOut.updateAlpha(layer: contentTintView.layer, alpha: 0.0, completion: { [weak contentTintView] _ in contentTintView?.removeFromSuperview() }) } - ComponentTransition(alphaTransitionOut).animateBlur(layer: removedAccessoryPanelView.layer, fromRadius: 0.0, toRadius: accessoryPanelAnimationBlurRadius, removeOnCompletion: false) transition.updateFrame(view: removedAccessoryPanelView, frame: CGRect(origin: CGPoint(x: removedAccessoryPanelView.frame.minX, y: textFieldTopContentOffset - removedAccessoryPanelView.bounds.height), size: removedAccessoryPanelView.bounds.size)) alphaTransitionOut.updateAlpha(layer: removedAccessoryPanelView.layer, alpha: 0.0, completion: { [weak removedAccessoryPanelView] _ in removedAccessoryPanelView?.removeFromSuperview() @@ -2518,10 +2516,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } } - let textInputBackgroundFrame = CGRect(x: hideOffset.x + leftInset + textFieldInsets.left, y: hideOffset.y + textFieldInsets.top + textFieldTopContentOffset, width: baseWidth - textFieldInsets.left - textFieldInsets.right, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom + self.textInputViewInternalInsets.top + self.textInputViewInternalInsets.bottom) self.currentTextInputBackgroundWidthOffset = textInputBackgroundWidthOffset - transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: textInputBackgroundFrame) - transition.updateAlpha(node: self.textInputBackgroundNode, alpha: audioRecordingItemsAlpha) let textPlaceholderSize: CGSize let textPlaceholderMaxWidth: CGFloat = max(1.0, nextButtonTopRight.x - 12.0) @@ -2563,7 +2558,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg let textPlaceholderFrame: CGRect if sendingTextDisabled { - textPlaceholderFrame = CGRect(origin: CGPoint(x: floor((textInputBackgroundFrame.width - textPlaceholderSize.width) / 2.0), y: self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel + textFieldTopContentOffset), size: textPlaceholderSize) + textPlaceholderFrame = CGRect(origin: CGPoint(x: floor((textInputContainerBackgroundFrame.width - textPlaceholderSize.width) / 2.0), y: self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel + textFieldTopContentOffset), size: textPlaceholderSize) let textLockIconNode: ASImageNode var textLockIconTransition = transition @@ -4672,7 +4667,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg public func frameForAttachmentButton() -> CGRect? { if !self.attachmentButton.alpha.isZero { - return self.attachmentButton.frame.insetBy(dx: 0.0, dy: 6.0).offsetBy(dx: 2.0, dy: 0.0) + return self.attachmentButton.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0) } return nil } @@ -4727,9 +4722,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg return nil } - //TODO let backgroundView = UIImageView() - backgroundView.frame = self.textInputBackgroundNode.frame + backgroundView.frame = self.textInputBackgroundNode.view.convert(self.textInputBackgroundNode.bounds, to: self.view) let caretColor = textInputNode.textView.tintColor textInputNode.textView.tintColor = .clear @@ -4741,7 +4735,10 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg textInputNode.textView.tintColor = caretColor - contentView.frame = textInputNode.frame + if let textInputNodeSuperview = textInputNode.view.superview { + let _ = textInputNodeSuperview + contentView.frame = textInputNode.frame.offsetBy(dx: 0.0, dy: self.textInputNodeClippingContainer.frame.minY) + } return ( backgroundView: backgroundView, diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 4a48ba8fd2..3f1da2d2bf 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -142,6 +142,8 @@ import AVFoundation import BalanceNeededScreen import FaceScanScreen import ChatThemeScreen +import ChatTextInputPanelNode +import ChatInputAccessoryPanel public final class ChatControllerOverlayPresentationData { public let expandData: (ASDisplayNode?, () -> Void) @@ -2178,9 +2180,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let correlationId = Int64.random(in: 0 ..< Int64.max) - var replyPanel: ReplyAccessoryPanelNode? - if let accessoryPanelNode = strongSelf.chatDisplayNode.accessoryPanelNode as? ReplyAccessoryPanelNode { - replyPanel = accessoryPanelNode + var replyPanel: ChatInputAccessoryPanelView? + if let inputPanelNode = strongSelf.chatDisplayNode.inputPanelNode as? ChatTextInputPanelNode { + replyPanel = inputPanelNode.accessoryPanelView } var shouldAnimateMessageTransition = strongSelf.chatDisplayNode.shouldAnimateMessageTransition @@ -2188,8 +2190,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G shouldAnimateMessageTransition = true } - strongSelf.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in - guard let strongSelf = self else { + strongSelf.presentPaidMessageAlertIfNeeded(completion: { [weak strongSelf] postpone in + guard let strongSelf else { return } strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({ diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index d44c8df3b2..b0bb4848a8 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -49,6 +49,7 @@ import ChatSideTopicsPanel import GlassBackgroundComponent import ChatThemeScreen import ChatTextInputPanelNode +import ChatInputAccessoryPanel final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem { let itemNode: OverlayMediaItemNode @@ -4660,11 +4661,10 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { let correlationId = Int64.random(in: 0 ..< Int64.max) messages[messages.count - 1] = messages[messages.count - 1].withUpdatedCorrelationId(correlationId) - var replyPanel: ReplyAccessoryPanelNode? - if let accessoryPanelNode = self.accessoryPanelNode as? ReplyAccessoryPanelNode { - replyPanel = accessoryPanelNode - } + var replyPanel: ChatInputAccessoryPanelView? if self.shouldAnimateMessageTransition, let inputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode, let textInput = inputPanelNode.makeSnapshotForTransition() { + replyPanel = inputPanelNode.accessoryPanelView + usedCorrelationId = correlationId let source: ChatMessageTransitionNodeImpl.Source = .textInput(textInput: ChatMessageTransitionNodeImpl.Source.TextInput( backgroundView: textInput.backgroundView, diff --git a/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift b/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift index db193b7840..b3700c97f9 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift @@ -21,6 +21,7 @@ import ChatMessageBubbleItemNode import ChatEmptyNode import ChatMediaInputStickerGridItem import AccountContext +import ChatInputAccessoryPanel private func convertAnimatingSourceRect(_ rect: CGRect, fromView: UIView, toView: UIView?) -> CGRect { if let presentationLayer = fromView.layer.presentation() { @@ -105,26 +106,41 @@ private final class OverlayTransitionContainerController: ViewController, Standa } } +private func chatMessageTransitionAnimationDuration() -> Double { + #if DEBUG && false + return 3.0 + #else + return 0.3 + #endif +} + public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTransitionNode, ChatMessageTransitionProtocol { - static let animationDuration: Double = 0.3 + static let animationDuration: Double = chatMessageTransitionAnimationDuration() public static let verticalAnimationControlPoints: (Float, Float, Float, Float) = (0.19919472913616398, 0.010644531250000006, 0.27920937042459737, 0.91025390625) public static let verticalAnimationCurve: ContainedViewLayoutTransitionCurve = .custom(verticalAnimationControlPoints.0, verticalAnimationControlPoints.1, verticalAnimationControlPoints.2, verticalAnimationControlPoints.3) public static let horizontalAnimationCurve: ContainedViewLayoutTransitionCurve = .custom(0.23, 1.0, 0.32, 1.0) final class ReplyPanel { - let titleNode: ASDisplayNode - let textNode: ASDisplayNode - let lineNode: ASDisplayNode - let imageNode: ASDisplayNode + let titleView: UIView + let textView: UIView + let lineView: UIView + let imageView: UIView? let relativeSourceRect: CGRect let relativeTargetRect: CGRect - init(titleNode: ASDisplayNode, textNode: ASDisplayNode, lineNode: ASDisplayNode, imageNode: ASDisplayNode, relativeSourceRect: CGRect, relativeTargetRect: CGRect) { - self.titleNode = titleNode - self.textNode = textNode - self.lineNode = lineNode - self.imageNode = imageNode + init( + titleView: UIView, + textView: UIView, + lineView: UIView, + imageView: UIView?, + relativeSourceRect: CGRect, + relativeTargetRect: CGRect + ) { + self.titleView = titleView + self.textView = textView + self.lineView = lineView + self.imageView = imageView self.relativeSourceRect = relativeSourceRect self.relativeTargetRect = relativeTargetRect } @@ -232,8 +248,8 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran } } - case textInput(textInput: TextInput, replyPanel: ReplyAccessoryPanelNode?) - case stickerMediaInput(input: StickerInput, replyPanel: ReplyAccessoryPanelNode?) + case textInput(textInput: TextInput, replyPanel: ChatInputAccessoryPanelView?) + case stickerMediaInput(input: StickerInput, replyPanel: ChatInputAccessoryPanelView?) case audioMicInput(AudioMicInput) case videoMessage(VideoMessage) case mediaInput(MediaInput) @@ -403,9 +419,15 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran textInput.contentView.frame = textInput.contentView.frame.offsetBy(dx: 0.0, dy: sourceAbsoluteRect.height - sourceBackgroundAbsoluteRect.height) var sourceReplyPanel: ReplyPanel? - if let replyPanel = replyPanel, let replyPanelParentView = replyPanel.view.superview { - let replyPanelFrame = replyPanel.originalFrameBeforeDismissed ?? replyPanel.frame - var replySourceAbsoluteFrame = replyPanelParentView.convert(replyPanelFrame, to: self.view) + if let replyPanel, let replyPanelTransitionData = replyPanel.transitionData, let replyPanelParentView = replyPanel.superview { + let replyPanelFrame = replyPanel.frame + var replySourceAbsoluteFrame: CGRect + + if let storedFrameBeforeDismissed = replyPanel.storedFrameBeforeDismissed { + replySourceAbsoluteFrame = self.view.convert(storedFrameBeforeDismissed, from: nil) + } else { + replySourceAbsoluteFrame = replyPanelParentView.convert(replyPanelFrame, to: self.view) + } replySourceAbsoluteFrame.origin.x -= sourceAbsoluteRect.minX - self.contextSourceNode.contentRect.minX replySourceAbsoluteFrame.origin.y -= sourceAbsoluteRect.minY - self.contextSourceNode.contentRect.minY @@ -415,7 +437,14 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran globalTargetFrame.origin.x += sourceAbsoluteRect.minX - targetAbsoluteRect.minX globalTargetFrame.origin.y += sourceAbsoluteRect.minY - targetAbsoluteRect.minY - sourceReplyPanel = ReplyPanel(titleNode: replyPanel.titleNode, textNode: replyPanel.textNode, lineNode: replyPanel.lineNode, imageNode: replyPanel.imageNode, relativeSourceRect: replySourceAbsoluteFrame, relativeTargetRect: globalTargetFrame) + sourceReplyPanel = ReplyPanel( + titleView: replyPanelTransitionData.titleView, + textView: replyPanelTransitionData.textView, + lineView: replyPanelTransitionData.lineView, + imageView: replyPanelTransitionData.imageView, + relativeSourceRect: replySourceAbsoluteFrame, + relativeTargetRect: globalTargetFrame + ) } self.itemNode.cancelInsertionAnimations() @@ -449,13 +478,13 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran ), transition: combinedTransition ) - if let sourceReplyPanel = sourceReplyPanel { + if let sourceReplyPanel { itemNode.animateReplyPanel( sourceReplyPanel: ChatMessageBubbleItemNode.AnimationTransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ), @@ -475,10 +504,10 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran if let sourceReplyPanel = sourceReplyPanel { itemNode.animateReplyPanel( sourceReplyPanel: ChatMessageAnimatedStickerItemNode.AnimationTransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ), @@ -498,10 +527,10 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran if let sourceReplyPanel = sourceReplyPanel { itemNode.animateReplyPanel( sourceReplyPanel: ChatMessageStickerItemNode.AnimationTransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ), @@ -537,12 +566,27 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: self.view) var sourceReplyPanel: ReplyPanel? - if let replyPanel = replyPanel, let replyPanelParentView = replyPanel.view.superview { - var replySourceAbsoluteFrame = replyPanelParentView.convert(replyPanel.originalFrameBeforeDismissed ?? replyPanel.frame, to: self.view) + if let replyPanel, let replyPanelTransitionData = replyPanel.transitionData, let replyPanelParentView = replyPanel.superview { + let replyPanelFrame = replyPanel.frame + var replySourceAbsoluteFrame: CGRect + + if let storedFrameBeforeDismissed = replyPanel.storedFrameBeforeDismissed { + replySourceAbsoluteFrame = self.view.convert(storedFrameBeforeDismissed, from: nil) + } else { + replySourceAbsoluteFrame = replyPanelParentView.convert(replyPanelFrame, to: self.view) + } + replySourceAbsoluteFrame.origin.x -= sourceAbsoluteRect.midX - self.contextSourceNode.contentRect.midX replySourceAbsoluteFrame.origin.y -= sourceAbsoluteRect.midY - self.contextSourceNode.contentRect.midY - sourceReplyPanel = ReplyPanel(titleNode: replyPanel.titleNode, textNode: replyPanel.textNode, lineNode: replyPanel.lineNode, imageNode: replyPanel.imageNode, relativeSourceRect: replySourceAbsoluteFrame, relativeTargetRect: replySourceAbsoluteFrame.offsetBy(dx: 0.0, dy: replySourceAbsoluteFrame.height)) + sourceReplyPanel = ReplyPanel( + titleView: replyPanelTransitionData.titleView, + textView: replyPanelTransitionData.textView, + lineView: replyPanelTransitionData.lineView, + imageView: replyPanelTransitionData.imageView, + relativeSourceRect: replySourceAbsoluteFrame, + relativeTargetRect: replySourceAbsoluteFrame.offsetBy(dx: 0.0, dy: replySourceAbsoluteFrame.height) + ) } let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNodeImpl.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNodeImpl.verticalAnimationCurve)) @@ -564,10 +608,10 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran if let sourceReplyPanel = sourceReplyPanel { itemNode.animateReplyPanel( sourceReplyPanel: ChatMessageAnimatedStickerItemNode.AnimationTransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ), @@ -588,10 +632,10 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran if let sourceReplyPanel = sourceReplyPanel { itemNode.animateReplyPanel( sourceReplyPanel: ChatMessageStickerItemNode.AnimationTransitionReplyPanel( - titleNode: sourceReplyPanel.titleNode, - textNode: sourceReplyPanel.textNode, - lineNode: sourceReplyPanel.lineNode, - imageNode: sourceReplyPanel.imageNode, + titleView: sourceReplyPanel.titleView, + textView: sourceReplyPanel.textView, + lineView: sourceReplyPanel.lineView, + imageView: sourceReplyPanel.imageView, relativeSourceRect: sourceReplyPanel.relativeSourceRect, relativeTargetRect: sourceReplyPanel.relativeTargetRect ),