mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Temporary QR codes
This commit is contained in:
parent
dc4a04daa7
commit
3caedf5670
BIN
Telegram/Telegram-iOS/Resources/QrDataRain.tgs
Normal file
BIN
Telegram/Telegram-iOS/Resources/QrDataRain.tgs
Normal file
Binary file not shown.
Binary file not shown.
@ -79,6 +79,7 @@ public class AnimatedCountLabelNode: ASDisplayNode {
|
||||
fileprivate var resolvedSegments: [ResolvedSegment.Key: (ResolvedSegment, TextNode)] = [:]
|
||||
|
||||
public var reverseAnimationDirection: Bool = false
|
||||
public var alwaysOneDirection: Bool = false
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
@ -91,6 +92,7 @@ public class AnimatedCountLabelNode: ASDisplayNode {
|
||||
segmentLayouts[segmentKey] = TextNode.asyncLayout(segmentAndTextNode.1)
|
||||
}
|
||||
let reverseAnimationDirection = self.reverseAnimationDirection
|
||||
let alwaysOneDirection = self.alwaysOneDirection
|
||||
|
||||
return { [weak self] size, initialSegments in
|
||||
var segments: [ResolvedSegment] = []
|
||||
@ -173,7 +175,7 @@ public class AnimatedCountLabelNode: ASDisplayNode {
|
||||
fromAlpha = CGFloat(presentation.opacity)
|
||||
}
|
||||
var offsetY: CGFloat
|
||||
if currentValue > updatedValue {
|
||||
if currentValue > updatedValue || alwaysOneDirection {
|
||||
offsetY = -floor(currentTextNode.bounds.height * 0.6)
|
||||
} else {
|
||||
offsetY = floor(currentTextNode.bounds.height * 0.6)
|
||||
|
@ -38,7 +38,7 @@ public func qrCodeCutout(size: Int, dimensions: CGSize, scale: CGFloat?) -> (Int
|
||||
return (cutoutSize, cutoutRect, quadSize)
|
||||
}
|
||||
|
||||
public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = nil, icon: QrCodeIcon, ecl: String = "M") -> Signal<(Int, (TransformImageArguments) -> DrawingContext?), NoError> {
|
||||
public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = nil, icon: QrCodeIcon, ecl: String = "M", onlyMarkers: Bool = false) -> Signal<(Int, (TransformImageArguments) -> DrawingContext?), NoError> {
|
||||
return Signal<(Data, Int, Int), NoError> { subscriber in
|
||||
if let data = string.data(using: .isoLatin1, allowLossyConversion: false), let filter = CIFilter(name: "CIQRCodeGenerator") {
|
||||
filter.setValue(data, forKey: "inputMessage")
|
||||
@ -182,6 +182,7 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
|
||||
}
|
||||
}
|
||||
|
||||
if !onlyMarkers {
|
||||
for y in 0 ..< size {
|
||||
for x in 0 ..< size {
|
||||
if (y < markerSize + 1 && (x < markerSize + 1 || x > size - markerSize - 2)) || (y > size - markerSize - 2 && x < markerSize + 1) {
|
||||
@ -225,6 +226,7 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.translateBy(x: padding, y: padding)
|
||||
|
||||
|
@ -2,3 +2,34 @@ import Foundation
|
||||
import Postbox
|
||||
import TelegramApi
|
||||
import SwiftSignalKit
|
||||
|
||||
func _internal_importContactToken(account: Account, token: String) -> Signal<EnginePeer?, NoError> {
|
||||
return account.network.request(Api.functions.contacts.importContactToken(token: token))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.User?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> EnginePeer? in
|
||||
return result.flatMap { EnginePeer(TelegramUser(user: $0)) }
|
||||
}
|
||||
}
|
||||
|
||||
public struct ExportedContactToken {
|
||||
public let url: String
|
||||
public let expires: Int32
|
||||
}
|
||||
|
||||
func _internal_exportContactToken(account: Account) -> Signal<ExportedContactToken?, NoError> {
|
||||
return account.network.request(Api.functions.contacts.exportContactToken())
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.ExportedContactToken?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> ExportedContactToken? in
|
||||
if let result = result, case let .exportedContactToken(url, expires) = result {
|
||||
return ExportedContactToken(url: url, expires: expires)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -973,6 +973,14 @@ public extension TelegramEngine {
|
||||
public func forumChannelTopicNotificationExceptions(id: EnginePeer.Id) -> Signal<[EngineMessageHistoryThread.NotificationException], NoError> {
|
||||
return _internal_forumChannelTopicNotificationExceptions(account: self.account, id: id)
|
||||
}
|
||||
|
||||
public func importContactToken(token: String) -> Signal<EnginePeer?, NoError> {
|
||||
return _internal_importContactToken(account: self.account, token: token)
|
||||
}
|
||||
|
||||
public func exportContactToken() -> Signal<ExportedContactToken?, NoError> {
|
||||
return _internal_exportContactToken(account: self.account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ import TelegramUniversalVideoContent
|
||||
import GalleryUI
|
||||
import SaveToCameraRoll
|
||||
import SegmentedControlNode
|
||||
import AnimatedCountLabelNode
|
||||
|
||||
private func closeButtonImage(theme: PresentationTheme) -> UIImage? {
|
||||
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
||||
@ -787,6 +788,8 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
|
||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private let contactDisposable = MetaDisposable()
|
||||
private var currentContactToken: ExportedContactToken?
|
||||
|
||||
var present: ((ViewController) -> Void)?
|
||||
var previewTheme: ((String?, Bool?, PresentationTheme) -> Void)?
|
||||
@ -1154,6 +1157,43 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
|
||||
}
|
||||
|
||||
self.ready.set(self.contentNode.isReady)
|
||||
|
||||
if case let .peer(_, _, temporary) = controller.subject, temporary {
|
||||
self.contactDisposable.set(
|
||||
(context.engine.peers.exportContactToken()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] token in
|
||||
if let strongSelf = self {
|
||||
strongSelf.currentContactToken = token
|
||||
if let contentNode = strongSelf.contentNode as? QrContentNode, let token = token {
|
||||
contentNode.setContactToken(token, animated: true)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
if let contentNode = self.contentNode as? QrContentNode {
|
||||
contentNode.requestNextToken = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactDisposable.set(
|
||||
(context.engine.peers.exportContactToken()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] token in
|
||||
if let strongSelf = self {
|
||||
strongSelf.currentContactToken = token
|
||||
if let contentNode = strongSelf.contentNode as? QrContentNode, let token = token {
|
||||
contentNode.setContactToken(token, animated: true)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.contactDisposable.dispose()
|
||||
}
|
||||
|
||||
private func enqueueTransition(_ transition: ThemeSettingsThemeItemNodeTransition) {
|
||||
@ -1451,7 +1491,11 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
private var codeForegroundDimNode: ASDisplayNode
|
||||
private let codeMaskNode: ASDisplayNode
|
||||
private let codeTextNode: ImmediateTextNode
|
||||
private let codeCountdownNode: ImmediateAnimatedCountLabelNode
|
||||
private let codeImageNode: TransformImageNode
|
||||
private let codeMarkersNode: TransformImageNode
|
||||
private var codeSnapshotView: UIView?
|
||||
private var codePlaceholderNode: AnimatedStickerNode
|
||||
private let codeIconBackgroundNode: ASImageNode
|
||||
private let codeStaticIconNode: ASImageNode?
|
||||
private let codeAnimatedIconNode: AnimatedStickerNode?
|
||||
@ -1471,7 +1515,10 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
}
|
||||
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
private var setupTimestamp: Double
|
||||
private var token: ExportedContactToken?
|
||||
private var gettingNextToken = false
|
||||
private var tokenUpdated = false
|
||||
var requestNextToken: () -> Void = {}
|
||||
|
||||
init(context: AccountContext, peer: Peer, threadId: Int64?, isStatic: Bool = false, temporary: Bool) {
|
||||
self.context = context
|
||||
@ -1480,8 +1527,6 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
self.isStatic = isStatic
|
||||
self.temporary = temporary
|
||||
|
||||
self.setupTimestamp = CACurrentMediaTime()
|
||||
|
||||
self.containerNode = ASDisplayNode()
|
||||
|
||||
self.wallpaperBackgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true, useSharedAnimationPhase: false, useExperimentalImplementation: context.sharedContext.immediateExperimentalUISettings.experimentalBackground)
|
||||
@ -1503,8 +1548,11 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
self.codeMaskNode = ASDisplayNode()
|
||||
|
||||
self.codeImageNode = TransformImageNode()
|
||||
self.codeMarkersNode = TransformImageNode()
|
||||
self.codeIconBackgroundNode = ASImageNode()
|
||||
|
||||
self.codePlaceholderNode = DefaultAnimatedStickerNodeImpl()
|
||||
|
||||
if isStatic {
|
||||
let codeStaticIconNode = ASImageNode()
|
||||
codeStaticIconNode.displaysAsynchronously = false
|
||||
@ -1521,9 +1569,6 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
}
|
||||
|
||||
var codeText: String
|
||||
if temporary {
|
||||
codeText = "5:00"
|
||||
} else {
|
||||
if let addressName = peer.addressName, !addressName.isEmpty {
|
||||
codeText = "@\(peer.addressName ?? "")".uppercased()
|
||||
} else {
|
||||
@ -1532,16 +1577,33 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
if let threadId = self.threadId, threadId != 0 {
|
||||
codeText += "/\(threadId)"
|
||||
}
|
||||
}
|
||||
|
||||
let codeFont = Font.with(size: 23.0, design: .round, weight: .bold, traits: [.monospacedNumbers])
|
||||
|
||||
self.codeTextNode = ImmediateTextNode()
|
||||
self.codeTextNode.displaysAsynchronously = false
|
||||
self.codeTextNode.attributedText = NSAttributedString(string: codeText, font: Font.with(size: 23.0, design: .round, weight: .bold, traits: [.monospacedNumbers]), textColor: .black)
|
||||
self.codeTextNode.attributedText = NSAttributedString(string: codeText, font: codeFont, textColor: .black)
|
||||
self.codeTextNode.truncationMode = .byCharWrapping
|
||||
self.codeTextNode.maximumNumberOfLines = 2
|
||||
self.codeTextNode.textAlignment = .center
|
||||
|
||||
self.codeCountdownNode = ImmediateAnimatedCountLabelNode()
|
||||
self.codeCountdownNode.alwaysOneDirection = true
|
||||
|
||||
if isStatic {
|
||||
if temporary {
|
||||
self.codeCountdownNode.isHidden = true
|
||||
}
|
||||
self.codeTextNode.setNeedsDisplayAtScale(3.0)
|
||||
} else if temporary {
|
||||
self.codeTextNode.isHidden = true
|
||||
|
||||
self.codeCountdownNode.segments = [
|
||||
.number(Int(5), NSAttributedString(string: "5", font: codeFont, textColor: .black)),
|
||||
.text(0, NSAttributedString(string: ":", font: codeFont, textColor: .black)),
|
||||
.number(Int(0), NSAttributedString(string: "0", font: codeFont, textColor: .black)),
|
||||
.number(Int(0), NSAttributedString(string: "0", font: codeFont, textColor: .black))
|
||||
]
|
||||
}
|
||||
|
||||
self.avatarNode = ImageNode()
|
||||
@ -1560,8 +1622,13 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
self.codeForegroundNode.addSubnode(self.codeForegroundDimNode)
|
||||
|
||||
self.codeMaskNode.addSubnode(self.codeImageNode)
|
||||
self.codeMaskNode.addSubnode(self.codeMarkersNode)
|
||||
if temporary {
|
||||
self.codeMaskNode.addSubnode(self.codePlaceholderNode)
|
||||
}
|
||||
self.codeMaskNode.addSubnode(self.codeIconBackgroundNode)
|
||||
self.codeMaskNode.addSubnode(self.codeTextNode)
|
||||
self.codeMaskNode.addSubnode(self.codeCountdownNode)
|
||||
|
||||
self.containerNode.addSubnode(self.avatarNode)
|
||||
|
||||
@ -1607,6 +1674,13 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
self?.tick()
|
||||
}, queue: Queue.mainQueue())
|
||||
self.timer?.start()
|
||||
|
||||
self.codePlaceholderNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "QrDataRain"), width: 512, height: 512, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
self.codePlaceholderNode.visibility = true
|
||||
|
||||
self.codeImageNode.alpha = 0.0
|
||||
|
||||
self.codeMarkersNode.setSignal(qrCode(string: "https://t.me/contact/000000:abcdef", color: .black, backgroundColor: nil, icon: .cutout, ecl: "Q", onlyMarkers: true) |> map { $0.1 }, attemptSynchronously: true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1621,14 +1695,85 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
}
|
||||
|
||||
private func tick() {
|
||||
let timeout: Double = 5.0 * 60.0
|
||||
let currentTime = CACurrentMediaTime()
|
||||
let elapsed = max(0.0, timeout - (currentTime - self.setupTimestamp))
|
||||
let currentTime = Int32(Date().timeIntervalSince1970)
|
||||
let elapsed: Int32
|
||||
if let token = self.token {
|
||||
elapsed = token.expires - currentTime
|
||||
} else {
|
||||
elapsed = 300
|
||||
}
|
||||
|
||||
let string = stringForDuration(max(0, elapsed))
|
||||
|
||||
let codeFont = Font.with(size: 23.0, design: .round, weight: .bold, traits: [.monospacedNumbers])
|
||||
|
||||
var segments: [AnimatedCountLabelNode.Segment] = []
|
||||
for char in string {
|
||||
if let intValue = Int(String(char)) {
|
||||
segments.append(.number(intValue, NSAttributedString(string: String(char), font: codeFont, textColor: .black)))
|
||||
} else {
|
||||
segments.append(.text(0, NSAttributedString(string: String(char), font: codeFont, textColor: .black)))
|
||||
}
|
||||
}
|
||||
self.codeCountdownNode.segments = segments
|
||||
|
||||
self.codeTextNode.attributedText = NSAttributedString(string: stringForDuration(Int32(elapsed)), font: Font.with(size: 23.0, design: .round, weight: .bold, traits: [.monospacedNumbers]), textColor: .black)
|
||||
if let (size, topInset, bottomInset) = self.validLayout {
|
||||
self.updateLayout(size: size, topInset: topInset, bottomInset: bottomInset, transition: .immediate)
|
||||
}
|
||||
|
||||
if elapsed <= 1 {
|
||||
if !self.gettingNextToken {
|
||||
self.gettingNextToken = true
|
||||
self.requestNextToken()
|
||||
|
||||
let codeSnapshotView = UIImageView(image: self.codeImageNode.image)
|
||||
codeSnapshotView.frame = self.codeImageNode.frame
|
||||
self.codeImageNode.view.superview?.addSubview(codeSnapshotView)
|
||||
self.codeSnapshotView = codeSnapshotView
|
||||
|
||||
self.codeImageNode.isHidden = true
|
||||
}
|
||||
}
|
||||
if self.tokenUpdated {
|
||||
self.tokenUpdated = false
|
||||
|
||||
self.codeImageNode.isHidden = false
|
||||
self.codeImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
if let codeSnapshotView = self.codeSnapshotView {
|
||||
self.codeSnapshotView = nil
|
||||
codeSnapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak codeSnapshotView] _ in
|
||||
codeSnapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setContactToken(_ token: ExportedContactToken, animated: Bool) {
|
||||
self.token = token
|
||||
if self.gettingNextToken {
|
||||
self.gettingNextToken = false
|
||||
self.tokenUpdated = true
|
||||
}
|
||||
|
||||
self.codeImageNode.setSignal(qrCode(string: token.url, color: .black, backgroundColor: nil, icon: .cutout, ecl: "Q") |> beforeNext { [weak self] size, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.qrCodeSize = size
|
||||
if let (size, topInset, bottomInset) = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: size, topInset: topInset, bottomInset: bottomInset, transition: .immediate)
|
||||
}
|
||||
|
||||
if strongSelf.codePlaceholderNode.visibility {
|
||||
strongSelf.codeImageNode.alpha = 1.0
|
||||
strongSelf.codeImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
strongSelf.codePlaceholderNode.alpha = 0.0
|
||||
strongSelf.codePlaceholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak self] _ in
|
||||
self?.codePlaceholderNode.visibility = false
|
||||
})
|
||||
}
|
||||
|
||||
} |> map { $0.1 }, attemptSynchronously: true)
|
||||
}
|
||||
|
||||
func generateImage(completion: @escaping (UIImage?) -> Void) {
|
||||
@ -1640,6 +1785,9 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
let scale: CGFloat = 3.0
|
||||
|
||||
let copyNode = QrContentNode(context: self.context, peer: self.peer, threadId: self.threadId, isStatic: true, temporary: false)
|
||||
if let token = self.token {
|
||||
copyNode.setContactToken(token, animated: false)
|
||||
}
|
||||
|
||||
func prepare(view: UIView, scale: CGFloat) {
|
||||
view.contentScaleFactor = scale
|
||||
@ -1764,9 +1912,22 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
let imageFrame = CGRect(origin: CGPoint(x: floor((codeBackgroundFrame.width - imageSize.width) / 2.0), y: floor((codeBackgroundFrame.width - imageSize.height) / 2.0)), size: imageSize)
|
||||
transition.updateFrame(node: self.codeImageNode, frame: imageFrame)
|
||||
|
||||
let makeMarkersLayout = self.codeMarkersNode.asyncLayout()
|
||||
let markersApply = makeMarkersLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil, scale: self.isStatic ? 3.0 : nil ))
|
||||
let _ = markersApply()
|
||||
|
||||
transition.updateFrame(node: self.codeMarkersNode, frame: imageFrame)
|
||||
|
||||
let codePlaceholderFrame = imageFrame.insetBy(dx: 10.0, dy: 10.0)
|
||||
self.codePlaceholderNode.updateLayout(size: codePlaceholderFrame.size)
|
||||
self.codePlaceholderNode.frame = codePlaceholderFrame
|
||||
|
||||
let codeTextSize = self.codeTextNode.updateLayout(CGSize(width: codeBackgroundFrame.width - floor(imageFrame.minX * 1.2), height: codeBackgroundFrame.height))
|
||||
transition.updateFrame(node: self.codeTextNode, frame: CGRect(origin: CGPoint(x: floor((codeBackgroundFrame.width - codeTextSize.width) / 2.0), y: imageFrame.maxY + floor((codeBackgroundHeight - imageFrame.maxY - codeTextSize.height) / 2.0) - 5.0), size: codeTextSize))
|
||||
|
||||
let codeCountdownSize = self.codeCountdownNode.updateLayout(size: CGSize(width: codeBackgroundFrame.width - floor(imageFrame.minX * 1.2), height: codeBackgroundFrame.height), animated: true)
|
||||
transition.updateFrame(node: self.codeCountdownNode, frame: CGRect(origin: CGPoint(x: floor((codeBackgroundFrame.width - codeCountdownSize.width) / 2.0), y: imageFrame.maxY + floor((codeBackgroundHeight - imageFrame.maxY - codeCountdownSize.height) / 2.0) - 5.0), size: codeCountdownSize))
|
||||
|
||||
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarSize.width) / 2.0), y: codeBackgroundFrame.minY - floor(avatarSize.height * 0.7)), size: avatarSize))
|
||||
|
||||
if let qrCodeSize = self.qrCodeSize {
|
||||
|
@ -556,6 +556,22 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
convertedUrl = "https://t.me/login/\(code)"
|
||||
}
|
||||
}
|
||||
} else if parsedUrl.host == "contact" {
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
var token: String?
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
if queryItem.name == "token" {
|
||||
token = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let token = token {
|
||||
convertedUrl = "https://t.me/contact/\(token)"
|
||||
}
|
||||
}
|
||||
} else if parsedUrl.host == "confirmphone" {
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
var phone: String?
|
||||
|
@ -7024,11 +7024,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
threadId = Int64(message.messageId.id)
|
||||
}
|
||||
|
||||
// var temporary = false
|
||||
// if self.isSettings && self.data?.globalSettings?.privacySettings?.phoneDiscoveryEnabled == false {
|
||||
// temporary = true
|
||||
// }
|
||||
controller.present(ChatQrCodeScreen(context: self.context, subject: .peer(peer: peer, threadId: threadId, temporary: false)), in: .window(.root))
|
||||
var temporary = false
|
||||
if self.isSettings && self.data?.globalSettings?.privacySettings?.phoneDiscoveryEnabled == false {
|
||||
temporary = true
|
||||
}
|
||||
controller.present(ChatQrCodeScreen(context: self.context, subject: .peer(peer: peer, threadId: threadId, temporary: temporary)), in: .window(.root))
|
||||
}
|
||||
|
||||
fileprivate func openSettings(section: PeerInfoSettingsSection) {
|
||||
|
@ -94,6 +94,7 @@ public enum ParsedInternalUrl {
|
||||
case theme(String)
|
||||
case phone(String, String?, String?)
|
||||
case startAttach(String, String?, String?)
|
||||
case contactToken(String)
|
||||
}
|
||||
|
||||
private enum ParsedUrl {
|
||||
@ -160,7 +161,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
if let _ = url {
|
||||
return .internalInstantView(url: "https://t.me/\(query)")
|
||||
}
|
||||
} else if peerName == "login" {
|
||||
} else if peerName == "contact" {
|
||||
var code: String?
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
@ -290,6 +291,8 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
if let code = Int(pathComponents[1]) {
|
||||
return .confirmationCode(code)
|
||||
}
|
||||
} else if peerName == "contact" {
|
||||
return .contactToken(pathComponents[1])
|
||||
} else if pathComponents[0] == "share" && pathComponents[1] == "url" {
|
||||
if let queryItems = components.queryItems {
|
||||
var url: String?
|
||||
@ -655,6 +658,15 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
||||
return .single(.inaccessiblePeer)
|
||||
}
|
||||
}
|
||||
case let .contactToken(token):
|
||||
return context.engine.peers.importContactToken(token: token)
|
||||
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
|
||||
if let peer = peer {
|
||||
return .single(.peer(peer._asPeer(), .info))
|
||||
} else {
|
||||
return .single(.peer(nil, .info))
|
||||
}
|
||||
}
|
||||
case let .privateMessage(messageId, threadId, timecode):
|
||||
return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: messageId.peerId))
|
||||
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
|
||||
|
Loading…
x
Reference in New Issue
Block a user