Web app improvements

This commit is contained in:
Ilya Laktyushin 2022-03-31 16:14:02 +04:00
parent 61039505b7
commit 51613e0185
23 changed files with 687 additions and 490 deletions

View File

@ -258,7 +258,7 @@ public enum ResolvedUrl {
case settings(ResolvedUrlSettingsSection) case settings(ResolvedUrlSettingsSection)
case joinVoiceChat(PeerId, String?) case joinVoiceChat(PeerId, String?)
case importStickers case importStickers
case setAttach(PeerId) case startAttach(peerId: PeerId, payload: String?)
} }
public enum NavigateToChatKeepStack { public enum NavigateToChatKeepStack {
@ -346,7 +346,7 @@ public final class NavigateToChatControllerParams {
public let chatLocationContextHolder: Atomic<ChatLocationContextHolder?> public let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
public let subject: ChatControllerSubject? public let subject: ChatControllerSubject?
public let botStart: ChatControllerInitialBotStart? public let botStart: ChatControllerInitialBotStart?
public let attachBotId: PeerId? public let attachBotStart: ChatControllerInitialAttachBotStart?
public let updateTextInputState: ChatTextInputState? public let updateTextInputState: ChatTextInputState?
public let activateInput: Bool public let activateInput: Bool
public let keepStack: NavigateToChatKeepStack public let keepStack: NavigateToChatKeepStack
@ -365,7 +365,7 @@ public final class NavigateToChatControllerParams {
public let changeColors: Bool public let changeColors: Bool
public let completion: (ChatController) -> Void public let completion: (ChatController) -> Void
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(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<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(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.navigationController = navigationController
self.chatController = chatController self.chatController = chatController
self.chatLocationContextHolder = chatLocationContextHolder self.chatLocationContextHolder = chatLocationContextHolder
@ -373,7 +373,7 @@ public final class NavigateToChatControllerParams {
self.chatLocation = chatLocation self.chatLocation = chatLocation
self.subject = subject self.subject = subject
self.botStart = botStart self.botStart = botStart
self.attachBotId = attachBotId self.attachBotStart = attachBotStart
self.updateTextInputState = updateTextInputState self.updateTextInputState = updateTextInputState
self.activateInput = activateInput self.activateInput = activateInput
self.keepStack = keepStack self.keepStack = keepStack

View File

@ -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 { public enum ChatControllerInteractionNavigateToPeer {
case `default` case `default`
case chat(textInputState: ChatTextInputState?, subject: ChatControllerSubject?, peekData: ChatPeekTimeout?) case chat(textInputState: ChatTextInputState?, subject: ChatControllerSubject?, peekData: ChatPeekTimeout?)
case info case info
case withBotStartPayload(ChatControllerInitialBotStart) case withBotStartPayload(ChatControllerInitialBotStart)
case withAttachBot(PeerId) case withAttachBot(ChatControllerInitialAttachBotStart)
} }
public struct ChatInterfaceForwardOptionsState: Codable, Equatable { public struct ChatInterfaceForwardOptionsState: Codable, Equatable {

View File

@ -1248,9 +1248,9 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let navigationController = strongSelf.getNavigationController() { if let navigationController = strongSelf.getNavigationController() {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), botStart: botStart, keepStack: .always)) 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() { 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: case .info:
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId) let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId)

View File

@ -45,7 +45,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[571523412] = { return $0.readDouble() } dict[571523412] = { return $0.readDouble() }
dict[-1255641564] = { return parseString($0) } dict[-1255641564] = { return parseString($0) }
dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($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[1011024320] = { return Api.AttachMenuBots.parse_attachMenuBots($0) }
dict[-237467044] = { return Api.AttachMenuBots.parse_attachMenuBotsNotModified($0) } dict[-237467044] = { return Api.AttachMenuBots.parse_attachMenuBotsNotModified($0) }
dict[-1816172929] = { return Api.AttachMenuBotsBot.parse_attachMenuBotsBot($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[-981018084] = { return Api.WebPage.parse_webPagePending($0) }
dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) }
dict[211046684] = { return Api.WebViewMessageSent.parse_webViewMessageSent($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[202659196] = { return Api.WebViewResult.parse_webViewResultUrl($0) }
dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) }
dict[1275039392] = { return Api.account.Authorizations.parse_authorizations($0) } dict[1275039392] = { return Api.account.Authorizations.parse_authorizations($0) }
@ -1087,6 +1088,10 @@ public extension Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.AttachMenuBot: case let _1 as Api.AttachMenuBot:
_1.serialize(buffer, boxed) _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: case let _1 as Api.AttachMenuBots:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.AttachMenuBotsBot: case let _1 as Api.AttachMenuBotsBot:

View File

@ -36,26 +36,30 @@ public extension Api {
} }
public extension Api { public extension Api {
enum AttachMenuBot: TypeConstructorDescription { 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) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .attachMenuBot(let flags, let botId, let attachMenuName, let attachMenuIcon): case .attachMenuBot(let flags, let botId, let shortName, let icons):
if boxed { if boxed {
buffer.appendInt32(1340016040) buffer.appendInt32(-381896846)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(botId, buffer: buffer, boxed: false) serializeInt64(botId, buffer: buffer, boxed: false)
serializeString(attachMenuName, buffer: buffer, boxed: false) serializeString(shortName, buffer: buffer, boxed: false)
attachMenuIcon.serialize(buffer, true) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(icons.count))
for item in icons {
item.serialize(buffer, true)
}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .attachMenuBot(let flags, let botId, let attachMenuName, let attachMenuIcon): case .attachMenuBot(let flags, let botId, let shortName, let icons):
return ("attachMenuBot", [("flags", String(describing: flags)), ("botId", String(describing: botId)), ("attachMenuName", String(describing: attachMenuName)), ("attachMenuIcon", String(describing: attachMenuIcon))]) 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() _2 = reader.readInt64()
var _3: String? var _3: String?
_3 = parseString(reader) _3 = parseString(reader)
var _4: Api.Document? var _4: [Api.AttachMenuBotIcon]?
if let signature = reader.readInt32() { if let _ = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.Document _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AttachMenuBotIcon.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
let _c4 = _4 != nil let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 { 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 { else {
return nil 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
}
}
}
}

View File

@ -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 { public extension Api {
enum CdnConfig: TypeConstructorDescription { enum CdnConfig: TypeConstructorDescription {
case cdnConfig(publicKeys: [Api.CdnPublicKey]) case cdnConfig(publicKeys: [Api.CdnPublicKey])

View File

@ -94,22 +94,10 @@ public extension Api {
} }
public extension Api { public extension Api {
enum WebViewResult: TypeConstructorDescription { enum WebViewResult: TypeConstructorDescription {
case webViewResultConfirmationRequired(bot: Api.AttachMenuBot, users: [Api.User])
case webViewResultUrl(queryId: Int64, url: String) case webViewResultUrl(queryId: Int64, url: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { 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): case .webViewResultUrl(let queryId, let url):
if boxed { if boxed {
buffer.appendInt32(202659196) buffer.appendInt32(202659196)
@ -122,31 +110,11 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .webViewResultConfirmationRequired(let bot, let users):
return ("webViewResultConfirmationRequired", [("bot", String(describing: bot)), ("users", String(describing: users))])
case .webViewResultUrl(let queryId, let url): case .webViewResultUrl(let queryId, let url):
return ("webViewResultUrl", [("queryId", String(describing: queryId)), ("url", String(describing: 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? { public static func parse_webViewResultUrl(_ reader: BufferReader) -> WebViewResult? {
var _1: Int64? var _1: Int64?
_1 = reader.readInt64() _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
}
}
}
}

View File

@ -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 { public extension Api.auth {
enum LoginToken: TypeConstructorDescription { enum LoginToken: TypeConstructorDescription {
case loginToken(expires: Int32, token: Buffer) 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
}
}
}
}

View File

@ -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 { public extension Api.help {
enum CountryCode: TypeConstructorDescription { enum CountryCode: TypeConstructorDescription {
case countryCode(flags: Int32, countryCode: String, prefixes: [String]?, patterns: [String]?) 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
}
}
}
}

View File

@ -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 { public extension Api.messages {
enum DhConfig: TypeConstructorDescription { enum DhConfig: TypeConstructorDescription {
case dhConfig(g: Int32, p: Buffer, version: Int32, random: Buffer) case dhConfig(g: Int32, p: Buffer, version: Int32, random: Buffer)

View File

@ -5202,16 +5202,17 @@ public extension Api.functions.messages {
} }
} }
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<Api.WebViewResult>) { static func requestWebView(flags: Int32, peer: Api.InputPeer, bot: Api.InputUser, url: String?, startParam: String?, themeParams: Api.DataJSON?, replyToMsgId: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.WebViewResult>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(572653208) buffer.appendInt32(262163967)
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true) peer.serialize(buffer, true)
bot.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 << 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 << 2) != 0 {themeParams!.serialize(buffer, true)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} 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) let reader = BufferReader(buffer)
var result: Api.WebViewResult? var result: Api.WebViewResult?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {

View File

@ -83,8 +83,8 @@ public struct Namespaces {
public static let cachedSendAsPeers: Int8 = 18 public static let cachedSendAsPeers: Int8 = 18
public static let availableReactions: Int8 = 19 public static let availableReactions: Int8 = 19
public static let resolvedByPhonePeers: Int8 = 20 public static let resolvedByPhonePeers: Int8 = 20
public static let attachMenuBots: Int8 = 21
public static let notificationSoundList: Int8 = 22 public static let notificationSoundList: Int8 = 22
public static let attachMenuBots: Int8 = 23
} }
public struct UnorderedItemList { public struct UnorderedItemList {

View File

@ -3,27 +3,75 @@ import TelegramApi
import Postbox import Postbox
import SwiftSignalKit 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 AttachMenuBots: Equatable, Codable {
public final class Bot: Equatable, Codable { public final class Bot: Equatable, Codable {
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case peerId case peerId
case name 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 peerId: PeerId
public let name: String public let name: String
public let icon: TelegramMediaFile public let icons: [IconName: TelegramMediaFile]
public init( public init(
peerId: PeerId, peerId: PeerId,
name: String, name: String,
icon: TelegramMediaFile icons: [IconName: TelegramMediaFile]
) { ) {
self.peerId = peerId self.peerId = peerId
self.name = name self.name = name
self.icon = icon self.icons = icons
} }
public static func ==(lhs: Bot, rhs: Bot) -> Bool { public static func ==(lhs: Bot, rhs: Bot) -> Bool {
@ -33,7 +81,7 @@ public final class AttachMenuBots: Equatable, Codable {
if lhs.name != rhs.name { if lhs.name != rhs.name {
return false return false
} }
if lhs.icon != rhs.icon { if lhs.icons != rhs.icons {
return false return false
} }
return true return true
@ -47,8 +95,12 @@ public final class AttachMenuBots: Equatable, Codable {
self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
let iconData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .icon) let iconPairs = try container.decodeIfPresent([IconPair].self, forKey: .botIcons) ?? []
self.icon = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: iconData.data))) var icons: [IconName: TelegramMediaFile] = [:]
for iconPair in iconPairs {
icons[iconPair.name] = iconPair.value
}
self.icons = icons
} }
public func encode(to encoder: Encoder) throws { 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.peerId.toInt64(), forKey: .peerId)
try container.encode(self.name, forKey: .name) 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<Never, NoError> { subscriber in let poll = Signal<Never, NoError> { subscriber in
let signal: Signal<Never, NoError> = cachedAttachMenuBots(postbox: postbox) let signal: Signal<Never, NoError> = cachedAttachMenuBots(postbox: postbox)
|> mapToSignal { current in |> 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) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.AttachMenuBots?, NoError> in |> `catch` { _ -> Signal<Api.AttachMenuBots?, NoError> in
return .single(nil) return .single(nil)
@ -159,9 +216,18 @@ func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network) -> Sig
var resultBots: [AttachMenuBots.Bot] = [] var resultBots: [AttachMenuBots.Bot] = []
for bot in bots { for bot in bots {
switch bot { switch bot {
case let .attachMenuBot(_, botId, name, attachMenuIcon): case let .attachMenuBot(_, botId, name, botIcons):
if let icon = telegramMediaFileFromApiDocument(attachMenuIcon) { var icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] = [:]
resultBots.append(AttachMenuBots.Bot(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), name: name, icon: icon)) 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 |> restart
} }
func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, peerId: PeerId) -> Signal<Bool, NoError> { func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, botId: PeerId) -> Signal<Bool, NoError> {
return postbox.transaction { transaction -> Signal<Bool, NoError> in return postbox.transaction { transaction -> Signal<Bool, NoError> 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 .complete()
} }
return network.request(Api.functions.messages.toggleBotInAttachMenu(bot: inputUser, enabled: .boolTrue)) 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 |> switchToLatest
} }
func _internal_removeBotFromAttachMenu(postbox: Postbox, network: Network, peerId: PeerId) -> Signal<Bool, NoError> { func _internal_removeBotFromAttachMenu(postbox: Postbox, network: Network, botId: PeerId) -> Signal<Bool, NoError> {
return postbox.transaction { transaction -> Signal<Bool, NoError> in return postbox.transaction { transaction -> Signal<Bool, NoError> 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 .complete()
} }
return network.request(Api.functions.messages.toggleBotInAttachMenu(bot: inputUser, enabled: .boolFalse)) 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 struct AttachMenuBot {
public let peer: Peer 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.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] = [] var resultBots: [AttachMenuBot] = []
for bot in cachedBots { for bot in cachedBots {
if let peer = transaction.getPeer(bot.peerId) { 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 return resultBots
} }
} }
public enum GetAttachMenuBotError {
case generic
}
public func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId: PeerId) -> Signal<AttachMenuBot, GetAttachMenuBotError> {
return postbox.transaction { transaction -> Signal<AttachMenuBot, GetAttachMenuBotError> 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<AttachMenuBot, GetAttachMenuBotError> in
return postbox.transaction { transaction -> Signal<AttachMenuBot, GetAttachMenuBotError> 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
}

View File

@ -41,9 +41,10 @@ public enum KeepWebViewError {
case generic case generic
} }
public enum RequestWebViewResult { public struct RequestWebViewResult {
case webViewResult(queryId: Int64, url: String, keepAliveSignal: Signal<Never, KeepWebViewError>) public let queryId: Int64
case requestConfirmation(botIcon: TelegramMediaFile) public let url: String
public let keepAliveSignal: Signal<Never, KeepWebViewError>
} }
public enum RequestWebViewError { public enum RequestWebViewError {
@ -92,7 +93,7 @@ private func keepWebViewSignal(network: Network, stateManager: AccountStateManag
return signal return signal
} }
func _internal_requestWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, botId: PeerId, url: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> Signal<RequestWebViewResult, RequestWebViewError> { func _internal_requestWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, botId: PeerId, url: String?, payload: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> Signal<RequestWebViewResult, RequestWebViewError> {
var serializedThemeParams: Api.DataJSON? var serializedThemeParams: Api.DataJSON?
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) { if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
serializedThemeParams = .dataJSON(data: dataString) serializedThemeParams = .dataJSON(data: dataString)
@ -115,33 +116,17 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager:
flags |= (1 << 0) flags |= (1 << 0)
replyToMsgId = replyToMessageId.id 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 |> mapError { _ -> RequestWebViewError in
return .generic return .generic
} }
|> mapToSignal { result -> Signal<RequestWebViewResult, RequestWebViewError> in |> mapToSignal { result -> Signal<RequestWebViewResult, RequestWebViewError> in
switch result { switch result {
case let .webViewResultConfirmationRequired(bot, users):
return postbox.transaction { transaction -> Signal<RequestWebViewResult, RequestWebViewError> 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): 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)))
} }
} }
} }

View File

@ -322,8 +322,8 @@ public extension TelegramEngine {
return _internal_translate(network: self.account.network, text: text, fromLang: fromLang, toLang: toLang) 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<RequestWebViewResult, RequestWebViewError> { public func requestWebView(peerId: PeerId, botId: PeerId, url: String?, payload: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> Signal<RequestWebViewResult, RequestWebViewError> {
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) 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<String, RequestSimpleWebViewError> { public func requestSimpleWebView(botId: PeerId, url: String, themeParams: [String: Any]?) -> Signal<String, RequestSimpleWebViewError> {
@ -334,13 +334,17 @@ public extension TelegramEngine {
public func sendWebViewData(botId: PeerId, buttonText: String, data: String) -> Signal<Never, SendWebViewDataError> { public func sendWebViewData(botId: PeerId, buttonText: String, data: String) -> Signal<Never, SendWebViewDataError> {
return _internal_sendWebViewData(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, botId: botId, buttonText: buttonText, data: data) 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<Bool, NoError> { public func addBotToAttachMenu(botId: PeerId) -> Signal<Bool, NoError> {
return _internal_addBotToAttachMenu(postbox: self.account.postbox, network: self.account.network, peerId: peerId) return _internal_addBotToAttachMenu(postbox: self.account.postbox, network: self.account.network, botId: botId)
} }
public func removeBotFromAttachMenu(peerId: PeerId) -> Signal<Bool, NoError> { public func removeBotFromAttachMenu(botId: PeerId) -> Signal<Bool, NoError> {
return _internal_removeBotFromAttachMenu(postbox: self.account.postbox, network: self.account.network, peerId: peerId) return _internal_removeBotFromAttachMenu(postbox: self.account.postbox, network: self.account.network, botId: botId)
}
public func getAttachMenuBot(botId: PeerId) -> Signal<AttachMenuBot, GetAttachMenuBotError> {
return _internal_getAttachMenuBot(postbox: self.account.postbox, network: self.account.network, botId: botId)
} }
public func attachMenuBots() -> Signal<[AttachMenuBot], NoError> { public func attachMenuBots() -> Signal<[AttachMenuBot], NoError> {

View File

@ -219,7 +219,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
public let chatLocation: ChatLocation public let chatLocation: ChatLocation
public let subject: ChatControllerSubject? public let subject: ChatControllerSubject?
private let botStart: ChatControllerInitialBotStart? private let botStart: ChatControllerInitialBotStart?
private var attachBotId: PeerId? private var attachBotStart: ChatControllerInitialAttachBotStart?
private let peerDisposable = MetaDisposable() private let peerDisposable = MetaDisposable()
private let titleDisposable = MetaDisposable() private let titleDisposable = MetaDisposable()
@ -500,7 +500,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
private var inviteRequestsContext: PeerInvitationImportersContext? private var inviteRequestsContext: PeerInvitationImportersContext?
private var inviteRequestsDisposable = MetaDisposable() private var inviteRequestsDisposable = MetaDisposable()
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(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<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(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 let _ = ChatControllerCount.modify { value in
return value + 1 return value + 1
} }
@ -510,7 +510,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatLocationContextHolder = chatLocationContextHolder self.chatLocationContextHolder = chatLocationContextHolder
self.subject = subject self.subject = subject
self.botStart = botStart self.botStart = botStart
self.attachBotId = attachBotId self.attachBotStart = attachBotStart
self.peekData = peekData self.peekData = peekData
self.currentChatListFilter = chatListFilter self.currentChatListFilter = chatListFilter
self.chatNavigationStack = chatNavigationStack self.chatNavigationStack = chatNavigationStack
@ -3372,7 +3372,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
})) }))
} else { } 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 { |> afterDisposed {
updateProgress() updateProgress()
}) })
@ -3380,17 +3380,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
switch result { 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)
case let .webViewResult(queryId, url, keepAliveSignal): controller.getNavigationController = { [weak self] in
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) return self?.effectiveNavigationController
controller.getNavigationController = { [weak self] in
return self?.effectiveNavigationController
}
controller.navigationPresentation = .modal
strongSelf.push(controller)
case .requestConfirmation:
break
} }
controller.navigationPresentation = .modal
strongSelf.push(controller)
}, error: { [weak self] error in }, error: { [weak self] error in
if let strongSelf = self { 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: { 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 self.chatDisplayNode.historyNode.preloadPages = true
} }
if let attachBotId = self.attachBotId { if let attachBotStart = self.attachBotStart {
self.attachBotId = nil self.attachBotStart = nil
self.presentAttachmentBot(botId: attachBotId) self.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload)
} }
} }
@ -10491,11 +10486,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}) })
} }
public func presentAttachmentBot(botId: PeerId) { public func presentAttachmentBot(botId: PeerId, payload: String?) {
self.presentAttachmentMenu(editMediaOptions: nil, editMediaReference: nil, botId: botId) 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 { guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
return return
} }
@ -10550,12 +10545,23 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
initialButton = .gallery initialButton = .gallery
} }
for bot in attachMenuBots.reversed() { for bot in attachMenuBots.reversed() {
let peerTitle = EnginePeer(bot.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) let iconFile: TelegramMediaFile?
let button: AttachmentButtonType = .app(bot.peer.id, peerTitle, bot.icon) if let file = bot.icons[.iOSAnimated] {
buttons.insert(button, at: 1) iconFile = file
} else if let file = bot.icons[.iOSStatic] {
if initialButton == nil && bot.peer.id == botId { iconFile = file
initialButton = button } 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) return (buttons, initialButton)
@ -10572,30 +10578,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let initialButton = initialButton else { guard let initialButton = initialButton else {
if let botId = botId { if let botId = botId {
let _ = (strongSelf.context.engine.data.get( let _ = (context.engine.messages.getAttachMenuBot(botId: botId)
TelegramEngine.EngineData.Item.Peer.Peer(id: botId) |> deliverOnMainQueue).start(next: { bot in
) let peer = EnginePeer(bot.peer)
|> deliverOnMainQueue).start(next: { [weak self] peer in guard let icon = bot.icons[.default] else {
guard let strongSelf = self, let peer = peer else {
return return
} }
let _ = (strongSelf.context.engine.messages.requestWebView(peerId: peer.id, botId: botId, url: nil, themeParams: nil, replyToMessageId: nil) let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: icon, completion: {
|> deliverOnMainQueue).start(next: { [weak self] result in let _ = context.engine.messages.addBotToAttachMenu(botId: botId).start()
if let strongSelf = self, case let .requestConfirmation(botIcon) = result {
if case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.canBeAddedToAttachMenu) { Queue.mainQueue().after(1.0, {
let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: botIcon, completion: { strongSelf.presentAttachmentBot(botId: botId, payload: botPayload)
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))
}
}
}) })
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 return
@ -13934,9 +13932,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
case let .withBotStartPayload(botStart): case let .withBotStartPayload(botStart):
self.effectiveNavigationController?.pushViewController(ChatControllerImpl(context: self.context, chatLocation: .peer(id: peerId), botStart: 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 { 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 { } else if let navigationController = strongSelf.effectiveNavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), botStart: startPayload)) 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 { 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: default:
break break

View File

@ -938,7 +938,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}), .window(.root), nil) }), .window(.root), nil)
case .importStickers: case .importStickers:
break break
case .setAttach: case .startAttach:
break break
} }
} }

View File

@ -61,8 +61,8 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
return state.updatedBotStartPayload(botStart.payload) return state.updatedBotStartPayload(botStart.payload)
}) })
} }
if let botId = params.attachBotId { if let attachBotStart = params.attachBotStart {
controller.presentAttachmentBot(botId: botId) controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload)
} }
found = true found = true
break break
@ -79,11 +79,11 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
return state.updatedBotStartPayload(botStart.payload) return state.updatedBotStartPayload(botStart.payload)
}) })
} }
if let botId = params.attachBotId { if let attachBotStart = params.attachBotStart {
controller.presentAttachmentBot(botId: botId) controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload)
} }
} else { } 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 controller.purposefulAction = params.purposefulAction
if let search = params.activateMessageSearch { if let search = params.activateMessageSearch {

View File

@ -547,7 +547,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
present(controller, nil) present(controller, nil)
} }
} }
case let .setAttach(peerId): case let .startAttach(peerId, payload):
let presentError: (String) -> Void = { errorText in 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) 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 |> deliverOnMainQueue).start(next: { attachMenuBots in
if let _ = attachMenuBots.firstIndex(where: { $0.peer.id == peerId }) { if let _ = attachMenuBots.firstIndex(where: { $0.peer.id == peerId }) {
if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { 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 { } else {
presentError(presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError) presentError(presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError)
} }
} else { } else {
let _ = (context.engine.data.get( let _ = (context.engine.messages.getAttachMenuBot(botId: peerId)
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId) |> deliverOnMainQueue).start(next: { bot in
) let peer = EnginePeer(bot.peer)
|> deliverOnMainQueue).start(next: { peer in guard let icon = bot.icons[.default] else {
guard let peer = peer else {
return return
} }
let _ = (context.engine.messages.requestWebView(peerId: peer.id, botId: peer.id, url: nil, themeParams: nil, replyToMessageId: nil) let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: icon, completion: {
|> deliverOnMainQueue).start(next: { result in let _ = context.engine.messages.addBotToAttachMenu(botId: peerId).start()
if case let .requestConfirmation(botIcon) = result {
if case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.canBeAddedToAttachMenu) { Queue.mainQueue().after(1.0, {
let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: botIcon, completion: { if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext {
let _ = context.engine.messages.addBotToAttachMenu(peerId: peerId).start() let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peer.id, payload: payload), useExisting: true))
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)
} }
} })
}, error: { _ in
presentError(presentationData.strings.Login_UnknownError)
}) })
present(controller, nil)
}, error: { _ in
presentError(presentationData.strings.Login_UnknownError)
}) })
} }
}) })

View File

@ -208,10 +208,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
if let navigationController = navigationController { if let navigationController = navigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peerId), botStart: payload)) 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() context.sharedContext.applicationBindings.dismissNativeController()
if let navigationController = navigationController { 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: default:
break break
@ -642,6 +642,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
voiceChat = value voiceChat = value
} else if queryItem.name == "attach" { } else if queryItem.name == "attach" {
attach = value attach = value
} else if queryItem.name == "startattach" {
startAttach = value
} }
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
voiceChat = "" voiceChat = ""
@ -675,8 +677,12 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
} }
} else if let attach = attach { } else if let attach = attach {
result += "?attach=\(attach)" result += "?attach=\(attach)"
} else if let _ = startAttach { } else if let startAttach = startAttach {
result += "?startattach" if !startAttach.isEmpty {
result += "?startattach=\(startAttach)"
} else {
result += "?startattach"
}
} }
convertedUrl = result convertedUrl = result
} }

View File

@ -3307,8 +3307,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
})) }))
case let .withBotStartPayload(startPayload): case let .withBotStartPayload(startPayload):
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), botStart: startPayload)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peerId), botStart: startPayload))
case let .withAttachBot(botId): case let .withAttachBot(attachBotStart):
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: default:
break break
} }
@ -3385,9 +3385,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
if let navigationController = self.controller?.navigationController as? NavigationController { if let navigationController = self.controller?.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: peerId), botStart: startPayload)) 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 { 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))
} }
} }
} }

View File

@ -66,7 +66,7 @@ extension ResolvedBotAdminRights {
public enum ParsedInternalPeerUrlParameter { public enum ParsedInternalPeerUrlParameter {
case botStart(String) case botStart(String)
case groupBotStart(String, ResolvedBotAdminRights?) case groupBotStart(String, ResolvedBotAdminRights?)
case attachBotStart(String) case attachBotStart(String, String?)
case channelMessage(Int32, Double?) case channelMessage(Int32, Double?)
case replyThread(Int32, Int32) case replyThread(Int32, Int32)
case voiceChat(String?) case voiceChat(String?)
@ -87,7 +87,7 @@ public enum ParsedInternalUrl {
case wallpaper(WallpaperUrlParameter) case wallpaper(WallpaperUrlParameter)
case theme(String) case theme(String)
case phone(String) case phone(String)
case setAttach(String) case startAttach(String, String?)
} }
private enum ParsedUrl { private enum ParsedUrl {
@ -185,7 +185,14 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
for queryItem in queryItems { for queryItem in queryItems {
if let value = queryItem.value { if let value = queryItem.value {
if queryItem.name == "attach" { 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" { } else if queryItem.name == "start" {
return .peerName(peerName, .botStart(value)) return .peerName(peerName, .botStart(value))
} else if queryItem.name == "startgroup" { } else if queryItem.name == "startgroup" {
@ -201,11 +208,13 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
return nil return nil
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
return .peerName(peerName, .voiceChat(value)) return .peerName(peerName, .voiceChat(value))
} else if queryItem.name == "startattach" {
return .startAttach(peerName, value)
} }
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
return .peerName(peerName, .voiceChat(nil)) return .peerName(peerName, .voiceChat(nil))
} else if queryItem.name == "startattach" { } 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)) return .single(.botStart(peerId: peer.id, payload: payload))
case let .groupBotStart(payload, adminRights): case let .groupBotStart(payload, adminRights):
return .single(.groupBotStart(peerId: peer.id, payload: payload, adminRights: 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) return context.engine.peers.resolvePeerByName(name: name)
|> take(1) |> take(1)
|> mapToSignal { botPeer -> Signal<Peer?, NoError> in |> mapToSignal { botPeer -> Signal<Peer?, NoError> in
@ -445,7 +454,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
} }
|> mapToSignal { botPeer -> Signal<ResolvedUrl?, NoError> in |> mapToSignal { botPeer -> Signal<ResolvedUrl?, NoError> in
if let botPeer = botPeer { 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 { } else {
return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))) 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)) return .single(.wallpaper(parameter))
case let .theme(slug): case let .theme(slug):
return .single(.theme(slug)) return .single(.theme(slug))
case let .setAttach(name): case let .startAttach(name, payload):
return context.engine.peers.resolvePeerByName(name: name) return context.engine.peers.resolvePeerByName(name: name)
|> take(1) |> take(1)
|> mapToSignal { peer -> Signal<Peer?, NoError> in |> mapToSignal { peer -> Signal<Peer?, NoError> in
@ -550,7 +559,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
} }
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in |> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
if let peer = peer { if let peer = peer {
return .single(.setAttach(peer.id)) return .single(.startAttach(peerId: peer.id, payload: payload))
} else { } else {
return .single(.inaccessiblePeer) return .single(.inaccessiblePeer)
} }

View File

@ -248,30 +248,25 @@ public final class WebAppController: ViewController, AttachmentContainable {
}) })
} }
} else { } 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 |> deliverOnMainQueue).start(next: { [weak self] result in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
switch result { if let parsedUrl = URL(string: result.url) {
case let .webViewResult(queryId, url, keepAliveSignal): strongSelf.queryId = result.queryId
if let parsedUrl = URL(string: url) { strongSelf.webView?.load(URLRequest(url: parsedUrl))
strongSelf.queryId = queryId
strongSelf.webView?.load(URLRequest(url: parsedUrl)) strongSelf.keepAliveDisposable = (result.keepAliveSignal
|> deliverOnMainQueue).start(error: { [weak self] _ in
strongSelf.keepAliveDisposable = (keepAliveSignal if let strongSelf = self {
|> deliverOnMainQueue).start(error: { [weak self] _ in strongSelf.controller?.dismiss()
if let strongSelf = self {
strongSelf.controller?.dismiss()
}
}, completed: { [weak self] in
if let strongSelf = self {
strongSelf.controller?.dismiss()
}
})
} }
case .requestConfirmation: }, completed: { [weak self] in
break if let strongSelf = self {
strongSelf.controller?.dismiss()
}
})
} }
}) })
} }
@ -628,7 +623,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
f(.default) f(.default)
if let strongSelf = self { if let strongSelf = self {
let _ = context.engine.messages.removeBotFromAttachMenu(peerId: strongSelf.botId).start() let _ = context.engine.messages.removeBotFromAttachMenu(botId: strongSelf.botId).start()
strongSelf.dismiss() strongSelf.dismiss()
} }
}))) })))