Refactoring [skip ci]

This commit is contained in:
Ali
2023-10-15 14:47:43 +04:00
parent 76719a7c95
commit 8e566ed820
23 changed files with 417 additions and 144 deletions

View File

@@ -383,6 +383,9 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatSwipeToReplyRecognizer", "//submodules/TelegramUI/Components/Chat/ChatSwipeToReplyRecognizer",
"//submodules/TelegramUI/Components/Chat/ChatMessageInstantVideoItemNode", "//submodules/TelegramUI/Components/Chat/ChatMessageInstantVideoItemNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageInstantVideoBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageInstantVideoBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageTransitionNode",
"//submodules/TelegramUI/Components/Chat/ManagedDiceAnimationNode",
] + select({ ] + select({
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
"//build-system:ios_sim_arm64": [], "//build-system:ios_sim_arm64": [],

View File

@@ -0,0 +1,60 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ChatMessageAnimatedStickerItemNode",
module_name = "ChatMessageAnimatedStickerItemNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/TextFormat",
"//submodules/AccountContext",
"//submodules/MediaResources",
"//submodules/StickerResources",
"//submodules/ContextUI",
"//submodules/AnimatedStickerNode",
"//submodules/TelegramAnimatedStickerNode",
"//submodules/Emoji",
"//submodules/Markdown",
"//submodules/ManagedAnimationNode",
"//submodules/SlotMachineAnimationNode",
"//submodules/MediaPlayer:UniversalMediaPlayer",
"//submodules/ShimmerEffect",
"//submodules/WallpaperBackgroundNode",
"//submodules/LocalMediaResources",
"//submodules/AppBundle",
"//submodules/ChatPresentationInterfaceState",
"//submodules/TelegramUI/Components/TextNodeWithEntities",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
"//submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItem",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemView",
"//submodules/TelegramUI/Components/Chat/ChatMessageSwipeToReplyNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageSelectionNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageDeliveryFailedNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageShareButton",
"//submodules/TelegramUI/Components/Chat/ChatMessageThreadInfoNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode",
"//submodules/TelegramUI/Components/Chat/ChatSwipeToReplyRecognizer",
"//submodules/TelegramUI/Components/Chat/ChatMessageReactionsFooterContentNode",
"//submodules/TelegramUI/Components/Chat/ManagedDiceAnimationNode",
"//submodules/TelegramUI/Components/Chat/MessageHaptics",
"//submodules/TelegramUI/Components/Chat/ChatMessageTransitionNode",
],
visibility = [
"//visibility:public",
],
)

View File

@@ -43,12 +43,15 @@ import ChatMessageThreadInfoNode
import ChatMessageActionButtonsNode import ChatMessageActionButtonsNode
import ChatSwipeToReplyRecognizer import ChatSwipeToReplyRecognizer
import ChatMessageReactionsFooterContentNode import ChatMessageReactionsFooterContentNode
import ManagedDiceAnimationNode
import MessageHaptics
import ChatMessageTransitionNode
private let nameFont = Font.medium(14.0) private let nameFont = Font.medium(14.0)
private let inlineBotPrefixFont = Font.regular(14.0) private let inlineBotPrefixFont = Font.regular(14.0)
private let inlineBotNameFont = nameFont private let inlineBotNameFont = nameFont
protocol GenericAnimatedStickerNode: ASDisplayNode { public protocol GenericAnimatedStickerNode: ASDisplayNode {
func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool) func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool)
var currentFrameIndex: Int { get } var currentFrameIndex: Int { get }
@@ -56,29 +59,32 @@ protocol GenericAnimatedStickerNode: ASDisplayNode {
} }
extension DefaultAnimatedStickerNodeImpl: GenericAnimatedStickerNode { extension DefaultAnimatedStickerNodeImpl: GenericAnimatedStickerNode {
func setFrameIndex(_ frameIndex: Int) { public func setFrameIndex(_ frameIndex: Int) {
self.stop() self.stop()
self.play(fromIndex: frameIndex) self.play(fromIndex: frameIndex)
} }
} }
extension SlotMachineAnimationNode: GenericAnimatedStickerNode { extension SlotMachineAnimationNode: GenericAnimatedStickerNode {
var currentFrameIndex: Int { public var currentFrameIndex: Int {
return 0 return 0
} }
func setFrameIndex(_ frameIndex: Int) { public func setFrameIndex(_ frameIndex: Int) {
} }
} }
class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { extension ManagedDiceAnimationNode: GenericAnimatedStickerNode {
let contextSourceNode: ContextExtractedContentContainingNode }
public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
public let contextSourceNode: ContextExtractedContentContainingNode
private let containerNode: ContextControllerSourceNode private let containerNode: ContextControllerSourceNode
let imageNode: TransformImageNode public let imageNode: TransformImageNode
private var enableSynchronousImageApply: Bool = false private var enableSynchronousImageApply: Bool = false
private var backgroundNode: WallpaperBubbleBackgroundNode? private var backgroundNode: WallpaperBubbleBackgroundNode?
private(set) var placeholderNode: StickerShimmerEffectNode public private(set) var placeholderNode: StickerShimmerEffectNode
private(set) var animationNode: GenericAnimatedStickerNode? public private(set) var animationNode: GenericAnimatedStickerNode?
private var animationSize: CGSize? private var animationSize: CGSize?
private var didSetUpAnimationNode = false private var didSetUpAnimationNode = false
private var isPlaying = false private var isPlaying = false
@@ -86,7 +92,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
private let textNode: TextNodeWithEntities private let textNode: TextNodeWithEntities
private var additionalAnimationNodes: [ChatMessageTransitionNode.DecorationItemNode] = [] private var additionalAnimationNodes: [ChatMessageTransitionNode.DecorationItemNode] = []
private var overlayMeshAnimationNode: ChatMessageTransitionNode.DecorationItemNode?
private var enqueuedAdditionalAnimations: [(Int, Double)] = [] private var enqueuedAdditionalAnimations: [(Int, Double)] = []
private var additionalAnimationsCommitTimer: SwiftSignalKit.Timer? private var additionalAnimationsCommitTimer: SwiftSignalKit.Timer?
@@ -97,10 +102,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
private var deliveryFailedNode: ChatMessageDeliveryFailedNode? private var deliveryFailedNode: ChatMessageDeliveryFailedNode?
private var shareButtonNode: ChatMessageShareButton? private var shareButtonNode: ChatMessageShareButton?
var telegramFile: TelegramMediaFile? public var telegramFile: TelegramMediaFile?
var emojiFile: TelegramMediaFile? public var emojiFile: TelegramMediaFile?
var telegramDice: TelegramMediaDice? public var telegramDice: TelegramMediaDice?
var emojiString: String? public var emojiString: String?
private let disposable = MetaDisposable() private let disposable = MetaDisposable()
private let disposables = DisposableSet() private let disposables = DisposableSet()
@@ -136,7 +141,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
private var wasPending: Bool = false private var wasPending: Bool = false
private var didChangeFromPendingToSent: Bool = false private var didChangeFromPendingToSent: Bool = false
required init() { required public init() {
self.contextSourceNode = ContextExtractedContentContainingNode() self.contextSourceNode = ContextExtractedContentContainingNode()
self.containerNode = ContextControllerSourceNode() self.containerNode = ContextControllerSourceNode()
self.imageNode = TransformImageNode() self.imageNode = TransformImageNode()
@@ -233,7 +238,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
self.additionalAnimationsCommitTimer?.invalidate() self.additionalAnimationsCommitTimer?.invalidate()
} }
required init?(coder aDecoder: NSCoder) { required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@@ -248,7 +253,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func didLoad() { override public func didLoad() {
super.didLoad() super.didLoad()
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:))) let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
@@ -325,7 +330,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
self.view.addGestureRecognizer(replyRecognizer) self.view.addGestureRecognizer(replyRecognizer)
} }
override var visibility: ListViewItemNodeVisibility { override public var visibility: ListViewItemNodeVisibility {
didSet { didSet {
let wasVisible = oldValue != .none let wasVisible = oldValue != .none
let isVisible = self.visibility != .none let isVisible = self.visibility != .none
@@ -425,7 +430,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func setupItem(_ item: ChatMessageItem, synchronousLoad: Bool) { override public func setupItem(_ item: ChatMessageItem, synchronousLoad: Bool) {
super.setupItem(item, synchronousLoad: synchronousLoad) super.setupItem(item, synchronousLoad: synchronousLoad)
if item.message.id.namespace == Namespaces.Message.Local || item.message.id.namespace == Namespaces.Message.ScheduledLocal { if item.message.id.namespace == Namespaces.Message.Local || item.message.id.namespace == Namespaces.Message.ScheduledLocal {
@@ -587,13 +592,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let isPlaying = self.visibilityStatus == true && !self.forceStopAnimations let isPlaying = self.visibilityStatus == true && !self.forceStopAnimations
if !isPlaying { if !isPlaying {
self.removeAdditionalAnimations() self.removeAdditionalAnimations()
if let overlayMeshAnimationNode = self.overlayMeshAnimationNode {
self.overlayMeshAnimationNode = nil
if let transitionNode = item.controllerInteraction.getMessageTransitionNode() as? ChatMessageTransitionNode {
transitionNode.remove(decorationNode: overlayMeshAnimationNode)
}
}
} }
if let animationNode = self.animationNode as? AnimatedStickerNode { if let animationNode = self.animationNode as? AnimatedStickerNode {
if self.isPlaying != isPlaying || (isPlaying && !self.didSetUpAnimationNode) { if self.isPlaying != isPlaying || (isPlaying && !self.didSetUpAnimationNode) {
@@ -663,13 +661,13 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func updateStickerSettings(forceStopAnimations: Bool) { override public func updateStickerSettings(forceStopAnimations: Bool) {
self.forceStopAnimations = forceStopAnimations self.forceStopAnimations = forceStopAnimations
self.updateVisibility() self.updateVisibility()
} }
private var absoluteRect: (CGRect, CGSize)? private var absoluteRect: (CGRect, CGSize)?
override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
self.absoluteRect = (rect, containerSize) self.absoluteRect = (rect, containerSize)
if !self.contextSourceNode.isExtractedToContextPreview { if !self.contextSourceNode.isExtractedToContextPreview {
var rect = rect var rect = rect
@@ -723,7 +721,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func applyAbsoluteOffset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) { override public func applyAbsoluteOffset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
if let backgroundNode = self.backgroundNode { if let backgroundNode = self.backgroundNode {
backgroundNode.offset(value: value, animationCurve: animationCurve, duration: duration) backgroundNode.offset(value: value, animationCurve: animationCurve, duration: duration)
} }
@@ -733,7 +731,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) { override public func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {
super.updateAccessibilityData(accessibilityData) super.updateAccessibilityData(accessibilityData)
self.messageAccessibilityArea.accessibilityLabel = accessibilityData.label self.messageAccessibilityArea.accessibilityLabel = accessibilityData.label
@@ -764,7 +762,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) { override public func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) {
var displaySize = CGSize(width: 180.0, height: 180.0) var displaySize = CGSize(width: 180.0, height: 180.0)
let telegramFile = self.telegramFile let telegramFile = self.telegramFile
let emojiFile = self.emojiFile let emojiFile = self.emojiFile
@@ -1761,7 +1759,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
item.controllerInteraction.commitEmojiInteraction(item.message.id, item.message.text.strippedEmoji, EmojiInteraction(animations: animations), file) item.controllerInteraction.commitEmojiInteraction(item.message.id, item.message.text.strippedEmoji, EmojiInteraction(animations: animations), file)
} }
func playEmojiInteraction(_ interaction: EmojiInteraction) { public func playEmojiInteraction(_ interaction: EmojiInteraction) {
guard interaction.animations.count <= 7 else { guard interaction.animations.count <= 7 else {
return return
} }
@@ -1807,7 +1805,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
func playAdditionalEmojiAnimation(index: Int) { public func playAdditionalEmojiAnimation(index: Int) {
guard let item = self.item else { guard let item = self.item else {
return return
} }
@@ -1846,7 +1844,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
self.playEffectAnimation(resource: effect.resource, isStickerEffect: true) self.playEffectAnimation(resource: effect.resource, isStickerEffect: true)
} }
func playEffectAnimation(resource: MediaResource, isStickerEffect: Bool = false) { public func playEffectAnimation(resource: MediaResource, isStickerEffect: Bool = false) {
guard let item = self.item else { guard let item = self.item else {
return return
} }
@@ -2282,7 +2280,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
private var playedSwipeToReplyHaptic = false private var playedSwipeToReplyHaptic = false
@objc func swipeToReplyGesture(_ recognizer: ChatSwipeToReplyRecognizer) { @objc private func swipeToReplyGesture(_ recognizer: ChatSwipeToReplyRecognizer) {
var offset: CGFloat = 0.0 var offset: CGFloat = 0.0
var leftOffset: CGFloat = 0.0 var leftOffset: CGFloat = 0.0
var swipeOffset: CGFloat = 45.0 var swipeOffset: CGFloat = 45.0
@@ -2406,7 +2404,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if let shareButtonNode = self.shareButtonNode, shareButtonNode.frame.contains(point) { if let shareButtonNode = self.shareButtonNode, shareButtonNode.frame.contains(point) {
return shareButtonNode.view return shareButtonNode.view
} }
@@ -2421,7 +2419,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
return super.hitTest(point, with: event) return super.hitTest(point, with: event)
} }
override func updateSelectionState(animated: Bool) { override public func updateSelectionState(animated: Bool) {
guard let item = self.item else { guard let item = self.item else {
return return
} }
@@ -2503,7 +2501,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func updateHighlightedState(animated: Bool) { override public func updateHighlightedState(animated: Bool) {
super.updateHighlightedState(animated: animated) super.updateHighlightedState(animated: animated)
if let item = self.item { if let item = self.item {
@@ -2528,11 +2526,11 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func cancelInsertionAnimations() { override public func cancelInsertionAnimations() {
self.layer.removeAllAnimations() self.layer.removeAllAnimations()
} }
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
super.animateInsertion(currentTimestamp, duration: duration, short: short) super.animateInsertion(currentTimestamp, duration: duration, short: short)
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
@@ -2550,27 +2548,41 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
override func animateRemoved(_ currentTimestamp: Double, duration: Double) { override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
super.animateRemoved(currentTimestamp, duration: duration) super.animateRemoved(currentTimestamp, duration: duration)
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
} }
override func animateAdded(_ currentTimestamp: Double, duration: Double) { override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
super.animateAdded(currentTimestamp, duration: duration) super.animateAdded(currentTimestamp, duration: duration)
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
} }
override func getMessageContextSourceNode(stableId: UInt32?) -> ContextExtractedContentContainingNode? { override public func getMessageContextSourceNode(stableId: UInt32?) -> ContextExtractedContentContainingNode? {
return self.contextSourceNode return self.contextSourceNode
} }
override func addAccessoryItemNode(_ accessoryItemNode: ListViewAccessoryItemNode) { override public func addAccessoryItemNode(_ accessoryItemNode: ListViewAccessoryItemNode) {
self.contextSourceNode.contentNode.addSubnode(accessoryItemNode) self.contextSourceNode.contentNode.addSubnode(accessoryItemNode)
} }
public final class AnimationTransitionTextInput {
public let backgroundView: UIView
public let contentView: UIView
public let sourceRect: CGRect
public let scrollOffset: CGFloat
func animateContentFromTextInputField(textInput: ChatMessageTransitionNode.Source.TextInput, transition: CombinedTransition) { public init(backgroundView: UIView, contentView: UIView, sourceRect: CGRect, scrollOffset: CGFloat) {
self.backgroundView = backgroundView
self.contentView = contentView
self.sourceRect = sourceRect
self.scrollOffset = scrollOffset
}
}
public func animateContentFromTextInputField(textInput: AnimationTransitionTextInput, transition: CombinedTransition) {
guard let _ = self.item else { guard let _ = self.item else {
return return
} }
@@ -2629,8 +2641,56 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
self.dateAndStatusNode.layer.animateAlpha(from: 0.0, to: self.dateAndStatusNode.alpha, duration: 0.15, delay: 0.16) self.dateAndStatusNode.layer.animateAlpha(from: 0.0, to: self.dateAndStatusNode.alpha, duration: 0.15, delay: 0.16)
} }
public final class AnimationTransitionSticker {
public let imageNode: TransformImageNode?
public let animationNode: ASDisplayNode?
public let placeholderNode: ASDisplayNode?
public let imageLayer: CALayer?
public let relativeSourceRect: CGRect
var sourceFrame: CGRect {
if let imageNode = self.imageNode {
return imageNode.frame
} else if let imageLayer = self.imageLayer {
return imageLayer.bounds
} else {
return CGRect(origin: CGPoint(), size: relativeSourceRect.size)
}
}
var sourceLayer: CALayer? {
if let imageNode = self.imageNode {
return imageNode.layer
} else if let imageLayer = self.imageLayer {
return imageLayer
} else {
return nil
}
}
func snapshotContentTree() -> UIView? {
if let animationNode = self.animationNode {
return animationNode.view.snapshotContentTree()
} else if let imageNode = self.imageNode {
return imageNode.view.snapshotContentTree()
} else if let sourceLayer = self.imageLayer {
return sourceLayer.snapshotContentTreeAsView()
} else {
return nil
}
}
public init(imageNode: TransformImageNode?, animationNode: ASDisplayNode?, placeholderNode: ASDisplayNode?, imageLayer: CALayer?, relativeSourceRect: CGRect) {
self.imageNode = imageNode
self.animationNode = animationNode
self.placeholderNode = placeholderNode
self.imageLayer = imageLayer
self.relativeSourceRect = relativeSourceRect
}
}
func animateContentFromStickerGridItem(stickerSource: ChatMessageTransitionNode.Sticker, transition: CombinedTransition) { public func animateContentFromStickerGridItem(stickerSource: AnimationTransitionSticker, transition: CombinedTransition) {
guard let _ = self.item else { guard let _ = self.item else {
return return
} }
@@ -2716,8 +2776,26 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
placeholderNode.layer.animateAlpha(from: 0.0, to: placeholderNode.alpha, duration: 0.4) placeholderNode.layer.animateAlpha(from: 0.0, to: placeholderNode.alpha, duration: 0.4)
} }
} }
public final class AnimationTransitionReplyPanel {
public let titleNode: ASDisplayNode
public let textNode: ASDisplayNode
public let lineNode: ASDisplayNode
public let imageNode: ASDisplayNode
public let relativeSourceRect: CGRect
public let relativeTargetRect: CGRect
func animateReplyPanel(sourceReplyPanel: ChatMessageTransitionNode.ReplyPanel, transition: CombinedTransition) { 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
self.relativeSourceRect = relativeSourceRect
self.relativeTargetRect = relativeTargetRect
}
}
public func animateReplyPanel(sourceReplyPanel: AnimationTransitionReplyPanel, transition: CombinedTransition) {
if let replyInfoNode = self.replyInfoNode { if let replyInfoNode = self.replyInfoNode {
let localRect = self.contextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view) let localRect = self.contextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view)
@@ -2737,7 +2815,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
func animateFromLoadingPlaceholder(delay: Double, transition: ContainedViewLayoutTransition) { public func animateFromLoadingPlaceholder(delay: Double, transition: ContainedViewLayoutTransition) {
guard let item = self.item else { guard let item = self.item else {
return return
} }
@@ -2747,14 +2825,14 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
transition.animateTransformScale(node: self, from: CGPoint(x: 0.85, y: 0.85), delay: delay) transition.animateTransformScale(node: self, from: CGPoint(x: 0.85, y: 0.85), delay: delay)
} }
override func openMessageContextMenu() { override public func openMessageContextMenu() {
guard let item = self.item else { guard let item = self.item else {
return return
} }
item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil, nil) item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil, nil)
} }
override func targetReactionView(value: MessageReaction.Reaction) -> UIView? { override public func targetReactionView(value: MessageReaction.Reaction) -> UIView? {
if let result = self.reactionButtonsNode?.reactionTargetView(value: value) { if let result = self.reactionButtonsNode?.reactionTargetView(value: value) {
return result return result
} }
@@ -2764,7 +2842,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
return nil return nil
} }
override func targetForStoryTransition(id: StoryId) -> UIView? { override public func targetForStoryTransition(id: StoryId) -> UIView? {
guard let item = self.item else { guard let item = self.item else {
return nil return nil
} }
@@ -2780,17 +2858,17 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
return nil return nil
} }
override func unreadMessageRangeUpdated() { override public func unreadMessageRangeUpdated() {
self.updateVisibility() self.updateVisibility()
} }
override func contentFrame() -> CGRect { override public func contentFrame() -> CGRect {
return self.imageNode.frame return self.imageNode.frame
} }
} }
struct AnimatedEmojiSoundsConfiguration { public struct AnimatedEmojiSoundsConfiguration {
static var defaultValue: AnimatedEmojiSoundsConfiguration { public static var defaultValue: AnimatedEmojiSoundsConfiguration {
return AnimatedEmojiSoundsConfiguration(sounds: [:]) return AnimatedEmojiSoundsConfiguration(sounds: [:])
} }
@@ -2800,7 +2878,7 @@ struct AnimatedEmojiSoundsConfiguration {
self.sounds = sounds self.sounds = sounds
} }
static func with(appConfiguration: AppConfiguration, account: Account) -> AnimatedEmojiSoundsConfiguration { public static func with(appConfiguration: AppConfiguration, account: Account) -> AnimatedEmojiSoundsConfiguration {
if let data = appConfiguration.data, let values = data["emojies_sounds"] as? [String: Any] { if let data = appConfiguration.data, let values = data["emojies_sounds"] as? [String: Any] {
var sounds: [String: TelegramMediaFile] = [:] var sounds: [String: TelegramMediaFile] = [:]
for (key, value) in values { for (key, value) in values {

View File

@@ -0,0 +1,19 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ChatMessageTransitionNode",
module_name = "ChatMessageTransitionNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemView",
],
visibility = [
"//visibility:public",
],
)

View File

@@ -0,0 +1,15 @@
import Foundation
import UIKit
import ChatMessageItemView
import AsyncDisplayKit
public protocol ChatMessageTransitionNodeDecorationItemNode: ASDisplayNode {
var contentView: UIView { get }
}
public protocol ChatMessageTransitionNode: AnyObject {
typealias DecorationItemNode = ChatMessageTransitionNodeDecorationItemNode
func add(decorationView: UIView, itemNode: ChatMessageItemView) -> DecorationItemNode
func remove(decorationNode: DecorationItemNode)
}

View File

@@ -0,0 +1,25 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ManagedDiceAnimationNode",
module_name = "ManagedDiceAnimationNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/AsyncDisplayKit",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/AccountContext",
"//submodules/StickerResources",
"//submodules/ManagedAnimationNode",
],
visibility = [
"//visibility:public",
],
)

View File

@@ -8,7 +8,7 @@ import AccountContext
import StickerResources import StickerResources
import ManagedAnimationNode import ManagedAnimationNode
enum ManagedDiceAnimationState: Equatable { public enum ManagedDiceAnimationState: Equatable {
case rolling case rolling
case value(Int32, Bool) case value(Int32, Bool)
} }
@@ -86,7 +86,7 @@ private struct InteractiveEmojiSuccessParameters {
} }
public struct InteractiveEmojiConfiguration { public struct InteractiveEmojiConfiguration {
static var defaultValue: InteractiveEmojiConfiguration { public static var defaultValue: InteractiveEmojiConfiguration {
return InteractiveEmojiConfiguration(emojis: [], successParameters: [:]) return InteractiveEmojiConfiguration(emojis: [], successParameters: [:])
} }
@@ -98,7 +98,7 @@ public struct InteractiveEmojiConfiguration {
self.successParameters = successParameters self.successParameters = successParameters
} }
static func with(appConfiguration: AppConfiguration) -> InteractiveEmojiConfiguration { public static func with(appConfiguration: AppConfiguration) -> InteractiveEmojiConfiguration {
if let data = appConfiguration.data, let emojis = data["emojies_send_dice"] as? [String] { if let data = appConfiguration.data, let emojis = data["emojies_send_dice"] as? [String] {
var successParameters: [String: InteractiveEmojiSuccessParameters] = [:] var successParameters: [String: InteractiveEmojiSuccessParameters] = [:]
if let success = data["emojies_send_dice_success"] as? [String: [String: Double]] { if let success = data["emojies_send_dice_success"] as? [String: [String: Double]] {
@@ -115,7 +115,7 @@ public struct InteractiveEmojiConfiguration {
} }
} }
final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStickerNode { public final class ManagedDiceAnimationNode: ManagedAnimationNode {
private let context: AccountContext private let context: AccountContext
private let emoji: String private let emoji: String
@@ -125,9 +125,9 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
private let configuration = Promise<InteractiveEmojiConfiguration?>() private let configuration = Promise<InteractiveEmojiConfiguration?>()
private let emojis = Promise<[TelegramMediaFile]>() private let emojis = Promise<[TelegramMediaFile]>()
var success: (() -> Void)? public var success: (() -> Void)?
init(context: AccountContext, emoji: String) { public init(context: AccountContext, emoji: String) {
self.context = context self.context = context
self.emoji = emoji self.emoji = emoji
@@ -157,7 +157,7 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
self.disposable.dispose() self.disposable.dispose()
} }
func setState(_ diceState: ManagedDiceAnimationState) { public func setState(_ diceState: ManagedDiceAnimationState) {
let previousState = self.diceState let previousState = self.diceState
self.diceState = diceState self.diceState = diceState
@@ -203,13 +203,13 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
} }
} }
func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool) { public func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool) {
} }
func setFrameIndex(_ frameIndex: Int) { public func setFrameIndex(_ frameIndex: Int) {
} }
var currentFrameIndex: Int { public var currentFrameIndex: Int {
return 0 return 0
} }
} }

View File

@@ -0,0 +1,19 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "MessageHaptics",
module_name = "MessageHaptics",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/SSignalKit/SwiftSignalKit",
],
visibility = [
"//visibility:public",
],
)

View File

@@ -5,11 +5,11 @@ import SwiftSignalKit
private let firstImpactTime: Double = 0.4 private let firstImpactTime: Double = 0.4
private let secondImpactTime: Double = 0.6 private let secondImpactTime: Double = 0.6
final class CoffinHaptic: EmojiHaptic { public final class CoffinHaptic: EmojiHaptic {
private var hapticFeedback = HapticFeedback() private var hapticFeedback = HapticFeedback()
private var timer: SwiftSignalKit.Timer? private var timer: SwiftSignalKit.Timer?
private var time: Double = 0.0 private var time: Double = 0.0
var enabled: Bool = false { public var enabled: Bool = false {
didSet { didSet {
if !self.enabled { if !self.enabled {
self.reset() self.reset()
@@ -17,9 +17,12 @@ final class CoffinHaptic: EmojiHaptic {
} }
} }
var active: Bool { public var active: Bool {
return self.timer != nil return self.timer != nil
} }
public init() {
}
private func reset() { private func reset() {
if let timer = self.timer { if let timer = self.timer {
@@ -36,7 +39,7 @@ final class CoffinHaptic: EmojiHaptic {
} }
} }
func start(time: Double) { public func start(time: Double) {
self.hapticFeedback.prepareImpact() self.hapticFeedback.prepareImpact()
if time > firstImpactTime { if time > firstImpactTime {

View File

@@ -2,18 +2,18 @@ import Foundation
import Display import Display
import SwiftSignalKit import SwiftSignalKit
protocol EmojiHaptic { public protocol EmojiHaptic {
var enabled: Bool { get set } var enabled: Bool { get set }
var active: Bool { get } var active: Bool { get }
func start(time: Double) func start(time: Double)
} }
final class HeartbeatHaptic: EmojiHaptic { public final class HeartbeatHaptic: EmojiHaptic {
private var hapticFeedback = HapticFeedback() private var hapticFeedback = HapticFeedback()
private var timer: SwiftSignalKit.Timer? private var timer: SwiftSignalKit.Timer?
private var time: Double = 0.0 private var time: Double = 0.0
var enabled: Bool = false { public var enabled: Bool = false {
didSet { didSet {
if !self.enabled { if !self.enabled {
self.reset() self.reset()
@@ -21,9 +21,12 @@ final class HeartbeatHaptic: EmojiHaptic {
} }
} }
var active: Bool { public var active: Bool {
return self.timer != nil return self.timer != nil
} }
public init() {
}
private func reset() { private func reset() {
if let timer = self.timer { if let timer = self.timer {
@@ -42,7 +45,7 @@ final class HeartbeatHaptic: EmojiHaptic {
} }
} }
func start(time: Double) { public func start(time: Double) {
self.hapticFeedback.prepareImpact() self.hapticFeedback.prepareImpact()
if time > 2.0 { if time > 2.0 {

View File

@@ -4,11 +4,11 @@ import SwiftSignalKit
private let impactTime: Double = 0.6 private let impactTime: Double = 0.6
final class PeachHaptic: EmojiHaptic { public final class PeachHaptic: EmojiHaptic {
private var hapticFeedback = HapticFeedback() private var hapticFeedback = HapticFeedback()
private var timer: SwiftSignalKit.Timer? private var timer: SwiftSignalKit.Timer?
private var time: Double = 0.0 private var time: Double = 0.0
var enabled: Bool = false { public var enabled: Bool = false {
didSet { didSet {
if !self.enabled { if !self.enabled {
self.reset() self.reset()
@@ -16,9 +16,12 @@ final class PeachHaptic: EmojiHaptic {
} }
} }
var active: Bool { public var active: Bool {
return self.timer != nil return self.timer != nil
} }
public init() {
}
private func reset() { private func reset() {
if let timer = self.timer { if let timer = self.timer {
@@ -35,7 +38,7 @@ final class PeachHaptic: EmojiHaptic {
} }
} }
func start(time: Double) { public func start(time: Double) {
self.hapticFeedback.prepareImpact() self.hapticFeedback.prepareImpact()
if time > impactTime { if time > impactTime {

View File

@@ -110,6 +110,7 @@ import ChatMessagePollBubbleContentNode
import ChatMessageItem import ChatMessageItem
import ChatMessageItemView import ChatMessageItemView
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatMessageAnimatedStickerItemNode
public enum ChatControllerPeekActions { public enum ChatControllerPeekActions {
case standard case standard
@@ -8089,9 +8090,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else { } else {
isScheduledMessages = false isScheduledMessages = false
} }
let duration: Double = strongSelf.chatDisplayNode.messageTransitionNode.hasScheduledTransitions ? ChatMessageTransitionNode.animationDuration : 0.18 let duration: Double = strongSelf.chatDisplayNode.messageTransitionNode.hasScheduledTransitions ? ChatMessageTransitionNodeImpl.animationDuration : 0.18
let curve: ContainedViewLayoutTransitionCurve = strongSelf.chatDisplayNode.messageTransitionNode.hasScheduledTransitions ? ChatMessageTransitionNode.verticalAnimationCurve : .easeInOut let curve: ContainedViewLayoutTransitionCurve = strongSelf.chatDisplayNode.messageTransitionNode.hasScheduledTransitions ? ChatMessageTransitionNodeImpl.verticalAnimationCurve : .easeInOut
let controlPoints: (Float, Float, Float, Float) = strongSelf.chatDisplayNode.messageTransitionNode.hasScheduledTransitions ? ChatMessageTransitionNode.verticalAnimationControlPoints : (0.5, 0.33, 0.0, 0.0) let controlPoints: (Float, Float, Float, Float) = strongSelf.chatDisplayNode.messageTransitionNode.hasScheduledTransitions ? ChatMessageTransitionNodeImpl.verticalAnimationControlPoints : (0.5, 0.33, 0.0, 0.0)
let shouldUseFastMessageSendAnimation = strongSelf.chatDisplayNode.shouldUseFastMessageSendAnimation let shouldUseFastMessageSendAnimation = strongSelf.chatDisplayNode.shouldUseFastMessageSendAnimation
@@ -15533,15 +15534,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
if addedTransitions.count > 1 { if addedTransitions.count > 1 {
var transitions: [(Int64, ChatMessageTransitionNode.Source, () -> Void)] = [] var transitions: [(Int64, ChatMessageTransitionNodeImpl.Source, () -> Void)] = []
for (correlationId, uniqueIds, initiated) in addedTransitions { for (correlationId, uniqueIds, initiated) in addedTransitions {
var source: ChatMessageTransitionNode.Source? var source: ChatMessageTransitionNodeImpl.Source?
if uniqueIds.count > 1 { if uniqueIds.count > 1 {
source = .groupedMediaInput(ChatMessageTransitionNode.Source.GroupedMediaInput(extractSnapshots: { source = .groupedMediaInput(ChatMessageTransitionNodeImpl.Source.GroupedMediaInput(extractSnapshots: {
return uniqueIds.compactMap({ getAnimatedTransitionSource?($0) }) return uniqueIds.compactMap({ getAnimatedTransitionSource?($0) })
})) }))
} else if let uniqueId = uniqueIds.first { } else if let uniqueId = uniqueIds.first {
source = .mediaInput(ChatMessageTransitionNode.Source.MediaInput(extractSnapshot: { source = .mediaInput(ChatMessageTransitionNodeImpl.Source.MediaInput(extractSnapshot: {
return getAnimatedTransitionSource?(uniqueId) return getAnimatedTransitionSource?(uniqueId)
})) }))
} }
@@ -15551,13 +15552,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
strongSelf.chatDisplayNode.messageTransitionNode.add(grouped: transitions) strongSelf.chatDisplayNode.messageTransitionNode.add(grouped: transitions)
} else if let (correlationId, uniqueIds, initiated) = addedTransitions.first { } else if let (correlationId, uniqueIds, initiated) = addedTransitions.first {
var source: ChatMessageTransitionNode.Source? var source: ChatMessageTransitionNodeImpl.Source?
if uniqueIds.count > 1 { if uniqueIds.count > 1 {
source = .groupedMediaInput(ChatMessageTransitionNode.Source.GroupedMediaInput(extractSnapshots: { source = .groupedMediaInput(ChatMessageTransitionNodeImpl.Source.GroupedMediaInput(extractSnapshots: {
return uniqueIds.compactMap({ getAnimatedTransitionSource?($0) }) return uniqueIds.compactMap({ getAnimatedTransitionSource?($0) })
})) }))
} else if let uniqueId = uniqueIds.first { } else if let uniqueId = uniqueIds.first {
source = .mediaInput(ChatMessageTransitionNode.Source.MediaInput(extractSnapshot: { source = .mediaInput(ChatMessageTransitionNodeImpl.Source.MediaInput(extractSnapshot: {
return getAnimatedTransitionSource?(uniqueId) return getAnimatedTransitionSource?(uniqueId)
})) }))
} }
@@ -15825,7 +15826,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if strongSelf.chatDisplayNode.shouldAnimateMessageTransition, let extractedView = videoController.extractVideoSnapshot() { if strongSelf.chatDisplayNode.shouldAnimateMessageTransition, let extractedView = videoController.extractVideoSnapshot() {
usedCorrelationId = true usedCorrelationId = true
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .videoMessage(ChatMessageTransitionNode.Source.VideoMessage(view: extractedView)), initiated: { [weak videoController] in strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .videoMessage(ChatMessageTransitionNodeImpl.Source.VideoMessage(view: extractedView)), initiated: { [weak videoController] in
videoController?.hideVideoSnapshot() videoController?.hideVideoSnapshot()
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@@ -15937,7 +15938,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if strongSelf.chatDisplayNode.shouldAnimateMessageTransition, let textInputPanelNode = strongSelf.chatDisplayNode.textInputPanelNode, let micButton = textInputPanelNode.micButton { if strongSelf.chatDisplayNode.shouldAnimateMessageTransition, let textInputPanelNode = strongSelf.chatDisplayNode.textInputPanelNode, let micButton = textInputPanelNode.micButton {
usedCorrelationId = true usedCorrelationId = true
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .audioMicInput(ChatMessageTransitionNode.Source.AudioMicInput(micButton: micButton)), initiated: { strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .audioMicInput(ChatMessageTransitionNodeImpl.Source.AudioMicInput(micButton: micButton)), initiated: {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }

View File

@@ -34,6 +34,8 @@ import TextSelectionNode
import ReplyAccessoryPanelNode import ReplyAccessoryPanelNode
import ChatMessageItemView import ChatMessageItemView
import ChatMessageSelectionNode import ChatMessageSelectionNode
import ManagedDiceAnimationNode
import ChatMessageTransitionNode
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem { final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
let itemNode: OverlayMediaItemNode let itemNode: OverlayMediaItemNode
@@ -267,7 +269,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private var dropDimNode: ASDisplayNode? private var dropDimNode: ASDisplayNode?
let messageTransitionNode: ChatMessageTransitionNode let messageTransitionNode: ChatMessageTransitionNodeImpl
private let presentationContextMarker = ASDisplayNode() private let presentationContextMarker = ASDisplayNode()
@@ -589,7 +591,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
source = .default source = .default
} }
var getMessageTransitionNode: (() -> ChatMessageTransitionNode?)? var getMessageTransitionNode: (() -> ChatMessageTransitionNodeImpl?)?
self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: controller?.updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: nil, source: source, subject: subject, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), messageTransitionNode: { self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: controller?.updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: nil, source: source, subject: subject, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), messageTransitionNode: {
return getMessageTransitionNode?() return getMessageTransitionNode?()
}) })
@@ -605,7 +607,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
var getContentAreaInScreenSpaceImpl: (() -> CGRect)? var getContentAreaInScreenSpaceImpl: (() -> CGRect)?
var onTransitionEventImpl: ((ContainedViewLayoutTransition) -> Void)? var onTransitionEventImpl: ((ContainedViewLayoutTransition) -> Void)?
self.messageTransitionNode = ChatMessageTransitionNode(listNode: self.historyNode, getContentAreaInScreenSpace: { self.messageTransitionNode = ChatMessageTransitionNodeImpl(listNode: self.historyNode, getContentAreaInScreenSpace: {
return getContentAreaInScreenSpaceImpl?() ?? CGRect() return getContentAreaInScreenSpaceImpl?() ?? CGRect()
}, onTransitionEvent: { transition in }, onTransitionEvent: { transition in
onTransitionEventImpl?(transition) onTransitionEventImpl?(transition)
@@ -3472,7 +3474,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
if self.shouldAnimateMessageTransition, let inputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode, let textInput = inputPanelNode.makeSnapshotForTransition() { if self.shouldAnimateMessageTransition, let inputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode, let textInput = inputPanelNode.makeSnapshotForTransition() {
usedCorrelationId = correlationId usedCorrelationId = correlationId
let source: ChatMessageTransitionNode.Source = .textInput(textInput: textInput, replyPanel: replyPanel) let source: ChatMessageTransitionNodeImpl.Source = .textInput(textInput: textInput, replyPanel: replyPanel)
self.messageTransitionNode.add(correlationId: correlationId, source: source, initiated: { self.messageTransitionNode.add(correlationId: correlationId, source: source, initiated: {
}) })
} }

View File

@@ -28,6 +28,7 @@ import ChatOverscrollControl
import ChatBotInfoItem import ChatBotInfoItem
import ChatMessageItem import ChatMessageItem
import ChatMessageItemView import ChatMessageItemView
import ChatMessageTransitionNode
struct ChatTopVisibleMessageRange: Equatable { struct ChatTopVisibleMessageRange: Equatable {
var lowerBound: MessageIndex var lowerBound: MessageIndex
@@ -662,7 +663,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
private var toLang: String? private var toLang: String?
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, tagMask: MessageTags?, source: ChatHistoryListSource = .default, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal<Set<MessageId>?, NoError>, mode: ChatHistoryListMode = .bubbles, messageTransitionNode: @escaping () -> ChatMessageTransitionNode? = { nil }) { public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, tagMask: MessageTags?, source: ChatHistoryListSource = .default, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal<Set<MessageId>?, NoError>, mode: ChatHistoryListMode = .bubbles, messageTransitionNode: @escaping () -> ChatMessageTransitionNodeImpl? = { nil }) {
var tagMask = tagMask var tagMask = tagMask
if case .pinnedMessages = subject { if case .pinnedMessages = subject {
tagMask = .pinned tagMask = .pinned
@@ -1015,7 +1016,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
private func beginChatHistoryTransitions( private func beginChatHistoryTransitions(
selectedMessages: Signal<Set<MessageId>?, NoError>, selectedMessages: Signal<Set<MessageId>?, NoError>,
messageTransitionNode: @escaping () -> ChatMessageTransitionNode? messageTransitionNode: @escaping () -> ChatMessageTransitionNodeImpl?
) { ) {
let context = self.context let context = self.context
let chatLocation = self.chatLocation let chatLocation = self.chatLocation

View File

@@ -14,6 +14,7 @@ import ChatMessageItem
import ChatMessageItemView import ChatMessageItemView
import ChatMessageStickerItemNode import ChatMessageStickerItemNode
import ChatMessageInstantVideoItemNode import ChatMessageInstantVideoItemNode
import ChatMessageAnimatedStickerItemNode
final class ChatLoadingNode: ASDisplayNode { final class ChatLoadingNode: ASDisplayNode {
private let backgroundNode: NavigationBackgroundNode private let backgroundNode: NavigationBackgroundNode

View File

@@ -851,7 +851,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
transition.animateTransformScale(node: self, from: CGPoint(x: 0.85, y: 0.85), delay: delay) transition.animateTransformScale(node: self, from: CGPoint(x: 0.85, y: 0.85), delay: delay)
} }
func animateContentFromTextInputField(textInput: ChatMessageTransitionNode.Source.TextInput, transition: CombinedTransition) { func animateContentFromTextInputField(textInput: ChatMessageTransitionNodeImpl.Source.TextInput, transition: CombinedTransition) {
let widthDifference = self.backgroundNode.frame.width - textInput.backgroundView.frame.width let widthDifference = self.backgroundNode.frame.width - textInput.backgroundView.frame.width
let heightDifference = self.backgroundNode.frame.height - textInput.backgroundView.frame.height let heightDifference = self.backgroundNode.frame.height - textInput.backgroundView.frame.height
@@ -884,7 +884,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
} }
func animateReplyPanel(sourceReplyPanel: ChatMessageTransitionNode.ReplyPanel, transition: CombinedTransition) { func animateReplyPanel(sourceReplyPanel: ChatMessageTransitionNodeImpl.ReplyPanel, transition: CombinedTransition) {
if let replyInfoNode = self.replyInfoNode { if let replyInfoNode = self.replyInfoNode {
let localRect = self.mainContextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view) let localRect = self.mainContextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view)
let mappedPanel = ChatMessageReplyInfoNode.TransitionReplyPanel( let mappedPanel = ChatMessageReplyInfoNode.TransitionReplyPanel(

View File

@@ -15,6 +15,7 @@ import ChatHistoryEntry
import ChatMessageItem import ChatMessageItem
import ChatMessageItemView import ChatMessageItemView
import ChatMessageStickerItemNode import ChatMessageStickerItemNode
import ChatMessageAnimatedStickerItemNode
private func mediaMergeableStyle(_ media: Media) -> ChatMessageMerge { private func mediaMergeableStyle(_ media: Media) -> ChatMessageMerge {
if let story = media as? TelegramMediaStory, story.isMention { if let story = media as? TelegramMediaStory, story.isMention {

View File

@@ -16,6 +16,8 @@ import ReplyAccessoryPanelNode
import ChatMessageItemView import ChatMessageItemView
import ChatMessageStickerItemNode import ChatMessageStickerItemNode
import ChatMessageInstantVideoItemNode import ChatMessageInstantVideoItemNode
import ChatMessageAnimatedStickerItemNode
import ChatMessageTransitionNode
private func convertAnimatingSourceRect(_ rect: CGRect, fromView: UIView, toView: UIView?) -> CGRect { private func convertAnimatingSourceRect(_ rect: CGRect, fromView: UIView, toView: UIView?) -> CGRect {
if let presentationLayer = fromView.layer.presentation() { if let presentationLayer = fromView.layer.presentation() {
@@ -100,7 +102,7 @@ private final class OverlayTransitionContainerController: ViewController, Standa
} }
} }
public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransitionProtocol { public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTransitionNode, ChatMessageTransitionProtocol {
static let animationDuration: Double = 0.3 static let animationDuration: Double = 0.3
static let verticalAnimationControlPoints: (Float, Float, Float, Float) = (0.19919472913616398, 0.010644531250000006, 0.27920937042459737, 0.91025390625) static let verticalAnimationControlPoints: (Float, Float, Float, Float) = (0.19919472913616398, 0.010644531250000006, 0.27920937042459737, 0.91025390625)
@@ -235,7 +237,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
case groupedMediaInput(GroupedMediaInput) case groupedMediaInput(GroupedMediaInput)
} }
final class DecorationItemNode: ASDisplayNode { final class DecorationItemNodeImpl: ASDisplayNode, ChatMessageTransitionNode.DecorationItemNode {
let itemNode: ChatMessageItemView let itemNode: ChatMessageItemView
let contentView: UIView let contentView: UIView
private let getContentAreaInScreenSpace: () -> CGRect private let getContentAreaInScreenSpace: () -> CGRect
@@ -288,7 +290,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
private final class AnimatingItemNode: ASDisplayNode { private final class AnimatingItemNode: ASDisplayNode {
let itemNode: ChatMessageItemView let itemNode: ChatMessageItemView
private let contextSourceNode: ContextExtractedContentContainingNode private let contextSourceNode: ContextExtractedContentContainingNode
private let source: ChatMessageTransitionNode.Source private let source: ChatMessageTransitionNodeImpl.Source
private let getContentAreaInScreenSpace: () -> CGRect private let getContentAreaInScreenSpace: () -> CGRect
private let scrollingContainer: ASDisplayNode private let scrollingContainer: ASDisplayNode
@@ -300,7 +302,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
var animationEnded: (() -> Void)? var animationEnded: (() -> Void)?
var updateAfterCompletion: Bool = false var updateAfterCompletion: Bool = false
init(itemNode: ChatMessageItemView, contextSourceNode: ContextExtractedContentContainingNode, source: ChatMessageTransitionNode.Source, getContentAreaInScreenSpace: @escaping () -> CGRect) { init(itemNode: ChatMessageItemView, contextSourceNode: ContextExtractedContentContainingNode, source: ChatMessageTransitionNodeImpl.Source, getContentAreaInScreenSpace: @escaping () -> CGRect) {
self.itemNode = itemNode self.itemNode = itemNode
self.getContentAreaInScreenSpace = getContentAreaInScreenSpace self.getContentAreaInScreenSpace = getContentAreaInScreenSpace
@@ -328,7 +330,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
} }
func beginAnimation() { func beginAnimation() {
let verticalDuration: Double = ChatMessageTransitionNode.animationDuration let verticalDuration: Double = ChatMessageTransitionNodeImpl.animationDuration
let horizontalDuration: Double = verticalDuration let horizontalDuration: Double = verticalDuration
let delay: Double = 0.0 let delay: Double = 0.0
@@ -367,7 +369,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
let sourceBackgroundAbsoluteRect = initialTextInput.backgroundView.frame.offsetBy(dx: sourceRect.minX, dy: sourceRect.minY) let sourceBackgroundAbsoluteRect = initialTextInput.backgroundView.frame.offsetBy(dx: sourceRect.minX, dy: sourceRect.minY)
let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.minX, y: sourceBackgroundAbsoluteRect.maxY - self.contextSourceNode.contentRect.height), size: self.contextSourceNode.contentRect.size) let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.minX, y: sourceBackgroundAbsoluteRect.maxY - self.contextSourceNode.contentRect.height), size: self.contextSourceNode.contentRect.size)
let textInput = ChatMessageTransitionNode.Source.TextInput(backgroundView: initialTextInput.backgroundView, contentView: initialTextInput.contentView, sourceRect: sourceRect, scrollOffset: initialTextInput.scrollOffset) let textInput = ChatMessageTransitionNodeImpl.Source.TextInput(backgroundView: initialTextInput.backgroundView, contentView: initialTextInput.contentView, sourceRect: sourceRect, scrollOffset: initialTextInput.scrollOffset)
textInput.backgroundView.frame = CGRect(origin: CGPoint(x: 0.0, y: sourceAbsoluteRect.height - sourceBackgroundAbsoluteRect.height), size: textInput.backgroundView.bounds.size) textInput.backgroundView.frame = CGRect(origin: CGPoint(x: 0.0, y: sourceAbsoluteRect.height - sourceBackgroundAbsoluteRect.height), size: textInput.backgroundView.bounds.size)
textInput.contentView.frame = textInput.contentView.frame.offsetBy(dx: 0.0, dy: sourceAbsoluteRect.height - sourceBackgroundAbsoluteRect.height) textInput.contentView.frame = textInput.contentView.frame.offsetBy(dx: 0.0, dy: sourceAbsoluteRect.height - sourceBackgroundAbsoluteRect.height)
@@ -390,9 +392,9 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
self.itemNode.cancelInsertionAnimations() self.itemNode.cancelInsertionAnimations()
let horizontalCurve = ChatMessageTransitionNode.horizontalAnimationCurve let horizontalCurve = ChatMessageTransitionNodeImpl.horizontalAnimationCurve
let horizontalTransition: ContainedViewLayoutTransition = .animated(duration: horizontalDuration, curve: horizontalCurve) let horizontalTransition: ContainedViewLayoutTransition = .animated(duration: horizontalDuration, curve: horizontalCurve)
let verticalCurve = ChatMessageTransitionNode.verticalAnimationCurve let verticalCurve = ChatMessageTransitionNodeImpl.verticalAnimationCurve
let verticalTransition: ContainedViewLayoutTransition = .animated(duration: verticalDuration, curve: verticalCurve) let verticalTransition: ContainedViewLayoutTransition = .animated(duration: verticalDuration, curve: verticalCurve)
let combinedTransition = CombinedTransition(horizontal: horizontalTransition, vertical: verticalTransition) let combinedTransition = CombinedTransition(horizontal: horizontalTransition, vertical: verticalTransition)
@@ -415,9 +417,27 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
itemNode.animateReplyPanel(sourceReplyPanel: sourceReplyPanel, transition: combinedTransition) itemNode.animateReplyPanel(sourceReplyPanel: sourceReplyPanel, transition: combinedTransition)
} }
} else if let itemNode = self.itemNode as? ChatMessageAnimatedStickerItemNode { } else if let itemNode = self.itemNode as? ChatMessageAnimatedStickerItemNode {
itemNode.animateContentFromTextInputField(textInput: textInput, transition: combinedTransition) itemNode.animateContentFromTextInputField(
textInput: ChatMessageAnimatedStickerItemNode.AnimationTransitionTextInput(
backgroundView: textInput.backgroundView,
contentView: textInput.contentView,
sourceRect: textInput.sourceRect,
scrollOffset: textInput.scrollOffset
),
transition: combinedTransition
)
if let sourceReplyPanel = sourceReplyPanel { if let sourceReplyPanel = sourceReplyPanel {
itemNode.animateReplyPanel(sourceReplyPanel: sourceReplyPanel, transition: combinedTransition) itemNode.animateReplyPanel(
sourceReplyPanel: ChatMessageAnimatedStickerItemNode.AnimationTransitionReplyPanel(
titleNode: sourceReplyPanel.titleNode,
textNode: sourceReplyPanel.textNode,
lineNode: sourceReplyPanel.lineNode,
imageNode: sourceReplyPanel.imageNode,
relativeSourceRect: sourceReplyPanel.relativeSourceRect,
relativeTargetRect: sourceReplyPanel.relativeTargetRect
),
transition: combinedTransition
)
} }
} else if let itemNode = self.itemNode as? ChatMessageStickerItemNode { } else if let itemNode = self.itemNode as? ChatMessageStickerItemNode {
itemNode.animateContentFromTextInputField( itemNode.animateContentFromTextInputField(
@@ -479,15 +499,34 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
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(titleNode: replyPanel.titleNode, textNode: replyPanel.textNode, lineNode: replyPanel.lineNode, imageNode: replyPanel.imageNode, relativeSourceRect: replySourceAbsoluteFrame, relativeTargetRect: replySourceAbsoluteFrame.offsetBy(dx: 0.0, dy: replySourceAbsoluteFrame.height))
} }
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve)) let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNodeImpl.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNodeImpl.verticalAnimationCurve))
if let itemNode = self.itemNode as? ChatMessageAnimatedStickerItemNode { if let itemNode = self.itemNode as? ChatMessageAnimatedStickerItemNode {
itemNode.animateContentFromStickerGridItem(stickerSource: stickerSource, transition: combinedTransition) itemNode.animateContentFromStickerGridItem(
stickerSource: ChatMessageAnimatedStickerItemNode.AnimationTransitionSticker(
imageNode: stickerSource.imageNode,
animationNode: stickerSource.animationNode,
placeholderNode: stickerSource.placeholderNode,
imageLayer: stickerSource.imageLayer,
relativeSourceRect: stickerSource.relativeSourceRect
),
transition: combinedTransition
)
if let sourceAnimationNode = stickerSource.animationNode { if let sourceAnimationNode = stickerSource.animationNode {
itemNode.animationNode?.setFrameIndex(sourceAnimationNode.currentFrameIndex) itemNode.animationNode?.setFrameIndex(sourceAnimationNode.currentFrameIndex)
} }
if let sourceReplyPanel = sourceReplyPanel { if let sourceReplyPanel = sourceReplyPanel {
itemNode.animateReplyPanel(sourceReplyPanel: sourceReplyPanel, transition: combinedTransition) itemNode.animateReplyPanel(
sourceReplyPanel: ChatMessageAnimatedStickerItemNode.AnimationTransitionReplyPanel(
titleNode: sourceReplyPanel.titleNode,
textNode: sourceReplyPanel.textNode,
lineNode: sourceReplyPanel.lineNode,
imageNode: sourceReplyPanel.imageNode,
relativeSourceRect: sourceReplyPanel.relativeSourceRect,
relativeTargetRect: sourceReplyPanel.relativeTargetRect
),
transition: combinedTransition
)
} }
} else if let itemNode = self.itemNode as? ChatMessageStickerItemNode { } else if let itemNode = self.itemNode as? ChatMessageStickerItemNode {
itemNode.animateContentFromStickerGridItem( itemNode.animateContentFromStickerGridItem(
@@ -517,15 +556,15 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY) self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY)
self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size) self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size)
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.endAnimation() strongSelf.endAnimation()
}) })
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration) self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), ChatMessageTransitionNodeImpl.horizontalAnimationCurve, horizontalDuration)
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration) self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), ChatMessageTransitionNodeImpl.verticalAnimationCurve, verticalDuration)
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true) self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.horizontalAnimationCurve.mediaTimingFunction, additive: true)
switch stickerMediaInput { switch stickerMediaInput {
case .inputPanel, .universal: case .inputPanel, .universal:
@@ -544,7 +583,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
container.isHidden = true container.isHidden = true
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve)) let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNodeImpl.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNodeImpl.verticalAnimationCurve))
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode { if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
if let contextContainer = itemNode.animateFromMicInput(micInputNode: snapshotView, transition: combinedTransition) { if let contextContainer = itemNode.animateFromMicInput(micInputNode: snapshotView, transition: combinedTransition) {
@@ -554,7 +593,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -contextContainer.contentRect.minX, dy: -contextContainer.contentRect.minY) self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -contextContainer.contentRect.minX, dy: -contextContainer.contentRect.minY)
contextContainer.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size) contextContainer.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size)
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self, weak contextContainer, weak container] _ in self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self, weak contextContainer, weak container] _ in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@@ -569,13 +608,13 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
strongSelf.endAnimation() strongSelf.endAnimation()
}) })
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true) self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.horizontalAnimationCurve.mediaTimingFunction, additive: true)
} }
} }
} }
} }
case let .videoMessage(videoMessage): case let .videoMessage(videoMessage):
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve)) let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNodeImpl.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNodeImpl.verticalAnimationCurve))
if let itemNode = self.itemNode as? ChatMessageInstantVideoItemNode { if let itemNode = self.itemNode as? ChatMessageInstantVideoItemNode {
itemNode.cancelInsertionAnimations() itemNode.cancelInsertionAnimations()
@@ -591,9 +630,9 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
videoMessage.view.frame = videoMessage.view.frame.offsetBy(dx: targetAbsoluteRect.midX - sourceAbsoluteRect.midX, dy: targetAbsoluteRect.midY - sourceAbsoluteRect.midY) videoMessage.view.frame = videoMessage.view.frame.offsetBy(dx: targetAbsoluteRect.midX - sourceAbsoluteRect.midX, dy: targetAbsoluteRect.midY - sourceAbsoluteRect.midY)
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY) self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY)
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true) self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true)
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, completion: { [weak self] _ in self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.verticalAnimationCurve.mediaTimingFunction, additive: true, completion: { [weak self] _ in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@@ -618,7 +657,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
let sourceBackgroundAbsoluteRect = snapshotView.frame let sourceBackgroundAbsoluteRect = snapshotView.frame
let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.midX - self.contextSourceNode.contentRect.size.width / 2.0, y: sourceBackgroundAbsoluteRect.midY - self.contextSourceNode.contentRect.size.height / 2.0), size: self.contextSourceNode.contentRect.size) let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.midX - self.contextSourceNode.contentRect.size.width / 2.0, y: sourceBackgroundAbsoluteRect.midY - self.contextSourceNode.contentRect.size.height / 2.0), size: self.contextSourceNode.contentRect.size)
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve)) let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNodeImpl.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNodeImpl.verticalAnimationCurve))
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode { if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
itemNode.animateContentFromMediaInput(snapshotView: snapshotView, transition: combinedTransition) itemNode.animateContentFromMediaInput(snapshotView: snapshotView, transition: combinedTransition)
@@ -631,8 +670,8 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size) self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size)
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true) self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true)
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@@ -647,8 +686,8 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
snapshotView?.removeFromSuperview() snapshotView?.removeFromSuperview()
}) })
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration) self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNodeImpl.horizontalAnimationCurve, horizontalDuration)
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration) self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNodeImpl.verticalAnimationCurve, verticalDuration)
} }
} }
} else { } else {
@@ -669,7 +708,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
self.containerNode.addSubnode(self.contextSourceNode.contentNode) self.containerNode.addSubnode(self.contextSourceNode.contentNode)
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve)) let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNodeImpl.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNodeImpl.verticalAnimationCurve))
var targetContentRects: [CGRect] = [] var targetContentRects: [CGRect] = []
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode { if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
@@ -709,8 +748,8 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size) self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size)
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true) self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true)
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNodeImpl.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@@ -736,8 +775,8 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
index += 1 index += 1
} }
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration) self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNodeImpl.horizontalAnimationCurve, horizontalDuration)
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration) self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNodeImpl.verticalAnimationCurve, verticalDuration)
} }
} }
} }
@@ -838,7 +877,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
private var currentPendingItems: [Int64: (Source, () -> Void)] = [:] private var currentPendingItems: [Int64: (Source, () -> Void)] = [:]
private var animatingItemNodes: [AnimatingItemNode] = [] private var animatingItemNodes: [AnimatingItemNode] = []
private var decorationItemNodes: [DecorationItemNode] = [] private var decorationItemNodes: [DecorationItemNodeImpl] = []
private var messageReactionContexts: [MessageReactionContext] = [] private var messageReactionContexts: [MessageReactionContext] = []
var hasScheduledTransitions: Bool { var hasScheduledTransitions: Bool {
@@ -891,8 +930,8 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
self.listNode.setCurrentSendAnimationCorrelationIds(correlationIds) self.listNode.setCurrentSendAnimationCorrelationIds(correlationIds)
} }
func add(decorationView: UIView, itemNode: ChatMessageItemView) -> DecorationItemNode { public func add(decorationView: UIView, itemNode: ChatMessageItemView) -> DecorationItemNode {
let decorationItemNode = DecorationItemNode(itemNode: itemNode, contentView: decorationView, getContentAreaInScreenSpace: self.getContentAreaInScreenSpace) let decorationItemNode = DecorationItemNodeImpl(itemNode: itemNode, contentView: decorationView, getContentAreaInScreenSpace: self.getContentAreaInScreenSpace)
decorationItemNode.updateLayout(size: self.bounds.size) decorationItemNode.updateLayout(size: self.bounds.size)
self.decorationItemNodes.append(decorationItemNode) self.decorationItemNodes.append(decorationItemNode)
@@ -907,10 +946,12 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
return decorationItemNode return decorationItemNode
} }
func remove(decorationNode: DecorationItemNode) { public func remove(decorationNode: DecorationItemNode) {
self.decorationItemNodes.removeAll(where: { $0 === decorationNode }) self.decorationItemNodes.removeAll(where: { $0 === decorationNode })
decorationNode.removeFromSupernode() decorationNode.removeFromSupernode()
decorationNode.overlayController?.dismiss() if let decorationNode = decorationNode as? DecorationItemNodeImpl {
decorationNode.overlayController?.dismiss()
}
} }
private func beginAnimation(itemNode: ChatMessageItemView, source: Source) { private func beginAnimation(itemNode: ChatMessageItemView, source: Source) {
@@ -961,7 +1002,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
animatingItemNode.frame = self.bounds animatingItemNode.frame = self.bounds
animatingItemNode.beginAnimation() animatingItemNode.beginAnimation()
self.onTransitionEvent(.animated(duration: ChatMessageTransitionNode.animationDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve)) self.onTransitionEvent(.animated(duration: ChatMessageTransitionNodeImpl.animationDuration, curve: ChatMessageTransitionNodeImpl.verticalAnimationCurve))
} }
} }

View File

@@ -4219,7 +4219,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
return nil return nil
} }
func makeSnapshotForTransition() -> ChatMessageTransitionNode.Source.TextInput? { func makeSnapshotForTransition() -> ChatMessageTransitionNodeImpl.Source.TextInput? {
guard let backgroundImage = self.transparentTextInputBackgroundImage else { guard let backgroundImage = self.transparentTextInputBackgroundImage else {
return nil return nil
} }
@@ -4242,7 +4242,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
contentView.frame = textInputNode.frame contentView.frame = textInputNode.frame
return ChatMessageTransitionNode.Source.TextInput( return ChatMessageTransitionNodeImpl.Source.TextInput(
backgroundView: backgroundView, backgroundView: backgroundView,
contentView: contentView, contentView: contentView,
sourceRect: self.view.convert(self.bounds, to: nil), sourceRect: self.view.convert(self.bounds, to: nil),

View File

@@ -8,6 +8,7 @@ import StickerResources
import Emoji import Emoji
import UniversalMediaPlayer import UniversalMediaPlayer
import ChatMessageInteractiveMediaNode import ChatMessageInteractiveMediaNode
import ChatMessageAnimatedStickerItemNode
private final class PrefetchMediaContext { private final class PrefetchMediaContext {
let fetchDisposable = MetaDisposable() let fetchDisposable = MetaDisposable()

View File

@@ -8,7 +8,7 @@ import AccountContext
import ChatControllerInteraction import ChatControllerInteraction
import ChatHistoryEntry import ChatHistoryEntry
func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toView: ChatHistoryView, reason: ChatHistoryViewTransitionReason, reverse: Bool, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, scrollPosition: ChatHistoryViewScrollPosition?, scrollAnimationCurve: ListViewAnimationCurve?, initialData: InitialMessageHistoryData?, keyboardButtonsMessage: Message?, cachedData: CachedPeerData?, cachedDataMessages: [MessageId: Message]?, readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?, flashIndicators: Bool, updatedMessageSelection: Bool, messageTransitionNode: ChatMessageTransitionNode?, allUpdated: Bool) -> ChatHistoryViewTransition { func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toView: ChatHistoryView, reason: ChatHistoryViewTransitionReason, reverse: Bool, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, scrollPosition: ChatHistoryViewScrollPosition?, scrollAnimationCurve: ListViewAnimationCurve?, initialData: InitialMessageHistoryData?, keyboardButtonsMessage: Message?, cachedData: CachedPeerData?, cachedDataMessages: [MessageId: Message]?, readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?, flashIndicators: Bool, updatedMessageSelection: Bool, messageTransitionNode: ChatMessageTransitionNodeImpl?, allUpdated: Bool) -> ChatHistoryViewTransition {
var mergeResult: (deleteIndices: [Int], indicesAndItems: [(Int, ChatHistoryEntry, Int?)], updateIndices: [(Int, ChatHistoryEntry, Int)]) var mergeResult: (deleteIndices: [Int], indicesAndItems: [(Int, ChatHistoryEntry, Int?)], updateIndices: [(Int, ChatHistoryEntry, Int)])
let allUpdated = allUpdated || (fromView?.associatedData != toView.associatedData) let allUpdated = allUpdated || (fromView?.associatedData != toView.associatedData)
if reverse { if reverse {

View File

@@ -1,3 +0,0 @@
module TelegramUIPrivate {
export *
}