Swiftgram/submodules/PeerInfoUI/Sources/SecretChatKeyControllerNode.swift
2023-04-20 18:43:29 +04:00

168 lines
8.1 KiB
Swift

import Foundation
import UIKit
import Display
import AsyncDisplayKit
import TelegramCore
import TelegramPresentationData
import TextFormat
import AccountContext
import EncryptionKeyVisualization
import LocalizedPeerData
private func processHexString(_ string: String) -> String {
var result = ""
var i = 0
for c in string {
if i % 2 == 0 && i != 0 {
result.append(" ")
}
if i % 8 == 0 && i != 0 {
result.append(" ")
}
result.append(c)
i += 1
}
return result
}
final class SecretChatKeyControllerNode: ViewControllerTracingNode {
private let context: AccountContext
private var presentationData: PresentationData
private let fingerprint: SecretChatKeyFingerprint
private let peer: EnginePeer
private let getNavigationController: () -> NavigationController?
private let scrollNode: ASScrollNode
private let imageNode: ASImageNode
private let keyTextNode: TextNode
private let infoNode: TextNode
private var validImageSize: CGSize?
init(context: AccountContext, presentationData: PresentationData, fingerprint: SecretChatKeyFingerprint, peer: EnginePeer, getNavigationController: @escaping () -> NavigationController?) {
self.context = context
self.presentationData = presentationData
self.fingerprint = fingerprint
self.peer = peer
self.getNavigationController = getNavigationController
self.scrollNode = ASScrollNode()
self.imageNode = ASImageNode()
self.imageNode.isLayerBacked = true
self.imageNode.displaysAsynchronously = false
self.imageNode.displayWithoutProcessing = true
self.keyTextNode = TextNode()
self.keyTextNode.isUserInteractionEnabled = false
self.keyTextNode.displaysAsynchronously = false
self.infoNode = TextNode()
self.infoNode.displaysAsynchronously = false
super.init()
self.backgroundColor = presentationData.theme.list.plainBackgroundColor
self.addSubnode(self.scrollNode)
self.scrollNode.addSubnode(self.imageNode)
self.scrollNode.addSubnode(self.keyTextNode)
self.scrollNode.addSubnode(self.infoNode)
}
override func didLoad() {
super.didLoad()
self.infoNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.infoTap(_:))))
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var insets = layout.insets(options: [.input])
insets.top += navigationBarHeight
self.scrollNode.frame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top))
let sideInset: CGFloat = 10.0
var imageSize = CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.width - sideInset * 2.0)
if imageSize.height > layout.size.height - insets.top - sideInset * 2.0 - 100.0 {
let side = layout.size.height - insets.top - sideInset * 2.0 - 100.0
imageSize = CGSize(width: side, height: side)
}
if imageSize.height > 512.0 {
imageSize = CGSize(width: 512.0, height: 512.0)
}
if self.validImageSize != imageSize {
self.validImageSize = imageSize
self.imageNode.image = secretChatKeyImage(self.fingerprint, size: imageSize)
}
let makeKeyTextLayout = TextNode.asyncLayout(self.keyTextNode)
let makeInfoLayout = TextNode.asyncLayout(self.infoNode)
let keySignatureData = self.fingerprint.sha1.data()
let additionalSignature = self.fingerprint.sha256.data()
var data = Data()
data.append(keySignatureData)
data.append(additionalSignature)
let s1: String = (data.subdata(in: 0 ..< 8) as NSData).stringByEncodingInHex()
let s2: String = (data.subdata(in: 8 ..< 16) as NSData).stringByEncodingInHex()
let s3: String = (additionalSignature.subdata(in: 0 ..< 8) as NSData).stringByEncodingInHex()
let s4: String = (additionalSignature.subdata(in : 8 ..< 16) as NSData).stringByEncodingInHex()
let text: String = "\(processHexString(s1))\n\(processHexString(s2))\n\(processHexString(s3))\n\(processHexString(s4))"
let (keyTextLayout, keyTextApply) = makeKeyTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: text, font: Font.semiboldMonospace(15.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: layout.size.width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .left, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets()))
let infoString = self.presentationData.strings.EncryptionKey_Description(self.peer.compactDisplayTitle, self.peer.compactDisplayTitle)
let infoText = NSMutableAttributedString(string: infoString.string, attributes: [.font: Font.regular(14.0), .foregroundColor: self.presentationData.theme.list.itemPrimaryTextColor])
for range in infoString.ranges {
infoText.addAttributes([.font: Font.semibold(14.0)], range: range.range)
}
let linkRange = (infoString.string as NSString).range(of: "telegram.org")
if linkRange.location != NSNotFound {
infoText.addAttributes([.foregroundColor: self.presentationData.theme.list.itemAccentColor, NSAttributedString.Key(rawValue: TelegramTextAttributes.URL): "https://telegram.org/faq#secret-chats"], range: linkRange)
}
let (infoLayout, infoApply) = makeInfoLayout(TextNodeLayoutArguments(attributedString: infoText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: layout.size.width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets()))
let _ = keyTextApply()
let _ = infoApply()
let imageSpacing: CGFloat = 12.0
let textSpacing: CGFloat = 10.0
let contentHeight = imageSize.height + imageSpacing + keyTextLayout.size.height + textSpacing + infoLayout.size.height
let contentOrigin = sideInset + max(0, floor((layout.size.height - insets.top - sideInset * 2.0 - contentHeight) / 2.0))
self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight + sideInset * 2.0)
let imageFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: contentOrigin), size: imageSize)
transition.updateFrame(node: self.imageNode, frame: imageFrame)
let keyTextFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - keyTextLayout.size.width) / 2.0), y: imageFrame.maxY + imageSpacing), size: keyTextLayout.size)
transition.updateFrame(node: self.keyTextNode, frame: keyTextFrame)
let infoFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - infoLayout.size.width) / 2.0), y: keyTextFrame.maxY + textSpacing), size: infoLayout.size)
transition.updateFrame(node: self.infoNode, frame: infoFrame)
}
@objc func infoTap(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
let point = recognizer.location(in: recognizer.view)
if let attributes = self.infoNode.attributesAtPoint(point)?.1 {
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: false, presentationData: self.presentationData, navigationController: self.getNavigationController(), dismissInput: { [weak self] in
self?.view.endEditing(true)
})
}
}
}
}
}