mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
454 lines
22 KiB
Swift
454 lines
22 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import Postbox
|
|
import TelegramCore
|
|
import TelegramPresentationData
|
|
|
|
private final class ActionSheetItemNode: ASDisplayNode {
|
|
private let action: () -> Void
|
|
|
|
private let separatorNode: ASDisplayNode
|
|
private let highlightedBackgroundNode: ASDisplayNode
|
|
private let buttonNode: HighlightTrackingButtonNode
|
|
private let iconNode: ASImageNode
|
|
private let titleNode: ImmediateTextNode
|
|
|
|
init(theme: PresentationTheme, title: String, action: @escaping () -> Void) {
|
|
self.action = action
|
|
|
|
self.separatorNode = ASDisplayNode()
|
|
self.separatorNode.backgroundColor = theme.actionSheet.opaqueItemSeparatorColor
|
|
|
|
self.highlightedBackgroundNode = ASDisplayNode()
|
|
self.highlightedBackgroundNode.backgroundColor = theme.actionSheet.opaqueItemHighlightedBackgroundColor
|
|
self.highlightedBackgroundNode.alpha = 0.0
|
|
|
|
self.buttonNode = HighlightTrackingButtonNode()
|
|
|
|
self.titleNode = ImmediateTextNode()
|
|
self.titleNode.maximumNumberOfLines = 1
|
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.regular(17.0), textColor: theme.actionSheet.primaryTextColor)
|
|
|
|
self.iconNode = ASImageNode()
|
|
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.actionSheet.primaryTextColor)
|
|
self.iconNode.contentMode = .center
|
|
|
|
super.init()
|
|
|
|
self.addSubnode(self.separatorNode)
|
|
self.addSubnode(self.highlightedBackgroundNode)
|
|
self.addSubnode(self.titleNode)
|
|
self.addSubnode(self.iconNode)
|
|
self.addSubnode(self.buttonNode)
|
|
|
|
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
|
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
|
if let strongSelf = self {
|
|
if highlighted {
|
|
strongSelf.highlightedBackgroundNode.layer.removeAnimation(forKey: "opacity")
|
|
strongSelf.highlightedBackgroundNode.alpha = 1.0
|
|
} else {
|
|
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
|
strongSelf.highlightedBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func updateLayout(maxWidth: CGFloat) -> (CGFloat, CGFloat, (CGFloat) -> Void) {
|
|
let leftInset: CGFloat = 16.0
|
|
let rightInset: CGFloat = 76.0
|
|
let titleSize = self.titleNode.updateLayout(CGSize(width: maxWidth - leftInset - rightInset, height: .greatestFiniteMagnitude))
|
|
let height: CGFloat = 44.0
|
|
|
|
return (titleSize.width + leftInset + rightInset, height, { width in
|
|
self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
|
|
|
if let image = self.iconNode.image {
|
|
self.iconNode.frame = CGRect(origin: CGPoint(x: width - floor((rightInset - image.size.width) / 2.0) - 10.0, y: floor((height - image.size.height) / 2.0)), size: image.size)
|
|
}
|
|
|
|
self.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: height - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))
|
|
self.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: height))
|
|
self.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: height))
|
|
})
|
|
}
|
|
|
|
@objc private func buttonPressed() {
|
|
self.action()
|
|
}
|
|
}
|
|
|
|
final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
|
|
private let presentationData: PresentationData
|
|
private let sendButtonFrame: CGRect
|
|
private let textFieldFrame: CGRect
|
|
private let textInputNode: EditableTextNode
|
|
|
|
private let send: (() -> Void)?
|
|
private let cancel: (() -> Void)?
|
|
|
|
private let coverNode: ASDisplayNode
|
|
|
|
private let effectView: UIVisualEffectView
|
|
private let dimNode: ASDisplayNode
|
|
|
|
private let contentContainerNode: ASDisplayNode
|
|
private let contentNodes: [ActionSheetItemNode]
|
|
private let sendButtonNode: HighlightableButtonNode
|
|
|
|
private let messageClipNode: ASDisplayNode
|
|
private let messageBackgroundNode: ASImageNode
|
|
private let messageTextNode: EditableTextNode
|
|
private let scrollNode: ASScrollNode
|
|
|
|
private var validLayout: ContainerViewLayout?
|
|
|
|
init(context: AccountContext, sendButtonFrame: CGRect, textInputNode: EditableTextNode, send: (() -> Void)?, sendSilently: (() -> Void)?, cancel: (() -> Void)?) {
|
|
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
self.sendButtonFrame = sendButtonFrame
|
|
self.textFieldFrame = textInputNode.convert(textInputNode.bounds, to: nil)
|
|
self.textInputNode = textInputNode
|
|
self.send = send
|
|
self.cancel = cancel
|
|
|
|
self.coverNode = ASDisplayNode()
|
|
|
|
self.effectView = UIVisualEffectView()
|
|
if #available(iOS 9.0, *) {
|
|
} else {
|
|
if presentationData.theme.chatList.searchBarKeyboardColor == .dark {
|
|
self.effectView.effect = UIBlurEffect(style: .dark)
|
|
} else {
|
|
self.effectView.effect = UIBlurEffect(style: .light)
|
|
}
|
|
self.effectView.alpha = 0.0
|
|
}
|
|
|
|
self.dimNode = ASDisplayNode()
|
|
self.dimNode.alpha = 1.0
|
|
if self.presentationData.theme.chatList.searchBarKeyboardColor == .light {
|
|
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.04)
|
|
} else {
|
|
self.dimNode.backgroundColor = presentationData.theme.chatList.backgroundColor.withAlphaComponent(0.2)
|
|
}
|
|
|
|
self.sendButtonNode = HighlightableButtonNode()
|
|
self.sendButtonNode.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(self.presentationData.theme), for: [])
|
|
|
|
self.messageClipNode = ASDisplayNode()
|
|
self.messageClipNode.clipsToBounds = true
|
|
self.messageClipNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
|
self.messageBackgroundNode = ASImageNode()
|
|
self.messageBackgroundNode.isUserInteractionEnabled = true
|
|
self.messageTextNode = EditableTextNode()
|
|
self.messageTextNode.isUserInteractionEnabled = false
|
|
|
|
self.scrollNode = ASScrollNode()
|
|
self.scrollNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
|
|
|
self.contentContainerNode = ASDisplayNode()
|
|
self.contentContainerNode.backgroundColor = self.presentationData.theme.actionSheet.opaqueItemBackgroundColor
|
|
self.contentContainerNode.cornerRadius = 12.0
|
|
self.contentContainerNode.clipsToBounds = true
|
|
|
|
var contentNodes: [ActionSheetItemNode] = []
|
|
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: self.presentationData.strings.Conversation_SendMessage_SendSilently, action: {
|
|
sendSilently?()
|
|
}))
|
|
self.contentNodes = contentNodes
|
|
|
|
super.init()
|
|
|
|
self.coverNode.backgroundColor = self.presentationData.theme.chat.inputPanel.inputBackgroundColor
|
|
self.addSubnode(self.coverNode)
|
|
|
|
self.sendButtonNode.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(self.presentationData.theme), for: [])
|
|
self.sendButtonNode.addTarget(self, action: #selector(sendButtonPressed), forControlEvents: .touchUpInside)
|
|
|
|
self.messageTextNode.attributedText = textInputNode.attributedText
|
|
self.messageBackgroundNode.contentMode = .scaleToFill
|
|
|
|
let graphics = PresentationResourcesChat.principalGraphics(self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper)
|
|
self.messageBackgroundNode.image = graphics.chatMessageBackgroundOutgoingImage
|
|
|
|
self.view.addSubview(self.effectView)
|
|
self.addSubnode(self.dimNode)
|
|
|
|
self.addSubnode(self.contentContainerNode)
|
|
|
|
self.addSubnode(self.scrollNode)
|
|
|
|
self.addSubnode(self.sendButtonNode)
|
|
self.scrollNode.addSubnode(self.messageClipNode)
|
|
self.messageClipNode.addSubnode(self.messageBackgroundNode)
|
|
self.messageClipNode.addSubnode(self.messageTextNode)
|
|
|
|
self.contentNodes.forEach(self.contentContainerNode.addSubnode)
|
|
}
|
|
|
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
let result = super.hitTest(point, with: event)
|
|
if result != self.scrollNode.view {
|
|
return result
|
|
} else {
|
|
return self.dimNode.view
|
|
}
|
|
}
|
|
|
|
override func didLoad() {
|
|
super.didLoad()
|
|
|
|
self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:))))
|
|
|
|
self.scrollNode.view.showsVerticalScrollIndicator = false
|
|
self.scrollNode.view.delaysContentTouches = false
|
|
self.scrollNode.view.delegate = self
|
|
self.scrollNode.view.alwaysBounceVertical = true
|
|
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
|
self.scrollNode.view.contentInsetAdjustmentBehavior = .never
|
|
}
|
|
}
|
|
|
|
func animateIn() {
|
|
UIView.animate(withDuration: 0.4, animations: {
|
|
if #available(iOS 9.0, *) {
|
|
if self.presentationData.theme.chatList.searchBarKeyboardColor == .dark {
|
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
|
self.effectView.effect = UIBlurEffect(style: .regular)
|
|
if self.effectView.subviews.count == 2 {
|
|
self.effectView.subviews[1].isHidden = true
|
|
}
|
|
} else {
|
|
self.effectView.effect = UIBlurEffect(style: .dark)
|
|
}
|
|
} else {
|
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
|
self.effectView.effect = UIBlurEffect(style: .regular)
|
|
} else {
|
|
self.effectView.effect = UIBlurEffect(style: .light)
|
|
}
|
|
}
|
|
} else {
|
|
self.effectView.alpha = 1.0
|
|
}
|
|
}, completion: { [weak self] _ in
|
|
guard let strongSelf = self else {
|
|
return
|
|
}
|
|
if strongSelf.presentationData.theme.chatList.searchBarKeyboardColor == .dark {
|
|
if strongSelf.effectView.subviews.count == 2 {
|
|
strongSelf.effectView.subviews[1].isHidden = true
|
|
}
|
|
}
|
|
})
|
|
self.effectView.subviews[1].layer.removeAnimation(forKey: "backgroundColor")
|
|
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
|
self.contentContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
self.messageBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
|
if let layout = self.validLayout {
|
|
let duration = 0.6
|
|
|
|
self.sendButtonNode.layer.animateScale(from: 0.75, to: 1.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionLinear, removeOnCompletion: false)
|
|
self.sendButtonNode.layer.animatePosition(from: self.sendButtonFrame.center, to: self.sendButtonNode.position, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
|
|
|
let initialWidth = self.textFieldFrame.width + 32.0
|
|
let fromFrame = CGRect(origin: CGPoint(), size: CGSize(width: initialWidth, height: self.textFieldFrame.height + 2.0))
|
|
let delta = (fromFrame.height - self.messageClipNode.bounds.height) / 2.0
|
|
|
|
let inputHeight = layout.inputHeight ?? 0.0
|
|
var clipDelta = delta
|
|
if inputHeight.isZero {
|
|
clipDelta -= 60.0
|
|
}
|
|
|
|
self.messageClipNode.layer.animateBounds(from: fromFrame, to: self.messageClipNode.bounds, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
|
self.messageClipNode.layer.animatePosition(from: CGPoint(x: (self.messageClipNode.bounds.width - initialWidth) / 2.0, y: clipDelta), to: CGPoint(), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, additive: true, completion: { [weak self] _ in
|
|
if let strongSelf = self {
|
|
strongSelf.insertSubnode(strongSelf.contentContainerNode, aboveSubnode: strongSelf.scrollNode)
|
|
}
|
|
})
|
|
|
|
self.messageBackgroundNode.layer.animateBounds(from: fromFrame, to: self.messageBackgroundNode.bounds, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
|
self.messageBackgroundNode.layer.animatePosition(from: CGPoint(x: (initialWidth - self.messageClipNode.bounds.width) / 2.0, y: delta), to: CGPoint(), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
|
self.messageTextNode.layer.animatePosition(from: CGPoint(x: 0.0, y: delta * 2.0), to: CGPoint(), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
|
|
|
self.contentContainerNode.layer.animatePosition(from: CGPoint(x: 160.0, y: 0.0), to: CGPoint(), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
|
self.contentContainerNode.layer.animateScale(from: 0.45, to: 1.0, duration: duration, timingFunction: kCAMediaTimingFunctionSpring)
|
|
}
|
|
}
|
|
|
|
func animateOut(cancel: Bool, completion: @escaping () -> Void) {
|
|
self.isUserInteractionEnabled = false
|
|
|
|
var completedEffect = false
|
|
var completedButton = false
|
|
var completedBubble = false
|
|
var completedAlpha = false
|
|
|
|
let intermediateCompletion: () -> Void = { [weak self] in
|
|
if completedEffect && completedButton && completedBubble && completedAlpha {
|
|
self?.coverNode.isHidden = true
|
|
completion()
|
|
}
|
|
}
|
|
|
|
UIView.animate(withDuration: 0.4, animations: {
|
|
if #available(iOS 9.0, *) {
|
|
self.effectView.effect = nil
|
|
} else {
|
|
self.effectView.alpha = 0.0
|
|
}
|
|
}, completion: { _ in
|
|
completedEffect = true
|
|
intermediateCompletion()
|
|
})
|
|
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
|
self.contentContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in })
|
|
|
|
if cancel {
|
|
self.messageBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: 0.15, removeOnCompletion: false, completion: { _ in
|
|
completedAlpha = true
|
|
intermediateCompletion()
|
|
})
|
|
} else {
|
|
self.coverNode.isHidden = true
|
|
self.messageClipNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
|
completedAlpha = true
|
|
intermediateCompletion()
|
|
})
|
|
}
|
|
|
|
if let layout = self.validLayout {
|
|
let duration = 0.6
|
|
|
|
self.sendButtonNode.layer.animatePosition(from: self.sendButtonNode.position, to: self.sendButtonFrame.center, duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
|
completedButton = true
|
|
intermediateCompletion()
|
|
})
|
|
|
|
if !cancel {
|
|
self.sendButtonNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2, timingFunction: kCAMediaTimingFunctionLinear, removeOnCompletion: false)
|
|
self.sendButtonNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionLinear, removeOnCompletion: false)
|
|
}
|
|
|
|
let initialWidth = self.textFieldFrame.width + 32.0
|
|
let toFrame = CGRect(origin: CGPoint(), size: CGSize(width: initialWidth, height: self.textFieldFrame.height + 1.0))
|
|
let delta = (toFrame.height - self.messageClipNode.bounds.height) / 2.0
|
|
|
|
let inputHeight = layout.inputHeight ?? 0.0
|
|
var clipDelta = delta
|
|
if inputHeight.isZero {
|
|
clipDelta -= 60.0
|
|
}
|
|
|
|
if cancel {
|
|
self.messageClipNode.layer.animateBounds(from: self.messageClipNode.bounds, to: toFrame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
|
completedBubble = true
|
|
intermediateCompletion()
|
|
})
|
|
self.messageClipNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: (self.messageClipNode.bounds.width - initialWidth) / 2.0, y: clipDelta), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
|
|
|
self.messageBackgroundNode.layer.animateBounds(from: self.messageBackgroundNode.bounds, to: toFrame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
|
self.messageBackgroundNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: (initialWidth - self.messageClipNode.bounds.width) / 2.0, y: delta), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
|
self.messageTextNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: delta * 2.0), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
|
}
|
|
|
|
self.contentContainerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 160.0, y: 0.0), duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
|
self.contentContainerNode.layer.animateScale(from: 1.0, to: 0.4, duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
|
}
|
|
}
|
|
|
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
|
self.validLayout = layout
|
|
|
|
transition.updateFrame(node: self.coverNode, frame: self.textFieldFrame)
|
|
|
|
transition.updateFrame(view: self.effectView, frame: CGRect(origin: CGPoint(), size: layout.size))
|
|
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
|
|
|
let sideInset: CGFloat = 43.0
|
|
|
|
var contentSize = CGSize()
|
|
contentSize.width = min(layout.size.width - 40.0, 240.0)
|
|
var applyNodes: [(ASDisplayNode, CGFloat, (CGFloat) -> Void)] = []
|
|
for itemNode in self.contentNodes {
|
|
let (width, height, apply) = itemNode.updateLayout(maxWidth: layout.size.width - sideInset * 2.0)
|
|
applyNodes.append((itemNode, height, apply))
|
|
contentSize.width = max(contentSize.width, width)
|
|
contentSize.height += height
|
|
}
|
|
|
|
let insets = layout.insets(options: [.statusBar, .input])
|
|
let inputHeight = layout.inputHeight ?? 0.0
|
|
|
|
var contentOrigin = CGPoint(x: layout.size.width - sideInset - contentSize.width, y: layout.size.height - 6.0 - insets.bottom - contentSize.height)
|
|
if inputHeight > 0.0 {
|
|
contentOrigin.y += 60.0
|
|
}
|
|
|
|
transition.updateFrame(node: self.contentContainerNode, frame: CGRect(origin: contentOrigin, size: contentSize))
|
|
var nextY: CGFloat = 0.0
|
|
for (itemNode, height, apply) in applyNodes {
|
|
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: nextY), size: CGSize(width: contentSize.width, height: height)))
|
|
apply(contentSize.width)
|
|
nextY += height
|
|
}
|
|
|
|
let initialSendButtonFrame = self.sendButtonFrame
|
|
var sendButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - initialSendButtonFrame.width + 1.0 - UIScreenPixel, y: layout.size.height - insets.bottom - initialSendButtonFrame.height), size: initialSendButtonFrame.size)
|
|
if inputHeight.isZero {
|
|
sendButtonFrame.origin.y -= 60.0
|
|
}
|
|
transition.updateFrame(node: self.sendButtonNode, frame: sendButtonFrame)
|
|
|
|
var messageFrame = self.textFieldFrame
|
|
messageFrame.size.width += 32.0
|
|
messageFrame.origin.x -= 13.0
|
|
messageFrame.origin.y = layout.size.height - messageFrame.origin.y - messageFrame.size.height - 1.0
|
|
if inputHeight.isZero {
|
|
messageFrame.origin.y += 60.0
|
|
}
|
|
|
|
if self.textInputNode.textView.numberOfLines == 1 {
|
|
let textWidth = min(self.textInputNode.textView.sizeThatFits(layout.size).width + 36.0, messageFrame.width)
|
|
messageFrame.origin.x += messageFrame.width - textWidth
|
|
messageFrame.size.width = textWidth
|
|
}
|
|
|
|
let messageHeight = max(messageFrame.size.height, self.textInputNode.textView.contentSize.height + 2.0)
|
|
messageFrame.size.height = messageHeight
|
|
|
|
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
|
|
|
var scrollContentSize = CGSize(width: layout.size.width, height: messageHeight + max(0.0, messageFrame.origin.y))
|
|
if messageHeight > layout.size.height - messageFrame.origin.y {
|
|
scrollContentSize.height += insets.top + 16.0
|
|
}
|
|
self.scrollNode.view.contentSize = scrollContentSize
|
|
|
|
let clipFrame = messageFrame
|
|
transition.updateFrame(node: self.messageClipNode, frame: clipFrame)
|
|
|
|
let backgroundFrame = CGRect(origin: CGPoint(), size: messageFrame.size)
|
|
transition.updateFrame(node: self.messageBackgroundNode, frame: backgroundFrame)
|
|
|
|
var textFrame = self.textFieldFrame
|
|
textFrame.origin = CGPoint(x: 13.0, y: 6.0 - UIScreenPixel)
|
|
textFrame.size.height = self.textInputNode.textView.contentSize.height
|
|
self.messageTextNode.frame = textFrame
|
|
}
|
|
|
|
@objc private func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
|
if case .ended = recognizer.state {
|
|
self.cancel?()
|
|
}
|
|
}
|
|
|
|
@objc private func sendButtonPressed() {
|
|
self.send?()
|
|
}
|
|
}
|