Files
ghostgram/submodules/TelegramUI/Sources/Chat/ChatControllerOpenTonAddressContextMenu.swift
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

119 lines
6.7 KiB
Swift

import Foundation
import UIKit
import SwiftSignalKit
import TelegramCore
import AsyncDisplayKit
import Display
import ContextUI
import AccountContext
import AvatarNode
import UndoUI
import ChatControllerInteraction
import WalletContext
extension ChatControllerImpl {
func openTonAddressContextMenu(address: String, params: ChatControllerInteraction.LongTapParams) {
guard let message = params.message, let contentNode = params.contentNode,
let normalizedAddress = WalletContext.transferAddress(from: address) else {
params.progress?.set(.single(false))
params.contentNode?.removeFromSupernode()
return
}
let context = self.context
let source: ContextContentSource = .extracted(ChatMessageLinkContextExtractedContentSource(chatNode: self.chatDisplayNode, contentNode: contentNode))
var menuPresented = false
params.progress?.set(.single(true))
let recipient = context.engine.wallet.getUserAddresses(addresses: [address])
|> `catch` { _ -> Signal<[WalletUserAddress], NoError> in
return .single([])
}
|> mapToSignal { addresses -> Signal<WalletSendRequest.Recipient, NoError> in
guard let userAddress = addresses.first(where: { WalletContext.transferAddress(from: $0.address) == normalizedAddress }),
let userId = userAddress.userId else {
return .single(.address(address))
}
return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: userId))
|> map { peer -> WalletSendRequest.Recipient in
guard let peer, case .user = peer else {
return .address(address)
}
return .peer(peer, resolvedAddress: WalletUserAddress(userId: peer.id, address: address, publicKey: userAddress.publicKey))
}
}
self.navigationActionDisposable.set((recipient
|> take(1)
|> deliverOnMainQueue
|> afterDisposed {
Queue.mainQueue().async {
params.progress?.set(.single(false))
if !menuPresented {
contentNode.removeFromSupernode()
}
}
}).startStrict(next: { [weak self] recipient in
params.progress?.set(.single(false))
guard let self, let window = self.window else {
return
}
var items: [ContextMenuItem] = []
if WalletConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }).isAvailable {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Wallet_SendMoney, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Ton"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, dismiss in
dismiss(.default)
self?.openResolved(result: .sendGrams(transfer: WalletSendRequest(recipient: recipient, amountNanograms: nil)), sourceMessageId: message.id)
})))
}
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Wallet_CopyAddress, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, dismiss in
dismiss(.default)
guard let self else {
return
}
UIPasteboard.general.string = address
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: self.presentationData.strings.Wallet_AddressCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})))
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Wallet_ViewInExplorer, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, dismiss in
dismiss(.default)
guard let self,
let encodedAddress = address.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPathAllowed.subtracting(CharacterSet(charactersIn: "/"))) else {
return
}
let configuration = WalletConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
let baseUrl = configuration.explorerUrl.hasSuffix("/") ? configuration.explorerUrl : configuration.explorerUrl + "/"
self.openUrl(baseUrl + encodedAddress, concealed: false)
})))
if case let .peer(peer, _) = recipient {
items.append(.separator)
let avatarSize = CGSize(width: 28.0, height: 28.0)
let avatarSignal = peerAvatarCompleteImage(account: self.context.account, peer: peer, size: avatarSize)
let subtitle = NSMutableAttributedString(string: self.presentationData.strings.Wallet_ViewProfile)
if let range = subtitle.string.range(of: ">"), let arrowImage = UIImage(bundleImageName: "Item List/InlineTextRightArrow") {
subtitle.addAttribute(.attachment, value: arrowImage, range: NSRange(range, in: subtitle.string))
subtitle.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: subtitle.string))
}
items.append(.action(ContextMenuActionItem(text: peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), textLayout: .secondLineWithAttributedValue(subtitle), icon: { _ in return nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), iconPosition: .left, action: { [weak self] _, dismiss in
dismiss(.default)
self?.openPeer(peer: peer, navigation: .info(ChatControllerInteractionNavigateToPeer.InfoParams(ignoreInSavedMessages: true)), fromMessage: nil)
})))
}
let controller = makeContextController(presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))), recognizer: params.gesture, gesture: nil, disableScreenshots: false)
controller.dismissed = { [weak self] in
self?.canReadHistory.set(true)
}
menuPresented = true
self.canReadHistory.set(false)
window.presentInGlobalOverlay(controller)
}))
}
}