mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Add support for app ads
This commit is contained in:
@@ -10497,3 +10497,8 @@ Sorry for the inconvenience.";
|
||||
"Stats.StoryReactionsByEmotionTitle" = "STORIES REACTIONS BY EMOTION";
|
||||
|
||||
"Stats.MessageReactionsTitle" = "REACTIONS";
|
||||
|
||||
"Conversation.LaunchApp" = "LAUNCH APP";
|
||||
|
||||
"Message.AdSponsoredLabel" = "Sponsored";
|
||||
"Message.AdRecommendedLabel" = "Recommended";
|
||||
|
||||
@@ -797,7 +797,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-651419003] = { return Api.SendMessageAction.parse_speakingInGroupCallAction($0) }
|
||||
dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) }
|
||||
dict[-2010155333] = { return Api.SimpleWebViewResult.parse_simpleWebViewResultUrl($0) }
|
||||
dict[-626000021] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[-313293833] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[1035529315] = { return Api.SponsoredWebPage.parse_sponsoredWebPage($0) }
|
||||
dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) }
|
||||
dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) }
|
||||
|
||||
@@ -434,13 +434,13 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
indirect enum SponsoredMessage: TypeConstructorDescription {
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer?, chatInvite: Api.ChatInvite?, chatInviteHash: String?, channelPost: Int32?, startParam: String?, webpage: Api.SponsoredWebPage?, message: String, entities: [Api.MessageEntity]?, sponsorInfo: String?, additionalInfo: String?)
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer?, chatInvite: Api.ChatInvite?, chatInviteHash: String?, channelPost: Int32?, startParam: String?, webpage: Api.SponsoredWebPage?, app: Api.BotApp?, message: String, entities: [Api.MessageEntity]?, buttonText: String?, sponsorInfo: String?, additionalInfo: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let webpage, let message, let entities, let sponsorInfo, let additionalInfo):
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let webpage, let app, let message, let entities, let buttonText, let sponsorInfo, let additionalInfo):
|
||||
if boxed {
|
||||
buffer.appendInt32(-626000021)
|
||||
buffer.appendInt32(-313293833)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeBytes(randomId, buffer: buffer, boxed: false)
|
||||
@@ -450,12 +450,14 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(channelPost!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 9) != 0 {webpage!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 10) != 0 {app!.serialize(buffer, true)}
|
||||
serializeString(message, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(entities!.count))
|
||||
for item in entities! {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 11) != 0 {serializeString(buttonText!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 7) != 0 {serializeString(sponsorInfo!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeString(additionalInfo!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
@@ -464,8 +466,8 @@ public extension Api {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let webpage, let message, let entities, let sponsorInfo, let additionalInfo):
|
||||
return ("sponsoredMessage", [("flags", flags as Any), ("randomId", randomId as Any), ("fromId", fromId as Any), ("chatInvite", chatInvite as Any), ("chatInviteHash", chatInviteHash as Any), ("channelPost", channelPost as Any), ("startParam", startParam as Any), ("webpage", webpage as Any), ("message", message as Any), ("entities", entities as Any), ("sponsorInfo", sponsorInfo as Any), ("additionalInfo", additionalInfo as Any)])
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let webpage, let app, let message, let entities, let buttonText, let sponsorInfo, let additionalInfo):
|
||||
return ("sponsoredMessage", [("flags", flags as Any), ("randomId", randomId as Any), ("fromId", fromId as Any), ("chatInvite", chatInvite as Any), ("chatInviteHash", chatInviteHash as Any), ("channelPost", channelPost as Any), ("startParam", startParam as Any), ("webpage", webpage as Any), ("app", app as Any), ("message", message as Any), ("entities", entities as Any), ("buttonText", buttonText as Any), ("sponsorInfo", sponsorInfo as Any), ("additionalInfo", additionalInfo as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,16 +494,22 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() {
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.SponsoredWebPage
|
||||
} }
|
||||
var _9: String?
|
||||
_9 = parseString(reader)
|
||||
var _10: [Api.MessageEntity]?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
|
||||
_10 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
var _9: Api.BotApp?
|
||||
if Int(_1!) & Int(1 << 10) != 0 {if let signature = reader.readInt32() {
|
||||
_9 = Api.parse(reader, signature: signature) as? Api.BotApp
|
||||
} }
|
||||
var _10: String?
|
||||
_10 = parseString(reader)
|
||||
var _11: [Api.MessageEntity]?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
|
||||
_11 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
} }
|
||||
var _11: String?
|
||||
if Int(_1!) & Int(1 << 7) != 0 {_11 = parseString(reader) }
|
||||
var _12: String?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_12 = parseString(reader) }
|
||||
if Int(_1!) & Int(1 << 11) != 0 {_12 = parseString(reader) }
|
||||
var _13: String?
|
||||
if Int(_1!) & Int(1 << 7) != 0 {_13 = parseString(reader) }
|
||||
var _14: String?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_14 = parseString(reader) }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 3) == 0) || _3 != nil
|
||||
@@ -510,12 +518,14 @@ public extension Api {
|
||||
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 0) == 0) || _7 != nil
|
||||
let _c8 = (Int(_1!) & Int(1 << 9) == 0) || _8 != nil
|
||||
let _c9 = _9 != nil
|
||||
let _c10 = (Int(_1!) & Int(1 << 1) == 0) || _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 8) == 0) || _12 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, fromId: _3, chatInvite: _4, chatInviteHash: _5, channelPost: _6, startParam: _7, webpage: _8, message: _9!, entities: _10, sponsorInfo: _11, additionalInfo: _12)
|
||||
let _c9 = (Int(_1!) & Int(1 << 10) == 0) || _9 != nil
|
||||
let _c10 = _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 1) == 0) || _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 11) == 0) || _12 != nil
|
||||
let _c13 = (Int(_1!) & Int(1 << 7) == 0) || _13 != nil
|
||||
let _c14 = (Int(_1!) & Int(1 << 8) == 0) || _14 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, fromId: _3, chatInvite: _4, chatInviteHash: _5, channelPost: _6, startParam: _7, webpage: _8, app: _9, message: _10!, entities: _11, buttonText: _12, sponsorInfo: _13, additionalInfo: _14)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
||||
@@ -11,20 +11,23 @@ public final class AdMessageAttribute: MessageAttribute {
|
||||
case peer(id: EnginePeer.Id, message: EngineMessage.Id?, startParam: String?)
|
||||
case join(title: String, joinHash: String)
|
||||
case webPage(title: String, url: String)
|
||||
case botApp(peerId: EnginePeer.Id, app: BotApp, startParam: String?)
|
||||
}
|
||||
|
||||
public let opaqueId: Data
|
||||
public let messageType: MessageType
|
||||
public let displayAvatar: Bool
|
||||
public let target: MessageTarget
|
||||
public let buttonText: String?
|
||||
public let sponsorInfo: String?
|
||||
public let additionalInfo: String?
|
||||
|
||||
public init(opaqueId: Data, messageType: MessageType, displayAvatar: Bool, target: MessageTarget, sponsorInfo: String?, additionalInfo: String?) {
|
||||
public init(opaqueId: Data, messageType: MessageType, displayAvatar: Bool, target: MessageTarget, buttonText: String?, sponsorInfo: String?, additionalInfo: String?) {
|
||||
self.opaqueId = opaqueId
|
||||
self.messageType = messageType
|
||||
self.displayAvatar = displayAvatar
|
||||
self.target = target
|
||||
self.buttonText = buttonText
|
||||
self.sponsorInfo = sponsorInfo
|
||||
self.additionalInfo = additionalInfo
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
case target
|
||||
case messageId
|
||||
case startParam
|
||||
case buttonText
|
||||
case sponsorInfo
|
||||
case additionalInfo
|
||||
}
|
||||
@@ -33,6 +34,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
case peer
|
||||
case invite
|
||||
case webPage
|
||||
case botApp
|
||||
}
|
||||
|
||||
struct Invite: Equatable, Codable {
|
||||
@@ -78,11 +80,14 @@ private class AdMessagesHistoryContextImpl {
|
||||
case peer(PeerId)
|
||||
case invite(Invite)
|
||||
case webPage(WebPage)
|
||||
case botApp(PeerId, BotApp)
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
if let peer = try container.decodeIfPresent(Int64.self, forKey: .peer) {
|
||||
if let botApp = try container.decodeIfPresent(BotApp.self, forKey: .botApp), let peer = try container.decodeIfPresent(Int64.self, forKey: .peer) {
|
||||
self = .botApp(PeerId(peer), botApp)
|
||||
} else if let peer = try container.decodeIfPresent(Int64.self, forKey: .peer) {
|
||||
self = .peer(PeerId(peer))
|
||||
} else if let invite = try container.decodeIfPresent(Invite.self, forKey: .invite) {
|
||||
self = .invite(invite)
|
||||
@@ -103,6 +108,9 @@ private class AdMessagesHistoryContextImpl {
|
||||
try container.encode(invite, forKey: .invite)
|
||||
case let .webPage(webPage):
|
||||
try container.encode(webPage, forKey: .webPage)
|
||||
case let .botApp(peerId, botApp):
|
||||
try container.encode(peerId.toInt64(), forKey: .peer)
|
||||
try container.encode(botApp, forKey: .botApp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +124,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
public let target: Target
|
||||
public let messageId: MessageId?
|
||||
public let startParam: String?
|
||||
public let buttonText: String?
|
||||
public let sponsorInfo: String?
|
||||
public let additionalInfo: String?
|
||||
|
||||
@@ -129,6 +138,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
target: Target,
|
||||
messageId: MessageId?,
|
||||
startParam: String?,
|
||||
buttonText: String?,
|
||||
sponsorInfo: String?,
|
||||
additionalInfo: String?
|
||||
) {
|
||||
@@ -141,6 +151,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
self.target = target
|
||||
self.messageId = messageId
|
||||
self.startParam = startParam
|
||||
self.buttonText = buttonText
|
||||
self.sponsorInfo = sponsorInfo
|
||||
self.additionalInfo = additionalInfo
|
||||
}
|
||||
@@ -169,6 +180,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
self.target = try container.decode(Target.self, forKey: .target)
|
||||
self.messageId = try container.decodeIfPresent(MessageId.self, forKey: .messageId)
|
||||
self.startParam = try container.decodeIfPresent(String.self, forKey: .startParam)
|
||||
self.buttonText = try container.decodeIfPresent(String.self, forKey: .buttonText)
|
||||
|
||||
self.sponsorInfo = try container.decodeIfPresent(String.self, forKey: .sponsorInfo)
|
||||
self.additionalInfo = try container.decodeIfPresent(String.self, forKey: .additionalInfo)
|
||||
@@ -193,6 +205,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
try container.encode(self.target, forKey: .target)
|
||||
try container.encodeIfPresent(self.messageId, forKey: .messageId)
|
||||
try container.encodeIfPresent(self.startParam, forKey: .startParam)
|
||||
try container.encodeIfPresent(self.buttonText, forKey: .buttonText)
|
||||
|
||||
try container.encodeIfPresent(self.sponsorInfo, forKey: .sponsorInfo)
|
||||
try container.encodeIfPresent(self.additionalInfo, forKey: .additionalInfo)
|
||||
@@ -228,6 +241,9 @@ private class AdMessagesHistoryContextImpl {
|
||||
if lhs.startParam != rhs.startParam {
|
||||
return false
|
||||
}
|
||||
if lhs.buttonText != rhs.buttonText {
|
||||
return false
|
||||
}
|
||||
if lhs.sponsorInfo != rhs.sponsorInfo {
|
||||
return false
|
||||
}
|
||||
@@ -248,6 +264,8 @@ private class AdMessagesHistoryContextImpl {
|
||||
target = .join(title: invite.title, joinHash: invite.joinHash)
|
||||
case let .webPage(webPage):
|
||||
target = .webPage(title: webPage.title, url: webPage.url)
|
||||
case let .botApp(peerId, botApp):
|
||||
target = .botApp(peerId: peerId, app: botApp, startParam: self.startParam)
|
||||
}
|
||||
let mappedMessageType: AdMessageAttribute.MessageType
|
||||
switch self.messageType {
|
||||
@@ -256,7 +274,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
case .recommended:
|
||||
mappedMessageType = .recommended
|
||||
}
|
||||
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, messageType: mappedMessageType, displayAvatar: self.displayAvatar, target: target, sponsorInfo: self.sponsorInfo, additionalInfo: self.additionalInfo))
|
||||
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, messageType: mappedMessageType, displayAvatar: self.displayAvatar, target: target, buttonText: self.buttonText, sponsorInfo: self.sponsorInfo, additionalInfo: self.additionalInfo))
|
||||
if !self.textEntities.isEmpty {
|
||||
let attribute = TextEntitiesMessageAttribute(entities: self.textEntities)
|
||||
attributes.append(attribute)
|
||||
@@ -270,7 +288,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
|
||||
let author: Peer
|
||||
switch self.target {
|
||||
case let .peer(peerId):
|
||||
case let .peer(peerId), let .botApp(peerId, _):
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
author = peer
|
||||
} else {
|
||||
@@ -523,7 +541,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
|
||||
for message in messages {
|
||||
switch message {
|
||||
case let .sponsoredMessage(flags, randomId, fromId, chatInvite, chatInviteHash, channelPost, startParam, webPage, message, entities, sponsorInfo, additionalInfo):
|
||||
case let .sponsoredMessage(flags, randomId, fromId, chatInvite, chatInviteHash, channelPost, startParam, webPage, botApp, message, entities, buttonText, sponsorInfo, additionalInfo):
|
||||
var parsedEntities: [MessageTextEntity] = []
|
||||
if let entities = entities {
|
||||
parsedEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
@@ -534,7 +552,11 @@ private class AdMessagesHistoryContextImpl {
|
||||
|
||||
var target: CachedMessage.Target?
|
||||
if let fromId = fromId {
|
||||
if let botApp = botApp, let app = BotApp(apiBotApp: botApp) {
|
||||
target = .botApp(fromId.peerId, app)
|
||||
} else {
|
||||
target = .peer(fromId.peerId)
|
||||
}
|
||||
} else if let webPage = webPage {
|
||||
switch webPage {
|
||||
case let .sponsoredWebPage(_, url, siteName, photo):
|
||||
@@ -575,6 +597,9 @@ private class AdMessagesHistoryContextImpl {
|
||||
}
|
||||
}
|
||||
}
|
||||
// else if let botApp = app.flatMap({ BotApp(apiBotApp: $0) }) {
|
||||
// target = .botApp(botApp)
|
||||
// }
|
||||
|
||||
var messageId: MessageId?
|
||||
if let fromId = fromId, let channelPost = channelPost {
|
||||
@@ -592,6 +617,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
target: target,
|
||||
messageId: messageId,
|
||||
startParam: startParam,
|
||||
buttonText: buttonText,
|
||||
sponsorInfo: sponsorInfo,
|
||||
additionalInfo: additionalInfo
|
||||
))
|
||||
|
||||
@@ -776,3 +776,14 @@ func _internal_getBotApp(account: Account, reference: BotAppReference) -> Signal
|
||||
|> castError(GetBotAppError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
extension BotApp {
|
||||
convenience init?(apiBotApp: Api.BotApp) {
|
||||
switch apiBotApp {
|
||||
case let .botApp(_, id, accessHash, shortName, title, description, photo, document, hash):
|
||||
self.init(id: id, accessHash: accessHash, shortName: shortName, title: title, description: description, photo: telegramMediaImageFromApiPhoto(photo), document: document.flatMap(telegramMediaFileFromApiDocument), hash: hash, flags: [])
|
||||
case .botAppNotModified:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,9 +479,12 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
}
|
||||
}
|
||||
} else if let adAttribute = item.message.adAttribute {
|
||||
//TODO:localize
|
||||
//Recommended?
|
||||
title = "Sponsored"
|
||||
switch adAttribute.messageType {
|
||||
case .sponsored:
|
||||
title = item.presentationData.strings.Message_AdSponsoredLabel
|
||||
case .recommended:
|
||||
title = item.presentationData.strings.Message_AdRecommendedLabel
|
||||
}
|
||||
subtitle = item.message.author.flatMap {
|
||||
NSAttributedString(string: EnginePeer($0).compactDisplayTitle, font: titleFont)
|
||||
}
|
||||
@@ -500,8 +503,14 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
}
|
||||
}
|
||||
|
||||
if let author = item.message.author as? TelegramUser, author.botInfo != nil {
|
||||
if let buttonText = adAttribute.buttonText {
|
||||
actionTitle = buttonText.uppercased()
|
||||
} else if let author = item.message.author as? TelegramUser, author.botInfo != nil {
|
||||
if case .botApp = adAttribute.target {
|
||||
actionTitle = item.presentationData.strings.Conversation_LaunchApp
|
||||
} else {
|
||||
actionTitle = item.presentationData.strings.Conversation_ViewBot
|
||||
}
|
||||
} else if let author = item.message.author as? TelegramChannel, case .group = author.info {
|
||||
if case let .peer(_, messageId, _) = adAttribute.target, messageId != nil {
|
||||
actionTitle = item.presentationData.strings.Conversation_ViewPost
|
||||
|
||||
@@ -4102,6 +4102,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.controllerInteraction?.openJoinLink(joinHash)
|
||||
case let .webPage(_, url):
|
||||
self.controllerInteraction?.openUrl(ChatControllerInteraction.OpenUrl(url: url, concealed: false, external: false))
|
||||
case let .botApp(peerId, botApp, startParam):
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
|
||||
if let self, let peer {
|
||||
self.presentBotApp(botApp: botApp, botPeer: peer, payload: startParam)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId in
|
||||
guard let self else {
|
||||
|
||||
Reference in New Issue
Block a user