mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
277 lines
13 KiB
Swift
277 lines
13 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import TelegramPresentationData
|
|
import ChatControllerInteraction
|
|
import AccountContext
|
|
import TelegramCore
|
|
import Postbox
|
|
import WallpaperBackgroundNode
|
|
import ChatMessageItemCommon
|
|
|
|
public class ChatMessageShareButton: ASDisplayNode {
|
|
private var backgroundContent: WallpaperBubbleBackgroundNode?
|
|
private var backgroundBlurView: PortalView?
|
|
|
|
private let topButton: HighlightTrackingButtonNode
|
|
private let topIconNode: ASImageNode
|
|
private var topIconOffset = CGPoint()
|
|
|
|
private var bottomButton: HighlightTrackingButtonNode?
|
|
private var bottomIconNode: ASImageNode?
|
|
|
|
private var separatorNode: ASDisplayNode?
|
|
|
|
private var theme: PresentationTheme?
|
|
private var isReplies: Bool = false
|
|
|
|
private var textNode: ImmediateTextNode?
|
|
|
|
private var absolutePosition: (CGRect, CGSize)?
|
|
|
|
public var pressed: (() -> Void)?
|
|
public var morePressed: (() -> Void)?
|
|
|
|
override public init() {
|
|
self.topButton = HighlightTrackingButtonNode()
|
|
self.topIconNode = ASImageNode()
|
|
self.topIconNode.displaysAsynchronously = false
|
|
|
|
super.init()
|
|
|
|
self.allowsGroupOpacity = true
|
|
|
|
self.addSubnode(self.topIconNode)
|
|
self.addSubnode(self.topButton)
|
|
|
|
self.topButton.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
|
self.topButton.highligthedChanged = { [weak self] highlighted in
|
|
guard let self else {
|
|
return
|
|
}
|
|
if highlighted {
|
|
self.topIconNode.layer.removeAnimation(forKey: "opacity")
|
|
self.topIconNode.alpha = 0.4
|
|
self.textNode?.layer.removeAnimation(forKey: "opacity")
|
|
self.textNode?.alpha = 0.4
|
|
} else {
|
|
self.topIconNode.alpha = 1.0
|
|
self.topIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
|
self.textNode?.alpha = 1.0
|
|
self.textNode?.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
|
}
|
|
}
|
|
}
|
|
|
|
required public init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
@objc private func buttonPressed() {
|
|
self.pressed?()
|
|
}
|
|
|
|
@objc private func moreButtonPressed() {
|
|
self.morePressed?()
|
|
}
|
|
|
|
public func update(presentationData: ChatPresentationData, controllerInteraction: ChatControllerInteraction, chatLocation: ChatLocation, subject: ChatControllerSubject?, message: Message, account: Account, disableComments: Bool = false) -> CGSize {
|
|
var isReplies = false
|
|
var replyCount = 0
|
|
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
|
for attribute in message.attributes {
|
|
if let attribute = attribute as? ReplyThreadMessageAttribute {
|
|
replyCount = Int(attribute.count)
|
|
isReplies = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if case let .replyThread(replyThreadMessage) = chatLocation, replyThreadMessage.effectiveTopId == message.id {
|
|
replyCount = 0
|
|
isReplies = false
|
|
}
|
|
if disableComments {
|
|
replyCount = 0
|
|
isReplies = false
|
|
}
|
|
|
|
if self.theme !== presentationData.theme.theme || self.isReplies != isReplies {
|
|
self.theme = presentationData.theme.theme
|
|
self.isReplies = isReplies
|
|
|
|
var updatedIconImage: UIImage?
|
|
var updatedBottomIconImage: UIImage?
|
|
var updatedIconOffset = CGPoint()
|
|
if message.adAttribute != nil {
|
|
updatedIconImage = PresentationResourcesChat.chatFreeCloseButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
|
updatedIconOffset = CGPoint(x: UIScreenPixel, y: UIScreenPixel)
|
|
|
|
updatedBottomIconImage = PresentationResourcesChat.chatFreeMoreButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
|
} else if case .pinnedMessages = subject {
|
|
updatedIconImage = PresentationResourcesChat.chatFreeNavigateButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
|
updatedIconOffset = CGPoint(x: UIScreenPixel, y: 1.0)
|
|
} else if isReplies {
|
|
updatedIconImage = PresentationResourcesChat.chatFreeCommentButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
|
} else if message.id.peerId.isRepliesOrSavedMessages(accountPeerId: account.peerId) {
|
|
updatedIconImage = PresentationResourcesChat.chatFreeNavigateButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
|
updatedIconOffset = CGPoint(x: UIScreenPixel, y: 1.0)
|
|
} else {
|
|
updatedIconImage = PresentationResourcesChat.chatFreeShareButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
|
}
|
|
|
|
self.topIconNode.image = updatedIconImage
|
|
self.topIconOffset = updatedIconOffset
|
|
|
|
if let updatedBottomIconImage {
|
|
let bottomButton: HighlightTrackingButtonNode
|
|
let bottomIconNode: ASImageNode
|
|
let separatorNode: ASDisplayNode
|
|
if let currentButton = self.bottomButton, let currentIcon = self.bottomIconNode, let currentSeparator = self.separatorNode {
|
|
bottomButton = currentButton
|
|
bottomIconNode = currentIcon
|
|
separatorNode = currentSeparator
|
|
} else {
|
|
bottomButton = HighlightTrackingButtonNode()
|
|
bottomButton.addTarget(self, action: #selector(self.moreButtonPressed), forControlEvents: .touchUpInside)
|
|
self.bottomButton = bottomButton
|
|
|
|
bottomIconNode = ASImageNode()
|
|
bottomIconNode.displaysAsynchronously = false
|
|
self.bottomIconNode = bottomIconNode
|
|
|
|
bottomButton.highligthedChanged = { [weak self] highlighted in
|
|
guard let self, let bottomIconNode = self.bottomIconNode else {
|
|
return
|
|
}
|
|
if highlighted {
|
|
bottomIconNode.layer.removeAnimation(forKey: "opacity")
|
|
bottomIconNode.alpha = 0.4
|
|
} else {
|
|
bottomIconNode.alpha = 1.0
|
|
bottomIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
|
}
|
|
}
|
|
|
|
separatorNode = ASDisplayNode()
|
|
self.separatorNode = separatorNode
|
|
|
|
self.addSubnode(separatorNode)
|
|
self.addSubnode(bottomIconNode)
|
|
self.addSubnode(bottomButton)
|
|
}
|
|
separatorNode.backgroundColor = bubbleVariableColor(variableColor: presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: presentationData.theme.wallpaper).withAlphaComponent(0.15)
|
|
bottomIconNode.image = updatedBottomIconImage
|
|
} else {
|
|
self.bottomButton?.removeFromSupernode()
|
|
self.bottomButton = nil
|
|
self.bottomIconNode?.removeFromSupernode()
|
|
self.bottomIconNode = nil
|
|
self.separatorNode?.removeFromSupernode()
|
|
self.separatorNode = nil
|
|
}
|
|
}
|
|
var size = CGSize(width: 30.0, height: 30.0)
|
|
if message.adAttribute != nil {
|
|
size.height += 30.0
|
|
}
|
|
var offsetIcon = false
|
|
if isReplies, replyCount > 0 {
|
|
offsetIcon = true
|
|
|
|
let textNode: ImmediateTextNode
|
|
if let current = self.textNode {
|
|
textNode = current
|
|
} else {
|
|
textNode = ImmediateTextNode()
|
|
self.textNode = textNode
|
|
self.addSubnode(textNode)
|
|
}
|
|
|
|
let textColor = bubbleVariableColor(variableColor: presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: presentationData.theme.wallpaper)
|
|
|
|
let countString: String
|
|
if replyCount >= 1000 * 1000 {
|
|
countString = "\(replyCount / 1000_000)M"
|
|
} else if replyCount >= 1000 {
|
|
countString = "\(replyCount / 1000)K"
|
|
} else {
|
|
countString = "\(replyCount)"
|
|
}
|
|
|
|
textNode.attributedText = NSAttributedString(string: countString, font: Font.regular(11.0), textColor: textColor)
|
|
let textSize = textNode.updateLayout(CGSize(width: 100.0, height: 100.0))
|
|
size.height += textSize.height - 1.0
|
|
textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: size.height - textSize.height - 4.0), size: textSize)
|
|
} else if let textNode = self.textNode {
|
|
self.textNode = nil
|
|
textNode.removeFromSupernode()
|
|
}
|
|
|
|
if self.backgroundBlurView == nil {
|
|
if let backgroundBlurView = controllerInteraction.presentationContext.backgroundNode?.makeFreeBackground() {
|
|
self.backgroundBlurView = backgroundBlurView
|
|
self.view.insertSubview(backgroundBlurView.view, at: 0)
|
|
|
|
backgroundBlurView.view.clipsToBounds = true
|
|
}
|
|
}
|
|
if let backgroundBlurView = self.backgroundBlurView {
|
|
backgroundBlurView.view.frame = CGRect(origin: CGPoint(), size: size)
|
|
backgroundBlurView.view.layer.cornerRadius = min(size.width, size.height) / 2.0
|
|
}
|
|
|
|
if let image = self.topIconNode.image {
|
|
self.topIconNode.frame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0) + self.topIconOffset.x, y: floor((size.width - image.size.width) / 2.0) - (offsetIcon ? 1.0 : 0.0) + self.topIconOffset.y), size: image.size)
|
|
}
|
|
self.topButton.frame = CGRect(origin: .zero, size: CGSize(width: size.width, height: size.width))
|
|
|
|
if let bottomIconNode = self.bottomIconNode, let bottomButton = self.bottomButton, let bottomImage = bottomIconNode.image {
|
|
bottomIconNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - bottomImage.size.width) / 2.0), y: size.height - size.width + floorToScreenPixels((size.width - bottomImage.size.height) / 2.0)), size: bottomImage.size)
|
|
bottomButton.frame = CGRect(origin: CGPoint(x: 0.0, y: size.height - size.width), size: CGSize(width: size.width, height: size.width))
|
|
}
|
|
|
|
self.separatorNode?.frame = CGRect(origin: CGPoint(x: 0.0, y: size.height / 2.0), size: CGSize(width: size.width, height: 1.0 - UIScreenPixel))
|
|
|
|
if controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true {
|
|
if self.backgroundContent == nil, let backgroundContent = controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
|
backgroundContent.clipsToBounds = true
|
|
self.backgroundContent = backgroundContent
|
|
self.insertSubnode(backgroundContent, at: 0)
|
|
}
|
|
} else {
|
|
self.backgroundContent?.removeFromSupernode()
|
|
self.backgroundContent = nil
|
|
}
|
|
|
|
if let backgroundContent = self.backgroundContent {
|
|
//self.backgroundNode.isHidden = true
|
|
self.backgroundBlurView?.view.isHidden = true
|
|
backgroundContent.cornerRadius = min(size.width, size.height) / 2.0
|
|
backgroundContent.frame = CGRect(origin: CGPoint(), size: size)
|
|
if let (rect, containerSize) = self.absolutePosition {
|
|
var backgroundFrame = backgroundContent.frame
|
|
backgroundFrame.origin.x += rect.minX
|
|
backgroundFrame.origin.y += rect.minY
|
|
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
|
}
|
|
} else {
|
|
//self.backgroundNode.isHidden = false
|
|
self.backgroundBlurView?.view.isHidden = false
|
|
}
|
|
|
|
return size
|
|
}
|
|
|
|
public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
|
self.absolutePosition = (rect, containerSize)
|
|
if let backgroundContent = self.backgroundContent {
|
|
var backgroundFrame = backgroundContent.frame
|
|
backgroundFrame.origin.x += rect.minX
|
|
backgroundFrame.origin.y += rect.minY
|
|
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
|
}
|
|
}
|
|
}
|