From 51613e018594ed5889c2a4bbca6f2ddb720b81d9 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 31 Mar 2022 16:14:02 +0400 Subject: [PATCH] Web app improvements --- .../Sources/AccountContext.swift | 8 +- .../Sources/ChatController.swift | 12 +- .../Sources/InstantPageControllerNode.swift | 4 +- submodules/TelegramApi/Sources/Api0.swift | 9 +- submodules/TelegramApi/Sources/Api1.swift | 250 ++++++++---------- submodules/TelegramApi/Sources/Api2.swift | 128 +++++++++ submodules/TelegramApi/Sources/Api21.swift | 72 ++--- submodules/TelegramApi/Sources/Api22.swift | 98 ++++--- submodules/TelegramApi/Sources/Api23.swift | 94 +++---- submodules/TelegramApi/Sources/Api24.swift | 36 --- submodules/TelegramApi/Sources/Api27.swift | 7 +- .../SyncCore/SyncCore_Namespaces.swift | 2 +- .../Messages/AttachMenuBots.swift | 168 ++++++++++-- .../TelegramEngine/Messages/BotWebView.swift | 35 +-- .../Messages/TelegramEngineMessages.swift | 18 +- .../TelegramUI/Sources/ChatController.swift | 100 ++++--- .../ChatRecentActionsControllerNode.swift | 2 +- .../Sources/NavigateToChatController.swift | 10 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 42 ++- submodules/TelegramUI/Sources/OpenUrl.swift | 14 +- .../Sources/PeerInfo/PeerInfoScreen.swift | 8 +- .../UrlHandling/Sources/UrlHandling.swift | 25 +- .../WebUI/Sources/WebAppController.swift | 35 ++- 23 files changed, 687 insertions(+), 490 deletions(-) diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 796dec7fbe..1fd13f2ede 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -258,7 +258,7 @@ public enum ResolvedUrl { case settings(ResolvedUrlSettingsSection) case joinVoiceChat(PeerId, String?) case importStickers - case setAttach(PeerId) + case startAttach(peerId: PeerId, payload: String?) } public enum NavigateToChatKeepStack { @@ -346,7 +346,7 @@ public final class NavigateToChatControllerParams { public let chatLocationContextHolder: Atomic public let subject: ChatControllerSubject? public let botStart: ChatControllerInitialBotStart? - public let attachBotId: PeerId? + public let attachBotStart: ChatControllerInitialAttachBotStart? public let updateTextInputState: ChatTextInputState? public let activateInput: Bool public let keepStack: NavigateToChatKeepStack @@ -365,7 +365,7 @@ public final class NavigateToChatControllerParams { public let changeColors: Bool public let completion: (ChatController) -> Void - public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic = Atomic(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotId: PeerId? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = [], changeColors: Bool = false, completion: @escaping (ChatController) -> Void = { _ in }) { + public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic = Atomic(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = [], changeColors: Bool = false, completion: @escaping (ChatController) -> Void = { _ in }) { self.navigationController = navigationController self.chatController = chatController self.chatLocationContextHolder = chatLocationContextHolder @@ -373,7 +373,7 @@ public final class NavigateToChatControllerParams { self.chatLocation = chatLocation self.subject = subject self.botStart = botStart - self.attachBotId = attachBotId + self.attachBotStart = attachBotStart self.updateTextInputState = updateTextInputState self.activateInput = activateInput self.keepStack = keepStack diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index 329e50c030..d37c5a53c1 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -143,12 +143,22 @@ public struct ChatControllerInitialBotStart { } } +public struct ChatControllerInitialAttachBotStart { + public let botId: PeerId + public let payload: String? + + public init(botId: PeerId, payload: String?) { + self.botId = botId + self.payload = payload + } +} + public enum ChatControllerInteractionNavigateToPeer { case `default` case chat(textInputState: ChatTextInputState?, subject: ChatControllerSubject?, peekData: ChatPeekTimeout?) case info case withBotStartPayload(ChatControllerInitialBotStart) - case withAttachBot(PeerId) + case withAttachBot(ChatControllerInitialAttachBotStart) } public struct ChatInterfaceForwardOptionsState: Codable, Equatable { diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index eebd61c71b..a272a7ca6f 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -1248,9 +1248,9 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { if let navigationController = strongSelf.getNavigationController() { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), botStart: botStart, keepStack: .always)) } - case let .withAttachBot(botId): + case let .withAttachBot(attachBotStart): if let navigationController = strongSelf.getNavigationController() { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), attachBotId: botId)) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), attachBotStart: attachBotStart)) } case .info: let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId) diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 9c39fd2c2b..42e7c0626a 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -45,7 +45,9 @@ 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[1340016040] = { return Api.AttachMenuBot.parse_attachMenuBot($0) } + dict[-381896846] = { return Api.AttachMenuBot.parse_attachMenuBot($0) } + dict[-1297663893] = { return Api.AttachMenuBotIcon.parse_attachMenuBotIcon($0) } + dict[1165423600] = { return Api.AttachMenuBotIconColor.parse_attachMenuBotIconColor($0) } dict[1011024320] = { return Api.AttachMenuBots.parse_attachMenuBots($0) } dict[-237467044] = { return Api.AttachMenuBots.parse_attachMenuBotsNotModified($0) } dict[-1816172929] = { return Api.AttachMenuBotsBot.parse_attachMenuBotsBot($0) } @@ -837,7 +839,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-981018084] = { return Api.WebPage.parse_webPagePending($0) } dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } dict[211046684] = { return Api.WebViewMessageSent.parse_webViewMessageSent($0) } - dict[-1312107643] = { return Api.WebViewResult.parse_webViewResultConfirmationRequired($0) } dict[202659196] = { return Api.WebViewResult.parse_webViewResultUrl($0) } dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } dict[1275039392] = { return Api.account.Authorizations.parse_authorizations($0) } @@ -1087,6 +1088,10 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.AttachMenuBot: _1.serialize(buffer, boxed) + case let _1 as Api.AttachMenuBotIcon: + _1.serialize(buffer, boxed) + case let _1 as Api.AttachMenuBotIconColor: + _1.serialize(buffer, boxed) case let _1 as Api.AttachMenuBots: _1.serialize(buffer, boxed) case let _1 as Api.AttachMenuBotsBot: diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 7119b94a6d..d5eecf39d5 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -36,26 +36,30 @@ public extension Api { } public extension Api { enum AttachMenuBot: TypeConstructorDescription { - case attachMenuBot(flags: Int32, botId: Int64, attachMenuName: String, attachMenuIcon: Api.Document) + case attachMenuBot(flags: Int32, botId: Int64, shortName: String, icons: [Api.AttachMenuBotIcon]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .attachMenuBot(let flags, let botId, let attachMenuName, let attachMenuIcon): + case .attachMenuBot(let flags, let botId, let shortName, let icons): if boxed { - buffer.appendInt32(1340016040) + buffer.appendInt32(-381896846) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt64(botId, buffer: buffer, boxed: false) - serializeString(attachMenuName, buffer: buffer, boxed: false) - attachMenuIcon.serialize(buffer, true) + serializeString(shortName, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(icons.count)) + for item in icons { + item.serialize(buffer, true) + } break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .attachMenuBot(let flags, let botId, let attachMenuName, let attachMenuIcon): - return ("attachMenuBot", [("flags", String(describing: flags)), ("botId", String(describing: botId)), ("attachMenuName", String(describing: attachMenuName)), ("attachMenuIcon", String(describing: attachMenuIcon))]) + case .attachMenuBot(let flags, let botId, let shortName, let icons): + return ("attachMenuBot", [("flags", String(describing: flags)), ("botId", String(describing: botId)), ("shortName", String(describing: shortName)), ("icons", String(describing: icons))]) } } @@ -66,16 +70,112 @@ public extension Api { _2 = reader.readInt64() var _3: String? _3 = parseString(reader) - var _4: Api.Document? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.Document + var _4: [Api.AttachMenuBotIcon]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AttachMenuBotIcon.self) } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil if _c1 && _c2 && _c3 && _c4 { - return Api.AttachMenuBot.attachMenuBot(flags: _1!, botId: _2!, attachMenuName: _3!, attachMenuIcon: _4!) + return Api.AttachMenuBot.attachMenuBot(flags: _1!, botId: _2!, shortName: _3!, icons: _4!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum AttachMenuBotIcon: TypeConstructorDescription { + case attachMenuBotIcon(flags: Int32, name: String, icon: Api.Document, colors: [Api.AttachMenuBotIconColor]?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .attachMenuBotIcon(let flags, let name, let icon, let colors): + if boxed { + buffer.appendInt32(-1297663893) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(name, buffer: buffer, boxed: false) + icon.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(colors!.count)) + for item in colors! { + item.serialize(buffer, true) + }} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .attachMenuBotIcon(let flags, let name, let icon, let colors): + return ("attachMenuBotIcon", [("flags", String(describing: flags)), ("name", String(describing: name)), ("icon", String(describing: icon)), ("colors", String(describing: colors))]) + } + } + + public static func parse_attachMenuBotIcon(_ reader: BufferReader) -> AttachMenuBotIcon? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Api.Document? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Document + } + var _4: [Api.AttachMenuBotIconColor]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AttachMenuBotIconColor.self) + } } + 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.AttachMenuBotIcon.attachMenuBotIcon(flags: _1!, name: _2!, icon: _3!, colors: _4) + } + else { + return nil + } + } + + } +} +public extension Api { + enum AttachMenuBotIconColor: TypeConstructorDescription { + case attachMenuBotIconColor(name: String, color: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .attachMenuBotIconColor(let name, let color): + if boxed { + buffer.appendInt32(1165423600) + } + serializeString(name, buffer: buffer, boxed: false) + serializeInt32(color, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .attachMenuBotIconColor(let name, let color): + return ("attachMenuBotIconColor", [("name", String(describing: name)), ("color", String(describing: color))]) + } + } + + public static func parse_attachMenuBotIconColor(_ reader: BufferReader) -> AttachMenuBotIconColor? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.AttachMenuBotIconColor.attachMenuBotIconColor(name: _1!, color: _2!) } else { return nil @@ -1086,131 +1186,3 @@ public extension Api { } } -public extension Api { - enum BotInlineResult: TypeConstructorDescription { - case botInlineMediaResult(flags: Int32, id: String, type: String, photo: Api.Photo?, document: Api.Document?, title: String?, description: String?, sendMessage: Api.BotInlineMessage) - case botInlineResult(flags: Int32, id: String, type: String, title: String?, description: String?, url: String?, thumb: Api.WebDocument?, content: Api.WebDocument?, sendMessage: Api.BotInlineMessage) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .botInlineMediaResult(let flags, let id, let type, let photo, let document, let title, let description, let sendMessage): - if boxed { - buffer.appendInt32(400266251) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(id, buffer: buffer, boxed: false) - serializeString(type, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)} - if Int(flags) & Int(1 << 1) != 0 {document!.serialize(buffer, true)} - if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 3) != 0 {serializeString(description!, buffer: buffer, boxed: false)} - sendMessage.serialize(buffer, true) - break - case .botInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): - if boxed { - buffer.appendInt32(295067450) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(id, buffer: buffer, boxed: false) - serializeString(type, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 2) != 0 {serializeString(description!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 3) != 0 {serializeString(url!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 4) != 0 {thumb!.serialize(buffer, true)} - if Int(flags) & Int(1 << 5) != 0 {content!.serialize(buffer, true)} - sendMessage.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .botInlineMediaResult(let flags, let id, let type, let photo, let document, let title, let description, let sendMessage): - return ("botInlineMediaResult", [("flags", String(describing: flags)), ("id", String(describing: id)), ("type", String(describing: type)), ("photo", String(describing: photo)), ("document", String(describing: document)), ("title", String(describing: title)), ("description", String(describing: description)), ("sendMessage", String(describing: sendMessage))]) - case .botInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): - return ("botInlineResult", [("flags", String(describing: flags)), ("id", String(describing: id)), ("type", String(describing: type)), ("title", String(describing: title)), ("description", String(describing: description)), ("url", String(describing: url)), ("thumb", String(describing: thumb)), ("content", String(describing: content)), ("sendMessage", String(describing: sendMessage))]) - } - } - - public static func parse_botInlineMediaResult(_ reader: BufferReader) -> BotInlineResult? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) - var _4: Api.Photo? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.Photo - } } - var _5: Api.Document? - if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.Document - } } - var _6: String? - if Int(_1!) & Int(1 << 2) != 0 {_6 = parseString(reader) } - var _7: String? - if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) } - var _8: Api.BotInlineMessage? - if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.BotInlineMessage - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil - let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil - let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil - let _c8 = _8 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { - return Api.BotInlineResult.botInlineMediaResult(flags: _1!, id: _2!, type: _3!, photo: _4, document: _5, title: _6, description: _7, sendMessage: _8!) - } - else { - return nil - } - } - public static func parse_botInlineResult(_ reader: BufferReader) -> BotInlineResult? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - _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: Api.WebDocument? - if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { - _7 = Api.parse(reader, signature: signature) as? Api.WebDocument - } } - var _8: Api.WebDocument? - if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.WebDocument - } } - var _9: Api.BotInlineMessage? - if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.BotInlineMessage - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _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 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil - let _c9 = _9 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.BotInlineResult.botInlineResult(flags: _1!, id: _2!, type: _3!, title: _4, description: _5, url: _6, thumb: _7, content: _8, sendMessage: _9!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index fca17647aa..e5f1723b9a 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -1,3 +1,131 @@ +public extension Api { + enum BotInlineResult: TypeConstructorDescription { + case botInlineMediaResult(flags: Int32, id: String, type: String, photo: Api.Photo?, document: Api.Document?, title: String?, description: String?, sendMessage: Api.BotInlineMessage) + case botInlineResult(flags: Int32, id: String, type: String, title: String?, description: String?, url: String?, thumb: Api.WebDocument?, content: Api.WebDocument?, sendMessage: Api.BotInlineMessage) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botInlineMediaResult(let flags, let id, let type, let photo, let document, let title, let description, let sendMessage): + if boxed { + buffer.appendInt32(400266251) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {document!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + sendMessage.serialize(buffer, true) + break + case .botInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): + if boxed { + buffer.appendInt32(295067450) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {thumb!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {content!.serialize(buffer, true)} + sendMessage.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botInlineMediaResult(let flags, let id, let type, let photo, let document, let title, let description, let sendMessage): + return ("botInlineMediaResult", [("flags", String(describing: flags)), ("id", String(describing: id)), ("type", String(describing: type)), ("photo", String(describing: photo)), ("document", String(describing: document)), ("title", String(describing: title)), ("description", String(describing: description)), ("sendMessage", String(describing: sendMessage))]) + case .botInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): + return ("botInlineResult", [("flags", String(describing: flags)), ("id", String(describing: id)), ("type", String(describing: type)), ("title", String(describing: title)), ("description", String(describing: description)), ("url", String(describing: url)), ("thumb", String(describing: thumb)), ("content", String(describing: content)), ("sendMessage", String(describing: sendMessage))]) + } + } + + public static func parse_botInlineMediaResult(_ reader: BufferReader) -> BotInlineResult? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.Photo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _5: Api.Document? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Document + } } + var _6: String? + if Int(_1!) & Int(1 << 2) != 0 {_6 = parseString(reader) } + var _7: String? + if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) } + var _8: Api.BotInlineMessage? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.BotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.BotInlineResult.botInlineMediaResult(flags: _1!, id: _2!, type: _3!, photo: _4, document: _5, title: _6, description: _7, sendMessage: _8!) + } + else { + return nil + } + } + public static func parse_botInlineResult(_ reader: BufferReader) -> BotInlineResult? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _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: Api.WebDocument? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.WebDocument + } } + var _8: Api.WebDocument? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.WebDocument + } } + var _9: Api.BotInlineMessage? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.BotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _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 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.BotInlineResult.botInlineResult(flags: _1!, id: _2!, type: _3!, title: _4, description: _5, url: _6, thumb: _7, content: _8, sendMessage: _9!) + } + else { + return nil + } + } + + } +} public extension Api { enum CdnConfig: TypeConstructorDescription { case cdnConfig(publicKeys: [Api.CdnPublicKey]) diff --git a/submodules/TelegramApi/Sources/Api21.swift b/submodules/TelegramApi/Sources/Api21.swift index f4dd7fe7d7..0dd575e4ff 100644 --- a/submodules/TelegramApi/Sources/Api21.swift +++ b/submodules/TelegramApi/Sources/Api21.swift @@ -94,22 +94,10 @@ public extension Api { } public extension Api { enum WebViewResult: TypeConstructorDescription { - case webViewResultConfirmationRequired(bot: Api.AttachMenuBot, users: [Api.User]) case webViewResultUrl(queryId: Int64, url: String) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .webViewResultConfirmationRequired(let bot, let users): - if boxed { - buffer.appendInt32(-1312107643) - } - bot.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users.count)) - for item in users { - item.serialize(buffer, true) - } - break case .webViewResultUrl(let queryId, let url): if boxed { buffer.appendInt32(202659196) @@ -122,31 +110,11 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .webViewResultConfirmationRequired(let bot, let users): - return ("webViewResultConfirmationRequired", [("bot", String(describing: bot)), ("users", String(describing: users))]) case .webViewResultUrl(let queryId, let url): return ("webViewResultUrl", [("queryId", String(describing: queryId)), ("url", String(describing: url))]) } } - public static func parse_webViewResultConfirmationRequired(_ reader: BufferReader) -> WebViewResult? { - var _1: Api.AttachMenuBot? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.AttachMenuBot - } - var _2: [Api.User]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.WebViewResult.webViewResultConfirmationRequired(bot: _1!, users: _2!) - } - else { - return nil - } - } public static func parse_webViewResultUrl(_ reader: BufferReader) -> WebViewResult? { var _1: Int64? _1 = reader.readInt64() @@ -1212,3 +1180,43 @@ public extension Api.auth { } } +public extension Api.auth { + enum LoggedOut: TypeConstructorDescription { + case loggedOut(flags: Int32, futureAuthToken: Buffer?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .loggedOut(let flags, let futureAuthToken): + if boxed { + buffer.appendInt32(-1012759713) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeBytes(futureAuthToken!, buffer: buffer, boxed: false)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .loggedOut(let flags, let futureAuthToken): + return ("loggedOut", [("flags", String(describing: flags)), ("futureAuthToken", String(describing: futureAuthToken))]) + } + } + + public static func parse_loggedOut(_ reader: BufferReader) -> LoggedOut? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseBytes(reader) } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + if _c1 && _c2 { + return Api.auth.LoggedOut.loggedOut(flags: _1!, futureAuthToken: _2) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramApi/Sources/Api22.swift b/submodules/TelegramApi/Sources/Api22.swift index 1a0126bbac..1c4e854c8f 100644 --- a/submodules/TelegramApi/Sources/Api22.swift +++ b/submodules/TelegramApi/Sources/Api22.swift @@ -1,43 +1,3 @@ -public extension Api.auth { - enum LoggedOut: TypeConstructorDescription { - case loggedOut(flags: Int32, futureAuthToken: Buffer?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .loggedOut(let flags, let futureAuthToken): - if boxed { - buffer.appendInt32(-1012759713) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeBytes(futureAuthToken!, buffer: buffer, boxed: false)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .loggedOut(let flags, let futureAuthToken): - return ("loggedOut", [("flags", String(describing: flags)), ("futureAuthToken", String(describing: futureAuthToken))]) - } - } - - public static func parse_loggedOut(_ reader: BufferReader) -> LoggedOut? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Buffer? - if Int(_1!) & Int(1 << 0) != 0 {_2 = parseBytes(reader) } - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil - if _c1 && _c2 { - return Api.auth.LoggedOut.loggedOut(flags: _1!, futureAuthToken: _2) - } - else { - return nil - } - } - - } -} public extension Api.auth { enum LoginToken: TypeConstructorDescription { case loginToken(expires: Int32, token: Buffer) @@ -1304,3 +1264,61 @@ public extension Api.help { } } +public extension Api.help { + enum Country: TypeConstructorDescription { + case country(flags: Int32, iso2: String, defaultName: String, name: String?, countryCodes: [Api.help.CountryCode]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .country(let flags, let iso2, let defaultName, let name, let countryCodes): + if boxed { + buffer.appendInt32(-1014526429) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(iso2, buffer: buffer, boxed: false) + serializeString(defaultName, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(name!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(countryCodes.count)) + for item in countryCodes { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .country(let flags, let iso2, let defaultName, let name, let countryCodes): + return ("country", [("flags", String(describing: flags)), ("iso2", String(describing: iso2)), ("defaultName", String(describing: defaultName)), ("name", String(describing: name)), ("countryCodes", String(describing: countryCodes))]) + } + } + + public static func parse_country(_ reader: BufferReader) -> Country? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: [Api.help.CountryCode]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.help.CountryCode.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.help.Country.country(flags: _1!, iso2: _2!, defaultName: _3!, name: _4, countryCodes: _5!) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramApi/Sources/Api23.swift b/submodules/TelegramApi/Sources/Api23.swift index 70e96ff045..6781cecc18 100644 --- a/submodules/TelegramApi/Sources/Api23.swift +++ b/submodules/TelegramApi/Sources/Api23.swift @@ -1,61 +1,3 @@ -public extension Api.help { - enum Country: TypeConstructorDescription { - case country(flags: Int32, iso2: String, defaultName: String, name: String?, countryCodes: [Api.help.CountryCode]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .country(let flags, let iso2, let defaultName, let name, let countryCodes): - if boxed { - buffer.appendInt32(-1014526429) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(iso2, buffer: buffer, boxed: false) - serializeString(defaultName, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 1) != 0 {serializeString(name!, buffer: buffer, boxed: false)} - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(countryCodes.count)) - for item in countryCodes { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .country(let flags, let iso2, let defaultName, let name, let countryCodes): - return ("country", [("flags", String(describing: flags)), ("iso2", String(describing: iso2)), ("defaultName", String(describing: defaultName)), ("name", String(describing: name)), ("countryCodes", String(describing: countryCodes))]) - } - } - - public static func parse_country(_ reader: BufferReader) -> Country? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) - var _4: String? - if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } - var _5: [Api.help.CountryCode]? - if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.help.CountryCode.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil - let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.help.Country.country(flags: _1!, iso2: _2!, defaultName: _3!, name: _4, countryCodes: _5!) - } - else { - return nil - } - } - - } -} public extension Api.help { enum CountryCode: TypeConstructorDescription { case countryCode(flags: Int32, countryCode: String, prefixes: [String]?, patterns: [String]?) @@ -1350,3 +1292,39 @@ public extension Api.messages { } } +public extension Api.messages { + enum CheckedHistoryImportPeer: TypeConstructorDescription { + case checkedHistoryImportPeer(confirmText: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .checkedHistoryImportPeer(let confirmText): + if boxed { + buffer.appendInt32(-1571952873) + } + serializeString(confirmText, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .checkedHistoryImportPeer(let confirmText): + return ("checkedHistoryImportPeer", [("confirmText", String(describing: confirmText))]) + } + } + + public static func parse_checkedHistoryImportPeer(_ reader: BufferReader) -> CheckedHistoryImportPeer? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.messages.CheckedHistoryImportPeer.checkedHistoryImportPeer(confirmText: _1!) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramApi/Sources/Api24.swift b/submodules/TelegramApi/Sources/Api24.swift index b12751463a..fd0350a042 100644 --- a/submodules/TelegramApi/Sources/Api24.swift +++ b/submodules/TelegramApi/Sources/Api24.swift @@ -1,39 +1,3 @@ -public extension Api.messages { - enum CheckedHistoryImportPeer: TypeConstructorDescription { - case checkedHistoryImportPeer(confirmText: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .checkedHistoryImportPeer(let confirmText): - if boxed { - buffer.appendInt32(-1571952873) - } - serializeString(confirmText, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .checkedHistoryImportPeer(let confirmText): - return ("checkedHistoryImportPeer", [("confirmText", String(describing: confirmText))]) - } - } - - public static func parse_checkedHistoryImportPeer(_ reader: BufferReader) -> CheckedHistoryImportPeer? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.messages.CheckedHistoryImportPeer.checkedHistoryImportPeer(confirmText: _1!) - } - else { - return nil - } - } - - } -} public extension Api.messages { enum DhConfig: TypeConstructorDescription { case dhConfig(g: Int32, p: Buffer, version: Int32, random: Buffer) diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index d467ba00b0..76a317add6 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -5202,16 +5202,17 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func requestWebView(flags: Int32, peer: Api.InputPeer, bot: Api.InputUser, url: String?, themeParams: Api.DataJSON?, replyToMsgId: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func requestWebView(flags: Int32, peer: Api.InputPeer, bot: Api.InputUser, url: String?, startParam: String?, themeParams: Api.DataJSON?, replyToMsgId: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(572653208) + buffer.appendInt32(262163967) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) bot.serialize(buffer, true) if Int(flags) & Int(1 << 1) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {themeParams!.serialize(buffer, true)} if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} - return (FunctionDescription(name: "messages.requestWebView", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("bot", String(describing: bot)), ("url", String(describing: url)), ("themeParams", String(describing: themeParams)), ("replyToMsgId", String(describing: replyToMsgId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.WebViewResult? in + return (FunctionDescription(name: "messages.requestWebView", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("bot", String(describing: bot)), ("url", String(describing: url)), ("startParam", String(describing: startParam)), ("themeParams", String(describing: themeParams)), ("replyToMsgId", String(describing: replyToMsgId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.WebViewResult? in let reader = BufferReader(buffer) var result: Api.WebViewResult? if let signature = reader.readInt32() { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index 06ba62576d..a3416cd99e 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -83,8 +83,8 @@ public struct Namespaces { public static let cachedSendAsPeers: Int8 = 18 public static let availableReactions: Int8 = 19 public static let resolvedByPhonePeers: Int8 = 20 - public static let attachMenuBots: Int8 = 21 public static let notificationSoundList: Int8 = 22 + public static let attachMenuBots: Int8 = 23 } public struct UnorderedItemList { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift index 44d0ed905a..4de064d6b5 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift @@ -3,27 +3,75 @@ import TelegramApi import Postbox import SwiftSignalKit -//# inactive:flags.0?true bot_id:long attach_menu_name:string attach_menu_icon:Document = AttachMenuBot; + public final class AttachMenuBots: Equatable, Codable { public final class Bot: Equatable, Codable { private enum CodingKeys: String, CodingKey { case peerId case name - case icon + case botIcons + } + + public enum IconName: Int32, Codable { + case `default` = 0 + case iOSStatic + case iOSAnimated + case macOSAnimated + + init?(string: String) { + switch string { + case "default_static": + self = .default + case "ios_static": + self = .iOSStatic + case "ios_animated": + self = .iOSAnimated + case "macos_animated": + self = .macOSAnimated + default: + return nil + } + } + } + + private struct IconPair: Codable { + var name: IconName + var value: TelegramMediaFile + + init(_ name: IconName, value: TelegramMediaFile) { + self.name = name + self.value = value + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.name = IconName(rawValue: try container.decode(Int32.self, forKey: "k")) ?? .default + + let data = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "v") + self.value = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: data.data))) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.name.rawValue, forKey: "k") + try container.encode(PostboxEncoder().encodeObjectToRawData(self.value), forKey: "v") + } } public let peerId: PeerId public let name: String - public let icon: TelegramMediaFile + public let icons: [IconName: TelegramMediaFile] public init( peerId: PeerId, name: String, - icon: TelegramMediaFile + icons: [IconName: TelegramMediaFile] ) { self.peerId = peerId self.name = name - self.icon = icon + self.icons = icons } public static func ==(lhs: Bot, rhs: Bot) -> Bool { @@ -33,7 +81,7 @@ public final class AttachMenuBots: Equatable, Codable { if lhs.name != rhs.name { return false } - if lhs.icon != rhs.icon { + if lhs.icons != rhs.icons { return false } return true @@ -47,8 +95,12 @@ public final class AttachMenuBots: Equatable, Codable { self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" - let iconData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .icon) - self.icon = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: iconData.data))) + let iconPairs = try container.decodeIfPresent([IconPair].self, forKey: .botIcons) ?? [] + var icons: [IconName: TelegramMediaFile] = [:] + for iconPair in iconPairs { + icons[iconPair.name] = iconPair.value + } + self.icons = icons } public func encode(to encoder: Encoder) throws { @@ -56,7 +108,12 @@ public final class AttachMenuBots: Equatable, Codable { try container.encode(self.peerId.toInt64(), forKey: .peerId) try container.encode(self.name, forKey: .name) - try container.encode(PostboxEncoder().encodeObjectToRawData(self.icon), forKey: .icon) + + var iconPairs: [IconPair] = [] + for (key, value) in self.icons { + iconPairs.append(IconPair(key, value: value)) + } + try container.encode(iconPairs, forKey: .botIcons) } } @@ -135,7 +192,7 @@ func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network) -> Sig let poll = Signal { subscriber in let signal: Signal = cachedAttachMenuBots(postbox: postbox) |> mapToSignal { current in - return (network.request(Api.functions.messages.getAttachMenuBots(hash: current?.hash ?? 0)) + return (network.request(Api.functions.messages.getAttachMenuBots(hash: 0)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) @@ -159,9 +216,18 @@ func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network) -> Sig var resultBots: [AttachMenuBots.Bot] = [] for bot in bots { switch bot { - case let .attachMenuBot(_, botId, name, attachMenuIcon): - if let icon = telegramMediaFileFromApiDocument(attachMenuIcon) { - resultBots.append(AttachMenuBots.Bot(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), name: name, icon: icon)) + case let .attachMenuBot(_, botId, name, botIcons): + var icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] = [:] + for icon in botIcons { + switch icon { + case let .attachMenuBotIcon(_, name, icon, _): + if let iconName = AttachMenuBots.Bot.IconName(string: name), let icon = telegramMediaFileFromApiDocument(icon) { + icons[iconName] = icon + } + } + } + if !icons.isEmpty { + resultBots.append(AttachMenuBots.Bot(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), name: name, icons: icons)) } } } @@ -190,9 +256,9 @@ func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network) -> Sig |> restart } -func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, peerId: PeerId) -> Signal { +func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, botId: PeerId) -> Signal { return postbox.transaction { transaction -> Signal in - guard let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) else { + guard let peer = transaction.getPeer(botId), let inputUser = apiInputUser(peer) else { return .complete() } return network.request(Api.functions.messages.toggleBotInAttachMenu(bot: inputUser, enabled: .boolTrue)) @@ -215,9 +281,9 @@ func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, peerId: Pe |> switchToLatest } -func _internal_removeBotFromAttachMenu(postbox: Postbox, network: Network, peerId: PeerId) -> Signal { +func _internal_removeBotFromAttachMenu(postbox: Postbox, network: Network, botId: PeerId) -> Signal { return postbox.transaction { transaction -> Signal in - guard let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) else { + guard let peer = transaction.getPeer(botId), let inputUser = apiInputUser(peer) else { return .complete() } return network.request(Api.functions.messages.toggleBotInAttachMenu(bot: inputUser, enabled: .boolFalse)) @@ -242,11 +308,13 @@ func _internal_removeBotFromAttachMenu(postbox: Postbox, network: Network, peerI public struct AttachMenuBot { public let peer: Peer - public let icon: TelegramMediaFile + public let shortName: String + public let icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] - init(peer: Peer, icon: TelegramMediaFile) { + init(peer: Peer, shortName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile]) { self.peer = peer - self.icon = icon + self.shortName = shortName + self.icons = icons } } @@ -258,9 +326,67 @@ func _internal_attachMenuBots(postbox: Postbox) -> Signal<[AttachMenuBot], NoErr var resultBots: [AttachMenuBot] = [] for bot in cachedBots { if let peer = transaction.getPeer(bot.peerId) { - resultBots.append(AttachMenuBot(peer: peer, icon: bot.icon)) + resultBots.append(AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons)) } } return resultBots } } + +public enum GetAttachMenuBotError { + case generic +} + +public func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId: PeerId) -> Signal { + return postbox.transaction { transaction -> Signal in + guard let peer = transaction.getPeer(botId), let inputUser = apiInputUser(peer) else { + return .complete() + } + return network.request(Api.functions.messages.getAttachMenuBot(bot: inputUser)) + |> mapError { _ -> GetAttachMenuBotError in + return .generic + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Signal in + switch result { + case let .attachMenuBotsBot(bot, users): + var peers: [Peer] = [] + var peer: Peer? + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + + if telegramUser.id == botId { + peer = telegramUser + } + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + guard let peer = peer else { + return .fail(.generic) + } + + switch bot { + case let .attachMenuBot(_, _, name, botIcons): + var icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] = [:] + for icon in botIcons { + switch icon { + case let .attachMenuBotIcon(_, name, icon, _): + if let iconName = AttachMenuBots.Bot.IconName(string: name), let icon = telegramMediaFileFromApiDocument(icon) { + icons[iconName] = icon + } + } + } + return .single(AttachMenuBot(peer: peer, shortName: name, icons: icons)) + } + } + } + |> castError(GetAttachMenuBotError.self) + |> switchToLatest + } + } + |> castError(GetAttachMenuBotError.self) + |> switchToLatest +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift index 75b6809c1c..9ef08633e1 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/BotWebView.swift @@ -41,9 +41,10 @@ public enum KeepWebViewError { case generic } -public enum RequestWebViewResult { - case webViewResult(queryId: Int64, url: String, keepAliveSignal: Signal) - case requestConfirmation(botIcon: TelegramMediaFile) +public struct RequestWebViewResult { + public let queryId: Int64 + public let url: String + public let keepAliveSignal: Signal } public enum RequestWebViewError { @@ -92,7 +93,7 @@ private func keepWebViewSignal(network: Network, stateManager: AccountStateManag return signal } -func _internal_requestWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, botId: PeerId, url: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> Signal { +func _internal_requestWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, botId: PeerId, url: String?, payload: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> 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) @@ -115,33 +116,17 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager: flags |= (1 << 0) replyToMsgId = replyToMessageId.id } - return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputBot, url: url, themeParams: serializedThemeParams, replyToMsgId: replyToMsgId)) + if let _ = payload { + flags |= (1 << 3) + } + return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputBot, url: url, startParam: payload, themeParams: serializedThemeParams, replyToMsgId: replyToMsgId)) |> mapError { _ -> RequestWebViewError in return .generic } |> mapToSignal { result -> Signal in switch result { - case let .webViewResultConfirmationRequired(bot, users): - return postbox.transaction { transaction -> Signal in - var peers: [Peer] = [] - for user in users { - let telegramUser = TelegramUser(user: user) - peers.append(telegramUser) - } - updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in - return updated - }) - - if case let .attachMenuBot(_, _, _, attachMenuIcon) = bot, let icon = telegramMediaFileFromApiDocument(attachMenuIcon) { - return .single(.requestConfirmation(botIcon: icon)) - } else { - return .complete() - } - } - |> castError(RequestWebViewError.self) - |> switchToLatest case let .webViewResultUrl(queryId, url): - return .single(.webViewResult(queryId: queryId, url: url, keepAliveSignal: keepWebViewSignal(network: network, stateManager: stateManager, flags: flags, peer: inputPeer, bot: inputBot, queryId: queryId, replyToMessageId: replyToMessageId))) + return .single(RequestWebViewResult(queryId: queryId, url: url, keepAliveSignal: keepWebViewSignal(network: network, stateManager: stateManager, flags: flags, peer: inputPeer, bot: inputBot, queryId: queryId, replyToMessageId: replyToMessageId))) } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 182eaa1b3f..2b49d5386f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -322,8 +322,8 @@ public extension TelegramEngine { return _internal_translate(network: self.account.network, text: text, fromLang: fromLang, toLang: toLang) } - public func requestWebView(peerId: PeerId, botId: PeerId, url: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> Signal { - return _internal_requestWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, botId: botId, url: url, themeParams: themeParams, replyToMessageId: replyToMessageId) + public func requestWebView(peerId: PeerId, botId: PeerId, url: String?, payload: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> Signal { + 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, replyToMessageId: replyToMessageId) } public func requestSimpleWebView(botId: PeerId, url: String, themeParams: [String: Any]?) -> Signal { @@ -334,13 +334,17 @@ public extension TelegramEngine { public func sendWebViewData(botId: PeerId, buttonText: String, data: String) -> Signal { return _internal_sendWebViewData(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, botId: botId, buttonText: buttonText, data: data) } - - public func addBotToAttachMenu(peerId: PeerId) -> Signal { - return _internal_addBotToAttachMenu(postbox: self.account.postbox, network: self.account.network, peerId: peerId) + + public func addBotToAttachMenu(botId: PeerId) -> Signal { + return _internal_addBotToAttachMenu(postbox: self.account.postbox, network: self.account.network, botId: botId) } - public func removeBotFromAttachMenu(peerId: PeerId) -> Signal { - return _internal_removeBotFromAttachMenu(postbox: self.account.postbox, network: self.account.network, peerId: peerId) + public func removeBotFromAttachMenu(botId: PeerId) -> Signal { + return _internal_removeBotFromAttachMenu(postbox: self.account.postbox, network: self.account.network, botId: botId) + } + + public func getAttachMenuBot(botId: PeerId) -> Signal { + return _internal_getAttachMenuBot(postbox: self.account.postbox, network: self.account.network, botId: botId) } public func attachMenuBots() -> Signal<[AttachMenuBot], NoError> { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index f6f02a2b2e..96dfc876b1 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -219,7 +219,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G public let chatLocation: ChatLocation public let subject: ChatControllerSubject? private let botStart: ChatControllerInitialBotStart? - private var attachBotId: PeerId? + private var attachBotStart: ChatControllerInitialAttachBotStart? private let peerDisposable = MetaDisposable() private let titleDisposable = MetaDisposable() @@ -500,7 +500,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private var inviteRequestsContext: PeerInvitationImportersContext? private var inviteRequestsDisposable = MetaDisposable() - public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic = Atomic(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotId: PeerId? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = []) { + public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic = Atomic(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = []) { let _ = ChatControllerCount.modify { value in return value + 1 } @@ -510,7 +510,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatLocationContextHolder = chatLocationContextHolder self.subject = subject self.botStart = botStart - self.attachBotId = attachBotId + self.attachBotStart = attachBotStart self.peekData = peekData self.currentChatListFilter = chatListFilter self.chatNavigationStack = chatNavigationStack @@ -3372,7 +3372,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } })) } else { - strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: url, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), replyToMessageId: nil) + strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: url, payload: nil, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), replyToMessageId: nil) |> afterDisposed { updateProgress() }) @@ -3380,17 +3380,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } - switch result { - case let .webViewResult(queryId, url, keepAliveSignal): - let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: queryId, buttonText: buttonText, keepAliveSignal: keepAliveSignal, replyToMessageId: nil, iconFile: nil) - controller.getNavigationController = { [weak self] in - return self?.effectiveNavigationController - } - controller.navigationPresentation = .modal - strongSelf.push(controller) - case .requestConfirmation: - break + let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, replyToMessageId: nil, iconFile: nil) + controller.getNavigationController = { [weak self] in + return self?.effectiveNavigationController } + controller.navigationPresentation = .modal + strongSelf.push(controller) }, 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: { @@ -9146,9 +9141,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.historyNode.preloadPages = true } - if let attachBotId = self.attachBotId { - self.attachBotId = nil - self.presentAttachmentBot(botId: attachBotId) + if let attachBotStart = self.attachBotStart { + self.attachBotStart = nil + self.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload) } } @@ -10491,11 +10486,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } - public func presentAttachmentBot(botId: PeerId) { - self.presentAttachmentMenu(editMediaOptions: nil, editMediaReference: nil, botId: botId) + public func presentAttachmentBot(botId: PeerId, payload: String?) { + self.presentAttachmentMenu(editMediaOptions: nil, editMediaReference: nil, botId: botId, botPayload: payload) } - private func presentAttachmentMenu(editMediaOptions: MessageMediaEditingOptions?, editMediaReference: AnyMediaReference?, botId: PeerId? = nil) { + private func presentAttachmentMenu(editMediaOptions: MessageMediaEditingOptions?, editMediaReference: AnyMediaReference?, botId: PeerId? = nil, botPayload: String? = nil) { guard let peer = self.presentationInterfaceState.renderedPeer?.peer else { return } @@ -10550,12 +10545,23 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G initialButton = .gallery } for bot in attachMenuBots.reversed() { - let peerTitle = EnginePeer(bot.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let button: AttachmentButtonType = .app(bot.peer.id, peerTitle, bot.icon) - buttons.insert(button, at: 1) - - if initialButton == nil && bot.peer.id == botId { - initialButton = button + let iconFile: TelegramMediaFile? + if let file = bot.icons[.iOSAnimated] { + iconFile = file + } else if let file = bot.icons[.iOSStatic] { + iconFile = file + } else if let file = bot.icons[.default] { + iconFile = file + } else { + iconFile = nil + } + if let iconFile = iconFile { + let button: AttachmentButtonType = .app(bot.peer.id, bot.shortName, iconFile) + buttons.insert(button, at: 1) + + if initialButton == nil && bot.peer.id == botId { + initialButton = button + } } } return (buttons, initialButton) @@ -10572,30 +10578,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let initialButton = initialButton else { if let botId = botId { - let _ = (strongSelf.context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.Peer(id: botId) - ) - |> deliverOnMainQueue).start(next: { [weak self] peer in - guard let strongSelf = self, let peer = peer else { + let _ = (context.engine.messages.getAttachMenuBot(botId: botId) + |> deliverOnMainQueue).start(next: { bot in + let peer = EnginePeer(bot.peer) + guard let icon = bot.icons[.default] else { return } - let _ = (strongSelf.context.engine.messages.requestWebView(peerId: peer.id, botId: botId, url: nil, themeParams: nil, replyToMessageId: nil) - |> deliverOnMainQueue).start(next: { [weak self] result in - if let strongSelf = self, case let .requestConfirmation(botIcon) = result { - if case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.canBeAddedToAttachMenu) { - let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: botIcon, completion: { - let _ = context.engine.messages.addBotToAttachMenu(peerId: botId).start() - - Queue.mainQueue().after(1.0, { - strongSelf.presentAttachmentBot(botId: botId) - }) - }) - strongSelf.present(controller, in: .window(.root)) - } else { - strongSelf.present(textAlertController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - } - } + let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: icon, completion: { + let _ = context.engine.messages.addBotToAttachMenu(botId: botId).start() + + Queue.mainQueue().after(1.0, { + strongSelf.presentAttachmentBot(botId: botId, payload: botPayload) + }) }) + strongSelf.present(controller, in: .window(.root)) + }, error: { _ in + strongSelf.present(textAlertController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) } return @@ -13934,9 +13932,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } case let .withBotStartPayload(botStart): self.effectiveNavigationController?.pushViewController(ChatControllerImpl(context: self.context, chatLocation: .peer(id: peerId), botStart: botStart)) - case let .withAttachBot(botId): + case let .withAttachBot(attachBotStart): if let navigationController = self.effectiveNavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: peerId), attachBotId: botId)) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: peerId), attachBotStart: attachBotStart)) } } } @@ -14398,9 +14396,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else if let navigationController = strongSelf.effectiveNavigationController { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), botStart: startPayload)) } - case let .withAttachBot(botId): + case let .withAttachBot(attachBotStart): if let navigationController = strongSelf.effectiveNavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), attachBotId: botId)) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), attachBotStart: attachBotStart)) } default: break diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 098863dbb5..e04279eb49 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -938,7 +938,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }), .window(.root), nil) case .importStickers: break - case .setAttach: + case .startAttach: break } } diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index e1d6232dec..44b7d5466b 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -61,8 +61,8 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam return state.updatedBotStartPayload(botStart.payload) }) } - if let botId = params.attachBotId { - controller.presentAttachmentBot(botId: botId) + if let attachBotStart = params.attachBotStart { + controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload) } found = true break @@ -79,11 +79,11 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam return state.updatedBotStartPayload(botStart.payload) }) } - if let botId = params.attachBotId { - controller.presentAttachmentBot(botId: botId) + if let attachBotStart = params.attachBotStart { + controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload) } } else { - controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotId: params.attachBotId, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack) + controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack) } controller.purposefulAction = params.purposefulAction if let search = params.activateMessageSearch { diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 2cc3abb37d..16a01f94f8 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -547,7 +547,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur present(controller, nil) } } - case let .setAttach(peerId): + case let .startAttach(peerId, payload): let presentError: (String) -> Void = { errorText in present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } @@ -555,39 +555,29 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur |> deliverOnMainQueue).start(next: { attachMenuBots in if let _ = attachMenuBots.firstIndex(where: { $0.peer.id == peerId }) { if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotId: peerId, useExisting: true)) + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peerId, payload: payload), useExisting: true)) } else { presentError(presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError) } } else { - let _ = (context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.Peer(id: peerId) - ) - |> deliverOnMainQueue).start(next: { peer in - guard let peer = peer else { + let _ = (context.engine.messages.getAttachMenuBot(botId: peerId) + |> deliverOnMainQueue).start(next: { bot in + let peer = EnginePeer(bot.peer) + guard let icon = bot.icons[.default] else { return } - let _ = (context.engine.messages.requestWebView(peerId: peer.id, botId: peer.id, url: nil, themeParams: nil, replyToMessageId: nil) - |> deliverOnMainQueue).start(next: { result in - if case let .requestConfirmation(botIcon) = result { - if case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.canBeAddedToAttachMenu) { - let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: botIcon, completion: { - let _ = context.engine.messages.addBotToAttachMenu(peerId: peerId).start() - - Queue.mainQueue().after(1.0, { - if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotId: peer.id, useExisting: true)) - } - }) - }) - present(controller, nil) - } else { - presentError(presentationData.strings.Login_UnknownError) + let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: icon, completion: { + let _ = context.engine.messages.addBotToAttachMenu(botId: peerId).start() + + Queue.mainQueue().after(1.0, { + if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peer.id, payload: payload), useExisting: true)) } - } - }, error: { _ in - presentError(presentationData.strings.Login_UnknownError) + }) }) + present(controller, nil) + }, error: { _ in + presentError(presentationData.strings.Login_UnknownError) }) } }) diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index d2d2751ab3..7cdac5fc92 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -208,10 +208,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur if let navigationController = navigationController { context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peerId), botStart: payload)) } - case let .withAttachBot(botId): + case let .withAttachBot(attachBotStart): context.sharedContext.applicationBindings.dismissNativeController() if let navigationController = navigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peerId), attachBotId: botId)) + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peerId), attachBotStart: attachBotStart)) } default: break @@ -642,6 +642,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur voiceChat = value } else if queryItem.name == "attach" { attach = value + } else if queryItem.name == "startattach" { + startAttach = value } } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { voiceChat = "" @@ -675,8 +677,12 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur } } else if let attach = attach { result += "?attach=\(attach)" - } else if let _ = startAttach { - result += "?startattach" + } else if let startAttach = startAttach { + if !startAttach.isEmpty { + result += "?startattach=\(startAttach)" + } else { + result += "?startattach" + } } convertedUrl = result } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 08b236937c..095aead872 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -3307,8 +3307,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate })) case let .withBotStartPayload(startPayload): strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), botStart: startPayload)) - case let .withAttachBot(botId): - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), attachBotId: botId)) + case let .withAttachBot(attachBotStart): + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), attachBotStart: attachBotStart)) default: break } @@ -3385,9 +3385,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate if let navigationController = self.controller?.navigationController as? NavigationController { self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: peerId), botStart: startPayload)) } - case let .withAttachBot(botId): + case let .withAttachBot(attachBotStart): if let navigationController = self.controller?.navigationController as? NavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: peerId), attachBotId: botId)) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: peerId), attachBotStart: attachBotStart)) } } } diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index dfc2a83c33..f86957711a 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -66,7 +66,7 @@ extension ResolvedBotAdminRights { public enum ParsedInternalPeerUrlParameter { case botStart(String) case groupBotStart(String, ResolvedBotAdminRights?) - case attachBotStart(String) + case attachBotStart(String, String?) case channelMessage(Int32, Double?) case replyThread(Int32, Int32) case voiceChat(String?) @@ -87,7 +87,7 @@ public enum ParsedInternalUrl { case wallpaper(WallpaperUrlParameter) case theme(String) case phone(String) - case setAttach(String) + case startAttach(String, String?) } private enum ParsedUrl { @@ -185,7 +185,14 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { for queryItem in queryItems { if let value = queryItem.value { if queryItem.name == "attach" { - return .peerName(peerName, .attachBotStart(value)) + var startAttach: String? + for queryItem in queryItems { + if queryItem.name == "startattach", let value = queryItem.value { + startAttach = value + break + } + } + return .peerName(peerName, .attachBotStart(value, startAttach)) } else if queryItem.name == "start" { return .peerName(peerName, .botStart(value)) } else if queryItem.name == "startgroup" { @@ -201,11 +208,13 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { return nil } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { return .peerName(peerName, .voiceChat(value)) + } else if queryItem.name == "startattach" { + return .startAttach(peerName, value) } } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { return .peerName(peerName, .voiceChat(nil)) } else if queryItem.name == "startattach" { - return .setAttach(peerName) + return .startAttach(peerName, nil) } } } @@ -437,7 +446,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) return .single(.botStart(peerId: peer.id, payload: payload)) case let .groupBotStart(payload, adminRights): return .single(.groupBotStart(peerId: peer.id, payload: payload, adminRights: adminRights)) - case let .attachBotStart(name): + case let .attachBotStart(name, payload): return context.engine.peers.resolvePeerByName(name: name) |> take(1) |> mapToSignal { botPeer -> Signal in @@ -445,7 +454,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) } |> mapToSignal { botPeer -> Signal in if let botPeer = botPeer { - return .single(.peer(peer.id, .withAttachBot(botPeer.id))) + return .single(.peer(peer.id, .withAttachBot(ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload)))) } else { return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))) } @@ -542,7 +551,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) return .single(.wallpaper(parameter)) case let .theme(slug): return .single(.theme(slug)) - case let .setAttach(name): + case let .startAttach(name, payload): return context.engine.peers.resolvePeerByName(name: name) |> take(1) |> mapToSignal { peer -> Signal in @@ -550,7 +559,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) } |> mapToSignal { peer -> Signal in if let peer = peer { - return .single(.setAttach(peer.id)) + return .single(.startAttach(peerId: peer.id, payload: payload)) } else { return .single(.inaccessiblePeer) } diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index d1a7a758e8..3758199eca 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -248,30 +248,25 @@ public final class WebAppController: ViewController, AttachmentContainable { }) } } else { - let _ = (context.engine.messages.requestWebView(peerId: controller.peerId, botId: controller.botId, url: controller.url, themeParams: generateWebAppThemeParams(presentationData.theme), replyToMessageId: controller.replyToMessageId) + let _ = (context.engine.messages.requestWebView(peerId: controller.peerId, botId: controller.botId, url: controller.url, payload: nil, themeParams: generateWebAppThemeParams(presentationData.theme), replyToMessageId: controller.replyToMessageId) |> deliverOnMainQueue).start(next: { [weak self] result in guard let strongSelf = self else { return } - switch result { - case let .webViewResult(queryId, url, keepAliveSignal): - if let parsedUrl = URL(string: url) { - strongSelf.queryId = queryId - strongSelf.webView?.load(URLRequest(url: parsedUrl)) - - 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?.dismiss() - } - }) + if let parsedUrl = URL(string: result.url) { + 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() } - case .requestConfirmation: - break + }, completed: { [weak self] in + if let strongSelf = self { + strongSelf.controller?.dismiss() + } + }) } }) } @@ -628,7 +623,7 @@ public final class WebAppController: ViewController, AttachmentContainable { f(.default) if let strongSelf = self { - let _ = context.engine.messages.removeBotFromAttachMenu(peerId: strongSelf.botId).start() + let _ = context.engine.messages.removeBotFromAttachMenu(botId: strongSelf.botId).start() strongSelf.dismiss() } })))