diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 6443c3d4dc..4d19e9e044 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -108,6 +108,7 @@ "PUSH_MESSAGE_NOTHEME" = "%1$@|disabled chat theme"; "PUSH_MESSAGE_RECURRING_PAY" = "%1$@|You were charged %2$@"; "CHAT_MESSAGE_RECURRING_PAY" = "%1$@|You were charged %2$@"; +"PUSH_MESSAGE_PAID_MEDIA" = "%1$@sent you a paid post for %2$@ stars"; "PUSH_CHANNEL_MESSAGE_TEXT" = "%1$@|%2$@"; "PUSH_CHANNEL_MESSAGE_NOTEXT" = "%1$@|posted a message"; @@ -138,6 +139,7 @@ "PUSH_CHANNEL_ALBUM" = "%1$@|posted an album"; "PUSH_CHANNEL_MESSAGE_DOCS_TEXT_1" = "posted a file"; "PUSH_CHANNEL_MESSAGE_DOCS_TEXT_any" = "posted %d files"; +"PUSH_CHANNEL_MESSAGE_PAID_MEDIA" = "%1$@ sent a paid post for %2$@ stars"; "PUSH_CHAT_MESSAGE_TEXT" = "%2$@|%1$@:%3$@"; "PUSH_CHAT_MESSAGE_NOTEXT" = "%2$@|%1$@ sent a message to the group"; @@ -183,6 +185,7 @@ "PUSH_CHAT_MESSAGE_THEME" = "%1$@|set theme to %3$@ in the group %2$@"; "PUSH_CHAT_MESSAGE_NOTHEME" = "%1$@|disabled theme in the group %2$@"; "PUSH_CHAT_REQ_JOINED" = "%1$@ was accepted into the group %2$@"; +"PUSH_CHAT_MESSAGE_PAID_MEDIA" = "%1$@ sent a paid post to the group %2$@ for %3$@ stars"; "PUSH_PINNED_TEXT" = "%1$@|pinned \"%2$@\" "; "PUSH_PINNED_NOTEXT" = "%1$@|pinned a message"; @@ -200,6 +203,7 @@ "PUSH_PINNED_GAME" = "%1$@|pinned a game"; "PUSH_PINNED_INVOICE" = "%1$@|pinned an invoice"; "PUSH_PINNED_GIF" = "%1$@|pinned a GIF"; +"PUSH_PINNED_PAID_MEDIA" = "%1$@|pinned a paid post for %2$@"; "PUSH_CONTACT_JOINED" = "%1$@|joined Telegram!"; @@ -252,6 +256,7 @@ "PUSH_CHAT_REACT_GAME" = "%2$@|%1$@ %3$@ to your game"; "PUSH_CHAT_REACT_INVOICE" = "%2$@|%1$@ %3$@ to your invoice"; "PUSH_CHAT_REACT_GIF" = "%2$@|%1$@ %3$@ to your GIF"; +"PUSH_CHAT_REACT_PAID_MEDIA" = "%2$@|%1$@ %3$@ to your paid post"; "PUSH_MESSAGE_SUGGEST_USERPIC" = "%1$@|suggested you new profile photo"; @@ -273,6 +278,7 @@ "PUSH_REACT_STORY" = "%1$@|%2$@ to your story"; "PUSH_REACT_STORY_HIDDEN" = "New reaction to your story"; + "LOCAL_MESSAGE_FWDS" = "%1$@ forwarded you %2$d messages"; "LOCAL_CHANNEL_MESSAGE_FWDS" = "%1$@ posted %2$d forwarded messages"; "LOCAL_CHAT_MESSAGE_FWDS" = "%1$@ forwarded %2$d messages"; diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index b953b6c506..1071fb22eb 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -295,11 +295,13 @@ public struct ChatControllerInitialBotAppStart { public let botApp: BotApp public let payload: String? public let justInstalled: Bool + public let compact: Bool - public init(botApp: BotApp, payload: String?, justInstalled: Bool) { + public init(botApp: BotApp, payload: String?, justInstalled: Bool, compact: Bool) { self.botApp = botApp self.payload = payload self.justInstalled = justInstalled + self.compact = compact } } diff --git a/submodules/AttachmentUI/Sources/AttachmentContainer.swift b/submodules/AttachmentUI/Sources/AttachmentContainer.swift index dca2ee0b5a..0a36720815 100644 --- a/submodules/AttachmentUI/Sources/AttachmentContainer.swift +++ b/submodules/AttachmentUI/Sources/AttachmentContainer.swift @@ -47,6 +47,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { private var isDismissed = false private var isInteractiveDimissEnabled = true + private let isFullSize: Bool public private(set) var isExpanded = false private var validLayout: (layout: ContainerViewLayout, controllers: [AttachmentContainable], coveredByModalTransition: CGFloat)? @@ -72,7 +73,12 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { var isPanGestureEnabled: (() -> Bool)? var onExpandAnimationCompleted: () -> Void = {} - override init() { + init(isFullSize: Bool) { + self.isFullSize = isFullSize + if isFullSize { + self.isExpanded = true + } + self.wrappingNode = ASDisplayNode() self.clipNode = ASDisplayNode() @@ -268,14 +274,14 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { } } - if !self.isExpanded, translation > 40.0, let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() { + if !self.isExpanded || self.isFullSize, translation > 40.0, let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() { self.cancelPanGesture() self.requestDismiss?() return } var bounds = self.bounds - if self.isExpanded { + if self.isExpanded && !self.isFullSize { bounds.origin.y = -max(0.0, translation - edgeTopInset) } else { bounds.origin.y = -translation @@ -307,7 +313,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { } var bounds = self.bounds - if self.isExpanded { + if self.isExpanded && !self.isFullSize { bounds.origin.y = -max(0.0, translation - edgeTopInset) } else { bounds.origin.y = -translation @@ -326,21 +332,29 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { var minimizing = false var dismissing = false - if (bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 1800.0)) && !ignoreDismiss { + + let thresholdOffset: CGFloat + if self.isFullSize { + thresholdOffset = -180.0 + } else { + thresholdOffset = -60.0 + } + + if (bounds.minY < thresholdOffset || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 1800.0)) && !ignoreDismiss { if self.interactivelyDismissed?(velocity.y) == true { dismissing = true } else { minimizing = true } } else if self.isExpanded { - if velocity.y > 300.0 || offset > topInset / 2.0 { + if (velocity.y > 300.0 || offset > topInset / 2.0) && !self.isFullSize { self.isExpanded = false if let listNode = listNode { listNode.scroller.setContentOffset(CGPoint(), animated: false) } else if let scrollView = scrollView { scrollView.setContentOffset(CGPoint(x: scrollView.contentOffset.x, y: -scrollView.contentInset.top), animated: false) } - + let distance = topInset - offset let initialVelocity: CGFloat = distance.isZero ? 0.0 : abs(velocity.y / distance) let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity)) @@ -432,6 +446,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { } self.isUpdatingState = true + let isFirstTime = self.validLayout == nil self.validLayout = (layout, controllers, coveredByModalTransition) self.panGestureRecognizer?.isEnabled = (layout.inputHeight == nil || layout.inputHeight == 0.0) @@ -446,7 +461,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { } let topInset: CGFloat - if let (panInitialTopInset, panOffset, _, _) = self.panGestureArguments { + if !self.isFullSize, let (panInitialTopInset, panOffset, _, _) = self.panGestureArguments { if effectiveExpanded { topInset = min(edgeTopInset, panInitialTopInset + max(0.0, panOffset)) } else { @@ -459,9 +474,29 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate { completion() }) - let modalProgress = isLandscape ? 0.0 : (1.0 - topInset / defaultTopInset) - self.updateModalProgress?(modalProgress, topInset, self.bounds, transition) - + let modalProgress: CGFloat + if isLandscape { + modalProgress = 0.0 + } else { + if self.isFullSize, self.panGestureArguments != nil { + modalProgress = 1.0 - min(1.0, max(0.0, -1.0 * self.bounds.minY / defaultTopInset)) + } else { + modalProgress = 1.0 - topInset / defaultTopInset + } + } + + if isFirstTime { + Queue.mainQueue().justDispatch { + var transition = transition + if modalProgress == 1.0 { + transition = .animated(duration: 0.4, curve: .spring) + } + self.updateModalProgress?(modalProgress, topInset, self.bounds, transition) + } + } else { + self.updateModalProgress?(modalProgress, topInset, self.bounds, transition) + } + let containerLayout: ContainerViewLayout let containerFrame: CGRect let clipFrame: CGRect diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index 8564c2c7f0..c314403b0b 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -131,6 +131,8 @@ public protocol AttachmentContainable: ViewController { func requestDismiss(completion: @escaping () -> Void) func shouldDismissImmediately() -> Bool + + func beforeMaximize(navigationController: NavigationController, completion: @escaping () -> Void) } public extension AttachmentContainable { @@ -154,6 +156,10 @@ public extension AttachmentContainable { return true } + func beforeMaximize(navigationController: NavigationController, completion: @escaping () -> Void) { + completion() + } + var isPanGestureEnabled: (() -> Bool)? { return nil } @@ -234,6 +240,7 @@ public class AttachmentController: ViewController { private let initialButton: AttachmentButtonType private let fromMenu: Bool private var hasTextInput: Bool + private let isFullSize: Bool private let makeEntityInputView: () -> AttachmentTextInputPanelInputView? public var animateAppearance: Bool = false @@ -345,7 +352,7 @@ public class AttachmentController: ViewController { self.wrapperNode = ASDisplayNode() self.wrapperNode.clipsToBounds = true - self.container = AttachmentContainer() + self.container = AttachmentContainer(isFullSize: controller.isFullSize) self.container.canHaveKeyboardFocus = true self.panel = AttachmentPanel(controller: controller, context: controller.context, chatLocation: controller.chatLocation, isScheduledMessages: controller.isScheduledMessages, updatedPresentationData: controller.updatedPresentationData, makeEntityInputView: makeEntityInputView) self.panel.fromMenu = controller.fromMenu @@ -574,7 +581,13 @@ public class AttachmentController: ViewController { guard let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else { return } - navigationController.minimizeViewController(controller, damping: damping, velocity: initialVelocity, setupContainer: { [weak self] current in + navigationController.minimizeViewController(controller, damping: damping, velocity: initialVelocity, beforeMaximize: { navigationController, completion in + if let controller = controller.mainController as? AttachmentContainable { + controller.beforeMaximize(navigationController: navigationController, completion: completion) + } else { + completion() + } + }, setupContainer: { [weak self] current in let minimizedContainer: MinimizedContainerImpl? if let current = current as? MinimizedContainerImpl { minimizedContainer = current @@ -1062,7 +1075,7 @@ public class AttachmentController: ViewController { public var shouldMinimizeOnSwipe: ((AttachmentButtonType?) -> Bool)? - public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, chatLocation: ChatLocation?, isScheduledMessages: Bool = false, buttons: [AttachmentButtonType], initialButton: AttachmentButtonType = .gallery, fromMenu: Bool = false, hasTextInput: Bool = true, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView? = { return nil}) { + public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, chatLocation: ChatLocation?, isScheduledMessages: Bool = false, buttons: [AttachmentButtonType], initialButton: AttachmentButtonType = .gallery, fromMenu: Bool = false, hasTextInput: Bool = true, isFullSize: Bool = false, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView? = { return nil}) { self.context = context self.updatedPresentationData = updatedPresentationData self.chatLocation = chatLocation @@ -1071,6 +1084,7 @@ public class AttachmentController: ViewController { self.initialButton = initialButton self.fromMenu = fromMenu self.hasTextInput = hasTextInput + self.isFullSize = isFullSize self.makeEntityInputView = makeEntityInputView super.init(navigationBarPresentationData: nil) diff --git a/submodules/BrowserUI/Sources/BrowserScreen.swift b/submodules/BrowserUI/Sources/BrowserScreen.swift index 2c0c2250eb..c2f9f0dc4d 100644 --- a/submodules/BrowserUI/Sources/BrowserScreen.swift +++ b/submodules/BrowserUI/Sources/BrowserScreen.swift @@ -447,7 +447,9 @@ public class BrowserScreen: ViewController { guard let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else { return } - navigationController.minimizeViewController(controller, damping: nil, setupContainer: { [weak self] current in + navigationController.minimizeViewController(controller, damping: nil, beforeMaximize: { _, completion in + completion() + }, setupContainer: { [weak self] current in let minimizedContainer: MinimizedContainerImpl? if let current = current as? MinimizedContainerImpl { minimizedContainer = current diff --git a/submodules/Display/Source/Navigation/MinimizedContainer.swift b/submodules/Display/Source/Navigation/MinimizedContainer.swift index 8460e77ce3..b8b5b2b1fa 100644 --- a/submodules/Display/Source/Navigation/MinimizedContainer.swift +++ b/submodules/Display/Source/Navigation/MinimizedContainer.swift @@ -8,7 +8,7 @@ public protocol MinimizedContainer: ASDisplayNode { var willMaximize: (() -> Void)? { get set } - func addController(_ viewController: ViewController, transition: ContainedViewLayoutTransition) + func addController(_ viewController: ViewController, beforeMaximize: @escaping (NavigationController, @escaping () -> Void) -> Void, transition: ContainedViewLayoutTransition) func maximizeController(_ viewController: ViewController, animated: Bool, completion: @escaping (Bool) -> Void) func collapse() func dismissAll(completion: @escaping () -> Void) diff --git a/submodules/Display/Source/Navigation/NavigationController.swift b/submodules/Display/Source/Navigation/NavigationController.swift index 8423ad324b..5e7a82697e 100644 --- a/submodules/Display/Source/Navigation/NavigationController.swift +++ b/submodules/Display/Source/Navigation/NavigationController.swift @@ -842,7 +842,11 @@ open class NavigationController: UINavigationController, ContainableController, if case .flat = navigationLayout.root, let minimizedContainer = self.minimizedContainer { if minimizedContainer.supernode !== self.displayNode { if let rootContainer = self.rootContainer, case let .flat(flatContainer) = rootContainer { - self.displayNode.insertSubnode(minimizedContainer, aboveSubnode: flatContainer) + if let rootModalFrame = self.rootModalFrame { + self.displayNode.insertSubnode(minimizedContainer, aboveSubnode: rootModalFrame) + } else { + self.displayNode.insertSubnode(minimizedContainer, aboveSubnode: flatContainer) + } } else { self.displayNode.insertSubnode(minimizedContainer, at: 0) } @@ -1572,7 +1576,7 @@ open class NavigationController: UINavigationController, ContainableController, self._viewControllersPromise.set(self.viewControllers) } - public func minimizeViewController(_ viewController: ViewController, damping: CGFloat?, velocity: CGFloat? = nil, setupContainer: (MinimizedContainer?) -> MinimizedContainer?, animated: Bool) { + public func minimizeViewController(_ viewController: ViewController, damping: CGFloat?, velocity: CGFloat? = nil, beforeMaximize: @escaping (NavigationController, @escaping () -> Void) -> Void, setupContainer: (MinimizedContainer?) -> MinimizedContainer?, animated: Bool) { let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .customSpring(damping: damping ?? 124.0, initialVelocity: velocity ?? 0.0)) : .immediate let minimizedContainer = setupContainer(self.minimizedContainer) @@ -1592,7 +1596,7 @@ open class NavigationController: UINavigationController, ContainableController, } viewController.isMinimized = true self.filterController(viewController, animated: true) - minimizedContainer?.addController(viewController, transition: transition) + minimizedContainer?.addController(viewController, beforeMaximize: beforeMaximize, transition: transition) } private var isMaximizing = false diff --git a/submodules/Display/Source/Navigation/NavigationModalContainer.swift b/submodules/Display/Source/Navigation/NavigationModalContainer.swift index 1e7603dcbf..65128341fa 100644 --- a/submodules/Display/Source/Navigation/NavigationModalContainer.swift +++ b/submodules/Display/Source/Navigation/NavigationModalContainer.swift @@ -485,6 +485,9 @@ final class NavigationModalContainer: ASDisplayNode, ASScrollViewDelegate, ASGes let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut) let positionTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut) alphaTransition.updateAlpha(node: self.dim, alpha: 0.0, beginWithCurrentState: true) + if let lastController = self.container.controllers.last, lastController.isMinimized { + self.dim.layer.removeAllAnimations() + } positionTransition.updatePosition(node: self.container, position: CGPoint(x: self.container.position.x, y: self.bounds.height + self.container.bounds.height / 2.0 + self.bounds.height), beginWithCurrentState: true, completion: { [weak self] _ in guard let strongSelf = self else { return diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 31de7f2a99..46ce36c45d 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -54,7 +54,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[571523412] = { return $0.readDouble() } dict[-1255641564] = { return parseString($0) } dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($0) } - dict[1008422669] = { return Api.AppWebViewResult.parse_appWebViewResultUrl($0) } dict[-653423106] = { return Api.AttachMenuBot.parse_attachMenuBot($0) } dict[-1297663893] = { return Api.AttachMenuBotIcon.parse_attachMenuBotIcon($0) } dict[1165423600] = { return Api.AttachMenuBotIconColor.parse_attachMenuBotIconColor($0) } @@ -446,6 +445,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[859091184] = { return Api.InputSecureFile.parse_inputSecureFileUploaded($0) } dict[-618540889] = { return Api.InputSecureValue.parse_inputSecureValue($0) } dict[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($0) } + dict[543876817] = { return Api.InputStarsTransaction.parse_inputStarsTransaction($0) } dict[42402760] = { return Api.InputStickerSet.parse_inputStickerSetAnimatedEmoji($0) } dict[215889721] = { return Api.InputStickerSet.parse_inputStickerSetAnimatedEmojiAnimations($0) } dict[-427863538] = { return Api.InputStickerSet.parse_inputStickerSetDice($0) } @@ -870,7 +870,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-378127636] = { return Api.SendMessageAction.parse_sendMessageUploadVideoAction($0) } dict[-651419003] = { return Api.SendMessageAction.parse_speakingInGroupCallAction($0) } dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) } - dict[-2010155333] = { return Api.SimpleWebViewResult.parse_simpleWebViewResultUrl($0) } dict[-425595208] = { return Api.SmsJob.parse_smsJob($0) } dict[-1108478618] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) } dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) } @@ -1105,7 +1104,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[781501415] = { return Api.WebPageAttribute.parse_webPageAttributeStory($0) } dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } dict[211046684] = { return Api.WebViewMessageSent.parse_webViewMessageSent($0) } - dict[202659196] = { return Api.WebViewResult.parse_webViewResultUrl($0) } + dict[1294139288] = { return Api.WebViewResult.parse_webViewResultUrl($0) } dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } dict[1275039392] = { return Api.account.Authorizations.parse_authorizations($0) } dict[1674235686] = { return Api.account.AutoDownloadSettings.parse_autoDownloadSettings($0) } @@ -1155,7 +1154,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1035688326] = { return Api.auth.SentCodeType.parse_sentCodeTypeApp($0) } dict[1398007207] = { return Api.auth.SentCodeType.parse_sentCodeTypeCall($0) } dict[-196020837] = { return Api.auth.SentCodeType.parse_sentCodeTypeEmailCode($0) } - dict[331943703] = { return Api.auth.SentCodeType.parse_sentCodeTypeFirebaseSms($0) } + dict[10475318] = { return Api.auth.SentCodeType.parse_sentCodeTypeFirebaseSms($0) } dict[-1425815847] = { return Api.auth.SentCodeType.parse_sentCodeTypeFlashCall($0) } dict[-648651719] = { return Api.auth.SentCodeType.parse_sentCodeTypeFragmentSms($0) } dict[-2113903484] = { return Api.auth.SentCodeType.parse_sentCodeTypeMissedCall($0) } @@ -1437,8 +1436,6 @@ public extension Api { switch object { case let _1 as Api.AccountDaysTTL: _1.serialize(buffer, boxed) - case let _1 as Api.AppWebViewResult: - _1.serialize(buffer, boxed) case let _1 as Api.AttachMenuBot: _1.serialize(buffer, boxed) case let _1 as Api.AttachMenuBotIcon: @@ -1749,6 +1746,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.InputSingleMedia: _1.serialize(buffer, boxed) + case let _1 as Api.InputStarsTransaction: + _1.serialize(buffer, boxed) case let _1 as Api.InputStickerSet: _1.serialize(buffer, boxed) case let _1 as Api.InputStickerSetItem: @@ -1979,8 +1978,6 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.ShippingOption: _1.serialize(buffer, boxed) - case let _1 as Api.SimpleWebViewResult: - _1.serialize(buffer, boxed) case let _1 as Api.SmsJob: _1.serialize(buffer, boxed) case let _1 as Api.SponsoredMessage: diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 425a83a533..2a79ef6f9e 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -34,42 +34,6 @@ public extension Api { } } -public extension Api { - enum AppWebViewResult: TypeConstructorDescription { - case appWebViewResultUrl(url: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .appWebViewResultUrl(let url): - if boxed { - buffer.appendInt32(1008422669) - } - serializeString(url, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .appWebViewResultUrl(let url): - return ("appWebViewResultUrl", [("url", url as Any)]) - } - } - - public static func parse_appWebViewResultUrl(_ reader: BufferReader) -> AppWebViewResult? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.AppWebViewResult.appWebViewResultUrl(url: _1!) - } - else { - return nil - } - } - - } -} public extension Api { enum AttachMenuBot: TypeConstructorDescription { case attachMenuBot(flags: Int32, botId: Int64, shortName: String, peerTypes: [Api.AttachMenuPeerType]?, icons: [Api.AttachMenuBotIcon]) @@ -1196,3 +1160,43 @@ public extension Api { } } +public extension Api { + enum BotCommand: TypeConstructorDescription { + case botCommand(command: String, description: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botCommand(let command, let description): + if boxed { + buffer.appendInt32(-1032140601) + } + serializeString(command, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botCommand(let command, let description): + return ("botCommand", [("command", command as Any), ("description", description as Any)]) + } + } + + public static func parse_botCommand(_ reader: BufferReader) -> BotCommand? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.BotCommand.botCommand(command: _1!, description: _2!) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramApi/Sources/Api12.swift b/submodules/TelegramApi/Sources/Api12.swift index b318ced6ef..66a1ef3822 100644 --- a/submodules/TelegramApi/Sources/Api12.swift +++ b/submodules/TelegramApi/Sources/Api12.swift @@ -58,6 +58,46 @@ public extension Api { } } +public extension Api { + enum InputStarsTransaction: TypeConstructorDescription { + case inputStarsTransaction(flags: Int32, id: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputStarsTransaction(let flags, let id): + if boxed { + buffer.appendInt32(543876817) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputStarsTransaction(let flags, let id): + return ("inputStarsTransaction", [("flags", flags as Any), ("id", id as Any)]) + } + } + + public static func parse_inputStarsTransaction(_ reader: BufferReader) -> InputStarsTransaction? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputStarsTransaction.inputStarsTransaction(flags: _1!, id: _2!) + } + else { + return nil + } + } + + } +} public extension Api { enum InputStickerSet: TypeConstructorDescription { case inputStickerSetAnimatedEmoji @@ -918,119 +958,3 @@ public extension Api { } } -public extension Api { - enum InputWebFileLocation: TypeConstructorDescription { - case inputWebFileAudioAlbumThumbLocation(flags: Int32, document: Api.InputDocument?, title: String?, performer: String?) - case inputWebFileGeoPointLocation(geoPoint: Api.InputGeoPoint, accessHash: Int64, w: Int32, h: Int32, zoom: Int32, scale: Int32) - case inputWebFileLocation(url: String, accessHash: Int64) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inputWebFileAudioAlbumThumbLocation(let flags, let document, let title, let performer): - if boxed { - buffer.appendInt32(-193992412) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)} - if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 1) != 0 {serializeString(performer!, buffer: buffer, boxed: false)} - break - case .inputWebFileGeoPointLocation(let geoPoint, let accessHash, let w, let h, let zoom, let scale): - if boxed { - buffer.appendInt32(-1625153079) - } - geoPoint.serialize(buffer, true) - serializeInt64(accessHash, buffer: buffer, boxed: false) - serializeInt32(w, buffer: buffer, boxed: false) - serializeInt32(h, buffer: buffer, boxed: false) - serializeInt32(zoom, buffer: buffer, boxed: false) - serializeInt32(scale, buffer: buffer, boxed: false) - break - case .inputWebFileLocation(let url, let accessHash): - if boxed { - buffer.appendInt32(-1036396922) - } - serializeString(url, buffer: buffer, boxed: false) - serializeInt64(accessHash, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inputWebFileAudioAlbumThumbLocation(let flags, let document, let title, let performer): - return ("inputWebFileAudioAlbumThumbLocation", [("flags", flags as Any), ("document", document as Any), ("title", title as Any), ("performer", performer as Any)]) - case .inputWebFileGeoPointLocation(let geoPoint, let accessHash, let w, let h, let zoom, let scale): - return ("inputWebFileGeoPointLocation", [("geoPoint", geoPoint as Any), ("accessHash", accessHash as Any), ("w", w as Any), ("h", h as Any), ("zoom", zoom as Any), ("scale", scale as Any)]) - case .inputWebFileLocation(let url, let accessHash): - return ("inputWebFileLocation", [("url", url as Any), ("accessHash", accessHash as Any)]) - } - } - - public static func parse_inputWebFileAudioAlbumThumbLocation(_ reader: BufferReader) -> InputWebFileLocation? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.InputDocument? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.InputDocument - } } - var _3: String? - if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } - var _4: String? - if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil - let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil - let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.InputWebFileLocation.inputWebFileAudioAlbumThumbLocation(flags: _1!, document: _2, title: _3, performer: _4) - } - else { - return nil - } - } - public static func parse_inputWebFileGeoPointLocation(_ reader: BufferReader) -> InputWebFileLocation? { - var _1: Api.InputGeoPoint? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint - } - var _2: Int64? - _2 = reader.readInt64() - var _3: Int32? - _3 = reader.readInt32() - var _4: Int32? - _4 = reader.readInt32() - var _5: Int32? - _5 = reader.readInt32() - var _6: Int32? - _6 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.InputWebFileLocation.inputWebFileGeoPointLocation(geoPoint: _1!, accessHash: _2!, w: _3!, h: _4!, zoom: _5!, scale: _6!) - } - else { - return nil - } - } - public static func parse_inputWebFileLocation(_ reader: BufferReader) -> InputWebFileLocation? { - var _1: String? - _1 = parseString(reader) - var _2: Int64? - _2 = reader.readInt64() - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.InputWebFileLocation.inputWebFileLocation(url: _1!, accessHash: _2!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api13.swift b/submodules/TelegramApi/Sources/Api13.swift index 39e9b04e84..ecddafbffd 100644 --- a/submodules/TelegramApi/Sources/Api13.swift +++ b/submodules/TelegramApi/Sources/Api13.swift @@ -1,3 +1,119 @@ +public extension Api { + enum InputWebFileLocation: TypeConstructorDescription { + case inputWebFileAudioAlbumThumbLocation(flags: Int32, document: Api.InputDocument?, title: String?, performer: String?) + case inputWebFileGeoPointLocation(geoPoint: Api.InputGeoPoint, accessHash: Int64, w: Int32, h: Int32, zoom: Int32, scale: Int32) + case inputWebFileLocation(url: String, accessHash: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputWebFileAudioAlbumThumbLocation(let flags, let document, let title, let performer): + if boxed { + buffer.appendInt32(-193992412) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(performer!, buffer: buffer, boxed: false)} + break + case .inputWebFileGeoPointLocation(let geoPoint, let accessHash, let w, let h, let zoom, let scale): + if boxed { + buffer.appendInt32(-1625153079) + } + geoPoint.serialize(buffer, true) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(zoom, buffer: buffer, boxed: false) + serializeInt32(scale, buffer: buffer, boxed: false) + break + case .inputWebFileLocation(let url, let accessHash): + if boxed { + buffer.appendInt32(-1036396922) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputWebFileAudioAlbumThumbLocation(let flags, let document, let title, let performer): + return ("inputWebFileAudioAlbumThumbLocation", [("flags", flags as Any), ("document", document as Any), ("title", title as Any), ("performer", performer as Any)]) + case .inputWebFileGeoPointLocation(let geoPoint, let accessHash, let w, let h, let zoom, let scale): + return ("inputWebFileGeoPointLocation", [("geoPoint", geoPoint as Any), ("accessHash", accessHash as Any), ("w", w as Any), ("h", h as Any), ("zoom", zoom as Any), ("scale", scale as Any)]) + case .inputWebFileLocation(let url, let accessHash): + return ("inputWebFileLocation", [("url", url as Any), ("accessHash", accessHash as Any)]) + } + } + + public static func parse_inputWebFileAudioAlbumThumbLocation(_ reader: BufferReader) -> InputWebFileLocation? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputDocument? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputDocument + } } + var _3: String? + if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputWebFileLocation.inputWebFileAudioAlbumThumbLocation(flags: _1!, document: _2, title: _3, performer: _4) + } + else { + return nil + } + } + public static func parse_inputWebFileGeoPointLocation(_ reader: BufferReader) -> InputWebFileLocation? { + var _1: Api.InputGeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint + } + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.InputWebFileLocation.inputWebFileGeoPointLocation(geoPoint: _1!, accessHash: _2!, w: _3!, h: _4!, zoom: _5!, scale: _6!) + } + else { + return nil + } + } + public static func parse_inputWebFileLocation(_ reader: BufferReader) -> InputWebFileLocation? { + var _1: String? + _1 = parseString(reader) + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputWebFileLocation.inputWebFileLocation(url: _1!, accessHash: _2!) + } + else { + return nil + } + } + + } +} public extension Api { enum Invoice: TypeConstructorDescription { case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice], maxTipAmount: Int64?, suggestedTipAmounts: [Int64]?, termsUrl: String?) @@ -934,111 +1050,3 @@ public extension Api { } } -public extension Api { - enum LangPackString: TypeConstructorDescription { - case langPackString(key: String, value: String) - case langPackStringDeleted(key: String) - case langPackStringPluralized(flags: Int32, key: String, zeroValue: String?, oneValue: String?, twoValue: String?, fewValue: String?, manyValue: String?, otherValue: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .langPackString(let key, let value): - if boxed { - buffer.appendInt32(-892239370) - } - serializeString(key, buffer: buffer, boxed: false) - serializeString(value, buffer: buffer, boxed: false) - break - case .langPackStringDeleted(let key): - if boxed { - buffer.appendInt32(695856818) - } - serializeString(key, buffer: buffer, boxed: false) - break - case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): - if boxed { - buffer.appendInt32(1816636575) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(key, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeString(zeroValue!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 1) != 0 {serializeString(oneValue!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 2) != 0 {serializeString(twoValue!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 3) != 0 {serializeString(fewValue!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 4) != 0 {serializeString(manyValue!, buffer: buffer, boxed: false)} - serializeString(otherValue, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .langPackString(let key, let value): - return ("langPackString", [("key", key as Any), ("value", value as Any)]) - case .langPackStringDeleted(let key): - return ("langPackStringDeleted", [("key", key as Any)]) - case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): - return ("langPackStringPluralized", [("flags", flags as Any), ("key", key as Any), ("zeroValue", zeroValue as Any), ("oneValue", oneValue as Any), ("twoValue", twoValue as Any), ("fewValue", fewValue as Any), ("manyValue", manyValue as Any), ("otherValue", otherValue as Any)]) - } - } - - public static func parse_langPackString(_ reader: BufferReader) -> LangPackString? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.LangPackString.langPackString(key: _1!, value: _2!) - } - else { - return nil - } - } - public static func parse_langPackStringDeleted(_ reader: BufferReader) -> LangPackString? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.LangPackString.langPackStringDeleted(key: _1!) - } - else { - return nil - } - } - public static func parse_langPackStringPluralized(_ reader: BufferReader) -> LangPackString? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } - var _4: String? - if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } - var _5: String? - if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } - var _6: String? - if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } - var _7: String? - if Int(_1!) & Int(1 << 4) != 0 {_7 = parseString(reader) } - var _8: String? - _8 = parseString(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil - let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil - let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil - let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil - let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil - let _c8 = _8 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { - return Api.LangPackString.langPackStringPluralized(flags: _1!, key: _2!, zeroValue: _3, oneValue: _4, twoValue: _5, fewValue: _6, manyValue: _7, otherValue: _8!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api14.swift b/submodules/TelegramApi/Sources/Api14.swift index da6d3ef627..737b1ea933 100644 --- a/submodules/TelegramApi/Sources/Api14.swift +++ b/submodules/TelegramApi/Sources/Api14.swift @@ -1,3 +1,111 @@ +public extension Api { + enum LangPackString: TypeConstructorDescription { + case langPackString(key: String, value: String) + case langPackStringDeleted(key: String) + case langPackStringPluralized(flags: Int32, key: String, zeroValue: String?, oneValue: String?, twoValue: String?, fewValue: String?, manyValue: String?, otherValue: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .langPackString(let key, let value): + if boxed { + buffer.appendInt32(-892239370) + } + serializeString(key, buffer: buffer, boxed: false) + serializeString(value, buffer: buffer, boxed: false) + break + case .langPackStringDeleted(let key): + if boxed { + buffer.appendInt32(695856818) + } + serializeString(key, buffer: buffer, boxed: false) + break + case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): + if boxed { + buffer.appendInt32(1816636575) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(key, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(zeroValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(oneValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(twoValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(fewValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeString(manyValue!, buffer: buffer, boxed: false)} + serializeString(otherValue, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .langPackString(let key, let value): + return ("langPackString", [("key", key as Any), ("value", value as Any)]) + case .langPackStringDeleted(let key): + return ("langPackStringDeleted", [("key", key as Any)]) + case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): + return ("langPackStringPluralized", [("flags", flags as Any), ("key", key as Any), ("zeroValue", zeroValue as Any), ("oneValue", oneValue as Any), ("twoValue", twoValue as Any), ("fewValue", fewValue as Any), ("manyValue", manyValue as Any), ("otherValue", otherValue as Any)]) + } + } + + public static func parse_langPackString(_ reader: BufferReader) -> LangPackString? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.LangPackString.langPackString(key: _1!, value: _2!) + } + else { + return nil + } + } + public static func parse_langPackStringDeleted(_ reader: BufferReader) -> LangPackString? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.LangPackString.langPackStringDeleted(key: _1!) + } + else { + return nil + } + } + public static func parse_langPackStringPluralized(_ reader: BufferReader) -> LangPackString? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + var _7: String? + if Int(_1!) & Int(1 << 4) != 0 {_7 = parseString(reader) } + var _8: String? + _8 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.LangPackString.langPackStringPluralized(flags: _1!, key: _2!, zeroValue: _3, oneValue: _4, twoValue: _5, fewValue: _6, manyValue: _7, otherValue: _8!) + } + else { + return nil + } + } + + } +} public extension Api { enum MaskCoords: TypeConstructorDescription { case maskCoords(n: Int32, x: Double, y: Double, zoom: Double) diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 0880c7cd5a..51d1fb1d7f 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -1,43 +1,3 @@ -public extension Api { - enum BotCommand: TypeConstructorDescription { - case botCommand(command: String, description: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .botCommand(let command, let description): - if boxed { - buffer.appendInt32(-1032140601) - } - serializeString(command, buffer: buffer, boxed: false) - serializeString(description, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .botCommand(let command, let description): - return ("botCommand", [("command", command as Any), ("description", description as Any)]) - } - } - - public static func parse_botCommand(_ reader: BufferReader) -> BotCommand? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.BotCommand.botCommand(command: _1!, description: _2!) - } - else { - return nil - } - } - - } -} public extension Api { indirect enum BotCommandScope: TypeConstructorDescription { case botCommandScopeChatAdmins @@ -1200,3 +1160,53 @@ public extension Api { } } +public extension Api { + enum BusinessIntro: TypeConstructorDescription { + case businessIntro(flags: Int32, title: String, description: String, sticker: Api.Document?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessIntro(let flags, let title, let description, let sticker): + if boxed { + buffer.appendInt32(1510606445) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {sticker!.serialize(buffer, true)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessIntro(let flags, let title, let description, let sticker): + return ("businessIntro", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("sticker", sticker as Any)]) + } + } + + public static func parse_businessIntro(_ reader: BufferReader) -> BusinessIntro? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.Document? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Document + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.BusinessIntro.businessIntro(flags: _1!, title: _2!, description: _3!, sticker: _4) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramApi/Sources/Api23.swift b/submodules/TelegramApi/Sources/Api23.swift index 8cc11bf4c7..3a9094cca9 100644 --- a/submodules/TelegramApi/Sources/Api23.swift +++ b/submodules/TelegramApi/Sources/Api23.swift @@ -396,42 +396,6 @@ public extension Api { } } -public extension Api { - enum SimpleWebViewResult: TypeConstructorDescription { - case simpleWebViewResultUrl(url: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .simpleWebViewResultUrl(let url): - if boxed { - buffer.appendInt32(-2010155333) - } - serializeString(url, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .simpleWebViewResultUrl(let url): - return ("simpleWebViewResultUrl", [("url", url as Any)]) - } - } - - public static func parse_simpleWebViewResultUrl(_ reader: BufferReader) -> SimpleWebViewResult? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.SimpleWebViewResult.simpleWebViewResultUrl(url: _1!) - } - else { - return nil - } - } - - } -} public extension Api { enum SmsJob: TypeConstructorDescription { case smsJob(jobId: String, phoneNumber: String, text: String) diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index 189331107c..2518361353 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -160,15 +160,16 @@ public extension Api { } public extension Api { enum WebViewResult: TypeConstructorDescription { - case webViewResultUrl(queryId: Int64, url: String) + case webViewResultUrl(flags: Int32, queryId: Int64?, url: String) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .webViewResultUrl(let queryId, let url): + case .webViewResultUrl(let flags, let queryId, let url): if boxed { - buffer.appendInt32(202659196) + buffer.appendInt32(1294139288) } - serializeInt64(queryId, buffer: buffer, boxed: false) + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt64(queryId!, buffer: buffer, boxed: false)} serializeString(url, buffer: buffer, boxed: false) break } @@ -176,20 +177,23 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .webViewResultUrl(let queryId, let url): - return ("webViewResultUrl", [("queryId", queryId as Any), ("url", url as Any)]) + case .webViewResultUrl(let flags, let queryId, let url): + return ("webViewResultUrl", [("flags", flags as Any), ("queryId", queryId as Any), ("url", url as Any)]) } } public static func parse_webViewResultUrl(_ reader: BufferReader) -> WebViewResult? { - var _1: Int64? - _1 = reader.readInt64() - var _2: String? - _2 = parseString(reader) + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt64() } + var _3: String? + _3 = parseString(reader) let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.WebViewResult.webViewResultUrl(queryId: _1!, url: _2!) + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.WebViewResult.webViewResultUrl(flags: _1!, queryId: _2, url: _3!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api28.swift b/submodules/TelegramApi/Sources/Api28.swift index a8f5ef4aa7..29cc8fa57a 100644 --- a/submodules/TelegramApi/Sources/Api28.swift +++ b/submodules/TelegramApi/Sources/Api28.swift @@ -589,7 +589,7 @@ public extension Api.auth { case sentCodeTypeApp(length: Int32) case sentCodeTypeCall(length: Int32) case sentCodeTypeEmailCode(flags: Int32, emailPattern: String, length: Int32, resetAvailablePeriod: Int32?, resetPendingDate: Int32?) - case sentCodeTypeFirebaseSms(flags: Int32, nonce: Buffer?, playIntegrityNonce: Buffer?, receipt: String?, pushTimeout: Int32?, length: Int32) + case sentCodeTypeFirebaseSms(flags: Int32, nonce: Buffer?, playIntegrityProjectId: Int64?, playIntegrityNonce: Buffer?, receipt: String?, pushTimeout: Int32?, length: Int32) case sentCodeTypeFlashCall(pattern: String) case sentCodeTypeFragmentSms(url: String, length: Int32) case sentCodeTypeMissedCall(prefix: String, length: Int32) @@ -622,12 +622,13 @@ public extension Api.auth { if Int(flags) & Int(1 << 3) != 0 {serializeInt32(resetAvailablePeriod!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 4) != 0 {serializeInt32(resetPendingDate!, buffer: buffer, boxed: false)} break - case .sentCodeTypeFirebaseSms(let flags, let nonce, let playIntegrityNonce, let receipt, let pushTimeout, let length): + case .sentCodeTypeFirebaseSms(let flags, let nonce, let playIntegrityProjectId, let playIntegrityNonce, let receipt, let pushTimeout, let length): if boxed { - buffer.appendInt32(331943703) + buffer.appendInt32(10475318) } serializeInt32(flags, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 0) != 0 {serializeBytes(nonce!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt64(playIntegrityProjectId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {serializeBytes(playIntegrityNonce!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeString(receipt!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeInt32(pushTimeout!, buffer: buffer, boxed: false)} @@ -690,8 +691,8 @@ public extension Api.auth { return ("sentCodeTypeCall", [("length", length as Any)]) case .sentCodeTypeEmailCode(let flags, let emailPattern, let length, let resetAvailablePeriod, let resetPendingDate): return ("sentCodeTypeEmailCode", [("flags", flags as Any), ("emailPattern", emailPattern as Any), ("length", length as Any), ("resetAvailablePeriod", resetAvailablePeriod as Any), ("resetPendingDate", resetPendingDate as Any)]) - case .sentCodeTypeFirebaseSms(let flags, let nonce, let playIntegrityNonce, let receipt, let pushTimeout, let length): - return ("sentCodeTypeFirebaseSms", [("flags", flags as Any), ("nonce", nonce as Any), ("playIntegrityNonce", playIntegrityNonce as Any), ("receipt", receipt as Any), ("pushTimeout", pushTimeout as Any), ("length", length as Any)]) + case .sentCodeTypeFirebaseSms(let flags, let nonce, let playIntegrityProjectId, let playIntegrityNonce, let receipt, let pushTimeout, let length): + return ("sentCodeTypeFirebaseSms", [("flags", flags as Any), ("nonce", nonce as Any), ("playIntegrityProjectId", playIntegrityProjectId as Any), ("playIntegrityNonce", playIntegrityNonce as Any), ("receipt", receipt as Any), ("pushTimeout", pushTimeout as Any), ("length", length as Any)]) case .sentCodeTypeFlashCall(let pattern): return ("sentCodeTypeFlashCall", [("pattern", pattern as Any)]) case .sentCodeTypeFragmentSms(let url, let length): @@ -759,22 +760,25 @@ public extension Api.auth { _1 = reader.readInt32() var _2: Buffer? if Int(_1!) & Int(1 << 0) != 0 {_2 = parseBytes(reader) } - var _3: Buffer? - if Int(_1!) & Int(1 << 2) != 0 {_3 = parseBytes(reader) } - var _4: String? - if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } - var _5: Int32? - if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } + var _3: Int64? + if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt64() } + var _4: Buffer? + if Int(_1!) & Int(1 << 2) != 0 {_4 = parseBytes(reader) } + var _5: String? + if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } var _6: Int32? - _6 = reader.readInt32() + if Int(_1!) & Int(1 << 1) != 0 {_6 = reader.readInt32() } + var _7: Int32? + _7 = reader.readInt32() let _c1 = _1 != nil let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil - let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil - let _c6 = _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.auth.SentCodeType.sentCodeTypeFirebaseSms(flags: _1!, nonce: _2, playIntegrityNonce: _3, receipt: _4, pushTimeout: _5, length: _6!) + let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.auth.SentCodeType.sentCodeTypeFirebaseSms(flags: _1!, nonce: _2, playIntegrityProjectId: _3, playIntegrityNonce: _4, receipt: _5, pushTimeout: _6, length: _7!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 3ec0b4d752..331ac6b496 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -1,53 +1,3 @@ -public extension Api { - enum BusinessIntro: TypeConstructorDescription { - case businessIntro(flags: Int32, title: String, description: String, sticker: Api.Document?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .businessIntro(let flags, let title, let description, let sticker): - if boxed { - buffer.appendInt32(1510606445) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(title, buffer: buffer, boxed: false) - serializeString(description, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {sticker!.serialize(buffer, true)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .businessIntro(let flags, let title, let description, let sticker): - return ("businessIntro", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("sticker", sticker as Any)]) - } - } - - public static func parse_businessIntro(_ reader: BufferReader) -> BusinessIntro? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) - var _4: Api.Document? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.Document - } } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.BusinessIntro.businessIntro(flags: _1!, title: _2!, description: _3!, sticker: _4) - } - else { - return nil - } - } - - } -} public extension Api { enum BusinessLocation: TypeConstructorDescription { case businessLocation(flags: Int32, geoPoint: Api.GeoPoint?, address: String) diff --git a/submodules/TelegramApi/Sources/Api36.swift b/submodules/TelegramApi/Sources/Api36.swift index a5d0bf164d..e2e23ca711 100644 --- a/submodules/TelegramApi/Sources/Api36.swift +++ b/submodules/TelegramApi/Sources/Api36.swift @@ -7308,20 +7308,20 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func requestAppWebView(flags: Int32, peer: Api.InputPeer, app: Api.InputBotApp, startParam: String?, themeParams: Api.DataJSON?, platform: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func requestAppWebView(flags: Int32, peer: Api.InputPeer, app: Api.InputBotApp, startParam: String?, themeParams: Api.DataJSON?, platform: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-1940243652) + buffer.appendInt32(1398901710) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) app.serialize(buffer, true) if Int(flags) & Int(1 << 1) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {themeParams!.serialize(buffer, true)} serializeString(platform, buffer: buffer, boxed: false) - return (FunctionDescription(name: "messages.requestAppWebView", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("app", String(describing: app)), ("startParam", String(describing: startParam)), ("themeParams", String(describing: themeParams)), ("platform", String(describing: platform))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.AppWebViewResult? in + return (FunctionDescription(name: "messages.requestAppWebView", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("app", String(describing: app)), ("startParam", String(describing: startParam)), ("themeParams", String(describing: themeParams)), ("platform", String(describing: platform))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.WebViewResult? in let reader = BufferReader(buffer) - var result: Api.AppWebViewResult? + var result: Api.WebViewResult? if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.AppWebViewResult + result = Api.parse(reader, signature: signature) as? Api.WebViewResult } return result }) @@ -7345,20 +7345,20 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func requestSimpleWebView(flags: Int32, bot: Api.InputUser, url: String?, startParam: String?, themeParams: Api.DataJSON?, platform: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func requestSimpleWebView(flags: Int32, bot: Api.InputUser, url: String?, startParam: String?, themeParams: Api.DataJSON?, platform: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(440815626) + buffer.appendInt32(1094336115) serializeInt32(flags, buffer: buffer, boxed: false) bot.serialize(buffer, true) if Int(flags) & Int(1 << 3) != 0 {serializeString(url!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 4) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {themeParams!.serialize(buffer, true)} serializeString(platform, buffer: buffer, boxed: false) - return (FunctionDescription(name: "messages.requestSimpleWebView", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot)), ("url", String(describing: url)), ("startParam", String(describing: startParam)), ("themeParams", String(describing: themeParams)), ("platform", String(describing: platform))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.SimpleWebViewResult? in + return (FunctionDescription(name: "messages.requestSimpleWebView", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot)), ("url", String(describing: url)), ("startParam", String(describing: startParam)), ("themeParams", String(describing: themeParams)), ("platform", String(describing: platform))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.WebViewResult? in let reader = BufferReader(buffer) - var result: Api.SimpleWebViewResult? + var result: Api.WebViewResult? if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.SimpleWebViewResult + result = Api.parse(reader, signature: signature) as? Api.WebViewResult } return result }) @@ -8827,6 +8827,26 @@ public extension Api.functions.payments { }) } } +public extension Api.functions.payments { + static func getStarsTransactionsByID(peer: Api.InputPeer, id: [Api.InputStarsTransaction]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(662973742) + peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "payments.getStarsTransactionsByID", parameters: [("peer", String(describing: peer)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in + let reader = BufferReader(buffer) + var result: Api.payments.StarsStatus? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.StarsStatus + } + return result + }) + } +} public extension Api.functions.payments { static func launchPrepaidGiveaway(peer: Api.InputPeer, giveawayId: Int64, purpose: Api.InputStorePaymentPurpose) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 31875955eb..bd12468878 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -274,7 +274,7 @@ public func sendAuthorizationCode(accountManager: AccountManager map { mapping -> String? in guard let receipt = receipt else { @@ -432,7 +432,7 @@ private func internalResendAuthorizationCode(accountManager: AccountManager map { mapping -> String? in guard let receipt = receipt else { @@ -574,7 +574,7 @@ public func resendAuthorizationCode(accountManager: AccountManager map { mapping -> String? in guard let receipt = receipt else { diff --git a/submodules/TelegramCore/Sources/State/AccountState.swift b/submodules/TelegramCore/Sources/State/AccountState.swift index 554adf9845..844ad827df 100644 --- a/submodules/TelegramCore/Sources/State/AccountState.swift +++ b/submodules/TelegramCore/Sources/State/AccountState.swift @@ -36,7 +36,7 @@ extension SentAuthorizationCodeType { self = .emailSetupRequired(appleSignInAllowed: (flags & (1 << 0)) != 0) case let .sentCodeTypeFragmentSms(url, length): self = .fragment(url: url, length: length) - case let .sentCodeTypeFirebaseSms(_, _, _, _, pushTimeout, length): + case let .sentCodeTypeFirebaseSms(_, _, _, _, _, pushTimeout, length): self = .firebase(pushTimeout: pushTimeout, length: length) case let .sentCodeTypeSmsWord(_, beginning): self = .word(startsWith: beginning) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift index 14e527f598..7666b030d4 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift @@ -72,7 +72,7 @@ func _internal_requestChangeAccountPhoneNumberVerification(account: Account, api parsedNextType = AuthorizationCodeNextType(apiType: nextType) } - if case let .sentCodeTypeFirebaseSms(_, _, _, receipt, pushTimeout, _) = type { + if case let .sentCodeTypeFirebaseSms(_, _, _, _, receipt, pushTimeout, _) = type { return firebaseSecretStream |> map { mapping -> String? in guard let receipt = receipt else { @@ -147,7 +147,7 @@ private func internalResendChangeAccountPhoneNumberVerification(account: Account parsedNextType = AuthorizationCodeNextType(apiType: nextType) } - if case let .sentCodeTypeFirebaseSms(_, _, _, receipt, pushTimeout, _) = type { + if case let .sentCodeTypeFirebaseSms(_, _, _, _, receipt, pushTimeout, _) = type { return firebaseSecretStream |> map { mapping -> String? in guard let receipt = receipt else { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift index 380047db06..cdbcd868d8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift @@ -16,16 +16,12 @@ public enum RequestSimpleWebViewSource { case settings } -public enum RequestSimpleWebViewError { - case generic -} - -func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: PeerId, url: String?, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal { +func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: PeerId, url: String?, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal { var serializedThemeParams: Api.DataJSON? if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) { serializedThemeParams = .dataJSON(data: dataString) } - return postbox.transaction { transaction -> Signal in + return postbox.transaction { transaction -> Signal in guard let bot = transaction.getPeer(botId), let inputUser = apiInputUser(bot) else { return .fail(.generic) } @@ -46,17 +42,21 @@ func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: P flags |= (1 << 3) } return network.request(Api.functions.messages.requestSimpleWebView(flags: flags, bot: inputUser, url: url, startParam: nil, themeParams: serializedThemeParams, platform: botWebViewPlatform)) - |> mapError { _ -> RequestSimpleWebViewError in + |> mapError { _ -> RequestWebViewError in return .generic } - |> mapToSignal { result -> Signal in + |> mapToSignal { result -> Signal in switch result { - case let .simpleWebViewResultUrl(url): - return .single(url) + case let .webViewResultUrl(flags, queryId, url): + var resultFlags: RequestWebViewResult.Flags = [] + if (flags & (1 << 1)) != 0 { + resultFlags.insert(.fullSize) + } + return .single(RequestWebViewResult(flags: resultFlags, queryId: queryId, url: url, keepAliveSignal: nil)) } } } - |> castError(RequestSimpleWebViewError.self) + |> castError(RequestWebViewError.self) |> switchToLatest } @@ -65,9 +65,24 @@ public enum KeepWebViewError { } public struct RequestWebViewResult { - public let queryId: Int64 + public struct Flags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let fullSize = Flags(rawValue: 1 << 0) + } + + public let flags: Flags + public let queryId: Int64? public let url: String - public let keepAliveSignal: Signal + public let keepAliveSignal: Signal? } public enum RequestWebViewError { @@ -166,8 +181,19 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager: } |> mapToSignal { result -> Signal in switch result { - case let .webViewResultUrl(queryId, url): - return .single(RequestWebViewResult(queryId: queryId, url: url, keepAliveSignal: keepWebViewSignal(network: network, stateManager: stateManager, flags: flags, peer: inputPeer, bot: inputBot, queryId: queryId, replyToMessageId: replyToMessageId, threadId: threadId, sendAs: nil))) + case let .webViewResultUrl(webViewFlags, queryId, url): + var resultFlags: RequestWebViewResult.Flags = [] + if (webViewFlags & (1 << 1)) != 0 { + resultFlags.insert(.fullSize) + } + let keepAlive: Signal? + if let queryId { + keepAlive = keepWebViewSignal(network: network, stateManager: stateManager, flags: flags, peer: inputPeer, bot: inputBot, queryId: queryId, replyToMessageId: replyToMessageId, threadId: threadId, sendAs: nil) + } else { + keepAlive = nil + } + + return .single(RequestWebViewResult(flags: resultFlags, queryId: queryId, url: url, keepAliveSignal: keepAlive)) } } } @@ -199,17 +225,13 @@ func _internal_sendWebViewData(postbox: Postbox, network: Network, stateManager: |> switchToLatest } -public enum RequestAppWebViewError { - case generic -} - -func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, allowWrite: Bool) -> Signal { +func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, compact: Bool, allowWrite: Bool) -> Signal { var serializedThemeParams: Api.DataJSON? if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) { serializedThemeParams = .dataJSON(data: dataString) } - return postbox.transaction { transaction -> Signal in + return postbox.transaction { transaction -> Signal in guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else { return .fail(.generic) } @@ -235,19 +257,26 @@ func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManage if allowWrite { flags |= (1 << 0) } + if compact { + flags |= (1 << 7) + } return network.request(Api.functions.messages.requestAppWebView(flags: flags, peer: inputPeer, app: app, startParam: payload, themeParams: serializedThemeParams, platform: botWebViewPlatform)) - |> mapError { _ -> RequestAppWebViewError in + |> mapError { _ -> RequestWebViewError in return .generic } - |> mapToSignal { result -> Signal in + |> mapToSignal { result -> Signal in switch result { - case let .appWebViewResultUrl(url): - return .single(url) + case let .webViewResultUrl(flags, queryId, url): + var resultFlags: RequestWebViewResult.Flags = [] + if (flags & (1 << 1)) != 0 { + resultFlags.insert(.fullSize) + } + return .single(RequestWebViewResult(flags: resultFlags, queryId: queryId, url: url, keepAliveSignal: nil)) } } } - |> castError(RequestAppWebViewError.self) + |> castError(RequestWebViewError.self) |> switchToLatest } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index b8ddc75bde..c722016d4d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -566,12 +566,12 @@ public extension TelegramEngine { return _internal_requestWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, botId: botId, url: url, payload: payload, themeParams: themeParams, fromMenu: fromMenu, replyToMessageId: replyToMessageId, threadId: threadId) } - public func requestSimpleWebView(botId: PeerId, url: String?, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal { + public func requestSimpleWebView(botId: PeerId, url: String?, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal { return _internal_requestSimpleWebView(postbox: self.account.postbox, network: self.account.network, botId: botId, url: url, source: source, themeParams: themeParams) } - public func requestAppWebView(peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, allowWrite: Bool) -> Signal { - return _internal_requestAppWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, appReference: appReference, payload: payload, themeParams: themeParams, allowWrite: allowWrite) + public func requestAppWebView(peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, compact: Bool, allowWrite: Bool) -> Signal { + return _internal_requestAppWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, appReference: appReference, payload: payload, themeParams: themeParams, compact: compact, allowWrite: allowWrite) } public func sendWebViewData(botId: PeerId, buttonText: String, data: String) -> Signal { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/BUILD b/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/BUILD index 43f3ea0a24..0b8e57031f 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/BUILD @@ -17,6 +17,7 @@ swift_library( "//submodules/TelegramPresentationData", "//submodules/AccountContext", "//submodules/WallpaperBackgroundNode", + "//submodules/UrlHandling", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/Sources/ChatMessageActionButtonsNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/Sources/ChatMessageActionButtonsNode.swift index 66ca0c9d8b..730934d938 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/Sources/ChatMessageActionButtonsNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageActionButtonsNode/Sources/ChatMessageActionButtonsNode.swift @@ -7,6 +7,7 @@ import Display import TelegramPresentationData import AccountContext import WallpaperBackgroundNode +import UrlHandling private let titleFont = Font.medium(16.0) @@ -178,7 +179,9 @@ private final class ChatMessageActionButtonNode: ASDisplayNode { case .text: iconImage = incoming ? graphics.chatBubbleActionButtonIncomingMessageIconImage : graphics.chatBubbleActionButtonOutgoingMessageIconImage case let .url(value): - if value.lowercased().contains("?startgroup=") { + if isTelegramMeLink(value), let internalUrl = parseFullInternalUrl(sharedContext: context.sharedContext, url: value), case .peer(_, .appStart) = internalUrl { + iconImage = incoming ? graphics.chatBubbleActionButtonIncomingWebAppIconImage : graphics.chatBubbleActionButtonOutgoingWebAppIconImage + } else if value.lowercased().contains("?startgroup=") { iconImage = incoming ? graphics.chatBubbleActionButtonIncomingAddToChatIconImage : graphics.chatBubbleActionButtonOutgoingAddToChatIconImage } else { iconImage = incoming ? graphics.chatBubbleActionButtonIncomingLinkIconImage : graphics.chatBubbleActionButtonOutgoingLinkIconImage diff --git a/submodules/TelegramUI/Components/MinimizedContainer/Sources/MinimizedContainer.swift b/submodules/TelegramUI/Components/MinimizedContainer/Sources/MinimizedContainer.swift index 7c130707a9..7301427ffe 100644 --- a/submodules/TelegramUI/Components/MinimizedContainer/Sources/MinimizedContainer.swift +++ b/submodules/TelegramUI/Components/MinimizedContainer/Sources/MinimizedContainer.swift @@ -27,10 +27,12 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll final class Item { let id: AnyHashable let controller: ViewController + let beforeMaximize: (NavigationController, @escaping () -> Void) -> Void - init(id: AnyHashable, controller: ViewController) { + init(id: AnyHashable, controller: ViewController, beforeMaximize: @escaping (NavigationController, @escaping () -> Void) -> Void) { self.id = id self.controller = controller + self.beforeMaximize = beforeMaximize } } @@ -302,6 +304,8 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll private var dismissingItemId: AnyHashable? private var dismissingItemOffset: CGFloat? + private var expandedTapGestureRecoginzer: UITapGestureRecognizer? + private var currentTransition: Transition? private var isApplyingTransition = false private var validLayout: ContainerViewLayout? @@ -370,6 +374,11 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll panGestureRecognizer.delegate = self.wrappedGestureRecognizerDelegate panGestureRecognizer.delaysTouchesBegan = true self.scrollView.addGestureRecognizer(panGestureRecognizer) + + let expandedTapGestureRecoginzer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))) + expandedTapGestureRecoginzer.isEnabled = false + self.expandedTapGestureRecoginzer = expandedTapGestureRecoginzer + self.scrollView.addGestureRecognizer(expandedTapGestureRecoginzer) } func item(at y: CGFloat) -> Int? { @@ -401,6 +410,15 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll return false } + @objc func tapGesture(_ gestureRecognizer: UITapGestureRecognizer) { + guard self.isExpanded else { + return + } + if let result = self.scrollView.hitTest(gestureRecognizer.location(in: self.scrollView), with: nil), result === self.scrollView { + self.collapse() + } + } + @objc func panGesture(_ gestureRecognizer: UIPanGestureRecognizer) { if self.isExpanded { self.dismissPanGesture(gestureRecognizer) @@ -483,10 +501,11 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll return result } - public func addController(_ viewController: ViewController, transition: ContainedViewLayoutTransition) { + public func addController(_ viewController: ViewController, beforeMaximize: @escaping (NavigationController, @escaping () -> Void) -> Void, transition: ContainedViewLayoutTransition) { let item = Item( id: AnyHashable(Int64.random(in: Int64.min ... Int64.max)), - controller: viewController + controller: viewController, + beforeMaximize: beforeMaximize ) self.items.append(item) @@ -552,7 +571,11 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll return } if self.items.count == 1, let item = self.items.first { - self.navigationController?.maximizeViewController(item.controller, animated: true) + if let navigationController = self.navigationController { + item.beforeMaximize(navigationController, { [weak self] in + self?.navigationController?.maximizeViewController(item.controller, animated: true) + }) + } } else { self.isExpanded = true self.requestUpdate(transition: .animated(duration: 0.4, curve: .spring)) @@ -697,7 +720,11 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll return } if self.isExpanded { - self.navigationController?.maximizeViewController(item.controller, animated: true) + if let navigationController = self.navigationController { + itemNode.item.beforeMaximize(navigationController, { [weak self] in + self?.navigationController?.maximizeViewController(item.controller, animated: true) + }) + } } else { self.expand() } @@ -816,6 +843,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll } self.scrollView.passthrough = !self.isExpanded self.scrollView.isScrollEnabled = self.isExpanded + self.expandedTapGestureRecoginzer?.isEnabled = self.isExpanded if let currentTransition = self.currentTransition { self.isApplyingTransition = true @@ -904,28 +932,33 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll return } if self.items.count == 1 { - if let itemNode = self.itemNodes.first(where: { $0.0 != itemId })?.value { - let dimView = UIView() - dimView.frame = CGRect(origin: .zero, size: layout.size) - dimView.backgroundColor = UIColor(white: 0.0, alpha: 0.25) - self.view.insertSubview(dimView, aboveSubview: self.blurView) - dimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) - - itemNode.animateOut() - transition.updateTransform(node: itemNode, transform: CATransform3DIdentity) - transition.updatePosition(node: itemNode, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0 + topInset + self.scrollView.contentOffset.y), completion: { _ in - self.isApplyingTransition = false - if self.currentTransition == currentTransition { - self.currentTransition = nil + if let itemNode = self.itemNodes.first(where: { $0.0 != itemId })?.value, let navigationController = self.navigationController { + itemNode.item.beforeMaximize(navigationController, { [weak self] in + guard let self else { + return } - completion(currentTransition) - self.itemNodes[itemId] = nil - itemNode.removeFromSupernode() - dimView.removeFromSuperview() + let dimView = UIView() + dimView.frame = CGRect(origin: .zero, size: layout.size) + dimView.backgroundColor = UIColor(white: 0.0, alpha: 0.25) + self.view.insertSubview(dimView, aboveSubview: self.blurView) + dimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) - self.navigationController?.maximizeViewController(itemNode.item.controller, animated: false) - - self.requestUpdate(transition: .immediate) + itemNode.animateOut() + transition.updateTransform(node: itemNode, transform: CATransform3DIdentity) + transition.updatePosition(node: itemNode, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0 + topInset + self.scrollView.contentOffset.y), completion: { _ in + self.isApplyingTransition = false + if self.currentTransition == currentTransition { + self.currentTransition = nil + } + completion(currentTransition) + self.itemNodes[itemId] = nil + itemNode.removeFromSupernode() + dimView.removeFromSuperview() + + self.navigationController?.maximizeViewController(itemNode.item.controller, animated: false) + + self.requestUpdate(transition: .immediate) + }) }) } transition.updatePosition(node: dismissedItemNode, position: CGPoint(x: -layout.size.width, y: dismissedItemNode.position.y)) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 6cf96cfe89..8603bbe2fe 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -5312,7 +5312,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro return } - let params = WebAppParameters(source: .settings, peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: bot.flags.contains(.hasSettings)) + let params = WebAppParameters(source: .settings, peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: bot.flags.contains(.hasSettings), fullSize: true) let controller = standaloneWebAppController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, params: params, threadId: nil, openUrl: { [weak self] url, concealed, commit in self?.openUrl(url: url, concealed: concealed, external: false, forceExternal: true, commit: commit) }, requestSwitchInline: { _, _, _ in diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index 485b879508..279e2bee0d 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -1808,7 +1808,7 @@ final class StoryItemSetContainerSendMessage { //TODO:gift controller break case let .app(bot): - let params = WebAppParameters(source: .attachMenu, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false) + let params = WebAppParameters(source: .attachMenu, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: true) let theme = component.theme let updatedPresentationData: (initial: PresentationData, signal: Signal) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }) let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil) diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift index 376d6b226a..4429e9ddcd 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift @@ -10,8 +10,9 @@ import AttachmentUI import AccountContext import TelegramNotices import PresentationDataUtils +import UndoUI -extension ChatControllerImpl { +public extension ChatControllerImpl { func openWebApp(buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource) { guard let peerId = self.chatLocation.peerId, let peer = self.presentationInterfaceState.renderedPeer?.peer else { return @@ -76,14 +77,7 @@ extension ChatControllerImpl { if source == .menu { self.updateChatPresentationInterfaceState(interactive: false) { state in return state.updatedForceInputCommandsHidden(true) -// return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true) - } - - if let currentMenuWebAppController = self.currentMenuWebAppController { - if currentMenuWebAppController.isMinimized { - (currentMenuWebAppController.navigationController as? NavigationController)?.maximizeViewController(currentMenuWebAppController, animated: true) - return - } +// return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true) } if let navigationController = self.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer { @@ -96,7 +90,7 @@ extension ChatControllerImpl { } let context = self.context - let params = WebAppParameters(source: .menu, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false) + let params = WebAppParameters(source: .menu, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: false) let controller = standaloneWebAppController(context: self.context, updatedPresentationData: self.updatedPresentationData, params: params, threadId: self.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit) }, requestSwitchInline: { [weak self] query, chatTypes, completion in @@ -146,7 +140,6 @@ extension ChatControllerImpl { }) controller.navigationPresentation = .flatModal self.push(controller) - self.currentMenuWebAppController = controller } else if simple { var isInline = false var botId = peerId @@ -163,12 +156,12 @@ extension ChatControllerImpl { |> afterDisposed { updateProgress() }) - |> deliverOnMainQueue).startStrict(next: { [weak self] url in + |> deliverOnMainQueue).startStrict(next: { [weak self] result in guard let strongSelf = self else { return } let context = strongSelf.context - let params = WebAppParameters(source: isInline ? .inline : .simple, peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false) + let params = WebAppParameters(source: isInline ? .inline : .simple, peerId: peerId, botId: botId, botName: botName, url: result.url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: result.flags.contains(.fullSize)) let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit) }, requestSwitchInline: { [weak self] query, chatTypes, completion in @@ -209,7 +202,7 @@ extension ChatControllerImpl { return } let context = strongSelf.context - let params = WebAppParameters(source: .generic, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false) + let params = WebAppParameters(source: .generic, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize)) let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit) }, completion: { [weak self] in @@ -250,4 +243,164 @@ extension ChatControllerImpl { } }) } + + func presentBotApp(botApp: BotApp, botPeer: EnginePeer, payload: String?, compact: Bool, concealed: Bool = false, commit: @escaping () -> Void = {}) { + guard let peerId = self.chatLocation.peerId else { + return + } + self.attachmentController?.dismiss(animated: true, completion: nil) + + let openBotApp: (Bool, Bool) -> Void = { [weak self] allowWrite, justInstalled in + guard let strongSelf = self else { + return + } + commit() + + strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { + return $0.updatedTitlePanelContext { + if !$0.contains(where: { + switch $0 { + case .requestInProgress: + return true + default: + return false + } + }) { + var updatedContexts = $0 + updatedContexts.append(.requestInProgress) + return updatedContexts.sorted() + } + return $0 + } + }) + + let updateProgress = { [weak self] in + Queue.mainQueue().async { + if let strongSelf = self { + strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { + return $0.updatedTitlePanelContext { + if let index = $0.firstIndex(where: { + switch $0 { + case .requestInProgress: + return true + default: + return false + } + }) { + var updatedContexts = $0 + updatedContexts.remove(at: index) + return updatedContexts + } + return $0 + } + }) + } + } + } + + let botAddress = botPeer.addressName ?? "" + strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), compact: compact, allowWrite: allowWrite) + |> afterDisposed { + updateProgress() + }) + |> deliverOnMainQueue).startStrict(next: { [weak self] result in + guard let strongSelf = self else { + return + } + let context = strongSelf.context + let params = WebAppParameters(source: .generic, peerId: peerId, botId: botPeer.id, botName: botApp.title, url: result.url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, forceHasSettings: botApp.flags.contains(.hasSettings), fullSize: result.flags.contains(.fullSize)) + let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in + self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit) + }, requestSwitchInline: { [weak self] query, chatTypes, completion in + if let strongSelf = self { + if let chatTypes { + let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: chatTypes, hasContactSelector: false, hasCreation: false)) + controller.peerSelected = { [weak self, weak controller] peer, _ in + if let strongSelf = self { + completion() + controller?.dismiss() + strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)", nil) + } + } + strongSelf.push(controller) + } else { + strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)", nil) + } + } + }, completion: { [weak self] in + self?.chatDisplayNode.historyNode.scrollToEndOfHistory() + }, getNavigationController: { [weak self] in + return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController + }) + controller.navigationPresentation = .flatModal + strongSelf.currentWebAppController = controller + strongSelf.push(controller) + + if justInstalled { + let content: UndoOverlayContent = .succeed(text: strongSelf.presentationData.strings.WebApp_ShortcutsSettingsAdded(botPeer.compactDisplayTitle).string, timeout: 5.0, customUndoText: nil) + controller.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: content, elevatedLayout: false, position: .top, action: { _ in return false }), in: .current) + } + }, error: { [weak self] error in + if let strongSelf = self { + strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + })]), in: .window(.root)) + } + })) + } + + let _ = combineLatest( + queue: Queue.mainQueue(), + ApplicationSpecificNotice.getBotGameNotice(accountManager: self.context.sharedContext.accountManager, peerId: botPeer.id), + self.context.engine.messages.attachMenuBots(), + self.context.engine.messages.getAttachMenuBot(botId: botPeer.id, cached: true) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + ).startStandalone(next: { [weak self] noticed, attachMenuBots, attachMenuBot in + guard let self else { + return + } + + var isAttachMenuBotInstalled: Bool? + if let _ = attachMenuBot { + if let _ = attachMenuBots.first(where: { $0.peer.id == botPeer.id && !$0.flags.contains(.notActivated) }) { + isAttachMenuBotInstalled = true + } else { + isAttachMenuBotInstalled = false + } + } + + let context = self.context + if !noticed || botApp.flags.contains(.notActivated) || isAttachMenuBotInstalled == false { + if let isAttachMenuBotInstalled, let attachMenuBot { + if !isAttachMenuBotInstalled { + let controller = webAppTermsAlertController(context: context, updatedPresentationData: self.updatedPresentationData, bot: attachMenuBot, completion: { allowWrite in + let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone() + let _ = (context.engine.messages.addBotToAttachMenu(botId: botPeer.id, allowWrite: allowWrite) + |> deliverOnMainQueue).startStandalone(error: { _ in + }, completed: { + openBotApp(allowWrite, true) + }) + }) + self.present(controller, in: .window(.root)) + } else { + openBotApp(false, false) + } + } else { + let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: self.updatedPresentationData, peer: botPeer, requestWriteAccess: botApp.flags.contains(.notActivated) && botApp.flags.contains(.requiresWriteAccess), completion: { allowWrite in + let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone() + openBotApp(allowWrite, false) + }, showMore: { [weak self] in + if let self { + self.openResolved(result: .peer(botPeer._asPeer(), .info(nil)), sourceMessageId: nil) + } + }) + self.present(controller, in: .window(.root)) + } + } else { + openBotApp(false, false) + } + }) + } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 2a13f002a3..6d8181cb52 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -525,7 +525,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let chatLocationContextHolder: Atomic weak var attachmentController: AttachmentController? - weak var currentMenuWebAppController: ViewController? weak var currentWebAppController: ViewController? weak var currentImportMessageTooltip: UndoOverlayController? @@ -7917,166 +7916,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.presentAttachmentMenu(subject: .bot(id: botId, payload: payload, justInstalled: justInstalled)) } - public func presentBotApp(botApp: BotApp, botPeer: EnginePeer, payload: String?, concealed: Bool = false, commit: @escaping () -> Void = {}) { - guard let peerId = self.chatLocation.peerId else { - return - } - self.attachmentController?.dismiss(animated: true, completion: nil) - - let openBotApp: (Bool, Bool) -> Void = { [weak self] allowWrite, justInstalled in - guard let strongSelf = self else { - return - } - commit() - - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { - return $0.updatedTitlePanelContext { - if !$0.contains(where: { - switch $0 { - case .requestInProgress: - return true - default: - return false - } - }) { - var updatedContexts = $0 - updatedContexts.append(.requestInProgress) - return updatedContexts.sorted() - } - return $0 - } - }) - - let updateProgress = { [weak self] in - Queue.mainQueue().async { - if let strongSelf = self { - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { - return $0.updatedTitlePanelContext { - if let index = $0.firstIndex(where: { - switch $0 { - case .requestInProgress: - return true - default: - return false - } - }) { - var updatedContexts = $0 - updatedContexts.remove(at: index) - return updatedContexts - } - return $0 - } - }) - } - } - } - - let botAddress = botPeer.addressName ?? "" - strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), allowWrite: allowWrite) - |> afterDisposed { - updateProgress() - }) - |> deliverOnMainQueue).startStrict(next: { [weak self] url in - guard let strongSelf = self else { - return - } - let context = strongSelf.context - let params = WebAppParameters(source: .generic, peerId: peerId, botId: botPeer.id, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, forceHasSettings: botApp.flags.contains(.hasSettings)) - let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in - self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit) - }, requestSwitchInline: { [weak self] query, chatTypes, completion in - if let strongSelf = self { - if let chatTypes { - let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: chatTypes, hasContactSelector: false, hasCreation: false)) - controller.peerSelected = { [weak self, weak controller] peer, _ in - if let strongSelf = self { - completion() - controller?.dismiss() - strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)", nil) - } - } - strongSelf.push(controller) - } else { - strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)", nil) - } - } - }, completion: { [weak self] in - self?.chatDisplayNode.historyNode.scrollToEndOfHistory() - }, getNavigationController: { [weak self] in - return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController - }) - controller.navigationPresentation = .flatModal - strongSelf.currentWebAppController = controller - strongSelf.push(controller) - - if justInstalled { - let content: UndoOverlayContent = .succeed(text: strongSelf.presentationData.strings.WebApp_ShortcutsSettingsAdded(botPeer.compactDisplayTitle).string, timeout: 5.0, customUndoText: nil) - controller.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: content, elevatedLayout: false, position: .top, action: { _ in return false }), in: .current) - } - }, error: { [weak self] error in - if let strongSelf = self { - strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { - })]), in: .window(.root)) - } - })) - } - - let _ = combineLatest( - queue: Queue.mainQueue(), - ApplicationSpecificNotice.getBotGameNotice(accountManager: self.context.sharedContext.accountManager, peerId: botPeer.id), - self.context.engine.messages.attachMenuBots(), - self.context.engine.messages.getAttachMenuBot(botId: botPeer.id, cached: true) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - ).startStandalone(next: { [weak self] value, attachMenuBots, attachMenuBot in - guard let self else { - return - } - - var isAttachMenuBotInstalled: Bool? - if let _ = attachMenuBot { - if let _ = attachMenuBots.first(where: { $0.peer.id == botPeer.id && !$0.flags.contains(.notActivated) }) { - isAttachMenuBotInstalled = true - } else { - isAttachMenuBotInstalled = false - } - } - - let context = self.context - if !value || concealed || botApp.flags.contains(.notActivated) || isAttachMenuBotInstalled == false { - if let isAttachMenuBotInstalled, let attachMenuBot { - if !isAttachMenuBotInstalled { - let controller = webAppTermsAlertController(context: context, updatedPresentationData: self.updatedPresentationData, bot: attachMenuBot, completion: { allowWrite in - let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone() - let _ = (context.engine.messages.addBotToAttachMenu(botId: botPeer.id, allowWrite: allowWrite) - |> deliverOnMainQueue).startStandalone(error: { _ in - }, completed: { - openBotApp(allowWrite, true) - }) - }) - self.present(controller, in: .window(.root)) - } else { - openBotApp(false, false) - } - } else { - let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: self.updatedPresentationData, peer: botPeer, requestWriteAccess: botApp.flags.contains(.notActivated) && botApp.flags.contains(.requiresWriteAccess), completion: { allowWrite in - let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone() - openBotApp(allowWrite, false) - }, showMore: { [weak self] in - if let self { - self.openResolved(result: .peer(botPeer._asPeer(), .info(nil)), sourceMessageId: nil) - } - }) - self.present(controller, in: .window(.root)) - } - } else { - openBotApp(false, false) - } - }) - } - func displayPollSolution(solution: TelegramMediaPollResults.Solution, sourceNode: ASDisplayNode, isAutomatic: Bool) { var maybeFoundItemNode: ChatMessageItemView? self.chatDisplayNode.historyNode.forEachItemNode { itemNode in @@ -9305,7 +9144,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId.id)) |> deliverOnMainQueue).startStandalone(next: { [weak self] peer in if let strongSelf = self, let peer { - strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, concealed: concealed, commit: { + strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact, concealed: concealed, commit: { dismissWebAppControllers() commit() }) diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift index 366751ca81..847b3f83f1 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift @@ -615,7 +615,7 @@ extension ChatControllerImpl { payload = botPayload fromAttachMenu = false } - let params = WebAppParameters(source: fromAttachMenu ? .attachMenu : .generic, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false) + let params = WebAppParameters(source: fromAttachMenu ? .attachMenu : .generic, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: false) let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageSubject?.messageId, threadId: strongSelf.chatLocation.threadId) controller.openUrl = { [weak self] url, concealed, commit in diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index f99072a72a..452a8deebf 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -165,7 +165,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled) } if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation { - controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload) + controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact) } params.setupController(controller) found = true @@ -188,7 +188,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam } if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation { Queue.mainQueue().after(0.1) { - controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload) + controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact) } } } else { @@ -196,7 +196,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation { Queue.mainQueue().after(0.1) { - controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload) + controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact) } } } diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 5b9c30e7d5..eff23dab0f 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -71,7 +71,7 @@ public enum ParsedInternalPeerUrlParameter { case channelMessage(Int32, Double?) case replyThread(Int32, Int32) case voiceChat(String?) - case appStart(String, String?) + case appStart(String, String?, Bool) case story(Int32) case boost case text(String) @@ -588,16 +588,19 @@ public func parseInternalUrl(sharedContext: SharedAccountContext, query: String) } else if pathComponents.count == 2 { let appName = pathComponents[1] var startApp: String? + var compact = false if let queryItems = components.queryItems { for queryItem in queryItems { if let value = queryItem.value { if queryItem.name == "startapp" { startApp = value + } else if queryItem.name == "mode", value == "compact" { + compact = true } } } } - return .peer(.name(peerName), .appStart(appName, startApp)) + return .peer(.name(peerName), .appStart(appName, startApp, compact)) } else { return nil } @@ -713,7 +716,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) } } } - case let .appStart(name, payload): + case let .appStart(name, payload, compact): return .single(.progress) |> then(context.engine.messages.getBotApp(botId: peer.id, shortName: name, cached: false) |> map(Optional.init) |> `catch` { _ -> Signal in @@ -721,7 +724,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) } |> mapToSignal { botApp -> Signal in if let botApp { - return .single(.result(.peer(peer._asPeer(), .withBotApp(ChatControllerInitialBotAppStart(botApp: botApp, payload: payload, justInstalled: false))))) + return .single(.result(.peer(peer._asPeer(), .withBotApp(ChatControllerInitialBotAppStart(botApp: botApp, payload: payload, justInstalled: false, compact: compact))))) } else { return .single(.result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))) } @@ -1138,6 +1141,21 @@ public func parseAdUrl(sharedContext: SharedAccountContext, url: String) -> Pars return nil } +public func parseFullInternalUrl(sharedContext: SharedAccountContext, url: String) -> ParsedInternalUrl? { + let schemes = ["http://", "https://", ""] + for basePath in baseTelegramMePaths { + for scheme in schemes { + let basePrefix = scheme + basePath + "/" + if url.lowercased().hasPrefix(basePrefix) { + if let internalUrl = parseInternalUrl(sharedContext: sharedContext, query: String(url[basePrefix.endIndex...])) { + return internalUrl + } + } + } + } + return nil +} + private struct UrlHandlingConfiguration { static var defaultValue: UrlHandlingConfiguration { return UrlHandlingConfiguration(domains: [], urlAuthDomains: []) diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 50abb887e3..b04fe06a64 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -208,6 +208,7 @@ public struct WebAppParameters { let buttonText: String? let keepAliveSignal: Signal? let forceHasSettings: Bool + let fullSize: Bool public init( source: Source, @@ -219,7 +220,8 @@ public struct WebAppParameters { payload: String?, buttonText: String?, keepAliveSignal: Signal?, - forceHasSettings: Bool + forceHasSettings: Bool, + fullSize: Bool ) { self.source = source self.peerId = peerId @@ -231,6 +233,7 @@ public struct WebAppParameters { self.buttonText = buttonText self.keepAliveSignal = keepAliveSignal self.forceHasSettings = forceHasSettings + self.fullSize = fullSize } } @@ -288,6 +291,7 @@ public final class WebAppController: ViewController, AttachmentContainable { private let context: AccountContext var presentationData: PresentationData private var queryId: Int64? + fileprivate let canMinimize = true private var placeholderDisposable: Disposable? private var iconDisposable: Disposable? @@ -306,7 +310,7 @@ public final class WebAppController: ViewController, AttachmentContainable { self.context = context self.controller = controller self.presentationData = controller.presentationData - + self.backgroundNode = ASDisplayNode() self.headerBackgroundNode = ASDisplayNode() self.topOverscrollNode = ASDisplayNode() @@ -477,7 +481,8 @@ public final class WebAppController: ViewController, AttachmentContainable { guard let strongSelf = self else { return } - if let parsedUrl = URL(string: result) { + if let parsedUrl = URL(string: result.url) { + strongSelf.queryId = result.queryId strongSelf.webView?.load(URLRequest(url: parsedUrl)) } }) @@ -491,17 +496,19 @@ public final class WebAppController: ViewController, AttachmentContainable { strongSelf.queryId = result.queryId strongSelf.webView?.load(URLRequest(url: parsedUrl)) - strongSelf.keepAliveDisposable = (result.keepAliveSignal - |> deliverOnMainQueue).start(error: { [weak self] _ in - if let strongSelf = self { - strongSelf.controller?.dismiss() - } - }, completed: { [weak self] in - if let strongSelf = self { - strongSelf.controller?.completion() - strongSelf.controller?.dismiss() - } - }) + if let keepAliveSignal = result.keepAliveSignal { + strongSelf.keepAliveDisposable = (keepAliveSignal + |> deliverOnMainQueue).start(error: { [weak self] _ in + if let strongSelf = self { + strongSelf.controller?.dismiss() + } + }, completed: { [weak self] in + if let strongSelf = self { + strongSelf.controller?.completion() + strongSelf.controller?.dismiss() + } + }) + } } }) } @@ -909,6 +916,11 @@ public final class WebAppController: ViewController, AttachmentContainable { } case "web_app_open_link": if let json = json, let url = json["url"] as? String { + let webAppConfiguration = WebAppConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }) + if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: escapedUrl), let scheme = url.scheme?.lowercased(), !["http", "https"].contains(scheme) && !webAppConfiguration.allowedProtocols.contains(scheme) { + return + } + let tryInstantView = json["try_instant_view"] as? Bool ?? false if let lastTouchTimestamp = self.webView?.lastTouchTimestamp, currentTimestamp < lastTouchTimestamp + 10.0 { self.webView?.lastTouchTimestamp = nil @@ -1877,6 +1889,25 @@ public final class WebAppController: ViewController, AttachmentContainable { self.presentationDataDisposable?.dispose() } + public func beforeMaximize(navigationController: NavigationController, completion: @escaping () -> Void) { + switch self.source { + case .generic, .settings: + completion() + case .inline, .attachMenu, .menu, .simple: + let _ = (self.context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId) + ) + |> deliverOnMainQueue).start(next: { [weak self] chatPeer in + guard let self, let chatPeer else { + return + } + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(chatPeer), completion: { _ in + completion() + })) + }) + } + } + fileprivate func updateNavigationBarTheme(transition: ContainedViewLayoutTransition) { let navigationBarPresentationData: NavigationBarPresentationData if let backgroundColor = self.controllerNode.headerColor, let textColor = self.controllerNode.headerPrimaryTextColor { @@ -2095,6 +2126,10 @@ public final class WebAppController: ViewController, AttachmentContainable { public func shouldDismissImmediately() -> Bool { return true } + + fileprivate var canMinimize: Bool { + return self.controllerNode.canMinimize + } } final class WebAppPickerContext: AttachmentMediaPickerContext { @@ -2172,8 +2207,9 @@ public func standaloneWebAppController( willDismiss: @escaping () -> Void = {}, didDismiss: @escaping () -> Void = {}, getNavigationController: @escaping () -> NavigationController? = { return nil }, - getSourceRect: (() -> CGRect?)? = nil) -> ViewController { - let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: params.peerId), buttons: [.standalone], initialButton: .standalone, fromMenu: params.source == .menu, hasTextInput: false, makeEntityInputView: { + getSourceRect: (() -> CGRect?)? = nil +) -> ViewController { + let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: params.peerId), buttons: [.standalone], initialButton: .standalone, fromMenu: params.source == .menu, hasTextInput: false, isFullSize: params.fullSize, makeEntityInputView: { return nil }) controller.requestController = { _, present in @@ -2188,8 +2224,35 @@ public func standaloneWebAppController( controller.didDismiss = didDismiss controller.getSourceRect = getSourceRect controller.title = params.botName - controller.shouldMinimizeOnSwipe = { _ in - return true + controller.shouldMinimizeOnSwipe = { [weak controller] _ in + if let controller, let mainController = controller.mainController as? WebAppController { + return mainController.canMinimize + } + return false } return controller } + +private struct WebAppConfiguration { + static var defaultValue: WebAppConfiguration { + return WebAppConfiguration(allowedProtocols: []) + } + + let allowedProtocols: [String] + + fileprivate init(allowedProtocols: [String]) { + self.allowedProtocols = allowedProtocols + } + + static func with(appConfiguration: AppConfiguration) -> WebAppConfiguration { + if let data = appConfiguration.data { + var allowedProtocols: [String] = [] + if let value = data["web_app_allowed_protocols"] as? [String] { + allowedProtocols = value + } + return WebAppConfiguration(allowedProtocols: allowedProtocols) + } else { + return .defaultValue + } + } +}