Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Mikhail Filimonov
2025-03-17 21:31:53 +04:00
22 changed files with 1138 additions and 638 deletions

View File

@@ -517,19 +517,11 @@ private class AdMessagesHistoryContextImpl {
}
func markAsSeen(opaqueId: Data) {
let signal: Signal<Never, NoError> = account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(self.peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
guard let inputPeer else {
return .complete()
}
return self.account.network.request(Api.functions.messages.viewSponsoredMessage(peer: inputPeer, randomId: Buffer(data: opaqueId)))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> ignoreValues
let signal: Signal<Never, NoError> = self.account.network.request(Api.functions.messages.viewSponsoredMessage(randomId: Buffer(data: opaqueId)))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> ignoreValues
self.maskAsSeenDisposables.set(signal.start(), forKey: opaqueId)
}
@@ -610,25 +602,17 @@ public class AdMessagesHistoryContext {
func _internal_markAdAction(account: Account, peerId: EnginePeer.Id, opaqueId: Data, media: Bool, fullscreen: Bool) {
let signal: Signal<Never, NoError> = account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
var flags: Int32 = 0
if media {
flags |= (1 << 0)
}
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
guard let inputPeer else {
return .complete()
}
var flags: Int32 = 0
if media {
flags |= (1 << 0)
}
if fullscreen {
flags |= (1 << 1)
}
return account.network.request(Api.functions.messages.clickSponsoredMessage(flags: flags, peer: inputPeer, randomId: Buffer(data: opaqueId)))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> ignoreValues
if fullscreen {
flags |= (1 << 1)
}
let signal = account.network.request(Api.functions.messages.clickSponsoredMessage(flags: flags, randomId: Buffer(data: opaqueId)))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> ignoreValues
let _ = signal.start()
}

View File

@@ -565,7 +565,7 @@ func _internal_removeChatManagingBot(account: Account, chatId: EnginePeer.Id) ->
excludePeers: excludePeers,
exclude: connectedBot.recipients.exclude
),
canReply: connectedBot.canReply
rights: connectedBot.rights
))
} else {
return current

View File

@@ -764,6 +764,59 @@ extension TelegramBusinessIntro {
}
}
extension TelegramBusinessBotRights {
init(apiValue: Api.BusinessBotRights) {
var value: TelegramBusinessBotRights = []
switch apiValue {
case let .businessBotRights(flags):
if (flags & (1 << 0)) != 0 {
value.insert(.reply)
}
if (flags & (1 << 1)) != 0 {
value.insert(.readMessages)
}
if (flags & (1 << 2)) != 0 {
value.insert(.deleteSentMessages)
}
if (flags & (1 << 3)) != 0 {
value.insert(.deleteReceivedMessages)
}
if (flags & (1 << 4)) != 0 {
value.insert(.editName)
}
if (flags & (1 << 5)) != 0 {
value.insert(.editBio)
}
if (flags & (1 << 6)) != 0 {
value.insert(.editProfilePhoto)
}
if (flags & (1 << 7)) != 0 {
value.insert(.editUsername)
}
if (flags & (1 << 8)) != 0 {
value.insert(.viewGifts)
}
if (flags & (1 << 9)) != 0 {
value.insert(.sellGifts)
}
if (flags & (1 << 10)) != 0 {
value.insert(.changeGiftSettings)
}
if (flags & (1 << 11)) != 0 {
value.insert(.transferAndUpgradeGifts)
}
if (flags & (1 << 12)) != 0 {
value.insert(.transferStars)
}
if (flags & (1 << 13)) != 0 {
value.insert(.manageStories)
}
}
self = value
}
}
extension TelegramBusinessRecipients {
convenience init(apiValue: Api.BusinessRecipients) {
switch apiValue {
@@ -1021,12 +1074,12 @@ func _internal_updateBusinessIntro(account: Account, intro: TelegramBusinessIntr
public final class TelegramAccountConnectedBot: Codable, Equatable {
public let id: PeerId
public let recipients: TelegramBusinessRecipients
public let canReply: Bool
public let rights: TelegramBusinessBotRights
public init(id: PeerId, recipients: TelegramBusinessRecipients, canReply: Bool) {
public init(id: PeerId, recipients: TelegramBusinessRecipients, rights: TelegramBusinessBotRights) {
self.id = id
self.recipients = recipients
self.canReply = canReply
self.rights = rights
}
public static func ==(lhs: TelegramAccountConnectedBot, rhs: TelegramAccountConnectedBot) -> Bool {
@@ -1039,13 +1092,51 @@ public final class TelegramAccountConnectedBot: Codable, Equatable {
if lhs.recipients != rhs.recipients {
return false
}
if lhs.canReply != rhs.canReply {
if lhs.rights != rhs.rights {
return false
}
return true
}
}
public struct TelegramBusinessBotRights: OptionSet, Codable {
public var rawValue: Int32
public init() {
self.rawValue = 0
}
public init(rawValue: Int32) {
self.rawValue = rawValue
}
public static let reply = TelegramBusinessBotRights(rawValue: 1 << 0)
public static let readMessages = TelegramBusinessBotRights(rawValue: 1 << 1)
public static let deleteSentMessages = TelegramBusinessBotRights(rawValue: 1 << 2)
public static let deleteReceivedMessages = TelegramBusinessBotRights(rawValue: 1 << 3)
public static let editName = TelegramBusinessBotRights(rawValue: 1 << 4)
public static let editBio = TelegramBusinessBotRights(rawValue: 1 << 5)
public static let editProfilePhoto = TelegramBusinessBotRights(rawValue: 1 << 6)
public static let editUsername = TelegramBusinessBotRights(rawValue: 1 << 7)
public static let viewGifts = TelegramBusinessBotRights(rawValue: 1 << 8)
public static let sellGifts = TelegramBusinessBotRights(rawValue: 1 << 9)
public static let changeGiftSettings = TelegramBusinessBotRights(rawValue: 1 << 10)
public static let transferAndUpgradeGifts = TelegramBusinessBotRights(rawValue: 1 << 11)
public static let transferStars = TelegramBusinessBotRights(rawValue: 1 << 12)
public static let manageStories = TelegramBusinessBotRights(rawValue: 1 << 13)
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
let value = try? container.decode(Int32.self, forKey: "v")
self = TelegramBusinessBotRights(rawValue: value ?? 0)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encode(self.rawValue, forKey: "v")
}
}
public func _internal_setAccountConnectedBot(account: Account, bot: TelegramAccountConnectedBot?) -> Signal<Never, NoError> {
let remoteApply = account.postbox.transaction { transaction -> (Peer?, [Peer], [Peer]) in
guard let bot else {
@@ -1059,20 +1150,65 @@ public func _internal_setAccountConnectedBot(account: Account, bot: TelegramAcco
}
|> mapToSignal { botUser, additionalPeers, excludePeers in
var flags: Int32 = 0
var mappedRights: Api.BusinessBotRights?
var mappedBot: Api.InputUser = .inputUserEmpty
var mappedRecipients: Api.InputBusinessBotRecipients = .inputBusinessBotRecipients(flags: 0, users: nil, excludeUsers: nil)
if let bot, let inputBotUser = botUser.flatMap(apiInputUser) {
mappedBot = inputBotUser
if bot.canReply {
flags |= 1 << 0
flags |= 1 << 0
var rightsFlags: Int32 = 0
if bot.rights.contains(.reply) {
rightsFlags |= (1 << 0)
}
if bot.rights.contains(.readMessages) {
rightsFlags |= (1 << 1)
}
if bot.rights.contains(.deleteSentMessages) {
rightsFlags |= (1 << 2)
}
if bot.rights.contains(.deleteReceivedMessages) {
rightsFlags |= (1 << 3)
}
if bot.rights.contains(.editName) {
rightsFlags |= (1 << 4)
}
if bot.rights.contains(.editBio) {
rightsFlags |= (1 << 5)
}
if bot.rights.contains(.editProfilePhoto) {
rightsFlags |= (1 << 6)
}
if bot.rights.contains(.editUsername) {
rightsFlags |= (1 << 7)
}
if bot.rights.contains(.viewGifts) {
rightsFlags |= (1 << 8)
}
if bot.rights.contains(.sellGifts) {
rightsFlags |= (1 << 9)
}
if bot.rights.contains(.changeGiftSettings) {
rightsFlags |= (1 << 10)
}
if bot.rights.contains(.transferAndUpgradeGifts) {
rightsFlags |= (1 << 11)
}
if bot.rights.contains(.transferStars) {
rightsFlags |= (1 << 12)
}
if bot.rights.contains(.manageStories) {
rightsFlags |= (1 << 13)
}
mappedRights = .businessBotRights(flags: rightsFlags)
mappedRecipients = bot.recipients.apiInputBotValue(additionalPeers: additionalPeers, excludePeers: excludePeers)
} else {
flags |= 1 << 1
}
return account.network.request(Api.functions.account.updateConnectedBot(flags: flags, rights: nil, bot: mappedBot, recipients: mappedRecipients))
return account.network.request(Api.functions.account.updateConnectedBot(flags: flags, rights: mappedRights, bot: mappedBot, recipients: mappedRecipients))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)

View File

@@ -20,33 +20,26 @@ public enum ReportAdMessageError {
}
func _internal_reportAdMessage(account: Account, peerId: EnginePeer.Id, opaqueId: Data, option: Data?) -> Signal<ReportAdMessageResult, ReportAdMessageError> {
return account.postbox.transaction { transaction -> Signal<ReportAdMessageResult, ReportAdMessageError> in
guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else {
return .fail(.generic)
return account.network.request(Api.functions.messages.reportSponsoredMessage(randomId: Buffer(data: opaqueId), option: Buffer(data: option)))
|> mapError { error -> ReportAdMessageError in
if error.errorDescription == "PREMIUM_ACCOUNT_REQUIRED" {
return .premiumRequired
}
return account.network.request(Api.functions.messages.reportSponsoredMessage(peer: inputPeer, randomId: Buffer(data: opaqueId), option: Buffer(data: option)))
|> mapError { error -> ReportAdMessageError in
if error.errorDescription == "PREMIUM_ACCOUNT_REQUIRED" {
return .premiumRequired
}
return .generic
}
|> map { result -> ReportAdMessageResult in
switch result {
case let .sponsoredMessageReportResultChooseOption(title, options):
return .options(title: title, options: options.map {
switch $0 {
case let .sponsoredMessageReportOption(text, option):
return ReportAdMessageResult.Option(text: text, option: option.makeData())
}
})
case .sponsoredMessageReportResultAdsHidden:
return .adsHidden
case .sponsoredMessageReportResultReported:
return .reported
}
return .generic
}
|> map { result -> ReportAdMessageResult in
switch result {
case let .sponsoredMessageReportResultChooseOption(title, options):
return .options(title: title, options: options.map {
switch $0 {
case let .sponsoredMessageReportOption(text, option):
return ReportAdMessageResult.Option(text: text, option: option.makeData())
}
})
case .sponsoredMessageReportResultAdsHidden:
return .adsHidden
case .sponsoredMessageReportResultReported:
return .reported
}
}
|> castError(ReportAdMessageError.self)
|> switchToLatest
}

View File

@@ -0,0 +1,75 @@
import Foundation
import Postbox
import SwiftSignalKit
import TelegramApi
public class AdPeer: Equatable {
public let opaqueId: Data
public let peer: EnginePeer
public let sponsorInfo: String?
public let additionalInfo: String?
public init(opaqueId: Data, peer: EnginePeer, sponsorInfo: String?, additionalInfo: String?) {
self.opaqueId = opaqueId
self.peer = peer
self.sponsorInfo = sponsorInfo
self.additionalInfo = additionalInfo
}
public static func ==(lhs: AdPeer, rhs: AdPeer) -> Bool {
if lhs.opaqueId != rhs.opaqueId {
return false
}
if lhs.peer != rhs.peer {
return false
}
if lhs.sponsorInfo != rhs.sponsorInfo {
return false
}
if lhs.additionalInfo != rhs.additionalInfo {
return false
}
return true
}
}
func _internal_searchAdPeers(account: Account, query: String) -> Signal<[AdPeer], NoError> {
return account.network.request(Api.functions.contacts.getSponsoredPeers(q: query))
|> map(Optional.init)
|> `catch` { _ in
return .single(nil)
}
|> mapToSignal { result in
guard let result else {
return .single([])
}
return account.postbox.transaction { transaction -> [AdPeer] in
switch result {
case let .sponsoredPeers(peers, chats, users):
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: parsedPeers)
var result: [AdPeer] = []
for peer in peers {
switch peer {
case let .sponsoredPeer(_, randomId, apiPeer, sponsorInfo, additionalInfo):
guard let peer = parsedPeers.peers[apiPeer.peerId] else {
continue
}
result.append(
AdPeer(
opaqueId: randomId.makeData(),
peer: EnginePeer(peer),
sponsorInfo: sponsorInfo,
additionalInfo: additionalInfo
)
)
}
}
return result
default:
return []
}
}
}
}

View File

@@ -1522,6 +1522,10 @@ public extension TelegramEngine {
return _internal_requestRecommendedBots(account: self.account, peerId: peerId, forceUpdate: forceUpdate)
}
public func searchAdPeers(query: String) -> Signal<[AdPeer], NoError> {
return _internal_searchAdPeers(account: self.account, query: query)
}
public func isPremiumRequiredToContact(_ peerIds: [EnginePeer.Id]) -> Signal<[EnginePeer.Id: RequirementToContact], NoError> {
return _internal_updateIsPremiumRequiredToContact(account: self.account, peerIds: peerIds)
}

View File

@@ -246,11 +246,11 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
if let apiBot = connectedBots.first {
switch apiBot {
case let .connectedBot(flags, botId, recipients, _):
case let .connectedBot(_, botId, recipients, rights):
mappedConnectedBot = TelegramAccountConnectedBot(
id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)),
recipients: TelegramBusinessRecipients(apiValue: recipients),
canReply: (flags & (1 << 0)) != 0
rights: TelegramBusinessBotRights(apiValue: rights)
)
}
}