Files
ghostgram/submodules/TelegramUI/Components/MessageFeeHeaderPanelComponent/Sources/ChatFeePanelNode.swift
T
ichmagmaus 812 db53826061 chore: migrate to new version + fixed several critical bugs
- Migrated project to latest Telegram iOS base (v12.3.2+)
- Fixed circular dependency between GhostModeManager and MiscSettingsManager
- Fixed multiple Bazel build configuration errors (select() default conditions)
- Fixed duplicate type definitions in PeerInfoScreen
- Fixed swiftmodule directory resolution in build scripts
- Added Ghostgram Settings tab in main Settings menu with all 5 features
- Cleared sensitive credentials from config.json (template-only now)
- Excluded bazel-cache from version control
2026-02-23 23:04:32 +01:00

156 lines
7.1 KiB
Swift

import Foundation
import UIKit
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import SwiftSignalKit
import TelegramPresentationData
import TelegramUIPreferences
import AccountContext
import TelegramStringFormatting
import TextFormat
import TextNodeWithEntities
final class ChatFeePanelNode: ASDisplayNode {
private let context: AccountContext
private let removeFee: () -> Void
private let contextContainer: ContextControllerSourceNode
private let clippingContainer: ASDisplayNode
private let contentContainer: ASDisplayNode
private let textContainer: ASDisplayNode
private let textNode: ImmediateTextNodeWithEntities
private let removeButtonNode: HighlightTrackingButtonNode
private let removeTextNode: ImmediateTextNode
private var currentLayout: (CGFloat, CGFloat, CGFloat)?
init(context: AccountContext, removeFee: @escaping () -> Void) {
self.context = context
self.removeFee = removeFee
self.contextContainer = ContextControllerSourceNode()
self.clippingContainer = ASDisplayNode()
self.clippingContainer.clipsToBounds = true
self.contentContainer = ASDisplayNode()
self.contextContainer.isGestureEnabled = false
self.textContainer = ASDisplayNode()
self.textNode = ImmediateTextNodeWithEntities()
self.textNode.anchorPoint = CGPoint()
self.textNode.displaysAsynchronously = false
self.textNode.isUserInteractionEnabled = false
self.textNode.maximumNumberOfLines = 2
self.textNode.textAlignment = .center
self.removeButtonNode = HighlightTrackingButtonNode()
self.removeTextNode = ImmediateTextNode()
self.removeTextNode.anchorPoint = CGPoint()
self.removeTextNode.displaysAsynchronously = false
self.removeTextNode.isUserInteractionEnabled = false
super.init()
self.addSubnode(self.contextContainer)
self.contextContainer.addSubnode(self.clippingContainer)
self.clippingContainer.addSubnode(self.contentContainer)
self.contextContainer.addSubnode(self.textContainer)
self.textContainer.addSubnode(self.textNode)
self.contextContainer.addSubnode(self.removeTextNode)
self.contextContainer.addSubnode(self.removeButtonNode)
self.removeButtonNode.addTarget(self, action: #selector(self.removePressed), forControlEvents: [.touchUpInside])
self.removeButtonNode.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.removeTextNode.layer.removeAnimation(forKey: "opacity")
strongSelf.removeTextNode.alpha = 0.4
} else {
strongSelf.removeTextNode.alpha = 1.0
strongSelf.removeTextNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
}
private var theme: PresentationTheme?
func updateLayout(width: CGFloat, theme: PresentationTheme, strings: PresentationStrings, info: MessageFeeHeaderPanelComponent.Info, transition: ContainedViewLayoutTransition) -> CGFloat {
let leftInset: CGFloat = 0.0
let rightInset: CGFloat = 0.0
if self.theme !== theme {
self.theme = theme
self.removeTextNode.attributedText = NSAttributedString(string: strings.Chat_PaidMessageFee_RemoveFee, font: Font.regular(17.0), textColor: theme.chat.inputPanel.panelControlColor)
}
let attributedText = NSMutableAttributedString(string: strings.Chat_PaidMessageFee_Text(info.peer.compactDisplayTitle, "⭐️\(info.value)").string, font: Font.regular(12.0), textColor: theme.rootController.navigationBar.secondaryTextColor)
let range = (attributedText.string as NSString).range(of: "⭐️")
if range.location != NSNotFound {
attributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: true)), range: range)
attributedText.addAttribute(.baselineOffset, value: 0.0, range: range)
}
self.textNode.attributedText = attributedText
self.textNode.visibility = true
self.textNode.arguments = TextNodeWithEntities.Arguments(
context: self.context,
cache: self.context.animationCache,
renderer: self.context.animationRenderer,
placeholderColor: UIColor(white: 1.0, alpha: 0.1),
attemptSynchronous: false
)
let sideInset = 12.0
let textSize = self.textNode.updateLayout(CGSize(width: width - leftInset - rightInset - sideInset * 2.0, height: .greatestFiniteMagnitude))
let textFrame = CGRect(origin: CGPoint(x: leftInset + floorToScreenPixels((width - leftInset - rightInset - textSize.width) / 2.0), y: 9.0), size: textSize)
transition.updateFrame(node: self.textContainer, frame: textFrame)
if self.textNode.bounds.size.width != 0.0, transition.isAnimated {
if let snapshotLayer = self.textNode.layer.snapshotContentTree() {
self.textContainer.layer.addSublayer(snapshotLayer)
snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in
snapshotLayer?.removeFromSuperlayer()
})
self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
}
}
transition.updatePosition(node: self.textNode, position: CGPoint())
self.textNode.bounds = CGRect(origin: CGPoint(), size: textFrame.size)
let panelHeight: CGFloat = 48.0 + textSize.height
let removeSize = self.removeTextNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude))
let removeFrame = CGRect(origin: CGPoint(x: leftInset + floorToScreenPixels((width - leftInset - rightInset - removeSize.width) / 2.0), y: panelHeight - removeSize.height - 9.0), size: removeSize)
transition.updatePosition(node: self.removeTextNode, position: removeFrame.origin)
self.removeTextNode.bounds = CGRect(origin: CGPoint(), size: removeFrame.size)
transition.updateFrame(node: self.removeButtonNode, frame: removeFrame.insetBy(dx: -8.0, dy: -4.0))
self.contextContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
self.clippingContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
self.currentLayout = (width, leftInset, rightInset)
return panelHeight
}
@objc func removePressed() {
self.removeFee()
}
}