From 3caedf56702c06a2b0f5e3a1f9d11a443541740d Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 27 Nov 2022 15:00:10 +0400 Subject: [PATCH] Temporary QR codes --- .../Telegram-iOS/Resources/QrDataRain.tgs | Bin 0 -> 26834 bytes Telegram/Telegram-iOS/Resources/QrLoading.tgs | Bin 29817 -> 0 bytes .../Sources/AnimatedCountLabelNode.swift | 4 +- submodules/QrCode/Sources/QrCode.swift | 80 +++---- .../TelegramEngine/Peers/ContactToken.swift | 31 +++ .../Peers/TelegramEnginePeers.swift | 8 + .../TelegramUI/Sources/ChatQrCodeScreen.swift | 201 ++++++++++++++++-- submodules/TelegramUI/Sources/OpenUrl.swift | 16 ++ .../Sources/PeerInfo/PeerInfoScreen.swift | 10 +- .../UrlHandling/Sources/UrlHandling.swift | 14 +- 10 files changed, 298 insertions(+), 66 deletions(-) create mode 100644 Telegram/Telegram-iOS/Resources/QrDataRain.tgs delete mode 100644 Telegram/Telegram-iOS/Resources/QrLoading.tgs diff --git a/Telegram/Telegram-iOS/Resources/QrDataRain.tgs b/Telegram/Telegram-iOS/Resources/QrDataRain.tgs new file mode 100644 index 0000000000000000000000000000000000000000..8a97b29eae7820ba8b5da82ec4443f956f3df929 GIT binary patch literal 26834 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 BrWpVL diff --git a/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift b/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift index 162445af7f..f34b9a1fa3 100644 --- a/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift +++ b/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift @@ -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) diff --git a/submodules/QrCode/Sources/QrCode.swift b/submodules/QrCode/Sources/QrCode.swift index ba0074e0e7..9f34ce850a 100644 --- a/submodules/QrCode/Sources/QrCode.swift +++ b/submodules/QrCode/Sources/QrCode.swift @@ -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,46 +182,48 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n } } - 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) { - continue - } - - var corners: UIRectCorner = [] - if valueAt(x: x, y: y) { - corners = .allCorners - if valueAt(x: x, y: y - 1) { - corners.remove(.topLeft) - corners.remove(.topRight) + 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) { + continue } - if valueAt(x: x, y: y + 1) { - corners.remove(.bottomLeft) - corners.remove(.bottomRight) + + var corners: UIRectCorner = [] + if valueAt(x: x, y: y) { + corners = .allCorners + if valueAt(x: x, y: y - 1) { + corners.remove(.topLeft) + corners.remove(.topRight) + } + if valueAt(x: x, y: y + 1) { + corners.remove(.bottomLeft) + corners.remove(.bottomRight) + } + if valueAt(x: x - 1, y: y) { + corners.remove(.topLeft) + corners.remove(.bottomLeft) + } + if valueAt(x: x + 1, y: y) { + corners.remove(.topRight) + corners.remove(.bottomRight) + } + drawAt(x: x, y: y, fill: true, corners: corners) + } else { + if valueAt(x: x - 1, y: y - 1) && valueAt(x: x - 1, y: y) && valueAt(x: x, y: y - 1) { + corners.insert(.topLeft) + } + if valueAt(x: x + 1, y: y - 1) && valueAt(x: x + 1, y: y) && valueAt(x: x, y: y - 1) { + corners.insert(.topRight) + } + if valueAt(x: x - 1, y: y + 1) && valueAt(x: x - 1, y: y) && valueAt(x: x, y: y + 1) { + corners.insert(.bottomLeft) + } + if valueAt(x: x + 1, y: y + 1) && valueAt(x: x + 1, y: y) && valueAt(x: x, y: y + 1) { + corners.insert(.bottomRight) + } + drawAt(x: x, y: y, fill: false, corners: corners) } - if valueAt(x: x - 1, y: y) { - corners.remove(.topLeft) - corners.remove(.bottomLeft) - } - if valueAt(x: x + 1, y: y) { - corners.remove(.topRight) - corners.remove(.bottomRight) - } - drawAt(x: x, y: y, fill: true, corners: corners) - } else { - if valueAt(x: x - 1, y: y - 1) && valueAt(x: x - 1, y: y) && valueAt(x: x, y: y - 1) { - corners.insert(.topLeft) - } - if valueAt(x: x + 1, y: y - 1) && valueAt(x: x + 1, y: y) && valueAt(x: x, y: y - 1) { - corners.insert(.topRight) - } - if valueAt(x: x - 1, y: y + 1) && valueAt(x: x - 1, y: y) && valueAt(x: x, y: y + 1) { - corners.insert(.bottomLeft) - } - if valueAt(x: x + 1, y: y + 1) && valueAt(x: x + 1, y: y) && valueAt(x: x, y: y + 1) { - corners.insert(.bottomRight) - } - drawAt(x: x, y: y, fill: false, corners: corners) } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ContactToken.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ContactToken.swift index f5902e1415..8a8910199d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ContactToken.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ContactToken.swift @@ -2,3 +2,34 @@ import Foundation import Postbox import TelegramApi import SwiftSignalKit + +func _internal_importContactToken(account: Account, token: String) -> Signal { + return account.network.request(Api.functions.contacts.importContactToken(token: token)) + |> map(Optional.init) + |> `catch` { _ -> Signal 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 { + return account.network.request(Api.functions.contacts.exportContactToken()) + |> map(Optional.init) + |> `catch` { _ -> Signal 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 + } + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index f82bef8fe0..7952dd019f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -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 { + return _internal_importContactToken(account: self.account, token: token) + } + + public func exportContactToken() -> Signal { + return _internal_exportContactToken(account: self.account) + } } } diff --git a/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift b/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift index 0a35d20bea..821cead160 100644 --- a/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift +++ b/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift @@ -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 @@ -1479,9 +1526,7 @@ private class QrContentNode: ASDisplayNode, ContentNode { self.threadId = threadId 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,27 +1569,41 @@ private class QrContentNode: ASDisplayNode, ContentNode { } var codeText: String - if temporary { - codeText = "5:00" + if let addressName = peer.addressName, !addressName.isEmpty { + codeText = "@\(peer.addressName ?? "")".uppercased() } else { - if let addressName = peer.addressName, !addressName.isEmpty { - codeText = "@\(peer.addressName ?? "")".uppercased() - } else { - codeText = peer.debugDisplayTitle.uppercased() - } - if let threadId = self.threadId, threadId != 0 { - codeText += "/\(threadId)" - } + codeText = peer.debugDisplayTitle.uppercased() } + 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 @@ -1763,10 +1911,23 @@ 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 { diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 026ce7f838..1cc5499d27 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -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? diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 56c4e6eda6..9cfc58c416 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -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) { diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 89d7ee6c72..086dd11966 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -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 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 in