Update API [skip ci]

This commit is contained in:
Ilya Laktyushin 2024-11-08 15:45:48 +01:00
parent 83a7019d0f
commit 85b6a8ffe9
40 changed files with 1686 additions and 841 deletions

View File

@ -278,6 +278,12 @@ public enum StickerPackUrlType {
case emoji
}
public enum ResolvedStartAppMode {
case generic
case compact
case fullscreen
}
public enum ResolvedUrl {
case externalUrl(String)
case urlAuth(String)
@ -1044,7 +1050,7 @@ public protocol SharedAccountContext: AnyObject {
func makeMiniAppListScreenInitialData(context: AccountContext) -> Signal<MiniAppListScreenInitialData, NoError>
func makeMiniAppListScreen(context: AccountContext, initialData: MiniAppListScreenInitialData) -> ViewController
func openWebApp(context: AccountContext, parentController: ViewController, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: EnginePeer, threadId: Int64?, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource, skipTermsOfService: Bool, payload: String?)
func openWebApp(context: AccountContext, parentController: ViewController, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, botPeer: EnginePeer, chatPeer: EnginePeer?, threadId: Int64?, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource, skipTermsOfService: Bool, payload: String?)
func makeDebugSettingsController(context: AccountContext?) -> ViewController?

View File

@ -301,13 +301,13 @@ public struct ChatControllerInitialBotAppStart {
public let botApp: BotApp?
public let payload: String?
public let justInstalled: Bool
public let compact: Bool
public let mode: ResolvedStartAppMode
public init(botApp: BotApp?, payload: String?, justInstalled: Bool, compact: Bool) {
public init(botApp: BotApp?, payload: String?, justInstalled: Bool, mode: ResolvedStartAppMode) {
self.botApp = botApp
self.payload = payload
self.justInstalled = justInstalled
self.compact = compact
self.mode = mode
}
}

View File

@ -1460,8 +1460,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
}
}
if result.isEmpty, let webViewUrl = self.webView.url {
let schemeAndHostUrl = webViewUrl.deletingPathExtension()
if result.isEmpty, let webViewUrl = self.webView.url, let schemeAndHostUrl = URL(string: "/", relativeTo: webViewUrl) {
let url = schemeAndHostUrl.appendingPathComponent("favicon.ico")
result.insert(Favicon(url: url.absoluteString, dimensions: nil))
}

View File

@ -3816,7 +3816,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
context: self.context,
parentController: parentController,
updatedPresentationData: nil,
peer: peer,
botPeer: peer,
chatPeer: nil,
threadId: nil,
buttonText: "",
url: "",
@ -3840,7 +3841,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
context: self.context,
parentController: parentController,
updatedPresentationData: nil,
peer: peer,
botPeer: peer,
chatPeer: nil,
threadId: nil,
buttonText: "",
url: "",

View File

@ -83,6 +83,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1262359766] = { return Api.Boost.parse_boost($0) }
dict[-1778593322] = { return Api.BotApp.parse_botApp($0) }
dict[1571189943] = { return Api.BotApp.parse_botAppNotModified($0) }
dict[-2103898979] = { return Api.BotAppSettings.parse_botAppSettings($0) }
dict[-1989921868] = { return Api.BotBusinessConnection.parse_botBusinessConnection($0) }
dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) }
dict[-1180016534] = { return Api.BotCommandScope.parse_botCommandScopeChatAdmins($0) }
@ -92,7 +93,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1071145937] = { return Api.BotCommandScope.parse_botCommandScopePeerAdmins($0) }
dict[169026035] = { return Api.BotCommandScope.parse_botCommandScopePeerUser($0) }
dict[1011811544] = { return Api.BotCommandScope.parse_botCommandScopeUsers($0) }
dict[-2109505932] = { return Api.BotInfo.parse_botInfo($0) }
dict[912290611] = { return Api.BotInfo.parse_botInfo($0) }
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) }
dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
@ -974,7 +975,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[675009298] = { return Api.Update.parse_updateBotPurchasedPaidMedia($0) }
dict[-1246823043] = { return Api.Update.parse_updateBotShippingQuery($0) }
dict[-997782967] = { return Api.Update.parse_updateBotStopped($0) }
dict[-1464975695] = { return Api.Update.parse_updateBotSubscriptionExpire($0) }
dict[756270830] = { return Api.Update.parse_updateBotSubscriptionExpire($0) }
dict[-2095595325] = { return Api.Update.parse_updateBotWebhookJSON($0) }
dict[-1684914010] = { return Api.Update.parse_updateBotWebhookJSONQuery($0) }
dict[-539401739] = { return Api.Update.parse_updateBroadcastRevenueTransactions($0) }
@ -1266,6 +1267,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1626924713] = { return Api.messages.AvailableReactions.parse_availableReactionsNotModified($0) }
dict[-347034123] = { return Api.messages.BotApp.parse_botApp($0) }
dict[911761060] = { return Api.messages.BotCallbackAnswer.parse_botCallbackAnswer($0) }
dict[-1899035375] = { return Api.messages.BotPreparedInlineMessage.parse_botPreparedInlineMessage($0) }
dict[-534646026] = { return Api.messages.BotResults.parse_botResults($0) }
dict[-1231326505] = { return Api.messages.ChatAdminsWithInvites.parse_chatAdminsWithInvites($0) }
dict[-438840932] = { return Api.messages.ChatFull.parse_chatFull($0) }
@ -1307,6 +1309,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-83926371] = { return Api.messages.MyStickers.parse_myStickers($0) }
dict[863093588] = { return Api.messages.PeerDialogs.parse_peerDialogs($0) }
dict[1753266509] = { return Api.messages.PeerSettings.parse_peerSettings($0) }
dict[1636301421] = { return Api.messages.PreparedInlineMessage.parse_preparedInlineMessage($0) }
dict[-963811691] = { return Api.messages.QuickReplies.parse_quickReplies($0) }
dict[1603398491] = { return Api.messages.QuickReplies.parse_quickRepliesNotModified($0) }
dict[-352454890] = { return Api.messages.Reactions.parse_reactions($0) }
@ -1511,6 +1514,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.BotApp:
_1.serialize(buffer, boxed)
case let _1 as Api.BotAppSettings:
_1.serialize(buffer, boxed)
case let _1 as Api.BotBusinessConnection:
_1.serialize(buffer, boxed)
case let _1 as Api.BotCommand:
@ -2297,6 +2302,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.messages.BotCallbackAnswer:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.BotPreparedInlineMessage:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.BotResults:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.ChatAdminsWithInvites:
@ -2355,6 +2362,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.messages.PeerSettings:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.PreparedInlineMessage:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.QuickReplies:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.Reactions:

View File

@ -1112,6 +1112,64 @@ public extension Api {
}
}
public extension Api {
enum BotAppSettings: TypeConstructorDescription {
case botAppSettings(flags: Int32, placeholderDocument: Api.Document?, backgroundColor: Int32?, backgroundDarkColor: Int32?, headerColor: Int32?, headerDarkColor: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botAppSettings(let flags, let placeholderDocument, let backgroundColor, let backgroundDarkColor, let headerColor, let headerDarkColor):
if boxed {
buffer.appendInt32(-2103898979)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {placeholderDocument!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(backgroundColor!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(backgroundDarkColor!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(headerColor!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(headerDarkColor!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botAppSettings(let flags, let placeholderDocument, let backgroundColor, let backgroundDarkColor, let headerColor, let headerDarkColor):
return ("botAppSettings", [("flags", flags as Any), ("placeholderDocument", placeholderDocument as Any), ("backgroundColor", backgroundColor as Any), ("backgroundDarkColor", backgroundDarkColor as Any), ("headerColor", headerColor as Any), ("headerDarkColor", headerDarkColor as Any)])
}
}
public static func parse_botAppSettings(_ reader: BufferReader) -> BotAppSettings? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Document?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Document
} }
var _3: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_3 = reader.readInt32() }
var _4: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() }
var _5: Int32?
if Int(_1!) & Int(1 << 3) != 0 {_5 = reader.readInt32() }
var _6: Int32?
if Int(_1!) & Int(1 << 4) != 0 {_6 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.BotAppSettings.botAppSettings(flags: _1!, placeholderDocument: _2, backgroundColor: _3, backgroundDarkColor: _4, headerColor: _5, headerDarkColor: _6)
}
else {
return nil
}
}
}
}
public extension Api {
enum BotBusinessConnection: TypeConstructorDescription {
case botBusinessConnection(flags: Int32, connectionId: String, userId: Int64, dcId: Int32, date: Int32)
@ -1164,43 +1222,3 @@ public extension Api {
}
}
public extension Api {
enum BotCommand: TypeConstructorDescription {
case botCommand(command: String, description: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botCommand(let command, let description):
if boxed {
buffer.appendInt32(-1032140601)
}
serializeString(command, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botCommand(let command, let description):
return ("botCommand", [("command", command as Any), ("description", description as Any)])
}
}
public static func parse_botCommand(_ reader: BufferReader) -> BotCommand? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.BotCommand.botCommand(command: _1!, description: _2!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,43 @@
public extension Api {
enum BotCommand: TypeConstructorDescription {
case botCommand(command: String, description: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botCommand(let command, let description):
if boxed {
buffer.appendInt32(-1032140601)
}
serializeString(command, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botCommand(let command, let description):
return ("botCommand", [("command", command as Any), ("description", description as Any)])
}
}
public static func parse_botCommand(_ reader: BufferReader) -> BotCommand? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.BotCommand.botCommand(command: _1!, description: _2!)
}
else {
return nil
}
}
}
}
public extension Api {
indirect enum BotCommandScope: TypeConstructorDescription {
case botCommandScopeChatAdmins
@ -136,13 +176,13 @@ public extension Api {
}
public extension Api {
enum BotInfo: TypeConstructorDescription {
case botInfo(flags: Int32, userId: Int64?, description: String?, descriptionPhoto: Api.Photo?, descriptionDocument: Api.Document?, commands: [Api.BotCommand]?, menuButton: Api.BotMenuButton?, privacyPolicyUrl: String?)
case botInfo(flags: Int32, userId: Int64?, description: String?, descriptionPhoto: Api.Photo?, descriptionDocument: Api.Document?, commands: [Api.BotCommand]?, menuButton: Api.BotMenuButton?, privacyPolicyUrl: String?, appSettings: Api.BotAppSettings?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton, let privacyPolicyUrl):
case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton, let privacyPolicyUrl, let appSettings):
if boxed {
buffer.appendInt32(-2109505932)
buffer.appendInt32(912290611)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(userId!, buffer: buffer, boxed: false)}
@ -156,14 +196,15 @@ public extension Api {
}}
if Int(flags) & Int(1 << 3) != 0 {menuButton!.serialize(buffer, true)}
if Int(flags) & Int(1 << 7) != 0 {serializeString(privacyPolicyUrl!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 8) != 0 {appSettings!.serialize(buffer, true)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton, let privacyPolicyUrl):
return ("botInfo", [("flags", flags as Any), ("userId", userId as Any), ("description", description as Any), ("descriptionPhoto", descriptionPhoto as Any), ("descriptionDocument", descriptionDocument as Any), ("commands", commands as Any), ("menuButton", menuButton as Any), ("privacyPolicyUrl", privacyPolicyUrl as Any)])
case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton, let privacyPolicyUrl, let appSettings):
return ("botInfo", [("flags", flags as Any), ("userId", userId as Any), ("description", description as Any), ("descriptionPhoto", descriptionPhoto as Any), ("descriptionDocument", descriptionDocument as Any), ("commands", commands as Any), ("menuButton", menuButton as Any), ("privacyPolicyUrl", privacyPolicyUrl as Any), ("appSettings", appSettings as Any)])
}
}
@ -192,6 +233,10 @@ public extension Api {
} }
var _8: String?
if Int(_1!) & Int(1 << 7) != 0 {_8 = parseString(reader) }
var _9: Api.BotAppSettings?
if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
_9 = Api.parse(reader, signature: signature) as? Api.BotAppSettings
} }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
@ -200,8 +245,9 @@ public extension Api {
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 7) == 0) || _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.BotInfo.botInfo(flags: _1!, userId: _2, description: _3, descriptionPhoto: _4, descriptionDocument: _5, commands: _6, menuButton: _7, privacyPolicyUrl: _8)
let _c9 = (Int(_1!) & Int(1 << 8) == 0) || _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.BotInfo.botInfo(flags: _1!, userId: _2, description: _3, descriptionPhoto: _4, descriptionDocument: _5, commands: _6, menuButton: _7, privacyPolicyUrl: _8, appSettings: _9)
}
else {
return nil
@ -1164,49 +1210,3 @@ public extension Api {
}
}
public extension Api {
enum BusinessGreetingMessage: TypeConstructorDescription {
case businessGreetingMessage(shortcutId: Int32, recipients: Api.BusinessRecipients, noActivityDays: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
if boxed {
buffer.appendInt32(-451302485)
}
serializeInt32(shortcutId, buffer: buffer, boxed: false)
recipients.serialize(buffer, true)
serializeInt32(noActivityDays, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
return ("businessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)])
}
}
public static func parse_businessGreetingMessage(_ reader: BufferReader) -> BusinessGreetingMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.BusinessRecipients?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.BusinessRecipients
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.BusinessGreetingMessage.businessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!)
}
else {
return nil
}
}
}
}

View File

@ -645,7 +645,7 @@ public extension Api {
case updateBotPurchasedPaidMedia(userId: Int64, payload: String, qts: Int32)
case updateBotShippingQuery(queryId: Int64, userId: Int64, payload: Buffer, shippingAddress: Api.PostAddress)
case updateBotStopped(userId: Int64, date: Int32, stopped: Api.Bool, qts: Int32)
case updateBotSubscriptionExpire(userId: Int64, payload: String, untilDate: Int32, qts: Int32)
case updateBotSubscriptionExpire(userId: Int64, payload: String, invoiceSlug: String, untilDate: Int32, qts: Int32)
case updateBotWebhookJSON(data: Api.DataJSON)
case updateBotWebhookJSONQuery(queryId: Int64, data: Api.DataJSON, timeout: Int32)
case updateBroadcastRevenueTransactions(peer: Api.Peer, balances: Api.BroadcastRevenueBalances)
@ -970,12 +970,13 @@ public extension Api {
stopped.serialize(buffer, true)
serializeInt32(qts, buffer: buffer, boxed: false)
break
case .updateBotSubscriptionExpire(let userId, let payload, let untilDate, let qts):
case .updateBotSubscriptionExpire(let userId, let payload, let invoiceSlug, let untilDate, let qts):
if boxed {
buffer.appendInt32(-1464975695)
buffer.appendInt32(756270830)
}
serializeInt64(userId, buffer: buffer, boxed: false)
serializeString(payload, buffer: buffer, boxed: false)
serializeString(invoiceSlug, buffer: buffer, boxed: false)
serializeInt32(untilDate, buffer: buffer, boxed: false)
serializeInt32(qts, buffer: buffer, boxed: false)
break
@ -2051,8 +2052,8 @@ public extension Api {
return ("updateBotShippingQuery", [("queryId", queryId as Any), ("userId", userId as Any), ("payload", payload as Any), ("shippingAddress", shippingAddress as Any)])
case .updateBotStopped(let userId, let date, let stopped, let qts):
return ("updateBotStopped", [("userId", userId as Any), ("date", date as Any), ("stopped", stopped as Any), ("qts", qts as Any)])
case .updateBotSubscriptionExpire(let userId, let payload, let untilDate, let qts):
return ("updateBotSubscriptionExpire", [("userId", userId as Any), ("payload", payload as Any), ("untilDate", untilDate as Any), ("qts", qts as Any)])
case .updateBotSubscriptionExpire(let userId, let payload, let invoiceSlug, let untilDate, let qts):
return ("updateBotSubscriptionExpire", [("userId", userId as Any), ("payload", payload as Any), ("invoiceSlug", invoiceSlug as Any), ("untilDate", untilDate as Any), ("qts", qts as Any)])
case .updateBotWebhookJSON(let data):
return ("updateBotWebhookJSON", [("data", data as Any)])
case .updateBotWebhookJSONQuery(let queryId, let data, let timeout):
@ -2749,16 +2750,19 @@ public extension Api {
_1 = reader.readInt64()
var _2: String?
_2 = parseString(reader)
var _3: Int32?
_3 = reader.readInt32()
var _3: String?
_3 = parseString(reader)
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.Update.updateBotSubscriptionExpire(userId: _1!, payload: _2!, untilDate: _3!, qts: _4!)
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.Update.updateBotSubscriptionExpire(userId: _1!, payload: _2!, invoiceSlug: _3!, untilDate: _4!, qts: _5!)
}
else {
return nil

View File

@ -1,3 +1,49 @@
public extension Api {
enum BusinessGreetingMessage: TypeConstructorDescription {
case businessGreetingMessage(shortcutId: Int32, recipients: Api.BusinessRecipients, noActivityDays: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
if boxed {
buffer.appendInt32(-451302485)
}
serializeInt32(shortcutId, buffer: buffer, boxed: false)
recipients.serialize(buffer, true)
serializeInt32(noActivityDays, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
return ("businessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)])
}
}
public static func parse_businessGreetingMessage(_ reader: BufferReader) -> BusinessGreetingMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.BusinessRecipients?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.BusinessRecipients
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.BusinessGreetingMessage.businessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum BusinessIntro: TypeConstructorDescription {
case businessIntro(flags: Int32, title: String, description: String, sticker: Api.Document?)

View File

@ -260,6 +260,46 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum BotPreparedInlineMessage: TypeConstructorDescription {
case botPreparedInlineMessage(id: String, expireDate: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botPreparedInlineMessage(let id, let expireDate):
if boxed {
buffer.appendInt32(-1899035375)
}
serializeString(id, buffer: buffer, boxed: false)
serializeInt32(expireDate, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botPreparedInlineMessage(let id, let expireDate):
return ("botPreparedInlineMessage", [("id", id as Any), ("expireDate", expireDate as Any)])
}
}
public static func parse_botPreparedInlineMessage(_ reader: BufferReader) -> BotPreparedInlineMessage? {
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.messages.BotPreparedInlineMessage.botPreparedInlineMessage(id: _1!, expireDate: _2!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum BotResults: TypeConstructorDescription {
case botResults(flags: Int32, queryId: Int64, nextOffset: String?, switchPm: Api.InlineBotSwitchPM?, switchWebview: Api.InlineBotWebView?, results: [Api.BotInlineResult], cacheTime: Int32, users: [Api.User])
@ -1398,61 +1438,3 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum FoundStickerSets: TypeConstructorDescription {
case foundStickerSets(hash: Int64, sets: [Api.StickerSetCovered])
case foundStickerSetsNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .foundStickerSets(let hash, let sets):
if boxed {
buffer.appendInt32(-1963942446)
}
serializeInt64(hash, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(sets.count))
for item in sets {
item.serialize(buffer, true)
}
break
case .foundStickerSetsNotModified:
if boxed {
buffer.appendInt32(223655517)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .foundStickerSets(let hash, let sets):
return ("foundStickerSets", [("hash", hash as Any), ("sets", sets as Any)])
case .foundStickerSetsNotModified:
return ("foundStickerSetsNotModified", [])
}
}
public static func parse_foundStickerSets(_ reader: BufferReader) -> FoundStickerSets? {
var _1: Int64?
_1 = reader.readInt64()
var _2: [Api.StickerSetCovered]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.FoundStickerSets.foundStickerSets(hash: _1!, sets: _2!)
}
else {
return nil
}
}
public static func parse_foundStickerSetsNotModified(_ reader: BufferReader) -> FoundStickerSets? {
return Api.messages.FoundStickerSets.foundStickerSetsNotModified
}
}
}

View File

@ -1,3 +1,61 @@
public extension Api.messages {
enum FoundStickerSets: TypeConstructorDescription {
case foundStickerSets(hash: Int64, sets: [Api.StickerSetCovered])
case foundStickerSetsNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .foundStickerSets(let hash, let sets):
if boxed {
buffer.appendInt32(-1963942446)
}
serializeInt64(hash, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(sets.count))
for item in sets {
item.serialize(buffer, true)
}
break
case .foundStickerSetsNotModified:
if boxed {
buffer.appendInt32(223655517)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .foundStickerSets(let hash, let sets):
return ("foundStickerSets", [("hash", hash as Any), ("sets", sets as Any)])
case .foundStickerSetsNotModified:
return ("foundStickerSetsNotModified", [])
}
}
public static func parse_foundStickerSets(_ reader: BufferReader) -> FoundStickerSets? {
var _1: Int64?
_1 = reader.readInt64()
var _2: [Api.StickerSetCovered]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.FoundStickerSets.foundStickerSets(hash: _1!, sets: _2!)
}
else {
return nil
}
}
public static func parse_foundStickerSetsNotModified(_ reader: BufferReader) -> FoundStickerSets? {
return Api.messages.FoundStickerSets.foundStickerSetsNotModified
}
}
}
public extension Api.messages {
enum HighScores: TypeConstructorDescription {
case highScores(scores: [Api.HighScore], users: [Api.User])
@ -806,6 +864,68 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum PreparedInlineMessage: TypeConstructorDescription {
case preparedInlineMessage(queryId: Int64, result: Api.BotInlineResult, peerTypes: [Api.InlineQueryPeerType], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .preparedInlineMessage(let queryId, let result, let peerTypes, let users):
if boxed {
buffer.appendInt32(1636301421)
}
serializeInt64(queryId, buffer: buffer, boxed: false)
result.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(peerTypes.count))
for item in peerTypes {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .preparedInlineMessage(let queryId, let result, let peerTypes, let users):
return ("preparedInlineMessage", [("queryId", queryId as Any), ("result", result as Any), ("peerTypes", peerTypes as Any), ("users", users as Any)])
}
}
public static func parse_preparedInlineMessage(_ reader: BufferReader) -> PreparedInlineMessage? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Api.BotInlineResult?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.BotInlineResult
}
var _3: [Api.InlineQueryPeerType]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InlineQueryPeerType.self)
}
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.messages.PreparedInlineMessage.preparedInlineMessage(queryId: _1!, result: _2!, peerTypes: _3!, users: _4!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum QuickReplies: TypeConstructorDescription {
case quickReplies(quickReplies: [Api.QuickReply], messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
@ -1340,203 +1460,3 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum SearchResultsCalendar: TypeConstructorDescription {
case searchResultsCalendar(flags: Int32, count: Int32, minDate: Int32, minMsgId: Int32, offsetIdOffset: Int32?, periods: [Api.SearchResultsCalendarPeriod], messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users):
if boxed {
buffer.appendInt32(343859772)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
serializeInt32(minDate, buffer: buffer, boxed: false)
serializeInt32(minMsgId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(periods.count))
for item in periods {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users):
return ("searchResultsCalendar", [("flags", flags as Any), ("count", count as Any), ("minDate", minDate as Any), ("minMsgId", minMsgId as Any), ("offsetIdOffset", offsetIdOffset as Any), ("periods", periods as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_searchResultsCalendar(_ reader: BufferReader) -> SearchResultsCalendar? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() }
var _6: [Api.SearchResultsCalendarPeriod]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsCalendarPeriod.self)
}
var _7: [Api.Message]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _8: [Api.Chat]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _9: [Api.User]?
if let _ = reader.readInt32() {
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.messages.SearchResultsCalendar.searchResultsCalendar(flags: _1!, count: _2!, minDate: _3!, minMsgId: _4!, offsetIdOffset: _5, periods: _6!, messages: _7!, chats: _8!, users: _9!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum SearchResultsPositions: TypeConstructorDescription {
case searchResultsPositions(count: Int32, positions: [Api.SearchResultsPosition])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultsPositions(let count, let positions):
if boxed {
buffer.appendInt32(1404185519)
}
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(positions.count))
for item in positions {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultsPositions(let count, let positions):
return ("searchResultsPositions", [("count", count as Any), ("positions", positions as Any)])
}
}
public static func parse_searchResultsPositions(_ reader: BufferReader) -> SearchResultsPositions? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.SearchResultsPosition]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsPosition.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.SearchResultsPositions.searchResultsPositions(count: _1!, positions: _2!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum SentEncryptedMessage: TypeConstructorDescription {
case sentEncryptedFile(date: Int32, file: Api.EncryptedFile)
case sentEncryptedMessage(date: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .sentEncryptedFile(let date, let file):
if boxed {
buffer.appendInt32(-1802240206)
}
serializeInt32(date, buffer: buffer, boxed: false)
file.serialize(buffer, true)
break
case .sentEncryptedMessage(let date):
if boxed {
buffer.appendInt32(1443858741)
}
serializeInt32(date, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .sentEncryptedFile(let date, let file):
return ("sentEncryptedFile", [("date", date as Any), ("file", file as Any)])
case .sentEncryptedMessage(let date):
return ("sentEncryptedMessage", [("date", date as Any)])
}
}
public static func parse_sentEncryptedFile(_ reader: BufferReader) -> SentEncryptedMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.EncryptedFile?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.EncryptedFile
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.SentEncryptedMessage.sentEncryptedFile(date: _1!, file: _2!)
}
else {
return nil
}
}
public static func parse_sentEncryptedMessage(_ reader: BufferReader) -> SentEncryptedMessage? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.messages.SentEncryptedMessage.sentEncryptedMessage(date: _1!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,203 @@
public extension Api.messages {
enum SearchResultsCalendar: TypeConstructorDescription {
case searchResultsCalendar(flags: Int32, count: Int32, minDate: Int32, minMsgId: Int32, offsetIdOffset: Int32?, periods: [Api.SearchResultsCalendarPeriod], messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users):
if boxed {
buffer.appendInt32(343859772)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
serializeInt32(minDate, buffer: buffer, boxed: false)
serializeInt32(minMsgId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(periods.count))
for item in periods {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users):
return ("searchResultsCalendar", [("flags", flags as Any), ("count", count as Any), ("minDate", minDate as Any), ("minMsgId", minMsgId as Any), ("offsetIdOffset", offsetIdOffset as Any), ("periods", periods as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_searchResultsCalendar(_ reader: BufferReader) -> SearchResultsCalendar? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() }
var _6: [Api.SearchResultsCalendarPeriod]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsCalendarPeriod.self)
}
var _7: [Api.Message]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _8: [Api.Chat]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _9: [Api.User]?
if let _ = reader.readInt32() {
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.messages.SearchResultsCalendar.searchResultsCalendar(flags: _1!, count: _2!, minDate: _3!, minMsgId: _4!, offsetIdOffset: _5, periods: _6!, messages: _7!, chats: _8!, users: _9!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum SearchResultsPositions: TypeConstructorDescription {
case searchResultsPositions(count: Int32, positions: [Api.SearchResultsPosition])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultsPositions(let count, let positions):
if boxed {
buffer.appendInt32(1404185519)
}
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(positions.count))
for item in positions {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultsPositions(let count, let positions):
return ("searchResultsPositions", [("count", count as Any), ("positions", positions as Any)])
}
}
public static func parse_searchResultsPositions(_ reader: BufferReader) -> SearchResultsPositions? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.SearchResultsPosition]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsPosition.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.SearchResultsPositions.searchResultsPositions(count: _1!, positions: _2!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum SentEncryptedMessage: TypeConstructorDescription {
case sentEncryptedFile(date: Int32, file: Api.EncryptedFile)
case sentEncryptedMessage(date: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .sentEncryptedFile(let date, let file):
if boxed {
buffer.appendInt32(-1802240206)
}
serializeInt32(date, buffer: buffer, boxed: false)
file.serialize(buffer, true)
break
case .sentEncryptedMessage(let date):
if boxed {
buffer.appendInt32(1443858741)
}
serializeInt32(date, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .sentEncryptedFile(let date, let file):
return ("sentEncryptedFile", [("date", date as Any), ("file", file as Any)])
case .sentEncryptedMessage(let date):
return ("sentEncryptedMessage", [("date", date as Any)])
}
}
public static func parse_sentEncryptedFile(_ reader: BufferReader) -> SentEncryptedMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.EncryptedFile?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.EncryptedFile
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.SentEncryptedMessage.sentEncryptedFile(date: _1!, file: _2!)
}
else {
return nil
}
}
public static func parse_sentEncryptedMessage(_ reader: BufferReader) -> SentEncryptedMessage? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.messages.SentEncryptedMessage.sentEncryptedMessage(date: _1!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum SponsoredMessages: TypeConstructorDescription {
case sponsoredMessages(flags: Int32, postsBetween: Int32?, messages: [Api.SponsoredMessage], chats: [Api.Chat], users: [Api.User])
@ -1330,243 +1530,3 @@ public extension Api.payments {
}
}
public extension Api.payments {
enum StarsRevenueStats: TypeConstructorDescription {
case starsRevenueStats(revenueGraph: Api.StatsGraph, status: Api.StarsRevenueStatus, usdRate: Double)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsRevenueStats(let revenueGraph, let status, let usdRate):
if boxed {
buffer.appendInt32(-919881925)
}
revenueGraph.serialize(buffer, true)
status.serialize(buffer, true)
serializeDouble(usdRate, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsRevenueStats(let revenueGraph, let status, let usdRate):
return ("starsRevenueStats", [("revenueGraph", revenueGraph as Any), ("status", status as Any), ("usdRate", usdRate as Any)])
}
}
public static func parse_starsRevenueStats(_ reader: BufferReader) -> StarsRevenueStats? {
var _1: Api.StatsGraph?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _2: Api.StarsRevenueStatus?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StarsRevenueStatus
}
var _3: Double?
_3 = reader.readDouble()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.payments.StarsRevenueStats.starsRevenueStats(revenueGraph: _1!, status: _2!, usdRate: _3!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum StarsRevenueWithdrawalUrl: TypeConstructorDescription {
case starsRevenueWithdrawalUrl(url: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsRevenueWithdrawalUrl(let url):
if boxed {
buffer.appendInt32(497778871)
}
serializeString(url, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsRevenueWithdrawalUrl(let url):
return ("starsRevenueWithdrawalUrl", [("url", url as Any)])
}
}
public static func parse_starsRevenueWithdrawalUrl(_ reader: BufferReader) -> StarsRevenueWithdrawalUrl? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.payments.StarsRevenueWithdrawalUrl.starsRevenueWithdrawalUrl(url: _1!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum StarsStatus: TypeConstructorDescription {
case starsStatus(flags: Int32, balance: Int64, subscriptions: [Api.StarsSubscription]?, subscriptionsNextOffset: String?, subscriptionsMissingBalance: Int64?, history: [Api.StarsTransaction]?, nextOffset: String?, chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsStatus(let flags, let balance, let subscriptions, let subscriptionsNextOffset, let subscriptionsMissingBalance, let history, let nextOffset, let chats, let users):
if boxed {
buffer.appendInt32(-1141231252)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(balance, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(subscriptions!.count))
for item in subscriptions! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 2) != 0 {serializeString(subscriptionsNextOffset!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeInt64(subscriptionsMissingBalance!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(history!.count))
for item in history! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsStatus(let flags, let balance, let subscriptions, let subscriptionsNextOffset, let subscriptionsMissingBalance, let history, let nextOffset, let chats, let users):
return ("starsStatus", [("flags", flags as Any), ("balance", balance as Any), ("subscriptions", subscriptions as Any), ("subscriptionsNextOffset", subscriptionsNextOffset as Any), ("subscriptionsMissingBalance", subscriptionsMissingBalance as Any), ("history", history as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_starsStatus(_ reader: BufferReader) -> StarsStatus? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: [Api.StarsSubscription]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarsSubscription.self)
} }
var _4: String?
if Int(_1!) & Int(1 << 2) != 0 {_4 = parseString(reader) }
var _5: Int64?
if Int(_1!) & Int(1 << 4) != 0 {_5 = reader.readInt64() }
var _6: [Api.StarsTransaction]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarsTransaction.self)
} }
var _7: String?
if Int(_1!) & Int(1 << 0) != 0 {_7 = parseString(reader) }
var _8: [Api.Chat]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _9: [Api.User]?
if let _ = reader.readInt32() {
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 0) == 0) || _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.payments.StarsStatus.starsStatus(flags: _1!, balance: _2!, subscriptions: _3, subscriptionsNextOffset: _4, subscriptionsMissingBalance: _5, history: _6, nextOffset: _7, chats: _8!, users: _9!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum UserStarGifts: TypeConstructorDescription {
case userStarGifts(flags: Int32, count: Int32, gifts: [Api.UserStarGift], nextOffset: String?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .userStarGifts(let flags, let count, let gifts, let nextOffset, let users):
if boxed {
buffer.appendInt32(1801827607)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(gifts.count))
for item in gifts {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .userStarGifts(let flags, let count, let gifts, let nextOffset, let users):
return ("userStarGifts", [("flags", flags as Any), ("count", count as Any), ("gifts", gifts as Any), ("nextOffset", nextOffset as Any), ("users", users as Any)])
}
}
public static func parse_userStarGifts(_ reader: BufferReader) -> UserStarGifts? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.UserStarGift]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.UserStarGift.self)
}
var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.payments.UserStarGifts.userStarGifts(flags: _1!, count: _2!, gifts: _3!, nextOffset: _4, users: _5!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,243 @@
public extension Api.payments {
enum StarsRevenueStats: TypeConstructorDescription {
case starsRevenueStats(revenueGraph: Api.StatsGraph, status: Api.StarsRevenueStatus, usdRate: Double)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsRevenueStats(let revenueGraph, let status, let usdRate):
if boxed {
buffer.appendInt32(-919881925)
}
revenueGraph.serialize(buffer, true)
status.serialize(buffer, true)
serializeDouble(usdRate, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsRevenueStats(let revenueGraph, let status, let usdRate):
return ("starsRevenueStats", [("revenueGraph", revenueGraph as Any), ("status", status as Any), ("usdRate", usdRate as Any)])
}
}
public static func parse_starsRevenueStats(_ reader: BufferReader) -> StarsRevenueStats? {
var _1: Api.StatsGraph?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _2: Api.StarsRevenueStatus?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StarsRevenueStatus
}
var _3: Double?
_3 = reader.readDouble()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.payments.StarsRevenueStats.starsRevenueStats(revenueGraph: _1!, status: _2!, usdRate: _3!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum StarsRevenueWithdrawalUrl: TypeConstructorDescription {
case starsRevenueWithdrawalUrl(url: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsRevenueWithdrawalUrl(let url):
if boxed {
buffer.appendInt32(497778871)
}
serializeString(url, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsRevenueWithdrawalUrl(let url):
return ("starsRevenueWithdrawalUrl", [("url", url as Any)])
}
}
public static func parse_starsRevenueWithdrawalUrl(_ reader: BufferReader) -> StarsRevenueWithdrawalUrl? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.payments.StarsRevenueWithdrawalUrl.starsRevenueWithdrawalUrl(url: _1!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum StarsStatus: TypeConstructorDescription {
case starsStatus(flags: Int32, balance: Int64, subscriptions: [Api.StarsSubscription]?, subscriptionsNextOffset: String?, subscriptionsMissingBalance: Int64?, history: [Api.StarsTransaction]?, nextOffset: String?, chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsStatus(let flags, let balance, let subscriptions, let subscriptionsNextOffset, let subscriptionsMissingBalance, let history, let nextOffset, let chats, let users):
if boxed {
buffer.appendInt32(-1141231252)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(balance, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(subscriptions!.count))
for item in subscriptions! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 2) != 0 {serializeString(subscriptionsNextOffset!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeInt64(subscriptionsMissingBalance!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(history!.count))
for item in history! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsStatus(let flags, let balance, let subscriptions, let subscriptionsNextOffset, let subscriptionsMissingBalance, let history, let nextOffset, let chats, let users):
return ("starsStatus", [("flags", flags as Any), ("balance", balance as Any), ("subscriptions", subscriptions as Any), ("subscriptionsNextOffset", subscriptionsNextOffset as Any), ("subscriptionsMissingBalance", subscriptionsMissingBalance as Any), ("history", history as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_starsStatus(_ reader: BufferReader) -> StarsStatus? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: [Api.StarsSubscription]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarsSubscription.self)
} }
var _4: String?
if Int(_1!) & Int(1 << 2) != 0 {_4 = parseString(reader) }
var _5: Int64?
if Int(_1!) & Int(1 << 4) != 0 {_5 = reader.readInt64() }
var _6: [Api.StarsTransaction]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarsTransaction.self)
} }
var _7: String?
if Int(_1!) & Int(1 << 0) != 0 {_7 = parseString(reader) }
var _8: [Api.Chat]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _9: [Api.User]?
if let _ = reader.readInt32() {
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 0) == 0) || _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.payments.StarsStatus.starsStatus(flags: _1!, balance: _2!, subscriptions: _3, subscriptionsNextOffset: _4, subscriptionsMissingBalance: _5, history: _6, nextOffset: _7, chats: _8!, users: _9!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum UserStarGifts: TypeConstructorDescription {
case userStarGifts(flags: Int32, count: Int32, gifts: [Api.UserStarGift], nextOffset: String?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .userStarGifts(let flags, let count, let gifts, let nextOffset, let users):
if boxed {
buffer.appendInt32(1801827607)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(gifts.count))
for item in gifts {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .userStarGifts(let flags, let count, let gifts, let nextOffset, let users):
return ("userStarGifts", [("flags", flags as Any), ("count", count as Any), ("gifts", gifts as Any), ("nextOffset", nextOffset as Any), ("users", users as Any)])
}
}
public static func parse_userStarGifts(_ reader: BufferReader) -> UserStarGifts? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.UserStarGift]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.UserStarGift.self)
}
var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.payments.UserStarGifts.userStarGifts(flags: _1!, count: _2!, gifts: _3!, nextOffset: _4, users: _5!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum ValidatedRequestedInfo: TypeConstructorDescription {
case validatedRequestedInfo(flags: Int32, id: String?, shippingOptions: [Api.ShippingOption]?)

View File

@ -2574,6 +2574,22 @@ public extension Api.functions.bots {
})
}
}
public extension Api.functions.bots {
static func toggleUserEmojiStatusPermission(bot: Api.InputUser, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(115237778)
bot.serialize(buffer, true)
enabled.serialize(buffer, true)
return (FunctionDescription(name: "bots.toggleUserEmojiStatusPermission", parameters: [("bot", String(describing: bot)), ("enabled", String(describing: enabled))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.bots {
static func toggleUsername(bot: Api.InputUser, username: String, active: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
@ -2591,6 +2607,22 @@ public extension Api.functions.bots {
})
}
}
public extension Api.functions.bots {
static func updateUserEmojiStatus(userId: Api.InputUser, emojiStatus: Api.EmojiStatus) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-308334395)
userId.serialize(buffer, true)
emojiStatus.serialize(buffer, true)
return (FunctionDescription(name: "bots.updateUserEmojiStatus", parameters: [("userId", String(describing: userId)), ("emojiStatus", String(describing: emojiStatus))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.channels {
static func checkUsername(channel: Api.InputChannel, username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
@ -6493,6 +6525,22 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func getPreparedInlineMessage(bot: Api.InputUser, id: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.PreparedInlineMessage>) {
let buffer = Buffer()
buffer.appendInt32(-2055291464)
bot.serialize(buffer, true)
serializeString(id, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getPreparedInlineMessage", parameters: [("bot", String(describing: bot)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.PreparedInlineMessage? in
let reader = BufferReader(buffer)
var result: Api.messages.PreparedInlineMessage?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.PreparedInlineMessage
}
return result
})
}
}
public extension Api.functions.messages {
static func getQuickReplies(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.QuickReplies>) {
let buffer = Buffer()
@ -7608,6 +7656,28 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func savePreparedInlineMessage(flags: Int32, result: Api.InputBotInlineResult, userId: Api.InputUser, peerTypes: [Api.InlineQueryPeerType]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.BotPreparedInlineMessage>) {
let buffer = Buffer()
buffer.appendInt32(-232816849)
serializeInt32(flags, buffer: buffer, boxed: false)
result.serialize(buffer, true)
userId.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(peerTypes!.count))
for item in peerTypes! {
item.serialize(buffer, true)
}}
return (FunctionDescription(name: "messages.savePreparedInlineMessage", parameters: [("flags", String(describing: flags)), ("result", String(describing: result)), ("userId", String(describing: userId)), ("peerTypes", String(describing: peerTypes))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.BotPreparedInlineMessage? in
let reader = BufferReader(buffer)
var result: Api.messages.BotPreparedInlineMessage?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.BotPreparedInlineMessage
}
return result
})
}
}
public extension Api.functions.messages {
static func saveRecentSticker(flags: Int32, id: Api.InputDocument, unsave: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
@ -8775,6 +8845,24 @@ public extension Api.functions.payments {
})
}
}
public extension Api.functions.payments {
static func botCancelStarsSubscription(flags: Int32, userId: Api.InputUser, invoiceSlug: String?, chargeId: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(1475996902)
serializeInt32(flags, buffer: buffer, boxed: false)
userId.serialize(buffer, true)
if Int(flags) & Int(1 << 1) != 0 {serializeString(invoiceSlug!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeString(chargeId!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "payments.botCancelStarsSubscription", parameters: [("flags", String(describing: flags)), ("userId", String(describing: userId)), ("invoiceSlug", String(describing: invoiceSlug)), ("chargeId", String(describing: chargeId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.payments {
static func canPurchasePremium(purpose: Api.InputStorePaymentPurpose) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()

View File

@ -13,10 +13,25 @@ extension BotMenuButton {
}
}
extension BotAppSettings {
init(apiBotAppSettings: Api.BotAppSettings) {
switch apiBotAppSettings {
case let .botAppSettings(_, placeholderDocument, backgroundColor, backgroundDarkColor, headerColor, headerDarkColor):
self.init(
placeholder: placeholderDocument.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: []) },
backgroundColor: backgroundColor,
backgroundDarkColor: backgroundDarkColor,
headerColor: headerColor,
headerDarkColor: headerDarkColor
)
}
}
}
extension BotInfo {
convenience init(apiBotInfo: Api.BotInfo) {
switch apiBotInfo {
case let .botInfo(_, _, description, descriptionPhoto, descriptionDocument, apiCommands, apiMenuButton, privacyPolicyUrl):
case let .botInfo(_, _, description, descriptionPhoto, descriptionDocument, apiCommands, apiMenuButton, privacyPolicyUrl, appSettings):
let photo: TelegramMediaImage? = descriptionPhoto.flatMap(telegramMediaImageFromApiPhoto)
let video: TelegramMediaFile? = descriptionDocument.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }
var commands: [BotCommand] = []
@ -32,7 +47,7 @@ extension BotInfo {
if let apiMenuButton = apiMenuButton {
menuButton = BotMenuButton(apiBotMenuButton: apiMenuButton)
}
self.init(description: description ?? "", photo: photo, video: video, commands: commands, menuButton: menuButton, privacyPolicyUrl: privacyPolicyUrl)
self.init(description: description ?? "", photo: photo, video: video, commands: commands, menuButton: menuButton, privacyPolicyUrl: privacyPolicyUrl, appSettings: appSettings.flatMap { BotAppSettings(apiBotAppSettings: $0) })
}
}
}

View File

@ -2,6 +2,22 @@ import Foundation
import Postbox
import TelegramApi
extension ReplyMarkupButtonAction.PeerTypes {
init?(apiType: Api.InlineQueryPeerType) {
switch apiType {
case .inlineQueryPeerTypePM:
self = .users
case .inlineQueryPeerTypeBotPM:
self = .bots
case .inlineQueryPeerTypeBroadcast:
self = .channels
case .inlineQueryPeerTypeChat, .inlineQueryPeerTypeMegagroup:
self = .groups
case .inlineQueryPeerTypeSameBotPM:
return nil
}
}
}
extension ReplyMarkupButton {
init(apiButton: Api.KeyboardButton) {

View File

@ -1706,14 +1706,14 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
updatedState.updateCachedPeerData(peer.peerId, { current in
if peer.peerId.namespace == Namespaces.Peer.CloudUser, let previous = current as? CachedUserData {
if let botInfo = previous.botInfo {
return previous.withUpdatedBotInfo(BotInfo(description: botInfo.description, photo: botInfo.photo, video: botInfo.video, commands: commands, menuButton: botInfo.menuButton, privacyPolicyUrl: botInfo.privacyPolicyUrl))
return previous.withUpdatedBotInfo(BotInfo(description: botInfo.description, photo: botInfo.photo, video: botInfo.video, commands: commands, menuButton: botInfo.menuButton, privacyPolicyUrl: botInfo.privacyPolicyUrl, appSettings: botInfo.appSettings))
}
} else if peer.peerId.namespace == Namespaces.Peer.CloudGroup, let previous = current as? CachedGroupData {
if let index = previous.botInfos.firstIndex(where: { $0.peerId == botPeerId }) {
var updatedBotInfos = previous.botInfos
let previousBotInfo = updatedBotInfos[index]
updatedBotInfos.remove(at: index)
updatedBotInfos.insert(CachedPeerBotInfo(peerId: botPeerId, botInfo: BotInfo(description: previousBotInfo.botInfo.description, photo: previousBotInfo.botInfo.photo, video: previousBotInfo.botInfo.video, commands: commands, menuButton: previousBotInfo.botInfo.menuButton, privacyPolicyUrl: previousBotInfo.botInfo.privacyPolicyUrl)), at: index)
updatedBotInfos.insert(CachedPeerBotInfo(peerId: botPeerId, botInfo: BotInfo(description: previousBotInfo.botInfo.description, photo: previousBotInfo.botInfo.photo, video: previousBotInfo.botInfo.video, commands: commands, menuButton: previousBotInfo.botInfo.menuButton, privacyPolicyUrl: previousBotInfo.botInfo.privacyPolicyUrl, appSettings: previousBotInfo.botInfo.appSettings)), at: index)
return previous.withUpdatedBotInfos(updatedBotInfos)
}
} else if peer.peerId.namespace == Namespaces.Peer.CloudChannel, let previous = current as? CachedChannelData {
@ -1721,7 +1721,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
var updatedBotInfos = previous.botInfos
let previousBotInfo = updatedBotInfos[index]
updatedBotInfos.remove(at: index)
updatedBotInfos.insert(CachedPeerBotInfo(peerId: botPeerId, botInfo: BotInfo(description: previousBotInfo.botInfo.description, photo: previousBotInfo.botInfo.photo, video: previousBotInfo.botInfo.video, commands: commands, menuButton: previousBotInfo.botInfo.menuButton, privacyPolicyUrl: previousBotInfo.botInfo.privacyPolicyUrl)), at: index)
updatedBotInfos.insert(CachedPeerBotInfo(peerId: botPeerId, botInfo: BotInfo(description: previousBotInfo.botInfo.description, photo: previousBotInfo.botInfo.photo, video: previousBotInfo.botInfo.video, commands: commands, menuButton: previousBotInfo.botInfo.menuButton, privacyPolicyUrl: previousBotInfo.botInfo.privacyPolicyUrl, appSettings: previousBotInfo.botInfo.appSettings)), at: index)
return previous.withUpdatedBotInfos(updatedBotInfos)
}
}
@ -1733,7 +1733,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
updatedState.updateCachedPeerData(botPeerId, { current in
if let previous = current as? CachedUserData {
if let botInfo = previous.botInfo {
return previous.withUpdatedBotInfo(BotInfo(description: botInfo.description, photo: botInfo.photo, video: botInfo.video, commands: botInfo.commands, menuButton: menuButton, privacyPolicyUrl: botInfo.privacyPolicyUrl))
return previous.withUpdatedBotInfo(BotInfo(description: botInfo.description, photo: botInfo.photo, video: botInfo.video, commands: botInfo.commands, menuButton: menuButton, privacyPolicyUrl: botInfo.privacyPolicyUrl, appSettings: botInfo.appSettings))
}
}
return current

View File

@ -45,6 +45,62 @@ public enum BotMenuButton: PostboxCoding, Hashable {
}
}
public struct BotAppSettings: PostboxCoding, Equatable {
public let placeholder: TelegramMediaFile?
public let backgroundColor: Int32?
public let backgroundDarkColor: Int32?
public let headerColor: Int32?
public let headerDarkColor: Int32?
public init(placeholder: TelegramMediaFile?, backgroundColor: Int32?, backgroundDarkColor: Int32?, headerColor: Int32?, headerDarkColor: Int32?) {
self.placeholder = placeholder
self.backgroundColor = backgroundColor
self.backgroundDarkColor = backgroundDarkColor
self.headerColor = headerColor
self.headerDarkColor = headerDarkColor
}
public init(decoder: PostboxDecoder) {
if let placeholder = decoder.decodeObjectForKey("p", decoder: { TelegramMediaFile(decoder: $0) }) as? TelegramMediaFile {
self.placeholder = placeholder
} else {
self.placeholder = nil
}
self.backgroundColor = decoder.decodeOptionalInt32ForKey("b")
self.backgroundDarkColor = decoder.decodeOptionalInt32ForKey("bd")
self.headerColor = decoder.decodeOptionalInt32ForKey("h")
self.headerDarkColor = decoder.decodeOptionalInt32ForKey("hd")
}
public func encode(_ encoder: PostboxEncoder) {
if let placeholder = self.placeholder {
encoder.encodeObject(placeholder, forKey: "p")
} else {
encoder.encodeNil(forKey: "p")
}
if let backgroundColor = self.backgroundColor {
encoder.encodeInt32(backgroundColor, forKey: "b")
} else {
encoder.encodeNil(forKey: "b")
}
if let backgroundDarkColor = self.backgroundDarkColor {
encoder.encodeInt32(backgroundDarkColor, forKey: "bd")
} else {
encoder.encodeNil(forKey: "bd")
}
if let headerColor = self.headerColor {
encoder.encodeInt32(headerColor, forKey: "h")
} else {
encoder.encodeNil(forKey: "h")
}
if let headerDarkColor = self.headerDarkColor {
encoder.encodeInt32(headerDarkColor, forKey: "hd")
} else {
encoder.encodeNil(forKey: "hd")
}
}
}
public final class BotInfo: PostboxCoding, Equatable {
public let description: String
public let photo: TelegramMediaImage?
@ -52,14 +108,16 @@ public final class BotInfo: PostboxCoding, Equatable {
public let commands: [BotCommand]
public let menuButton: BotMenuButton
public let privacyPolicyUrl: String?
public let appSettings: BotAppSettings?
public init(description: String, photo: TelegramMediaImage?, video: TelegramMediaFile?, commands: [BotCommand], menuButton: BotMenuButton, privacyPolicyUrl: String?) {
public init(description: String, photo: TelegramMediaImage?, video: TelegramMediaFile?, commands: [BotCommand], menuButton: BotMenuButton, privacyPolicyUrl: String?, appSettings: BotAppSettings?) {
self.description = description
self.photo = photo
self.video = video
self.commands = commands
self.menuButton = menuButton
self.privacyPolicyUrl = privacyPolicyUrl
self.appSettings = appSettings
}
public init(decoder: PostboxDecoder) {
@ -77,6 +135,11 @@ public final class BotInfo: PostboxCoding, Equatable {
self.commands = decoder.decodeObjectArrayWithDecoderForKey("c")
self.menuButton = (decoder.decodeObjectForKey("b", decoder: { BotMenuButton(decoder: $0) }) as? BotMenuButton) ?? .commands
self.privacyPolicyUrl = decoder.decodeOptionalStringForKey("pp")
if let appSettings = decoder.decodeObjectForKey("as", decoder: { BotAppSettings(decoder: $0) }) as? BotAppSettings {
self.appSettings = appSettings
} else {
self.appSettings = nil
}
}
public func encode(_ encoder: PostboxEncoder) {
@ -98,9 +161,14 @@ public final class BotInfo: PostboxCoding, Equatable {
} else {
encoder.encodeNil(forKey: "pp")
}
if let appSettings = self.appSettings {
encoder.encodeObject(appSettings, forKey: "as")
} else {
encoder.encodeNil(forKey: "as")
}
}
public static func ==(lhs: BotInfo, rhs: BotInfo) -> Bool {
return lhs.description == rhs.description && lhs.commands == rhs.commands && lhs.menuButton == rhs.menuButton && lhs.photo == rhs.photo && lhs.privacyPolicyUrl == rhs.privacyPolicyUrl
return lhs.description == rhs.description && lhs.commands == rhs.commands && lhs.menuButton == rhs.menuButton && lhs.photo == rhs.photo && lhs.privacyPolicyUrl == rhs.privacyPolicyUrl && lhs.appSettings == rhs.appSettings
}
}

View File

@ -299,6 +299,7 @@ public struct CachedUserFlags: OptionSet {
public static let premiumRequired = CachedUserFlags(rawValue: 1 << 3)
public static let adsEnabled = CachedUserFlags(rawValue: 1 << 4)
public static let canViewRevenue = CachedUserFlags(rawValue: 1 << 5)
public static let botCanManageEmojiStatus = CachedUserFlags(rawValue: 1 << 6)
}
public final class EditableBotInfo: PostboxCoding, Equatable {

View File

@ -1126,6 +1126,34 @@ public extension TelegramEngine.EngineData.Item {
}
}
public struct CanManageEmojiStatus: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Bool
fileprivate var id: EnginePeer.Id
public var mapKey: EnginePeer.Id {
return self.id
}
public init(id: EnginePeer.Id) {
self.id = id
}
var key: PostboxViewKey {
return .cachedPeerData(peerId: self.id)
}
func extract(view: PostboxView) -> Result {
guard let view = view as? CachedPeerDataView else {
preconditionFailure()
}
if let cachedData = view.cachedPeerData as? CachedUserData {
return cachedData.flags.contains(.botCanManageEmojiStatus)
} else {
return false
}
}
}
public struct CanViewStarsRevenue: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Bool

View File

@ -67,7 +67,7 @@ func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: P
|> switchToLatest
}
func _internal_requestMainWebView(postbox: Postbox, network: Network, botId: PeerId, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal<RequestWebViewResult, RequestWebViewError> {
func _internal_requestMainWebView(postbox: Postbox, network: Network, peerId: PeerId, botId: PeerId, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal<RequestWebViewResult, RequestWebViewError> {
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)
@ -76,7 +76,7 @@ func _internal_requestMainWebView(postbox: Postbox, network: Network, botId: Pee
guard let bot = transaction.getPeer(botId), let inputUser = apiInputUser(bot) else {
return .fail(.generic)
}
guard let peer = transaction.getPeer(botId), let inputPeer = apiInputPeer(peer) else {
guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else {
return .fail(.generic)
}
@ -286,7 +286,7 @@ func _internal_sendWebViewData(postbox: Postbox, network: Network, stateManager:
|> switchToLatest
}
func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, compact: Bool, allowWrite: Bool) -> Signal<RequestWebViewResult, RequestWebViewError> {
func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, compact: Bool, fullscreen: Bool, allowWrite: Bool) -> Signal<RequestWebViewResult, RequestWebViewError> {
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)
@ -321,6 +321,9 @@ func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManage
if compact {
flags |= (1 << 7)
}
if fullscreen {
flags |= (1 << 8)
}
return network.request(Api.functions.messages.requestAppWebView(flags: flags, peer: inputPeer, app: app, startParam: payload, themeParams: serializedThemeParams, platform: botWebViewPlatform))
|> mapError { _ -> RequestWebViewError in

View File

@ -0,0 +1,40 @@
import Foundation
import Postbox
import SwiftSignalKit
import TelegramApi
import MtProtoKit
public struct PreparedInlineMessage: Equatable {
let queryId: Int64
let result: ChatContextResult
let peerTypes: [ReplyMarkupButtonAction.PeerTypes]
}
func _internal_getPreparedInlineMessage(account: Account, botId: EnginePeer.Id, id: String) -> Signal<PreparedInlineMessage?, NoError> {
return account.postbox.transaction { transaction -> Api.InputUser? in
return transaction.getPeer(botId).flatMap(apiInputUser)
}
|> mapToSignal { inputBot -> Signal<PreparedInlineMessage?, NoError> in
guard let inputBot else {
return .single(nil)
}
return account.network.request(Api.functions.messages.getPreparedInlineMessage(bot: inputBot, id: id))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.PreparedInlineMessage?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<PreparedInlineMessage?, NoError> in
guard let result else {
return .single(nil)
}
return account.postbox.transaction { transaction -> PreparedInlineMessage? in
switch result {
case let .preparedInlineMessage(queryId, result, peerTypes, users):
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: users))
return PreparedInlineMessage(queryId: queryId, result: ChatContextResult(apiResult: result, queryId: queryId), peerTypes: peerTypes.compactMap { ReplyMarkupButtonAction.PeerTypes(apiType: $0) })
}
}
}
}
}

View File

@ -403,6 +403,10 @@ public extension TelegramEngine {
public func messageReadStats(id: MessageId) -> Signal<MessageReadStats?, NoError> {
return _internal_messageReadStats(account: self.account, id: id)
}
public func getPreparedInlineMessage(botId: EnginePeer.Id, id: String) -> Signal<PreparedInlineMessage?, NoError> {
return _internal_getPreparedInlineMessage(account: self.account, botId: botId, id: id)
}
public func requestCancelLiveLocation(ids: [MessageId]) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
@ -590,12 +594,12 @@ public extension TelegramEngine {
return _internal_requestSimpleWebView(postbox: self.account.postbox, network: self.account.network, botId: botId, url: url, source: source, themeParams: themeParams)
}
public func requestMainWebView(botId: PeerId, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal<RequestWebViewResult, RequestWebViewError> {
return _internal_requestMainWebView(postbox: self.account.postbox, network: self.account.network, botId: botId, source: source, themeParams: themeParams)
public func requestMainWebView(peerId: PeerId, botId: PeerId, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal<RequestWebViewResult, RequestWebViewError> {
return _internal_requestMainWebView(postbox: self.account.postbox, network: self.account.network, peerId: peerId, botId: botId, source: source, themeParams: themeParams)
}
public func requestAppWebView(peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, compact: Bool, allowWrite: Bool) -> Signal<RequestWebViewResult, RequestWebViewError> {
return _internal_requestAppWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, appReference: appReference, payload: payload, themeParams: themeParams, compact: compact, allowWrite: allowWrite)
public func requestAppWebView(peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, compact: Bool, fullscreen: Bool, allowWrite: Bool) -> Signal<RequestWebViewResult, RequestWebViewError> {
return _internal_requestAppWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, appReference: appReference, payload: payload, themeParams: themeParams, compact: compact, fullscreen: fullscreen, allowWrite: allowWrite)
}
public func sendWebViewData(botId: PeerId, buttonText: String, data: String) -> Signal<Never, SendWebViewDataError> {

View File

@ -811,6 +811,10 @@ public extension TelegramEngine {
return _internal_updateBotAbout(account: self.account, peerId: peerId, about: about)
}
public func toggleBotEmojiStatusAccess(peerId: PeerId, enabled: Bool) -> Signal<Never, ToggleBotEmojiStatusAccessError> {
return _internal_toggleBotEmojiStatusAccess(account: self.account, peerId: peerId, enabled: enabled)
}
public func updatePeerNameColorAndEmoji(peerId: EnginePeer.Id, nameColor: PeerNameColor, backgroundEmojiId: Int64?, profileColor: PeerNameColor?, profileBackgroundEmojiId: Int64?) -> Signal<Void, UpdatePeerNameColorAndEmojiError> {
return _internal_updatePeerNameColorAndEmoji(account: self.account, peerId: peerId, nameColor: nameColor, backgroundEmojiId: backgroundEmojiId, profileColor: profileColor, profileBackgroundEmojiId: profileBackgroundEmojiId)
}

View File

@ -100,7 +100,7 @@ func _internal_updateBotDescription(account: Account, peerId: PeerId, descriptio
if let botInfo = current.botInfo {
var updatedBotInfo = botInfo
if botInfo.description == editableBotInfo.description {
updatedBotInfo = BotInfo(description: description, photo: botInfo.photo, video: botInfo.video, commands: botInfo.commands, menuButton: botInfo.menuButton, privacyPolicyUrl: botInfo.privacyPolicyUrl)
updatedBotInfo = BotInfo(description: description, photo: botInfo.photo, video: botInfo.video, commands: botInfo.commands, menuButton: botInfo.menuButton, privacyPolicyUrl: botInfo.privacyPolicyUrl, appSettings: botInfo.appSettings)
}
return current.withUpdatedEditableBotInfo(editableBotInfo.withUpdatedDescription(description)).withUpdatedBotInfo(updatedBotInfo)
} else {
@ -121,3 +121,43 @@ func _internal_updateBotDescription(account: Account, peerId: PeerId, descriptio
|> mapError { _ -> UpdateBotInfoError in }
|> switchToLatest
}
public enum ToggleBotEmojiStatusAccessError {
case generic
}
func _internal_toggleBotEmojiStatusAccess(account: Account, peerId: PeerId, enabled: Bool) -> Signal<Never, ToggleBotEmojiStatusAccessError> {
return account.postbox.transaction { transaction -> Signal<Void, ToggleBotEmojiStatusAccessError> in
if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) {
return account.network.request(Api.functions.bots.toggleUserEmojiStatusPermission(bot: inputUser, enabled: enabled ? .boolTrue : .boolFalse))
|> mapError { _ -> ToggleBotEmojiStatusAccessError in
return .generic
}
|> mapToSignal { result -> Signal<Void, ToggleBotEmojiStatusAccessError> in
return account.postbox.transaction { transaction -> Void in
if case .boolTrue = result {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedUserData {
var updatedFlags: CachedUserFlags = current.flags
if enabled {
updatedFlags.insert(.botCanManageEmojiStatus)
} else {
updatedFlags.remove(.botCanManageEmojiStatus)
}
return current.withUpdatedFlags(updatedFlags)
} else {
return current
}
})
}
}
|> mapError { _ -> ToggleBotEmojiStatusAccessError in }
}
} else {
return .fail(.generic)
}
}
|> mapError { _ -> ToggleBotEmojiStatusAccessError in }
|> switchToLatest
|> ignoreValues
}

View File

@ -282,6 +282,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
let translationsDisabled = (userFullFlags & (1 << 23)) != 0
let adsEnabled = (userFullFlags2 & (1 << 7)) != 0
let canViewRevenue = (userFullFlags2 & (1 << 9)) != 0
let botCanManageEmojiStatus = (userFullFlags2 & (1 << 10)) != 0
var flags: CachedUserFlags = previous.flags
if premiumRequired {
@ -309,6 +310,11 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
} else {
flags.remove(.canViewRevenue)
}
if botCanManageEmojiStatus {
flags.insert(.botCanManageEmojiStatus)
} else {
flags.remove(.botCanManageEmojiStatus)
}
let callsPrivate = (userFullFlags & (1 << 5)) != 0
let canPinMessages = (userFullFlags & (1 << 7)) != 0
@ -446,7 +452,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
var botInfos: [CachedPeerBotInfo] = []
for botInfo in chatFullBotInfo ?? [] {
switch botInfo {
case let .botInfo(_, userId, _, _, _, _, _, _):
case let .botInfo(_, userId, _, _, _, _, _, _, _):
if let userId = userId {
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)
@ -636,7 +642,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
var botInfos: [CachedPeerBotInfo] = []
for botInfo in apiBotInfos {
switch botInfo {
case let .botInfo(_, userId, _, _, _, _, _, _):
case let .botInfo(_, userId, _, _, _, _, _, _, _):
if let userId = userId {
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)

View File

@ -1381,7 +1381,8 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
context: context,
parentController: parentController,
updatedPresentationData: nil,
peer: .user(user),
botPeer: .user(user),
chatPeer: nil,
threadId: nil,
buttonText: "",
url: "",
@ -1545,15 +1546,20 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if let _ = user.botInfo {
//TODO:localize
items[.permissions]!.append(PeerInfoScreenHeaderItem(id: 30, text: "ALLOW ACCESS TO"))
// items[.permissions]!.append(PeerInfoScreenSwitchItem(id: 31, text: "Emoji Status", value: false, icon: UIImage(bundleImageName: "Chat/Info/Status"), isLocked: false, toggled: { value in
//
// }))
var canManageEmojiStatus = false
if let cachedData = data.cachedData as? CachedUserData, cachedData.flags.contains(.botCanManageEmojiStatus) {
canManageEmojiStatus = true
}
items[.permissions]!.append(PeerInfoScreenSwitchItem(id: 31, text: "Emoji Status", value: canManageEmojiStatus, icon: UIImage(bundleImageName: "Chat/Info/Status"), isLocked: false, toggled: { value in
let _ = (context.engine.peers.toggleBotEmojiStatusAccess(peerId: user.id, enabled: value)
|> deliverOnMainQueue).startStandalone()
}))
if data.webAppPermissions?.location?.isRequested == true {
items[.permissions]!.append(PeerInfoScreenSwitchItem(id: 32, text: "Geolocation", value: data.webAppPermissions?.location?.isAllowed ?? false, icon: UIImage(bundleImageName: "Chat/Info/Location"), isLocked: false, toggled: { value in
let _ = updateWebAppPermissionsStateInteractively(context: context, peerId: user.id) { current in
return WebAppPermissionsState(location: WebAppPermissionsState.Location(isRequested: true, isAllowed: value))
}.start()
}.startStandalone()
}))
}
}

View File

@ -946,7 +946,7 @@ final class AuthorizedApplicationContext {
}
if openAppIfAny, case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.hasWebApp), let parentController = self.rootController.viewControllers.last as? ViewController {
self.context.sharedContext.openWebApp(context: self.context, parentController: parentController, updatedPresentationData: nil, peer: peer, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: true, payload: nil)
self.context.sharedContext.openWebApp(context: self.context, parentController: parentController, updatedPresentationData: nil, botPeer: peer, chatPeer: nil, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: true, payload: nil)
} else {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: chatLocation, subject: isOutgoingMessage ? messageId.flatMap { .message(id: .id($0), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false) } : nil, activateInput: activateInput ? .text : nil))
}

View File

@ -14,7 +14,20 @@ import UndoUI
import UrlHandling
import TelegramPresentationData
func openWebAppImpl(context: AccountContext, parentController: ViewController, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: EnginePeer, threadId: Int64?, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource, skipTermsOfService: Bool, payload: String?) {
func openWebAppImpl(
context: AccountContext,
parentController: ViewController,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?,
botPeer: EnginePeer,
chatPeer: EnginePeer?,
threadId: Int64?,
buttonText: String,
url: String,
simple: Bool,
source: ChatOpenWebViewSource,
skipTermsOfService: Bool,
payload: String?
) {
let presentationData: PresentationData
if let parentController = parentController as? ChatControllerImpl {
presentationData = parentController.presentationData
@ -30,9 +43,9 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
botAddress = bot.addressName ?? ""
botVerified = bot.isVerified
} else {
botName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
botAddress = peer.addressName ?? ""
botVerified = peer.isVerified
botName = botPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
botAddress = botPeer.addressName ?? ""
botVerified = botPeer.isVerified
}
if source == .generic {
@ -95,7 +108,7 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
if let navigationController = parentController.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer {
for controller in minimizedContainer.controllers {
if let controller = controller as? AttachmentController, let mainController = controller.mainController as? WebAppController, mainController.botId == peer.id && mainController.source == .menu {
if let controller = controller as? AttachmentController, let mainController = controller.mainController as? WebAppController, mainController.botId == botPeer.id && mainController.source == .menu {
navigationController.maximizeViewController(controller, animated: true)
return
}
@ -105,22 +118,22 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
var fullSize = false
var isFullscreen = false
if isTelegramMeLink(url), let internalUrl = parseFullInternalUrl(sharedContext: context.sharedContext, url: url), case .peer(_, .appStart) = internalUrl {
if url.contains("&mode=fullscreen") {
if url.contains("mode=fullscreen") {
isFullscreen = true
fullSize = true
} else {
fullSize = !url.contains("?mode=compact")
fullSize = !url.contains("mode=compact")
}
}
var presentImpl: ((ViewController, Any?) -> Void)?
let params = WebAppParameters(source: .menu, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: fullSize, isFullscreen: isFullscreen)
let params = WebAppParameters(source: .menu, peerId: chatPeer?.id ?? botPeer.id, botId: botPeer.id, botName: botName, botVerified: botVerified, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: fullSize, isFullscreen: isFullscreen)
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, forceUpdate, commit in
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
ChatControllerImpl.botOpenUrl(context: context, peerId: chatPeer?.id ?? botPeer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
presentImpl?(c, a)
}, commit: commit)
}, requestSwitchInline: { [weak parentController] query, chatTypes, completion in
ChatControllerImpl.botRequestSwitchInline(context: context, controller: parentController as? ChatControllerImpl, peerId: peer.id, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion)
ChatControllerImpl.botRequestSwitchInline(context: context, controller: parentController as? ChatControllerImpl, peerId: chatPeer?.id ?? botPeer.id, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion)
}, getInputContainerNode: { [weak parentController] in
if let parentController = parentController as? ChatControllerImpl, let layout = parentController.validLayout, case .compact = layout.metrics.widthClass {
return (parentController.chatDisplayNode.getWindowInputAccessoryHeight(), parentController.chatDisplayNode.inputPanelContainerNode, {
@ -160,10 +173,10 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
}
} else if simple {
var isInline = false
var botId = peer.id
var botId = botPeer.id
var botName = botName
var botAddress = ""
var botVerified = peer.isVerified
var botVerified = botPeer.isVerified
if case let .inline(bot) = source {
isInline = true
botId = bot.id
@ -180,9 +193,14 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
}
let webViewSignal: Signal<RequestWebViewResult, RequestWebViewError>
let webViewSource: RequestSimpleWebViewSource = isInline ? .inline(startParam: payload) : .generic
let webViewSource: RequestSimpleWebViewSource
if let payload {
webViewSource = .inline(startParam: payload)
} else {
webViewSource = .generic
}
if url.isEmpty {
webViewSignal = context.engine.messages.requestMainWebView(botId: botId, source: webViewSource, themeParams: generateWebAppThemeParams(presentationData.theme))
webViewSignal = context.engine.messages.requestMainWebView(peerId: chatPeer?.id ?? botId, botId: botId, source: webViewSource, themeParams: generateWebAppThemeParams(presentationData.theme))
} else {
webViewSignal = context.engine.messages.requestSimpleWebView(botId: botId, url: url, source: webViewSource, themeParams: generateWebAppThemeParams(presentationData.theme))
}
@ -202,13 +220,13 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
} else {
source = url.isEmpty ? .generic : .simple
}
let params = WebAppParameters(source: source, peerId: peer.id, botId: botId, botName: botName, botVerified: botVerified, url: result.url, queryId: nil, payload: payload, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: result.flags.contains(.fullSize), isFullscreen: result.flags.contains(.fullScreen))
let params = WebAppParameters(source: source, peerId: chatPeer?.id ?? botId, botId: botId, botName: botName, botVerified: botVerified, url: result.url, queryId: nil, payload: payload, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: result.flags.contains(.fullSize), isFullscreen: result.flags.contains(.fullScreen))
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, forceUpdate, commit in
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
ChatControllerImpl.botOpenUrl(context: context, peerId: chatPeer?.id ?? botId, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
presentImpl?(c, a)
}, commit: commit)
}, requestSwitchInline: { [weak parentController] query, chatTypes, completion in
ChatControllerImpl.botRequestSwitchInline(context: context, controller: parentController as? ChatControllerImpl, peerId: peer.id, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion)
ChatControllerImpl.botRequestSwitchInline(context: context, controller: parentController as? ChatControllerImpl, peerId: chatPeer?.id ?? botId, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion)
}, getNavigationController: { [weak parentController] in
var navigationController: NavigationController?
if let parentController = parentController as? ChatControllerImpl {
@ -239,7 +257,7 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
messageActionCallbackDisposable = MetaDisposable()
}
messageActionCallbackDisposable.set(((context.engine.messages.requestWebView(peerId: peer.id, botId: peer.id, url: !url.isEmpty ? url : nil, payload: nil, themeParams: generateWebAppThemeParams(presentationData.theme), fromMenu: false, replyToMessageId: nil, threadId: threadId)
messageActionCallbackDisposable.set(((context.engine.messages.requestWebView(peerId: chatPeer?.id ?? botPeer.id, botId: botPeer.id, url: !url.isEmpty ? url : nil, payload: nil, themeParams: generateWebAppThemeParams(presentationData.theme), fromMenu: false, replyToMessageId: nil, threadId: threadId)
|> afterDisposed {
updateProgress()
})
@ -248,9 +266,9 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
return
}
var presentImpl: ((ViewController, Any?) -> Void)?
let params = WebAppParameters(source: .button, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize), isFullscreen: result.flags.contains(.fullScreen))
let params = WebAppParameters(source: .button, peerId: chatPeer?.id ?? botPeer.id, botId: botPeer.id, botName: botName, botVerified: botVerified, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize), isFullscreen: result.flags.contains(.fullScreen))
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, forceUpdate, commit in
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
ChatControllerImpl.botOpenUrl(context: context, peerId: chatPeer?.id ?? botPeer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
presentImpl?(c, a)
}, commit: commit)
}, completion: { [weak parentController] in
@ -285,7 +303,7 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
if skipTermsOfService {
openWebView()
} else {
var botPeer = peer
var botPeer = botPeer
if case let .inline(bot) = source {
botPeer = bot
}
@ -319,7 +337,7 @@ public extension ChatControllerImpl {
}
self.chatDisplayNode.dismissInput()
self.context.sharedContext.openWebApp(context: self.context, parentController: self, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), threadId: self.chatLocation.threadId, buttonText: buttonText, url: url, simple: simple, source: source, skipTermsOfService: false, payload: nil)
self.context.sharedContext.openWebApp(context: self.context, parentController: self, updatedPresentationData: self.updatedPresentationData, botPeer: EnginePeer(peer), chatPeer: EnginePeer(peer), threadId: self.chatLocation.threadId, buttonText: buttonText, url: url, simple: simple, source: source, skipTermsOfService: false, payload: nil)
}
static func botRequestSwitchInline(context: AccountContext, controller: ChatControllerImpl?, peerId: EnginePeer.Id, botAddress: String, query: String, chatTypes: [ReplyMarkupButtonRequestPeerType]?, completion: @escaping () -> Void) -> Void {
@ -413,7 +431,7 @@ public extension ChatControllerImpl {
}
}
func presentBotApp(botApp: BotApp?, botPeer: EnginePeer, payload: String?, compact: Bool, concealed: Bool = false, commit: @escaping () -> Void = {}) {
func presentBotApp(botApp: BotApp?, botPeer: EnginePeer, payload: String?, mode: ResolvedStartAppMode, concealed: Bool = false, commit: @escaping () -> Void = {}) {
guard let peerId = self.chatLocation.peerId else {
return
}
@ -469,7 +487,7 @@ public extension ChatControllerImpl {
}
let botAddress = botPeer.addressName ?? ""
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), compact: compact, allowWrite: allowWrite)
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), compact: mode == .compact, fullscreen: mode == .fullscreen, allowWrite: allowWrite)
|> afterDisposed {
updateProgress()
})
@ -570,7 +588,7 @@ public extension ChatControllerImpl {
}
})
} else {
self.context.sharedContext.openWebApp(context: self.context, parentController: self, updatedPresentationData: self.updatedPresentationData, peer: botPeer, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: false, payload: payload)
self.context.sharedContext.openWebApp(context: self.context, parentController: self, updatedPresentationData: self.updatedPresentationData, botPeer: botPeer, chatPeer: nil, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: false, payload: payload)
}
}
}

View File

@ -9856,16 +9856,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case let .withBotApp(botAppStart):
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId.id))
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
if let strongSelf = self, let peer {
if let botApp = botAppStart.botApp {
strongSelf.presentBotApp(botApp: botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact, concealed: concealed, commit: {
dismissWebAppControllers()
commit()
})
} else {
strongSelf.context.sharedContext.openWebApp(context: strongSelf.context, parentController: strongSelf, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: false, payload: botAppStart.payload)
guard let self, let peer else {
return
}
if let botApp = botAppStart.botApp {
self.presentBotApp(botApp: botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode, concealed: concealed, commit: {
dismissWebAppControllers()
commit()
}
})
} else {
self.context.sharedContext.openWebApp(context: self.context, parentController: self, updatedPresentationData: self.updatedPresentationData, botPeer: peer, chatPeer: nil, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: false, payload: botAppStart.payload)
commit()
}
})
default:

View File

@ -668,9 +668,9 @@ func chatHistoryEntriesForView(
if reverse {
return (entries.reversed(), currentState)
} else {
#if DEBUG
assert(entries.map(\.stableId) == entries.sorted().map(\.stableId))
#endif
// #if DEBUG
// assert(entries.map(\.stableId) == entries.sorted().map(\.stableId))
// #endif
return (entries, currentState)
}
}

View File

@ -165,7 +165,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled)
}
if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact)
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode)
}
params.setupController(controller)
found = true
@ -188,7 +188,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
}
if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
Queue.mainQueue().after(0.1) {
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact)
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode)
}
}
} else {
@ -196,7 +196,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
Queue.mainQueue().after(0.1) {
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, compact: botAppStart.compact)
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode)
}
}
}

View File

@ -2825,8 +2825,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return MiniAppListScreen(context: context, initialData: initialData as! MiniAppListScreen.InitialData)
}
public func openWebApp(context: AccountContext, parentController: ViewController, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: EnginePeer, threadId: Int64?, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource, skipTermsOfService: Bool, payload: String?) {
openWebAppImpl(context: context, parentController: parentController, updatedPresentationData: updatedPresentationData, peer: peer, threadId: threadId, buttonText: buttonText, url: url, simple: simple, source: source, skipTermsOfService: skipTermsOfService, payload: payload)
public func openWebApp(context: AccountContext, parentController: ViewController, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, botPeer: EnginePeer, chatPeer: EnginePeer?, threadId: Int64?, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource, skipTermsOfService: Bool, payload: String?) {
openWebAppImpl(context: context, parentController: parentController, updatedPresentationData: updatedPresentationData, botPeer: botPeer, chatPeer: chatPeer, threadId: threadId, buttonText: buttonText, url: url, simple: simple, source: source, skipTermsOfService: skipTermsOfService, payload: payload)
}
}

View File

@ -50,6 +50,7 @@ public enum UndoOverlayContent {
case peers(context: AccountContext, peers: [EnginePeer], title: String?, text: String, customUndoText: String?)
case messageTagged(context: AccountContext, isSingleMessage: Bool, customEmoji: TelegramMediaFile, isBuiltinReaction: Bool, customUndoText: String?)
case media(context: AccountContext, file: FileMediaReference, title: String?, text: String, undoText: String?, customAction: (() -> Void)?)
case progress(progress: CGFloat, title: String, text: String, undoText: String?)
}
public enum UndoOverlayAction {

View File

@ -1351,6 +1351,45 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
if let updatedImageSignal = updatedImageSignal {
stillStickerNode.setSignal(updatedImageSignal)
}
case let .progress(progress, title, text, customUndoText):
self.avatarNode = nil
self.iconNode = ASImageNode()
self.iconNode?.displayWithoutProcessing = true
self.iconNode?.displaysAsynchronously = false
self.iconNode?.image = generateTintedImage(image: UIImage(bundleImageName: "Premium/File"), color: .white)
self.iconImageSize = CGSize(width: 14.0, height: 14.0)
self.iconCheckNode = nil
self.animationNode = nil
self.animatedStickerNode = nil
self.statusNode = RadialStatusNode(backgroundNodeColor: .clear)
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
let link = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: undoTextColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { contents in
return ("URL", contents)
}), textAlignment: .natural)
self.textNode.attributedText = attributedText
if text.contains("](") {
isUserInteractionEnabled = true
}
self.originalRemainingSeconds = 5
self.textNode.maximumNumberOfLines = 5
if let customUndoText = customUndoText {
undoText = customUndoText
displayUndo = true
} else {
displayUndo = false
}
self.statusNode?.transitionToState(.progress(color: .white, lineWidth: nil, value: max(progress, 0.027), cancelEnabled: false, animateRotation: true), completion: {})
}
self.remainingSeconds = self.originalRemainingSeconds
@ -1394,7 +1433,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} else {
self.isUserInteractionEnabled = false
}
case .sticker, .customEmoji, .media:
case .sticker, .customEmoji, .media, .progress:
self.isUserInteractionEnabled = displayUndo
case .dice:
self.panelWrapperNode.clipsToBounds = true
@ -1431,6 +1470,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode)
self.avatarNode.flatMap(self.panelWrapperNode.addSubnode)
self.multiAvatarsNode.flatMap(self.panelWrapperNode.addSubnode)
self.panelWrapperNode.addSubnode(self.buttonNode)
self.panelWrapperNode.addSubnode(self.titleNode)
self.panelWrapperNode.addSubnode(self.textNode)
@ -1629,6 +1669,15 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.renewWithCurrentContent()
transition = .animated(duration: 0.1, curve: .easeInOut)
case let .progress(progress, title, text, _):
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
let link = MarkdownAttributeSet(font: Font.regular(14.0), textColor: undoTextColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { _ in return nil }), textAlignment: .natural)
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
self.textNode.attributedText = attributedText
self.statusNode?.transitionToState(.progress(color: .white, lineWidth: nil, value: max(progress, 0.027), cancelEnabled: false, animateRotation: true), completion: {})
default:
break
}
@ -1667,7 +1716,10 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
var leftInset: CGFloat = 50.0
if let iconImageSize = self.iconImageSize {
leftInset = 9.0 + iconImageSize.width + 9.0
if case .progress = self.content {
} else {
leftInset = 9.0 + iconImageSize.width + 9.0
}
} else if let iconSize = preferredSize {
if iconSize.width > leftInset {
leftInset = iconSize.width - 8.0
@ -1802,8 +1854,13 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
iconSize = CGSize()
}
var isProgress = false
if case .progress = self.content {
isProgress = true
}
let iconFrame: CGRect
if self.iconImageSize != nil {
if self.iconImageSize != nil && !isProgress {
iconFrame = CGRect(origin: CGPoint(x: 9.0, y: floor((contentHeight - iconSize.height) / 2.0) + verticalOffset), size: iconSize)
} else {
iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0) + verticalOffset), size: iconSize)
@ -1885,13 +1942,17 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
}
transition.updateFrame(node: statusNode, frame: statusFrame)
if !self.didStartStatusNode {
let statusColor: UIColor
if case .starsSent = self.content {
statusColor = self.undoTextColor
if case .progress = self.content {
} else {
statusColor = .white
let statusColor: UIColor
if case .starsSent = self.content {
statusColor = self.undoTextColor
} else {
statusColor = .white
}
statusNode.transitionToState(.secretTimeout(color: statusColor, icon: .none, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {})
}
statusNode.transitionToState(.secretTimeout(color: statusColor, icon: .none, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {})
self.didStartStatusNode = true
}
}

View File

@ -71,7 +71,7 @@ public enum ParsedInternalPeerUrlParameter {
case channelMessage(Int32, Double?)
case replyThread(Int32, Int32)
case voiceChat(String?)
case appStart(String, String?, Bool)
case appStart(String, String?, ResolvedStartAppMode)
case story(Int32)
case boost
case text(String)
@ -293,18 +293,25 @@ public func parseInternalUrl(sharedContext: SharedAccountContext, query: String)
}
return .startAttach(peerName, value, choose)
} else if queryItem.name == "startapp" {
var compact = false
var mode: ResolvedStartAppMode = .generic
if let queryItems = components.queryItems {
for queryItem in queryItems {
if let value = queryItem.value {
if queryItem.name == "mode", value == "compact" {
compact = true
if queryItem.name == "mode" {
switch value {
case "compact":
mode = .compact
case "fullscreen":
mode = .fullscreen
default:
break
}
break
}
}
}
}
return .peer(.name(peerName), .appStart("", queryItem.value, compact))
return .peer(.name(peerName), .appStart("", queryItem.value, mode))
} else if queryItem.name == "story" {
if let id = Int32(value) {
return .peer(.name(peerName), .story(id))
@ -335,18 +342,25 @@ public func parseInternalUrl(sharedContext: SharedAccountContext, query: String)
} else if queryItem.name == "profile" {
return .peer(.name(peerName), .profile)
} else if queryItem.name == "startapp" {
var compact = false
var mode: ResolvedStartAppMode = .generic
if let queryItems = components.queryItems {
for queryItem in queryItems {
if let value = queryItem.value {
if queryItem.name == "mode", value == "compact" {
compact = true
if queryItem.name == "mode" {
switch value {
case "compact":
mode = .compact
case "fullscreen":
mode = .fullscreen
default:
break
}
break
}
}
}
}
return .peer(.name(peerName), .appStart("", nil, compact))
return .peer(.name(peerName), .appStart("", queryItem.value, mode))
}
}
}
@ -615,19 +629,28 @@ public func parseInternalUrl(sharedContext: SharedAccountContext, query: String)
} else if pathComponents.count == 2 {
let appName = pathComponents[1]
var startApp: String?
var compact = false
var mode: ResolvedStartAppMode = .generic
if let queryItems = components.queryItems {
for queryItem in queryItems {
if let value = queryItem.value {
if queryItem.name == "startapp" {
startApp = value
} else if queryItem.name == "mode", value == "compact" {
compact = true
}
if queryItem.name == "mode" {
switch value {
case "compact":
mode = .compact
case "fullscreen":
mode = .fullscreen
default:
break
}
break
}
}
}
}
return .peer(.name(peerName), .appStart(appName, startApp, compact))
return .peer(.name(peerName), .appStart(appName, startApp, mode))
} else {
return nil
}
@ -745,10 +768,10 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
}
}
}
case let .appStart(name, payload, compact):
case let .appStart(name, payload, mode):
if name.isEmpty {
if case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.hasWebApp) {
return .single(.result(.peer(peer._asPeer(), .withBotApp(ChatControllerInitialBotAppStart(botApp: nil, payload: payload, justInstalled: false, compact: compact)))))
return .single(.result(.peer(peer._asPeer(), .withBotApp(ChatControllerInitialBotAppStart(botApp: nil, payload: payload, justInstalled: false, mode: mode)))))
} else {
return .single(.result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil))))
}
@ -760,7 +783,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
}
|> mapToSignal { botApp -> Signal<ResolveInternalUrlResult, NoError> in
if let botApp {
return .single(.result(.peer(peer._asPeer(), .withBotApp(ChatControllerInitialBotAppStart(botApp: botApp, payload: payload, justInstalled: false, compact: compact)))))
return .single(.result(.peer(peer._asPeer(), .withBotApp(ChatControllerInitialBotAppStart(botApp: botApp, payload: payload, justInstalled: false, mode: mode)))))
} else {
return .single(.result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil))))
}

View File

@ -0,0 +1,75 @@
import Foundation
import SwiftSignalKit
final class FileDownload: NSObject, URLSessionDownloadDelegate {
private let fileSize: Int64?
private var urlSession: URLSession!
private var completion: ((URL?, Error?) -> Void)?
private var progressHandler: ((Double) -> Void)?
init(from url: URL, fileSize: Int64?, progressHandler: @escaping (Double) -> Void, completion: @escaping (URL?, Error?) -> Void) {
self.progressHandler = progressHandler
self.fileSize = fileSize
self.completion = completion
super.init()
let configuration = URLSessionConfiguration.default
urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
let downloadTask = self.urlSession.downloadTask(with: url)
downloadTask.resume()
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
var totalBytesExpectedToWrite = totalBytesExpectedToWrite
if totalBytesExpectedToWrite == -1, let fileSize = self.fileSize {
totalBytesExpectedToWrite = fileSize
}
let progress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
progressHandler?(progress)
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
completion?(location, nil)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let error = error {
completion?(nil, error)
}
}
static func getFileSize(url: String) -> Signal<Int64?, NoError> {
if #available(iOS 13.0, *) {
guard let url = URL(string: url) else {
return .single(nil)
}
var request = URLRequest(url: url)
request.httpMethod = "HEAD"
return Signal { subscriber in
let task = URLSession.shared.dataTask(with: request) { _, response, error in
if let _ = error {
subscriber.putNext(nil)
subscriber.putCompletion()
return
}
var fileSize: Int64?
if let httpResponse = response as? HTTPURLResponse, let contentLength = httpResponse.value(forHTTPHeaderField: "Content-Length"), let size = Int64(contentLength) {
fileSize = size
}
subscriber.putNext(fileSize)
subscriber.putCompletion()
}
task.resume()
return ActionDisposable {
task.cancel()
}
}
} else {
return .single(nil)
}
}
}

View File

@ -400,7 +400,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
controller.dismiss()
return
}
let _ = (self.context.engine.messages.requestAppWebView(peerId: peer.id, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: appStart.payload, themeParams: generateWebAppThemeParams(self.presentationData.theme), compact: appStart.compact, allowWrite: true)
let _ = (self.context.engine.messages.requestAppWebView(peerId: peer.id, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: appStart.payload, themeParams: generateWebAppThemeParams(self.presentationData.theme), compact: appStart.mode == .compact, fullscreen: appStart.mode == .fullscreen, allowWrite: true)
|> deliverOnMainQueue).startStandalone(next: { [weak self] result in
guard let self, let parsedUrl = URL(string: result.url) else {
return
@ -626,6 +626,69 @@ public final class WebAppController: ViewController, AttachmentContainable {
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: navigationBarHeight)))
transition.updateFrame(node: self.topOverscrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -1000.0), size: CGSize(width: layout.size.width, height: 1000.0)))
var contentTopInset: CGFloat = 0.0
if controller.isFullscreen {
var added = false
let fullscreenControls: ComponentView<Empty>
if let current = self.fullscreenControls {
fullscreenControls = current
} else {
fullscreenControls = ComponentView<Empty>()
self.fullscreenControls = fullscreenControls
added = true
}
let controlsMargin: CGFloat = 8.0
let componentTransition: ComponentTransition = added ? .immediate : ComponentTransition(transition)
let controlsSize = fullscreenControls.update(
transition: componentTransition,
component: AnyComponent(
FullscreenControlsComponent(
context: self.context,
title: controller.botName,
isVerified: controller.botVerified,
insets: UIEdgeInsets(top: 0.0, left: layout.safeInsets.left, bottom: 0.0, right: layout.safeInsets.right),
hasBack: self.hasBackButton,
backPressed: { [weak self] in
guard let self else {
return
}
self.controller?.cancelPressed()
},
minimizePressed: { [weak self] in
guard let self else {
return
}
self.controller?.requestMinimize(topEdgeOffset: nil, initialVelocity: nil)
},
morePressed: { [weak self] node, gesture in
guard let self else {
return
}
self.controller?.morePressed(node: node, gesture: gesture)
}
)
),
environment: {},
containerSize: layout.size
)
if let view = fullscreenControls.view {
if view.superview == nil {
self.view.addSubview(view)
}
transition.updateFrame(view: view, frame: CGRect(origin: CGPoint(x: 0.0, y: (layout.statusBarHeight ?? 0.0) + controlsMargin), size: controlsSize))
if added {
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
}
}
contentTopInset = controlsSize.height + controlsMargin * 2.0
} else if let fullscreenControls = self.fullscreenControls {
self.fullscreenControls = nil
fullscreenControls.view?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
fullscreenControls.view?.removeFromSuperview()
})
}
if let webView = self.webView {
var scrollInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0)
var frameBottomInset: CGFloat = 0.0
@ -683,6 +746,10 @@ public final class WebAppController: ViewController, AttachmentContainable {
if let controller = self.controller {
webView.updateMetrics(height: viewportFrame.height, isExpanded: controller.isContainerExpanded(), isStable: !controller.isContainerPanning(), transition: transition)
let contentInsetsData = "{top:\(contentTopInset), bottom:0.0, left:0.0, right:0.0}"
webView.sendEvent(name: "content_safe_area_changed", data: contentInsetsData)
if self.updateWebViewWhenStable && !controller.isContainerPanning() {
self.updateWebViewWhenStable = false
webView.setNeedsLayout()
@ -710,66 +777,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
placeholderNode.updateAbsoluteRect(placeholderFrame, within: layout.size)
}
if controller.isFullscreen {
var added = false
let fullscreenControls: ComponentView<Empty>
if let current = self.fullscreenControls {
fullscreenControls = current
} else {
fullscreenControls = ComponentView<Empty>()
self.fullscreenControls = fullscreenControls
added = true
}
let componentTransition: ComponentTransition = added ? .immediate : ComponentTransition(transition)
let controlsSize = fullscreenControls.update(
transition: componentTransition,
component: AnyComponent(
FullscreenControlsComponent(
context: self.context,
title: controller.botName,
isVerified: controller.botVerified,
insets: UIEdgeInsets(top: 0.0, left: layout.safeInsets.left, bottom: 0.0, right: layout.safeInsets.right),
hasBack: self.hasBackButton,
backPressed: { [weak self] in
guard let self else {
return
}
self.controller?.cancelPressed()
},
minimizePressed: { [weak self] in
guard let self else {
return
}
self.controller?.requestMinimize(topEdgeOffset: nil, initialVelocity: nil)
},
morePressed: { [weak self] node, gesture in
guard let self else {
return
}
self.controller?.morePressed(node: node, gesture: gesture)
}
)
),
environment: {},
containerSize: layout.size
)
if let view = fullscreenControls.view {
if view.superview == nil {
self.view.addSubview(view)
}
transition.updateFrame(view: view, frame: CGRect(origin: CGPoint(x: 0.0, y: (layout.statusBarHeight ?? 0.0) + 8.0), size: controlsSize))
if added {
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
}
}
} else if let fullscreenControls = self.fullscreenControls {
self.fullscreenControls = nil
fullscreenControls.view?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
fullscreenControls.view?.removeFromSuperview()
})
}
if let previousLayout = previousLayout, (previousLayout.inputHeight ?? 0.0).isZero, let inputHeight = layout.inputHeight, inputHeight > 44.0 {
Queue.mainQueue().justDispatch {
self.controller?.requestAttachmentMenuExpansion()
@ -891,6 +898,8 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.requestLayout(transition: .immediate)
case "web_app_request_safe_area":
self.requestLayout(transition: .immediate)
case "web_app_request_content_safe_area":
self.requestLayout(transition: .immediate)
case "web_app_request_theme":
self.sendThemeChangedEvent()
case "web_app_expand":
@ -1370,13 +1379,24 @@ public final class WebAppController: ViewController, AttachmentContainable {
case "web_app_add_to_home_screen":
self.addToHomeScreen()
case "web_app_check_home_screen":
self.webView?.sendEvent(name: "home_screen_checked", data: "{status: \"unknown\"}")
let data: JSON = ["status": "unknown"]
self.webView?.sendEvent(name: "home_screen_checked", data: data.string)
case "web_app_request_location":
self.requestLocation()
case "web_app_check_location":
self.checkLocation()
case "web_app_open_location_settings":
break
case "web_app_send_prepared_message":
if let json = json, let id = json["id"] as? String {
self.sendPreparedMessage(id: id)
}
case "web_app_request_emoji_status_access":
self.requestEmojiStatusAccess()
case "web_app_request_file_download":
if let json = json, let url = json["url"] as? String, let fileName = json["file_name"] as? String {
self.downloadFile(url: url, fileName: fileName)
}
default:
break
}
@ -1612,13 +1632,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
}
fileprivate func shareAccountContact() {
if "".isEmpty, let controller = self.controller {
let previewController = WebAppMessagePreviewScreen(context: controller.context, completion: { _ in })
previewController.navigationPresentation = .flatModal
controller.parentController()?.push(previewController)
return
}
guard let context = self.controller?.context, let botId = self.controller?.botId, let botName = self.controller?.botName else {
return
}
@ -2120,68 +2133,147 @@ public final class WebAppController: ViewController, AttachmentContainable {
}
}
fileprivate func setEmojiStatus(_ fileId: Int64, expirationDate: Int32? = nil) {
fileprivate func sendPreparedMessage(id: String) {
guard let controller = self.controller else {
return
}
let botName = controller.botName
if let _ = expirationDate {
let _ = combineLatest(
queue: Queue.mainQueue(),
self.context.engine.stickers.resolveInlineStickers(fileIds: [fileId]),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId)),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: controller.botId))
).start(next: { [weak self] files, accountPeer, botPeer in
guard let self, let accountPeer, let controller = self.controller else {
let _ = (self.context.engine.messages.getPreparedInlineMessage(botId: controller.botId, id: id)
|> deliverOnMainQueue).start(next: { [weak self, weak controller] preparedMessage in
guard let self, let controller, let preparedMessage else {
self?.webView?.sendEvent(name: "prepared_message_failed", data: "{error: \"MESSAGE_EXPIRED\"}")
return
}
let previewController = WebAppMessagePreviewScreen(context: controller.context, botName: controller.botName, preparedMessage: preparedMessage, completion: { [weak self] result in
guard let self else {
return
}
guard let file = files[fileId] else {
self.webView?.sendEvent(name: "emoji_status_failed", data: "{error: \"SUGGESTED_EMOJI_INVALID\"}")
return
if result {
self.webView?.sendEvent(name: "prepared_message_sent", data: nil)
} else {
self.webView?.sendEvent(name: "prepared_message_failed", data: "{error: \"USER_DECLINED\"}")
}
let confirmController = WebAppSetEmojiStatusScreen(
context: self.context,
botName: controller.botName,
accountPeer: accountPeer,
file: file,
completion: { [weak self, weak controller] result in
guard let self else {
return
}
if result {
let _ = (self.context.engine.accountData.setEmojiStatus(file: file, expirationDate: expirationDate)
|> deliverOnMainQueue).start(completed: { [weak self] in
self?.webView?.sendEvent(name: "emoji_status_set", data: nil)
})
//TODO:localize
let resultController = UndoOverlayController(
presentationData: self.presentationData,
content: .sticker(context: context, file: file, loop: false, title: nil, text: "Your emoji status updated.", undoText: nil, customAction: nil),
elevatedLayout: true,
action: { action in
if case .undo = action {
}
return true
}
)
controller?.present(resultController, in: .window(.root))
} else {
self.webView?.sendEvent(name: "emoji_status_failed", data: "{error: \"USER_DECLINED\"}")
}
}
)
controller.parentController()?.push(confirmController)
})
previewController.navigationPresentation = .flatModal
controller.parentController()?.push(previewController)
})
}
fileprivate func downloadFile(url: String, fileName: String) {
guard let controller = self.controller else {
return
}
var title: String?
let photoExtensions = [".jpg", ".png", ".gif", ".tiff"]
let videoExtensions = [".mp4", ".mov"]
let lowercasedFilename = fileName.lowercased()
for ext in photoExtensions {
if lowercasedFilename.hasSuffix(ext) {
title = "Download Photo"
break
}
}
if title == nil {
for ext in videoExtensions {
if lowercasedFilename.hasSuffix(ext) {
title = "Download Video"
break
}
}
}
if title == nil {
title = "Download Document"
}
let _ = (FileDownload.getFileSize(url: url)
|> deliverOnMainQueue).start(next: { [weak self] fileSize in
guard let self else {
return
}
var fileSizeString = ""
if let fileSize {
fileSizeString = " (\(dataSizeString(fileSize, formatting: DataSizeStringFormatting(presentationData: self.presentationData))))"
}
let text: String = "**\(controller.botName)** suggests you to download **\(fileName)**\(fileSizeString)."
let alertController = standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: title, text: text, actions: [
TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: { [weak self] in
self?.webView?.sendEvent(name: "file_download_requested", data: "{status: \"cancelled\"}")
}),
TextAlertAction(type: .defaultAction, title: "Download", action: { [weak self] in
self?.startDownload(url: url, fileName: fileName, fileSize: fileSize)
})
], parseMarkdown: true)
controller.present(alertController, in: .window(.root))
})
}
private var fileDownload: FileDownload?
private weak var fileDownloadTooltip: UndoOverlayController?
fileprivate func startDownload(url: String, fileName: String, fileSize: Int64?) {
guard let controller = self.controller else {
return
}
self.webView?.sendEvent(name: "file_download_requested", data: "{status: \"downloading\"}")
self.fileDownload = FileDownload(
from: URL(string: url)!,
fileSize: fileSize,
progressHandler: { [weak self] progress in
guard let self else {
return
}
let text: String
if let fileSize {
let downloadedSize = Int64(Double(fileSize) * progress)
text = "\(dataSizeString(downloadedSize, formatting: DataSizeStringFormatting(presentationData: self.presentationData))) / \(dataSizeString(fileSize, formatting: DataSizeStringFormatting(presentationData: self.presentationData)))"
} else {
text = "\(Int32(progress))%"
}
self.fileDownloadTooltip?.content = .progress(
progress: progress,
title: fileName,
text: text,
undoText: "Cancel"
)
},
completion: { resultUrl, _ in
}
)
let text: String
if let fileSize {
text = "0 KB / \(dataSizeString(fileSize, formatting: DataSizeStringFormatting(presentationData: self.presentationData)))"
} else {
text = "0%"
}
let tooltipController = UndoOverlayController(
presentationData: self.presentationData,
content: .progress(
progress: 0.0,
title: fileName,
text: text,
undoText: "Cancel"
),
elevatedLayout: false,
position: .top,
action: { _ in
return true
}
)
controller.present(tooltipController, in: .window(.root))
self.fileDownloadTooltip = tooltipController
}
fileprivate func requestEmojiStatusAccess() {
guard let controller = self.controller else {
return
}
let _ = combineLatest(
queue: Queue.mainQueue(),
self.context.engine.stickers.resolveInlineStickers(fileIds: [fileId]),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId)),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: controller.botId)),
self.context.engine.stickers.loadedStickerPack(reference: .iconStatusEmoji, forceActualized: false)
@ -2194,7 +2286,62 @@ public final class WebAppController: ViewController, AttachmentContainable {
}
}
|> take(1)
).start(next: { [weak self] files, accountPeer, botPeer, iconStatusEmoji in
).start(next: { [weak self] accountPeer, botPeer, iconStatusEmoji in
guard let self, let accountPeer, let controller = self.controller else {
return
}
let alertController = webAppEmojiStatusAlertController(
context: self.context,
accountPeer: accountPeer,
botName: controller.botName,
icons: iconStatusEmoji,
completion: { [weak self] result in
guard let self, let controller = self.controller else {
return
}
if result {
let context = self.context
let botId = controller.botId
let _ = (context.engine.peers.toggleBotEmojiStatusAccess(peerId: botId, enabled: true)
|> deliverOnMainQueue).startStandalone(completed: { [weak self] in
self?.webView?.sendEvent(name: "emoji_status_access_requested", data: "{status: \"allowed\"}")
})
//TODO:localize
if let botPeer {
let resultController = UndoOverlayController(
presentationData: presentationData,
content: .invitedToVoiceChat(context: self.context, peer: botPeer, title: nil, text: "**\(controller.botName)** can now set your emoji status anytime.", action: "Undo", duration: 5.0),
elevatedLayout: true,
action: { action in
if case .undo = action {
let _ = (context.engine.peers.toggleBotEmojiStatusAccess(peerId: botId, enabled: false)
|> deliverOnMainQueue).startStandalone()
}
return true
}
)
controller.present(resultController, in: .window(.root))
}
} else {
self.webView?.sendEvent(name: "emoji_status_access_requested", data: "{status: \"cancelled\"}")
}
}
)
controller.present(alertController, in: .window(.root))
})
}
fileprivate func setEmojiStatus(_ fileId: Int64, expirationDate: Int32? = nil) {
guard let controller = self.controller else {
return
}
let _ = combineLatest(
queue: Queue.mainQueue(),
self.context.engine.stickers.resolveInlineStickers(fileIds: [fileId]),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId)),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: controller.botId))
).start(next: { [weak self] files, accountPeer, botPeer in
guard let self, let accountPeer, let controller = self.controller else {
return
}
@ -2202,12 +2349,11 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.webView?.sendEvent(name: "emoji_status_failed", data: "{error: \"SUGGESTED_EMOJI_INVALID\"}")
return
}
let alertController = webAppEmojiStatusAlertController(
let confirmController = WebAppSetEmojiStatusScreen(
context: self.context,
botName: controller.botName,
accountPeer: accountPeer,
botName: botName,
icons: iconStatusEmoji,
expirationDate: expirationDate,
file: file,
completion: { [weak self, weak controller] result in
guard let self else {
return
@ -2218,26 +2364,24 @@ public final class WebAppController: ViewController, AttachmentContainable {
self?.webView?.sendEvent(name: "emoji_status_set", data: nil)
})
//TODO:localize
if let botPeer {
let resultController = UndoOverlayController(
presentationData: presentationData,
content: .invitedToVoiceChat(context: context, peer: botPeer, title: nil, text: "**\(botName)** can now set your emoji status anytime.", action: "Undo", duration: 5.0),
elevatedLayout: true,
action: { action in
if case .undo = action {
}
return true
let resultController = UndoOverlayController(
presentationData: self.presentationData,
content: .sticker(context: context, file: file, loop: false, title: nil, text: "Your emoji status updated.", undoText: nil, customAction: nil),
elevatedLayout: true,
action: { action in
if case .undo = action {
}
)
controller?.present(resultController, in: .window(.root))
}
return true
}
)
controller?.present(resultController, in: .window(.root))
} else {
self.webView?.sendEvent(name: "emoji_status_failed", data: "{error: \"USER_DECLINED\"}")
}
}
)
controller.present(alertController, in: .window(.root))
controller.parentController()?.push(confirmController)
})
}

View File

@ -332,7 +332,6 @@ func webAppEmojiStatusAlertController(
accountPeer: EnginePeer,
botName: String,
icons: [TelegramMediaFile],
expirationDate: Int32?,
completion: @escaping (Bool) -> Void
) -> AlertController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }

View File

@ -26,13 +26,19 @@ private final class SheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let botName: String
let preparedMessage: PreparedInlineMessage
let dismiss: () -> Void
init(
context: AccountContext,
botName: String,
preparedMessage: PreparedInlineMessage,
dismiss: @escaping () -> Void
) {
self.context = context
self.botName = botName
self.preparedMessage = preparedMessage
self.dismiss = dismiss
}
@ -225,11 +231,17 @@ private final class WebAppMessagePreviewSheetComponent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
private let context: AccountContext
private let botName: String
private let preparedMessage: PreparedInlineMessage
init(
context: AccountContext
context: AccountContext,
botName: String,
preparedMessage: PreparedInlineMessage
) {
self.context = context
self.botName = botName
self.preparedMessage = preparedMessage
}
static func ==(lhs: WebAppMessagePreviewSheetComponent, rhs: WebAppMessagePreviewSheetComponent) -> Bool {
@ -252,6 +264,8 @@ private final class WebAppMessagePreviewSheetComponent: CombinedComponent {
component: SheetComponent<EnvironmentType>(
content: AnyComponent<EnvironmentType>(SheetContent(
context: context.component.context,
botName: context.component.botName,
preparedMessage: context.component.preparedMessage,
dismiss: {
animateOut.invoke(Action { _ in
if let controller = controller() {
@ -307,6 +321,8 @@ public final class WebAppMessagePreviewScreen: ViewControllerComponentContainer
public init(
context: AccountContext,
botName: String,
preparedMessage: PreparedInlineMessage,
completion: @escaping (Bool) -> Void
) {
self.context = context
@ -315,7 +331,9 @@ public final class WebAppMessagePreviewScreen: ViewControllerComponentContainer
super.init(
context: context,
component: WebAppMessagePreviewSheetComponent(
context: context
context: context,
botName: botName,
preparedMessage: preparedMessage
),
navigationBarAppearance: .none,
statusBarStyle: .ignore,