From f16480f67e67d534b52835a47babcb28b4a1dc23 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 13 Jun 2024 20:54:21 +0400 Subject: [PATCH 1/3] Update API [skip ci] --- submodules/TelegramApi/Sources/Api0.swift | 13 +- submodules/TelegramApi/Sources/Api23.swift | 70 +++- submodules/TelegramApi/Sources/Api25.swift | 80 +++++ submodules/TelegramApi/Sources/Api33.swift | 176 +++++----- submodules/TelegramApi/Sources/Api34.swift | 230 ++++++------- submodules/TelegramApi/Sources/Api35.swift | 138 ++++++++ submodules/TelegramApi/Sources/Api36.swift | 33 ++ .../Account/AccountIntermediateState.swift | 17 +- .../State/AccountStateManagementUtils.swift | 10 +- .../Sources/State/AccountStateManager.swift | 41 +++ .../Statistics/StarsRevenueStatistics.swift | 305 ++++++++++++++++++ .../Payments/BotPaymentForm.swift | 23 ++ .../TelegramEngine/Payments/Stars.swift | 15 +- .../Peers/TelegramEnginePeers.swift | 8 + 14 files changed, 911 insertions(+), 248 deletions(-) create mode 100644 submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 7e46f31cc7..69315b7d98 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -872,8 +872,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-425595208] = { return Api.SmsJob.parse_smsJob($0) } dict[-1108478618] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) } dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) } + dict[-407138204] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) } dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) } - dict[-865044046] = { return Api.StarsTransaction.parse_starsTransaction($0) } + dict[-1442789224] = { return Api.StarsTransaction.parse_starsTransaction($0) } dict[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) } dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) } dict[-382740222] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerFragment($0) } @@ -944,6 +945,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-2095595325] = { return Api.Update.parse_updateBotWebhookJSON($0) } dict[-1684914010] = { return Api.Update.parse_updateBotWebhookJSONQuery($0) } dict[-539401739] = { return Api.Update.parse_updateBroadcastRevenueTransactions($0) } + dict[513998247] = { return Api.Update.parse_updateBusinessBotCallbackQuery($0) } dict[1666927625] = { return Api.Update.parse_updateChannel($0) } dict[-1304443240] = { return Api.Update.parse_updateChannelAvailableMessages($0) } dict[-761649164] = { return Api.Update.parse_updateChannelMessageForwards($0) } @@ -1045,6 +1047,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-337352679] = { return Api.Update.parse_updateServiceNotification($0) } dict[-245208620] = { return Api.Update.parse_updateSmsJob($0) } dict[263737752] = { return Api.Update.parse_updateStarsBalance($0) } + dict[-1518030823] = { return Api.Update.parse_updateStarsRevenueStatus($0) } dict[834816008] = { return Api.Update.parse_updateStickerSets($0) } dict[196268545] = { return Api.Update.parse_updateStickerSetsOrder($0) } dict[738741697] = { return Api.Update.parse_updateStoriesStealthMode($0) } @@ -1309,6 +1312,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) } dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) } dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) } + dict[-919881925] = { return Api.payments.StarsRevenueStats.parse_starsRevenueStats($0) } + dict[497778871] = { return Api.payments.StarsRevenueWithdrawalUrl.parse_starsRevenueWithdrawalUrl($0) } dict[-1930105248] = { return Api.payments.StarsStatus.parse_starsStatus($0) } dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } dict[541839704] = { return Api.phone.ExportedGroupCallInvite.parse_exportedGroupCallInvite($0) } @@ -1978,6 +1983,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.SponsoredMessageReportOption: _1.serialize(buffer, boxed) + case let _1 as Api.StarsRevenueStatus: + _1.serialize(buffer, boxed) case let _1 as Api.StarsTopupOption: _1.serialize(buffer, boxed) case let _1 as Api.StarsTransaction: @@ -2334,6 +2341,10 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.payments.SavedInfo: _1.serialize(buffer, boxed) + case let _1 as Api.payments.StarsRevenueStats: + _1.serialize(buffer, boxed) + case let _1 as Api.payments.StarsRevenueWithdrawalUrl: + _1.serialize(buffer, boxed) case let _1 as Api.payments.StarsStatus: _1.serialize(buffer, boxed) case let _1 as Api.payments.ValidatedRequestedInfo: diff --git a/submodules/TelegramApi/Sources/Api23.swift b/submodules/TelegramApi/Sources/Api23.swift index 733ac161c8..0194599f5b 100644 --- a/submodules/TelegramApi/Sources/Api23.swift +++ b/submodules/TelegramApi/Sources/Api23.swift @@ -602,6 +602,54 @@ public extension Api { } } +public extension Api { + enum StarsRevenueStatus: TypeConstructorDescription { + case starsRevenueStatus(flags: Int32, currentBalance: Int64, availableBalance: Int64, overallRevenue: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .starsRevenueStatus(let flags, let currentBalance, let availableBalance, let overallRevenue): + if boxed { + buffer.appendInt32(-407138204) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(currentBalance, buffer: buffer, boxed: false) + serializeInt64(availableBalance, buffer: buffer, boxed: false) + serializeInt64(overallRevenue, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .starsRevenueStatus(let flags, let currentBalance, let availableBalance, let overallRevenue): + return ("starsRevenueStatus", [("flags", flags as Any), ("currentBalance", currentBalance as Any), ("availableBalance", availableBalance as Any), ("overallRevenue", overallRevenue as Any)]) + } + } + + public static func parse_starsRevenueStatus(_ reader: BufferReader) -> StarsRevenueStatus? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Int64? + _4 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.StarsRevenueStatus.starsRevenueStatus(flags: _1!, currentBalance: _2!, availableBalance: _3!, overallRevenue: _4!) + } + else { + return nil + } + } + + } +} public extension Api { enum StarsTopupOption: TypeConstructorDescription { case starsTopupOption(flags: Int32, stars: Int64, storeProduct: String?, currency: String, amount: Int64) @@ -656,13 +704,13 @@ public extension Api { } public extension Api { enum StarsTransaction: TypeConstructorDescription { - case starsTransaction(flags: Int32, id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?) + case starsTransaction(flags: Int32, id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo): + case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl): if boxed { - buffer.appendInt32(-865044046) + buffer.appendInt32(-1442789224) } serializeInt32(flags, buffer: buffer, boxed: false) serializeString(id, buffer: buffer, boxed: false) @@ -672,14 +720,16 @@ public extension Api { if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {serializeInt32(transactionDate!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 5) != 0 {serializeString(transactionUrl!, buffer: buffer, boxed: false)} break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo): - return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any)]) + case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl): + return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any)]) } } @@ -704,6 +754,10 @@ public extension Api { if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { _8 = Api.parse(reader, signature: signature) as? Api.WebDocument } } + var _9: Int32? + if Int(_1!) & Int(1 << 5) != 0 {_9 = reader.readInt32() } + var _10: String? + if Int(_1!) & Int(1 << 5) != 0 {_10 = parseString(reader) } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -712,8 +766,10 @@ public extension Api { let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { - return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8) + let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 5) == 0) || _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api25.swift b/submodules/TelegramApi/Sources/Api25.swift index ffad9c1ca7..4f9ab1d4ab 100644 --- a/submodules/TelegramApi/Sources/Api25.swift +++ b/submodules/TelegramApi/Sources/Api25.swift @@ -271,6 +271,7 @@ public extension Api { case updateBotWebhookJSON(data: Api.DataJSON) case updateBotWebhookJSONQuery(queryId: Int64, data: Api.DataJSON, timeout: Int32) case updateBroadcastRevenueTransactions(peer: Api.Peer, balances: Api.BroadcastRevenueBalances) + case updateBusinessBotCallbackQuery(flags: Int32, queryId: Int64, userId: Int64, connectionId: String, message: Api.Message, replyToMessage: Api.Message?, chatInstance: Int64, data: Buffer?) case updateChannel(channelId: Int64) case updateChannelAvailableMessages(channelId: Int64, availableMinId: Int32) case updateChannelMessageForwards(channelId: Int64, id: Int32, forwards: Int32) @@ -372,6 +373,7 @@ public extension Api { case updateServiceNotification(flags: Int32, inboxDate: Int32?, type: String, message: String, media: Api.MessageMedia, entities: [Api.MessageEntity]) case updateSmsJob(jobId: String) case updateStarsBalance(balance: Int64) + case updateStarsRevenueStatus(peer: Api.Peer, status: Api.StarsRevenueStatus) case updateStickerSets(flags: Int32) case updateStickerSetsOrder(flags: Int32, order: [Int64]) case updateStoriesStealthMode(stealthMode: Api.StoriesStealthMode) @@ -602,6 +604,19 @@ public extension Api { peer.serialize(buffer, true) balances.serialize(buffer, true) break + case .updateBusinessBotCallbackQuery(let flags, let queryId, let userId, let connectionId, let message, let replyToMessage, let chatInstance, let data): + if boxed { + buffer.appendInt32(513998247) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + serializeInt64(userId, buffer: buffer, boxed: false) + serializeString(connectionId, buffer: buffer, boxed: false) + message.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {replyToMessage!.serialize(buffer, true)} + serializeInt64(chatInstance, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeBytes(data!, buffer: buffer, boxed: false)} + break case .updateChannel(let channelId): if boxed { buffer.appendInt32(1666927625) @@ -1460,6 +1475,13 @@ public extension Api { } serializeInt64(balance, buffer: buffer, boxed: false) break + case .updateStarsRevenueStatus(let peer, let status): + if boxed { + buffer.appendInt32(-1518030823) + } + peer.serialize(buffer, true) + status.serialize(buffer, true) + break case .updateStickerSets(let flags): if boxed { buffer.appendInt32(834816008) @@ -1621,6 +1643,8 @@ public extension Api { return ("updateBotWebhookJSONQuery", [("queryId", queryId as Any), ("data", data as Any), ("timeout", timeout as Any)]) case .updateBroadcastRevenueTransactions(let peer, let balances): return ("updateBroadcastRevenueTransactions", [("peer", peer as Any), ("balances", balances as Any)]) + case .updateBusinessBotCallbackQuery(let flags, let queryId, let userId, let connectionId, let message, let replyToMessage, let chatInstance, let data): + return ("updateBusinessBotCallbackQuery", [("flags", flags as Any), ("queryId", queryId as Any), ("userId", userId as Any), ("connectionId", connectionId as Any), ("message", message as Any), ("replyToMessage", replyToMessage as Any), ("chatInstance", chatInstance as Any), ("data", data as Any)]) case .updateChannel(let channelId): return ("updateChannel", [("channelId", channelId as Any)]) case .updateChannelAvailableMessages(let channelId, let availableMinId): @@ -1823,6 +1847,8 @@ public extension Api { return ("updateSmsJob", [("jobId", jobId as Any)]) case .updateStarsBalance(let balance): return ("updateStarsBalance", [("balance", balance as Any)]) + case .updateStarsRevenueStatus(let peer, let status): + return ("updateStarsRevenueStatus", [("peer", peer as Any), ("status", status as Any)]) case .updateStickerSets(let flags): return ("updateStickerSets", [("flags", flags as Any)]) case .updateStickerSetsOrder(let flags, let order): @@ -2333,6 +2359,42 @@ public extension Api { return nil } } + public static func parse_updateBusinessBotCallbackQuery(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + _4 = parseString(reader) + var _5: Api.Message? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Message + } + var _6: Api.Message? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.Message + } } + var _7: Int64? + _7 = reader.readInt64() + var _8: Buffer? + if Int(_1!) & Int(1 << 0) != 0 {_8 = parseBytes(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.Update.updateBusinessBotCallbackQuery(flags: _1!, queryId: _2!, userId: _3!, connectionId: _4!, message: _5!, replyToMessage: _6, chatInstance: _7!, data: _8) + } + else { + return nil + } + } public static func parse_updateChannel(_ reader: BufferReader) -> Update? { var _1: Int64? _1 = reader.readInt64() @@ -4010,6 +4072,24 @@ public extension Api { return nil } } + public static func parse_updateStarsRevenueStatus(_ reader: BufferReader) -> Update? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: Api.StarsRevenueStatus? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StarsRevenueStatus + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateStarsRevenueStatus(peer: _1!, status: _2!) + } + else { + return nil + } + } public static func parse_updateStickerSets(_ reader: BufferReader) -> Update? { var _1: Int32? _1 = reader.readInt32() diff --git a/submodules/TelegramApi/Sources/Api33.swift b/submodules/TelegramApi/Sources/Api33.swift index da4798d2ee..b86e14aa0f 100644 --- a/submodules/TelegramApi/Sources/Api33.swift +++ b/submodules/TelegramApi/Sources/Api33.swift @@ -1044,6 +1044,90 @@ 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, history: [Api.StarsTransaction], nextOffset: String?, chats: [Api.Chat], users: [Api.User]) @@ -1590,95 +1674,3 @@ public extension Api.photos { } } -public extension Api.photos { - enum Photos: TypeConstructorDescription { - case photos(photos: [Api.Photo], users: [Api.User]) - case photosSlice(count: Int32, photos: [Api.Photo], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .photos(let photos, let users): - if boxed { - buffer.appendInt32(-1916114267) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(photos.count)) - for item in photos { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users.count)) - for item in users { - item.serialize(buffer, true) - } - break - case .photosSlice(let count, let photos, let users): - if boxed { - buffer.appendInt32(352657236) - } - serializeInt32(count, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(photos.count)) - for item in photos { - 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 .photos(let photos, let users): - return ("photos", [("photos", photos as Any), ("users", users as Any)]) - case .photosSlice(let count, let photos, let users): - return ("photosSlice", [("count", count as Any), ("photos", photos as Any), ("users", users as Any)]) - } - } - - public static func parse_photos(_ reader: BufferReader) -> Photos? { - var _1: [Api.Photo]? - if let _ = reader.readInt32() { - _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) - } - var _2: [Api.User]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.photos.Photos.photos(photos: _1!, users: _2!) - } - else { - return nil - } - } - public static func parse_photosSlice(_ reader: BufferReader) -> Photos? { - var _1: Int32? - _1 = reader.readInt32() - var _2: [Api.Photo]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) - } - var _3: [Api.User]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.photos.Photos.photosSlice(count: _1!, photos: _2!, users: _3!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api34.swift b/submodules/TelegramApi/Sources/Api34.swift index b95acb0d27..b767d502a5 100644 --- a/submodules/TelegramApi/Sources/Api34.swift +++ b/submodules/TelegramApi/Sources/Api34.swift @@ -1,3 +1,95 @@ +public extension Api.photos { + enum Photos: TypeConstructorDescription { + case photos(photos: [Api.Photo], users: [Api.User]) + case photosSlice(count: Int32, photos: [Api.Photo], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .photos(let photos, let users): + if boxed { + buffer.appendInt32(-1916114267) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(photos.count)) + for item in photos { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .photosSlice(let count, let photos, let users): + if boxed { + buffer.appendInt32(352657236) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(photos.count)) + for item in photos { + 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 .photos(let photos, let users): + return ("photos", [("photos", photos as Any), ("users", users as Any)]) + case .photosSlice(let count, let photos, let users): + return ("photosSlice", [("count", count as Any), ("photos", photos as Any), ("users", users as Any)]) + } + } + + public static func parse_photos(_ reader: BufferReader) -> Photos? { + var _1: [Api.Photo]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.photos.Photos.photos(photos: _1!, users: _2!) + } + else { + return nil + } + } + public static func parse_photosSlice(_ reader: BufferReader) -> Photos? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Photo]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.photos.Photos.photosSlice(count: _1!, photos: _2!, users: _3!) + } + else { + return nil + } + } + + } +} public extension Api.premium { enum BoostsList: TypeConstructorDescription { case boostsList(flags: Int32, count: Int32, boosts: [Api.Boost], nextOffset: String?, users: [Api.User]) @@ -1498,141 +1590,3 @@ public extension Api.stories { } } -public extension Api.stories { - enum StoryViews: TypeConstructorDescription { - case storyViews(views: [Api.StoryViews], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .storyViews(let views, let users): - if boxed { - buffer.appendInt32(-560009955) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(views.count)) - for item in views { - 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 .storyViews(let views, let users): - return ("storyViews", [("views", views as Any), ("users", users as Any)]) - } - } - - public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? { - var _1: [Api.StoryViews]? - if let _ = reader.readInt32() { - _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryViews.self) - } - var _2: [Api.User]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.stories.StoryViews.storyViews(views: _1!, users: _2!) - } - else { - return nil - } - } - - } -} -public extension Api.stories { - enum StoryViewsList: TypeConstructorDescription { - case storyViewsList(flags: Int32, count: Int32, viewsCount: Int32, forwardsCount: Int32, reactionsCount: Int32, views: [Api.StoryView], chats: [Api.Chat], users: [Api.User], nextOffset: String?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset): - if boxed { - buffer.appendInt32(1507299269) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(count, buffer: buffer, boxed: false) - serializeInt32(viewsCount, buffer: buffer, boxed: false) - serializeInt32(forwardsCount, buffer: buffer, boxed: false) - serializeInt32(reactionsCount, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(views.count)) - for item in views { - 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) - } - if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset): - return ("storyViewsList", [("flags", flags as Any), ("count", count as Any), ("viewsCount", viewsCount as Any), ("forwardsCount", forwardsCount as Any), ("reactionsCount", reactionsCount as Any), ("views", views as Any), ("chats", chats as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)]) - } - } - - public static func parse_storyViewsList(_ reader: BufferReader) -> StoryViewsList? { - 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? - _5 = reader.readInt32() - var _6: [Api.StoryView]? - if let _ = reader.readInt32() { - _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryView.self) - } - var _7: [Api.Chat]? - if let _ = reader.readInt32() { - _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _8: [Api.User]? - if let _ = reader.readInt32() { - _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - var _9: String? - if Int(_1!) & Int(1 << 0) != 0 {_9 = parseString(reader) } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - let _c8 = _8 != nil - let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.stories.StoryViewsList.storyViewsList(flags: _1!, count: _2!, viewsCount: _3!, forwardsCount: _4!, reactionsCount: _5!, views: _6!, chats: _7!, users: _8!, nextOffset: _9) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api35.swift b/submodules/TelegramApi/Sources/Api35.swift index 0cfe25da84..e5b0c6e49a 100644 --- a/submodules/TelegramApi/Sources/Api35.swift +++ b/submodules/TelegramApi/Sources/Api35.swift @@ -1,3 +1,141 @@ +public extension Api.stories { + enum StoryViews: TypeConstructorDescription { + case storyViews(views: [Api.StoryViews], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .storyViews(let views, let users): + if boxed { + buffer.appendInt32(-560009955) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(views.count)) + for item in views { + 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 .storyViews(let views, let users): + return ("storyViews", [("views", views as Any), ("users", users as Any)]) + } + } + + public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? { + var _1: [Api.StoryViews]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryViews.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.stories.StoryViews.storyViews(views: _1!, users: _2!) + } + else { + return nil + } + } + + } +} +public extension Api.stories { + enum StoryViewsList: TypeConstructorDescription { + case storyViewsList(flags: Int32, count: Int32, viewsCount: Int32, forwardsCount: Int32, reactionsCount: Int32, views: [Api.StoryView], chats: [Api.Chat], users: [Api.User], nextOffset: String?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset): + if boxed { + buffer.appendInt32(1507299269) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(count, buffer: buffer, boxed: false) + serializeInt32(viewsCount, buffer: buffer, boxed: false) + serializeInt32(forwardsCount, buffer: buffer, boxed: false) + serializeInt32(reactionsCount, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(views.count)) + for item in views { + 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) + } + if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .storyViewsList(let flags, let count, let viewsCount, let forwardsCount, let reactionsCount, let views, let chats, let users, let nextOffset): + return ("storyViewsList", [("flags", flags as Any), ("count", count as Any), ("viewsCount", viewsCount as Any), ("forwardsCount", forwardsCount as Any), ("reactionsCount", reactionsCount as Any), ("views", views as Any), ("chats", chats as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)]) + } + } + + public static func parse_storyViewsList(_ reader: BufferReader) -> StoryViewsList? { + 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? + _5 = reader.readInt32() + var _6: [Api.StoryView]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryView.self) + } + var _7: [Api.Chat]? + if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _8: [Api.User]? + if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _9: String? + if Int(_1!) & Int(1 << 0) != 0 {_9 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.stories.StoryViewsList.storyViewsList(flags: _1!, count: _2!, viewsCount: _3!, forwardsCount: _4!, reactionsCount: _5!, views: _6!, chats: _7!, users: _8!, nextOffset: _9) + } + else { + return nil + } + } + + } +} public extension Api.updates { indirect enum ChannelDifference: TypeConstructorDescription { case channelDifference(flags: Int32, pts: Int32, timeout: Int32?, newMessages: [Api.Message], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User]) diff --git a/submodules/TelegramApi/Sources/Api36.swift b/submodules/TelegramApi/Sources/Api36.swift index 4b516b88f5..7cb64347a9 100644 --- a/submodules/TelegramApi/Sources/Api36.swift +++ b/submodules/TelegramApi/Sources/Api36.swift @@ -8731,6 +8731,39 @@ public extension Api.functions.payments { }) } } +public extension Api.functions.payments { + static func getStarsRevenueStats(flags: Int32, peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-652215594) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + return (FunctionDescription(name: "payments.getStarsRevenueStats", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsRevenueStats? in + let reader = BufferReader(buffer) + var result: Api.payments.StarsRevenueStats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.StarsRevenueStats + } + return result + }) + } +} +public extension Api.functions.payments { + static func getStarsRevenueWithdrawalUrl(peer: Api.InputPeer, stars: Int64, password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(331081907) + peer.serialize(buffer, true) + serializeInt64(stars, buffer: buffer, boxed: false) + password.serialize(buffer, true) + return (FunctionDescription(name: "payments.getStarsRevenueWithdrawalUrl", parameters: [("peer", String(describing: peer)), ("stars", String(describing: stars)), ("password", String(describing: password))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsRevenueWithdrawalUrl? in + let reader = BufferReader(buffer) + var result: Api.payments.StarsRevenueWithdrawalUrl? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.StarsRevenueWithdrawalUrl + } + return result + }) + } +} public extension Api.functions.payments { static func getStarsStatus(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index d52b1dc7b5..f45750f5d6 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -130,6 +130,7 @@ enum AccountStateMutationOperation { case UpdateWallpaper(peerId: PeerId, wallpaper: TelegramWallpaper?) case UpdateRevenueBalances(peerId: PeerId, balances: RevenueStats.Balances) case UpdateStarsBalance(peerId: PeerId, balance: Int64) + case UpdateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances) } struct HoleFromPreviousState { @@ -683,9 +684,13 @@ struct AccountMutableState { self.addOperation(.UpdateStarsBalance(peerId: peerId, balance: balance)) } + mutating func updateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances) { + self.addOperation(.UpdateStarsRevenueStatus(peerId: peerId, status: status)) + } + mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateRevenueBalances, .UpdateStarsBalance: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus: break case let .AddMessages(messages, location): for message in messages { @@ -831,6 +836,7 @@ struct AccountReplayedFinalState { let isPremiumUpdated: Bool let updatedRevenueBalances: [PeerId: RevenueStats.Balances] let updatedStarsBalance: [PeerId: Int64] + let updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] } struct AccountFinalStateEvents { @@ -859,12 +865,13 @@ struct AccountFinalStateEvents { let isPremiumUpdated: Bool let updatedRevenueBalances: [PeerId: RevenueStats.Balances] let updatedStarsBalance: [PeerId: Int64] + let updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] var isEmpty: Bool { - return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedRevenueBalances.isEmpty && self.updatedStarsBalance.isEmpty + return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedRevenueBalances.isEmpty && self.updatedStarsBalance.isEmpty && self.updatedStarsRevenueStatus.isEmpty } - init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedRevenueBalances: [PeerId: RevenueStats.Balances] = [:], updatedStarsBalance: [PeerId: Int64] = [:]) { + init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedRevenueBalances: [PeerId: RevenueStats.Balances] = [:], updatedStarsBalance: [PeerId: Int64] = [:], updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:]) { self.addedIncomingMessageIds = addedIncomingMessageIds self.addedReactionEvents = addedReactionEvents self.wasScheduledMessageIds = wasScheduledMessageIds @@ -890,6 +897,7 @@ struct AccountFinalStateEvents { self.isPremiumUpdated = isPremiumUpdated self.updatedRevenueBalances = updatedRevenueBalances self.updatedStarsBalance = updatedStarsBalance + self.updatedStarsRevenueStatus = updatedStarsRevenueStatus } init(state: AccountReplayedFinalState) { @@ -918,6 +926,7 @@ struct AccountFinalStateEvents { self.isPremiumUpdated = state.isPremiumUpdated self.updatedRevenueBalances = state.updatedRevenueBalances self.updatedStarsBalance = state.updatedStarsBalance + self.updatedStarsRevenueStatus = state.updatedStarsRevenueStatus } func union(with other: AccountFinalStateEvents) -> AccountFinalStateEvents { @@ -947,6 +956,6 @@ struct AccountFinalStateEvents { let isPremiumUpdated = self.isPremiumUpdated || other.isPremiumUpdated - return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: self.updatedRevenueBalances.merging(other.updatedRevenueBalances, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsBalance: self.updatedStarsBalance.merging(other.updatedStarsBalance, uniquingKeysWith: { lhs, _ in lhs })) + return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: self.updatedRevenueBalances.merging(other.updatedRevenueBalances, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsBalance: self.updatedStarsBalance.merging(other.updatedStarsBalance, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsRevenueStatus: self.updatedStarsRevenueStatus.merging(other.updatedStarsRevenueStatus, uniquingKeysWith: { lhs, _ in lhs })) } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index da19c7176e..c48b5fec35 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1780,6 +1780,8 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: updatedState.updateRevenueBalances(peerId: peer.peerId, balances: RevenueStats.Balances(apiRevenueBalances: balances)) case let .updateStarsBalance(balance): updatedState.updateStarsBalance(peerId: accountPeerId, balance: balance) + case let .updateStarsRevenueStatus(peer, status): + updatedState.updateStarsRevenueStatus(peerId: peer.peerId, status: StarsRevenueStats.Balances(apiStarsRevenueStatus: status)) default: break } @@ -3271,7 +3273,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddQuickReplyMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateRevenueBalances, .UpdateStarsBalance: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -3406,6 +3408,7 @@ func replayFinalState( var updateConfig = false var updatedRevenueBalances: [PeerId: RevenueStats.Balances] = [:] var updatedStarsBalance: [PeerId: Int64] = [:] + var updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:] var holesFromPreviousStateMessageIds: [MessageId] = [] var clearHolesFromPreviousStateForChannelMessagesWithPts: [PeerIdAndMessageNamespace: Int32] = [:] @@ -4842,6 +4845,9 @@ func replayFinalState( updatedRevenueBalances[peerId] = balances case let .UpdateStarsBalance(peerId, balance): updatedStarsBalance[peerId] = balance + case let .UpdateStarsRevenueStatus(peerId, status): + updatedStarsRevenueStatus[peerId] = status + } } @@ -5336,5 +5342,5 @@ func replayFinalState( } } - return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedReactionEvents: addedReactionEvents, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, storyUpdates: storyUpdates, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates, updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: updatedRevenueBalances, updatedStarsBalance: updatedStarsBalance) + return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedReactionEvents: addedReactionEvents, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, storyUpdates: storyUpdates, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates, updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: updatedRevenueBalances, updatedStarsBalance: updatedStarsBalance, updatedStarsRevenueStatus: updatedStarsRevenueStatus) } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index da4b4d9799..9fa6beed64 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -52,6 +52,10 @@ private final class UpdatedStarsBalanceSubscriberContext { let subscribers = Bag<([PeerId: Int64]) -> Void>() } +private final class UpdatedStarsRevenueStatusSubscriberContext { + let subscribers = Bag<([PeerId: StarsRevenueStats.Balances]) -> Void>() +} + public enum DeletedMessageId: Hashable { case global(Int32) case messageId(MessageId) @@ -287,6 +291,7 @@ public final class AccountStateManager { private var updatedPeersNearbyContext = UpdatedPeersNearbySubscriberContext() private var updatedRevenueBalancesContext = UpdatedRevenueBalancesSubscriberContext() private var updatedStarsBalanceContext = UpdatedStarsBalanceSubscriberContext() + private var updatedStarsRevenueStatusContext = UpdatedStarsRevenueStatusSubscriberContext() private let delayNotificatonsUntil = Atomic(value: nil) private let appliedMaxMessageIdPromise = Promise(nil) @@ -1038,6 +1043,9 @@ public final class AccountStateManager { if !events.updatedStarsBalance.isEmpty { strongSelf.notifyUpdatedStarsBalance(events.updatedStarsBalance) } + if !events.updatedStarsRevenueStatus.isEmpty { + strongSelf.notifyUpdatedStarsRevenueStatus(events.updatedStarsRevenueStatus) + } if !events.updatedCalls.isEmpty { for call in events.updatedCalls { strongSelf.callSessionManager?.updateSession(call, completion: { _ in }) @@ -1664,6 +1672,33 @@ public final class AccountStateManager { } } + public func updatedStarsRevenueStatus() -> Signal<[PeerId: StarsRevenueStats.Balances], NoError> { + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + queue.async { + if let strongSelf = self { + let index = strongSelf.updatedStarsRevenueStatusContext.subscribers.add({ revenueBalances in + subscriber.putNext(revenueBalances) + }) + + disposable.set(ActionDisposable { + if let strongSelf = self { + strongSelf.updatedStarsRevenueStatusContext.subscribers.remove(index) + } + }) + } + } + return disposable + } + } + + private func notifyUpdatedStarsRevenueStatus(_ updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances]) { + for subscriber in self.updatedStarsRevenueStatusContext.subscribers.copyItems() { + subscriber(updatedStarsRevenueStatus) + } + } + func notifyDeletedMessages(messageIds: [MessageId]) { self.deletedMessagesPipe.putNext(messageIds.map { .messageId($0) }) } @@ -1963,6 +1998,12 @@ public final class AccountStateManager { } } + public func updatedStarsRevenueStatus() -> Signal<[PeerId: StarsRevenueStats.Balances], NoError> { + return self.impl.signalWith { impl, subscriber in + return impl.updatedStarsRevenueStatus().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) + } + } + func addCustomOperation(_ f: Signal) -> Signal { return self.impl.signalWith { impl, subscriber in return impl.addCustomOperation(f).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) diff --git a/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift b/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift new file mode 100644 index 0000000000..a3377d99df --- /dev/null +++ b/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift @@ -0,0 +1,305 @@ +import Foundation +import SwiftSignalKit +import Postbox +import TelegramApi +import MtProtoKit + +public struct StarsRevenueStats: Equatable { + public struct Balances: Equatable { + public let currentBalance: Int64 + public let availableBalance: Int64 + public let overallRevenue: Int64 + } + + public let revenueGraph: StatsGraph + public let balances: Balances + public let usdRate: Double + + init(revenueGraph: StatsGraph, balances: Balances, usdRate: Double) { + self.revenueGraph = revenueGraph + self.balances = balances + self.usdRate = usdRate + } + + public static func == (lhs: StarsRevenueStats, rhs: StarsRevenueStats) -> Bool { + if lhs.revenueGraph != rhs.revenueGraph { + return false + } + if lhs.balances != rhs.balances { + return false + } + if lhs.usdRate != rhs.usdRate { + return false + } + return true + } +} + +public extension StarsRevenueStats { + func withUpdated(balances: StarsRevenueStats.Balances) -> StarsRevenueStats { + return StarsRevenueStats( + revenueGraph: self.revenueGraph, + balances: balances, + usdRate: self.usdRate + ) + } +} + +extension StarsRevenueStats { + init(apiStarsRevenueStats: Api.payments.StarsRevenueStats, peerId: PeerId) { + switch apiStarsRevenueStats { + case let .starsRevenueStats(revenueGraph, balances, usdRate): + self.init(revenueGraph: StatsGraph(apiStatsGraph: revenueGraph), balances: StarsRevenueStats.Balances(apiStarsRevenueStatus: balances), usdRate: usdRate) + } + } +} + +extension StarsRevenueStats.Balances { + init(apiStarsRevenueStatus: Api.StarsRevenueStatus) { + switch apiStarsRevenueStatus { + case let .starsRevenueStatus(flags, currentBalance, availableBalance, overallRevenue): + let _ = flags + self.init(currentBalance: currentBalance, availableBalance: availableBalance, overallRevenue: overallRevenue) + } + } +} + +public struct StarsRevenueStatsContextState: Equatable { + public var stats: StarsRevenueStats? +} + +private func requestStarsRevenueStats(postbox: Postbox, network: Network, peerId: PeerId, dark: Bool = false) -> Signal { + return postbox.transaction { transaction -> Peer? in + if let peer = transaction.getPeer(peerId) { + return peer + } + return nil + } |> mapToSignal { peer -> Signal in + guard let peer, let inputPeer = apiInputPeer(peer) else { + return .never() + } + + var flags: Int32 = 0 + if dark { + flags |= (1 << 1) + } + + return network.request(Api.functions.payments.getStarsRevenueStats(flags: flags, peer: inputPeer)) + |> map { result -> StarsRevenueStats? in + return StarsRevenueStats(apiStarsRevenueStats: result, peerId: peerId) + } + |> retryRequest + } +} + +private final class StarsRevenueStatsContextImpl { + private let account: Account + private let peerId: PeerId + + private var _state: StarsRevenueStatsContextState { + didSet { + if self._state != oldValue { + self._statePromise.set(.single(self._state)) + } + } + } + private let _statePromise = Promise() + var state: Signal { + return self._statePromise.get() + } + + private let disposable = MetaDisposable() + + init(account: Account, peerId: PeerId) { + assert(Queue.mainQueue().isCurrent()) + + self.account = account + self.peerId = peerId + self._state = StarsRevenueStatsContextState(stats: nil) + self._statePromise.set(.single(self._state)) + + self.load() + } + + deinit { + assert(Queue.mainQueue().isCurrent()) + self.disposable.dispose() + } + + fileprivate func load() { + assert(Queue.mainQueue().isCurrent()) + + let account = self.account + let peerId = self.peerId + let signal = requestStarsRevenueStats(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId) + |> mapToSignal { initial -> Signal in + guard let initial else { + return .single(nil) + } + return .single(initial) + |> then( + account.stateManager.updatedStarsRevenueStatus() + |> mapToSignal { updates in + if let balances = updates[peerId] { + return .single(initial.withUpdated(balances: balances)) + } + return .complete() + } + ) + } + + self.disposable.set((signal + |> deliverOnMainQueue).start(next: { [weak self] stats in + if let strongSelf = self { + strongSelf._state = StarsRevenueStatsContextState(stats: stats) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + })) + } + + func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal { + if let token = graph.token { + return requestGraph(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId, token: token, x: x) + } else { + return .single(nil) + } + } +} + +public final class StarsRevenueStatsContext { + private let impl: QueueLocalObject + + public var state: Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.state.start(next: { value in + subscriber.putNext(value) + })) + } + return disposable + } + } + + public init(account: Account, peerId: PeerId) { + self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: { + return StarsRevenueStatsContextImpl(account: account, peerId: peerId) + }) + } + + public func reload() { + self.impl.with { impl in + impl.load() + } + } + + public func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.loadDetailedGraph(graph, x: x).start(next: { value in + subscriber.putNext(value) + subscriber.putCompletion() + })) + } + return disposable + } + } +} + +public enum RequestStarsRevenueWithdrawalError : Equatable { + case generic + case twoStepAuthMissing + case twoStepAuthTooFresh(Int32) + case authSessionTooFresh(Int32) + case limitExceeded + case requestPassword + case invalidPassword +} + +func _internal_checkStarsRevenueWithdrawalAvailability(account: Account) -> Signal { + return account.network.request(Api.functions.payments.getStarsRevenueWithdrawalUrl(peer: .inputPeerEmpty, stars: 0, password: .inputCheckPasswordEmpty)) + |> mapError { error -> RequestStarsRevenueWithdrawalError in + if error.errorDescription == "PASSWORD_HASH_INVALID" { + return .requestPassword + } else if error.errorDescription == "PASSWORD_MISSING" { + return .twoStepAuthMissing + } else if error.errorDescription.hasPrefix("PASSWORD_TOO_FRESH_") { + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "PASSWORD_TOO_FRESH_".count)...]) + if let value = Int32(timeout) { + return .twoStepAuthTooFresh(value) + } + } else if error.errorDescription.hasPrefix("SESSION_TOO_FRESH_") { + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "SESSION_TOO_FRESH_".count)...]) + if let value = Int32(timeout) { + return .authSessionTooFresh(value) + } + } + return .generic + } + |> ignoreValues +} + +func _internal_requestStarsRevenueWithdrawalUrl(account: Account, peerId: PeerId, amount: Int64, password: String) -> Signal { + guard !password.isEmpty else { + return .fail(.invalidPassword) + } + + return account.postbox.transaction { transaction -> Signal in + guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else { + return .fail(.generic) + } + + let checkPassword = _internal_twoStepAuthData(account.network) + |> mapError { error -> RequestStarsRevenueWithdrawalError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else { + return .generic + } + } + |> mapToSignal { authData -> Signal in + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + guard let kdfResult = passwordKDF(encryptionProvider: account.network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { + return .fail(.generic) + } + return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))) + } else { + return .fail(.twoStepAuthMissing) + } + } + + return checkPassword + |> mapToSignal { password -> Signal in + return account.network.request(Api.functions.payments.getStarsRevenueWithdrawalUrl(peer: inputPeer, stars: amount, password: password), automaticFloodWait: false) + |> mapError { error -> RequestStarsRevenueWithdrawalError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PASSWORD_HASH_INVALID" { + return .invalidPassword + } else if error.errorDescription == "PASSWORD_MISSING" { + return .twoStepAuthMissing + } else if error.errorDescription.hasPrefix("PASSWORD_TOO_FRESH_") { + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "PASSWORD_TOO_FRESH_".count)...]) + if let value = Int32(timeout) { + return .twoStepAuthTooFresh(value) + } + } else if error.errorDescription.hasPrefix("SESSION_TOO_FRESH_") { + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "SESSION_TOO_FRESH_".count)...]) + if let value = Int32(timeout) { + return .authSessionTooFresh(value) + } + } + return .generic + } + |> map { result -> String in + switch result { + case let .starsRevenueWithdrawalUrl(url): + return url + } + } + } + } + |> mapError { _ -> RequestStarsRevenueWithdrawalError in } + |> switchToLatest +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift index 8ab99b612c..883b9b7351 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift @@ -59,6 +59,15 @@ public struct BotPaymentInvoice : Equatable { public let prices: [BotPaymentPrice] public let tip: Tip? public let termsInfo: RecurrentInfo? + + public init(isTest: Bool, requestedFields: BotPaymentInvoiceFields, currency: String, prices: [BotPaymentPrice], tip: Tip?, termsInfo: RecurrentInfo?) { + self.isTest = isTest + self.requestedFields = requestedFields + self.currency = currency + self.prices = prices + self.tip = tip + self.termsInfo = termsInfo + } } public struct BotPaymentNativeProvider : Equatable { @@ -125,6 +134,20 @@ public struct BotPaymentForm : Equatable { public let savedInfo: BotPaymentRequestedInfo? public let savedCredentials: [BotPaymentSavedCredentials] public let additionalPaymentMethods: [BotPaymentMethod] + + public init(id: Int64, canSaveCredentials: Bool, passwordMissing: Bool, invoice: BotPaymentInvoice, paymentBotId: PeerId, providerId: PeerId?, url: String?, nativeProvider: BotPaymentNativeProvider?, savedInfo: BotPaymentRequestedInfo?, savedCredentials: [BotPaymentSavedCredentials], additionalPaymentMethods: [BotPaymentMethod]) { + self.id = id + self.canSaveCredentials = canSaveCredentials + self.passwordMissing = passwordMissing + self.invoice = invoice + self.paymentBotId = paymentBotId + self.providerId = providerId + self.url = url + self.nativeProvider = nativeProvider + self.savedInfo = savedInfo + self.savedCredentials = savedCredentials + self.additionalPaymentMethods = additionalPaymentMethods + } } public struct BotPaymentMethod: Equatable { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 2283d9aae8..4a1f1a0ac5 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -199,7 +199,7 @@ private final class StarsContextImpl { return } var transactions = state.transactions - transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil), at: 0) + transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil), at: 0) self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: state.balance + balance, transactions: transactions, canLoadMore: state.canLoadMore, isLoading: state.isLoading)) } @@ -238,7 +238,7 @@ private final class StarsContextImpl { private extension StarsContext.State.Transaction { init?(apiTransaction: Api.StarsTransaction, transaction: Transaction) { switch apiTransaction { - case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo): + case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl): let parsedPeer: StarsContext.State.Transaction.Peer switch transactionPeer { case .starsTransactionPeerAppStore: @@ -262,7 +262,7 @@ private extension StarsContext.State.Transaction { if (apiFlags & (1 << 3)) != 0 { flags.insert(.isRefund) } - self.init(flags: flags, id: id, count: stars, date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init)) + self.init(flags: flags, id: id, count: stars, date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl) } } } @@ -279,6 +279,7 @@ public final class StarsContext { public static let isRefund = Flags(rawValue: 1 << 0) public static let isLocal = Flags(rawValue: 1 << 1) + public static let isPending = Flags(rawValue: 1 << 2) } public enum Peer: Equatable { @@ -298,6 +299,8 @@ public final class StarsContext { public let title: String? public let description: String? public let photo: TelegramMediaWebFile? + public let transactionDate: Int32? + public let transactionUrl: String? public init( flags: Flags, @@ -307,7 +310,9 @@ public final class StarsContext { peer: Peer, title: String?, description: String?, - photo: TelegramMediaWebFile? + photo: TelegramMediaWebFile?, + transactionDate: Int32?, + transactionUrl: String? ) { self.flags = flags self.id = id @@ -317,6 +322,8 @@ public final class StarsContext { self.title = title self.description = description self.photo = photo + self.transactionDate = transactionDate + self.transactionUrl = transactionUrl } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 7ed04d6676..1aa5476816 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -823,6 +823,14 @@ public extension TelegramEngine { return _internal_requestChannelRevenueWithdrawalUrl(account: self.account, peerId: peerId, password: password) } + public func checkStarsRevenueWithdrawalAvailability() -> Signal { + return _internal_checkStarsRevenueWithdrawalAvailability(account: self.account) + } + + public func requestStarsRevenueWithdrawalUrl(peerId: EnginePeer.Id, amount: Int64, password: String) -> Signal { + return _internal_requestStarsRevenueWithdrawalUrl(account: self.account, peerId: peerId, amount: amount, password: password) + } + public func getChatListPeers(filterPredicate: ChatListFilterPredicate) -> Signal<[EnginePeer], NoError> { return self.account.postbox.transaction { transaction -> [EnginePeer] in return transaction.getChatListPeers(groupId: .root, filterPredicate: filterPredicate, additionalFilter: nil).map(EnginePeer.init) From 2150d65f787be00dec7a36e4637e803d7413e135 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 13 Jun 2024 22:13:25 +0400 Subject: [PATCH 2/3] Update API [skip ci] --- submodules/TelegramApi/Sources/Api36.swift | 7 +- .../TelegramEngine/Payments/Stars.swift | 112 ++++++++++-------- .../Payments/TelegramEnginePayments.swift | 4 +- .../Sources/StarsStatisticsScreen.swift | 2 +- .../Sources/StarsTransactionsScreen.swift | 6 +- 5 files changed, 72 insertions(+), 59 deletions(-) diff --git a/submodules/TelegramApi/Sources/Api36.swift b/submodules/TelegramApi/Sources/Api36.swift index 7cb64347a9..736668c8f7 100644 --- a/submodules/TelegramApi/Sources/Api36.swift +++ b/submodules/TelegramApi/Sources/Api36.swift @@ -8795,13 +8795,14 @@ public extension Api.functions.payments { } } public extension Api.functions.payments { - static func getStarsTransactions(flags: Int32, peer: Api.InputPeer, offset: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func getStarsTransactions(flags: Int32, peer: Api.InputPeer, offset: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(1731904249) + buffer.appendInt32(-1751937702) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) serializeString(offset, buffer: buffer, boxed: false) - return (FunctionDescription(name: "payments.getStarsTransactions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("offset", String(describing: offset))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "payments.getStarsTransactions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("offset", String(describing: offset)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in let reader = BufferReader(buffer) var result: Api.payments.StarsStatus? if let signature = reader.readInt32() { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 4a1f1a0ac5..bb180303ab 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -76,7 +76,7 @@ private enum RequestStarsStateError { case generic } -private func _internal_requestStarsState(account: Account, peerId: EnginePeer.Id, subject: StarsTransactionsContext.Subject, offset: String?) -> Signal { +private func _internal_requestStarsState(account: Account, peerId: EnginePeer.Id, mode: StarsTransactionsContext.Mode, offset: String?, limit: Int32) -> Signal { return account.postbox.transaction { transaction -> Peer? in return transaction.getPeer(peerId) } @@ -89,7 +89,7 @@ private func _internal_requestStarsState(account: Account, peerId: EnginePeer.Id let signal: Signal if let offset { var flags: Int32 = 0 - switch subject { + switch mode { case .incoming: flags = 1 << 0 case .outgoing: @@ -97,7 +97,7 @@ private func _internal_requestStarsState(account: Account, peerId: EnginePeer.Id default: break } - signal = account.network.request(Api.functions.payments.getStarsTransactions(flags: flags, peer: inputPeer, offset: offset)) + signal = account.network.request(Api.functions.payments.getStarsTransactions(flags: flags, peer: inputPeer, offset: offset, limit: limit)) } else { signal = account.network.request(Api.functions.payments.getStarsStatus(peer: inputPeer)) } @@ -177,7 +177,7 @@ private final class StarsContextImpl { } self.previousLoadTimestamp = currentTimestamp - self.disposable.set((_internal_requestStarsState(account: self.account, peerId: self.peerId, subject: .all, offset: nil) + self.disposable.set((_internal_requestStarsState(account: self.account, peerId: self.peerId, mode: .all, offset: nil, limit: 5) |> deliverOnMainQueue).start(next: { [weak self] status in guard let self else { return @@ -220,7 +220,7 @@ private final class StarsContextImpl { self._state?.isLoading = true - self.disposable.set((_internal_requestStarsState(account: self.account, peerId: self.peerId, subject: .all, offset: nextOffset) + self.disposable.set((_internal_requestStarsState(account: self.account, peerId: self.peerId, mode: .all, offset: nextOffset, limit: 10) |> deliverOnMainQueue).start(next: { [weak self] status in if let self { self.updateState(StarsContext.State(flags: [], balance: status.balance, transactions: currentState.transactions + status.transactions, canLoadMore: status.nextOffset != nil, isLoading: false)) @@ -437,7 +437,7 @@ private final class StarsTransactionsContextImpl { private let account: Account private weak var starsContext: StarsContext? private let peerId: EnginePeer.Id - private let subject: StarsTransactionsContext.Subject + private let mode: StarsTransactionsContext.Mode private var _state: StarsTransactionsContext.State private let _statePromise = Promise() @@ -449,17 +449,22 @@ private final class StarsTransactionsContextImpl { private let disposable = MetaDisposable() private var stateDisposable: Disposable? - init(account: Account, starsContext: StarsContext, subject: StarsTransactionsContext.Subject) { + init(account: Account, subject: StarsTransactionsContext.Subject, mode: StarsTransactionsContext.Mode) { assert(Queue.mainQueue().isCurrent()) self.account = account - self.starsContext = starsContext - self.peerId = starsContext.peerId - self.subject = subject - - let currentTransactions = starsContext.currentState?.transactions ?? [] - let initialTransactions: [StarsContext.State.Transaction] switch subject { + case let .starsContext(starsContext): + self.starsContext = starsContext + self.peerId = starsContext.peerId + case let .peer(peerId): + self.peerId = peerId + } + self.mode = mode + + let currentTransactions = self.starsContext?.currentState?.transactions ?? [] + let initialTransactions: [StarsContext.State.Transaction] + switch mode { case .all: initialTransactions = currentTransactions case .incoming: @@ -471,41 +476,43 @@ private final class StarsTransactionsContextImpl { self._state = StarsTransactionsContext.State(transactions: initialTransactions, canLoadMore: true, isLoading: false) self._statePromise.set(.single(self._state)) - self.stateDisposable = (starsContext.state - |> deliverOnMainQueue).start(next: { [weak self] state in - guard let self, let state else { - return - } - - let currentTransactions = state.transactions - let filteredTransactions: [StarsContext.State.Transaction] - switch subject { - case .all: - filteredTransactions = currentTransactions - case .incoming: - filteredTransactions = currentTransactions.filter { $0.count > 0 } - case .outgoing: - filteredTransactions = currentTransactions.filter { $0.count < 0 } - } - - if filteredTransactions != initialTransactions { - var existingIds = Set() - for transaction in self._state.transactions { - if !transaction.flags.contains(.isLocal) { - existingIds.insert(transaction.id) - } + if let starsContext = self.starsContext { + self.stateDisposable = (starsContext.state + |> deliverOnMainQueue).start(next: { [weak self] state in + guard let self, let state else { + return } - - var updatedState = self._state - updatedState.transactions.removeAll(where: { $0.flags.contains(.isLocal) }) - for transaction in filteredTransactions.reversed() { - if !existingIds.contains(transaction.id) { - updatedState.transactions.insert(transaction, at: 0) - } + + let currentTransactions = state.transactions + let filteredTransactions: [StarsContext.State.Transaction] + switch mode { + case .all: + filteredTransactions = currentTransactions + case .incoming: + filteredTransactions = currentTransactions.filter { $0.count > 0 } + case .outgoing: + filteredTransactions = currentTransactions.filter { $0.count < 0 } } - self.updateState(updatedState) - } - }) + + if filteredTransactions != initialTransactions { + var existingIds = Set() + for transaction in self._state.transactions { + if !transaction.flags.contains(.isLocal) { + existingIds.insert(transaction.id) + } + } + + var updatedState = self._state + updatedState.transactions.removeAll(where: { $0.flags.contains(.isLocal) }) + for transaction in filteredTransactions.reversed() { + if !existingIds.contains(transaction.id) { + updatedState.transactions.insert(transaction, at: 0) + } + } + self.updateState(updatedState) + } + }) + } } deinit { @@ -529,7 +536,7 @@ private final class StarsTransactionsContextImpl { updatedState.isLoading = true self.updateState(updatedState) - self.disposable.set((_internal_requestStarsState(account: self.account, peerId: self.peerId, subject: self.subject, offset: nextOffset) + self.disposable.set((_internal_requestStarsState(account: self.account, peerId: self.peerId, mode: self.mode, offset: nextOffset, limit: 10) |> deliverOnMainQueue).start(next: { [weak self] status in guard let self else { return @@ -542,7 +549,7 @@ private final class StarsTransactionsContextImpl { updatedState.canLoadMore = self.nextOffset != nil self.updateState(updatedState) - if case .all = self.subject, nextOffset.isEmpty { + if case .all = self.mode, nextOffset.isEmpty { self.starsContext?.updateBalance(status.balance, transactions: status.transactions) } else { self.starsContext?.updateBalance(status.balance, transactions: nil) @@ -572,6 +579,11 @@ public final class StarsTransactionsContext { fileprivate let impl: QueueLocalObject public enum Subject { + case starsContext(StarsContext) + case peer(EnginePeer.Id) + } + + public enum Mode { case all case incoming case outgoing @@ -601,9 +613,9 @@ public final class StarsTransactionsContext { } } - init(account: Account, starsContext: StarsContext, subject: Subject) { + init(account: Account, subject: Subject, mode: Mode) { self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: { - return StarsTransactionsContextImpl(account: account, starsContext: starsContext, subject: subject) + return StarsTransactionsContextImpl(account: account, subject: subject, mode: mode) }) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift index fa68190c7c..9fea23af87 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift @@ -75,8 +75,8 @@ public extension TelegramEngine { } - public func peerStarsTransactionsContext(starsContext: StarsContext, subject: StarsTransactionsContext.Subject) -> StarsTransactionsContext { - return StarsTransactionsContext(account: self.account, starsContext: starsContext, subject: subject) + public func peerStarsTransactionsContext(subject: StarsTransactionsContext.Subject, mode: StarsTransactionsContext.Mode) -> StarsTransactionsContext { + return StarsTransactionsContext(account: self.account, subject: subject, mode: mode) } public func sendStarsPaymentForm(formId: Int64, source: BotPaymentInvoiceSource) -> Signal { diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift index 06aec07d41..fd45cc9a5d 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift @@ -433,7 +433,7 @@ final class StarsStatisticsScreenComponent: Component { if let current = self.allTransactionsContext { allTransactionsContext = current } else { - allTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(starsContext: component.starsContext, subject: .all) + allTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(subject: .starsContext(component.starsContext), mode: .all) } panelItems.append(StarsTransactionsPanelContainerComponent.Item( diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift index 27cbe04843..64744a6353 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift @@ -554,21 +554,21 @@ final class StarsTransactionsScreenComponent: Component { if let current = self.allTransactionsContext { allTransactionsContext = current } else { - allTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(starsContext: component.starsContext, subject: .all) + allTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(subject: .starsContext(component.starsContext), mode: .all) } let incomingTransactionsContext: StarsTransactionsContext if let current = self.incomingTransactionsContext { incomingTransactionsContext = current } else { - incomingTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(starsContext: component.starsContext, subject: .incoming) + incomingTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(subject: .starsContext(component.starsContext), mode: .incoming) } let outgoingTransactionsContext: StarsTransactionsContext if let current = self.outgoingTransactionsContext { outgoingTransactionsContext = current } else { - outgoingTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(starsContext: component.starsContext, subject: .outgoing) + outgoingTransactionsContext = component.context.engine.payments.peerStarsTransactionsContext(subject: .starsContext(component.starsContext), mode: .outgoing) } panelItems.append(StarsTransactionsPanelContainerComponent.Item( From 8ad27b9ef21990ebc224f9110b8e3ad6e83b2fd0 Mon Sep 17 00:00:00 2001 From: Mikhail Filimonov Date: Thu, 13 Jun 2024 17:59:31 -0300 Subject: [PATCH 3/3] update chartbar for XTR --- .../Controllers/BaseChartController.swift | 12 +++++ .../StackedBarsChartController.swift | 28 ++++++++--- .../Renderes/VerticalScalesRenderer.swift | 47 ++----------------- .../Helpers/ScalesNumberFormatter.swift | 2 + .../Sources/Helpers/UIColor+Utils.swift | 2 +- .../Sources/Helpers/UIView+Extensions.swift | 2 +- .../Statistics/StarsRevenueStatistics.swift | 5 +- .../Messages/StoryListContext.swift | 18 ++++--- 8 files changed, 56 insertions(+), 60 deletions(-) diff --git a/submodules/GraphCore/Sources/Charts/Controllers/BaseChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/BaseChartController.swift index f24cbb0325..8ecceb12ed 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/BaseChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/BaseChartController.swift @@ -72,6 +72,18 @@ enum BaseConstants { return numberFormatter }() + static let starNumberFormatter: NumberFormatter = { + let numberFormatter = NumberFormatter() + numberFormatter.allowsFloats = true + numberFormatter.numberStyle = .decimal + numberFormatter.usesGroupingSeparator = true + numberFormatter.groupingSeparator = " " + numberFormatter.minimumIntegerDigits = 1 + numberFormatter.minimumFractionDigits = 0 + numberFormatter.maximumFractionDigits = 2 + return numberFormatter + }() + static let detailsNumberFormatter: NumberFormatter = { let detailsNumberFormatter = NumberFormatter() detailsNumberFormatter.allowsFloats = false diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift index 0ac4feb20d..613e946a42 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift @@ -13,7 +13,23 @@ import Cocoa import UIKit #endif +public enum GraphCurrency : String { + case xtr = "XTR" + case ton = "TON" + + var formatter: NumberFormatter { + switch self { + case .xtr: + return BaseConstants.starNumberFormatter + case .ton: + return BaseConstants.tonNumberFormatter + } + } +} + public class StackedBarsChartController: BaseChartController { + + let barsController: BarsComponentController let zoomedBarsController: BarsComponentController @@ -23,12 +39,12 @@ public class StackedBarsChartController: BaseChartController { } } - public init(chartsCollection: ChartsCollection, isCrypto: Bool = false, rate: Double = 1.0) { + public init(chartsCollection: ChartsCollection, currency: GraphCurrency? = nil, drawCurrency:((CGContext, UIColor, CGPoint)->Void)? = nil, rate: Double = 1.0) { let horizontalScalesRenderer = HorizontalScalesRenderer() let verticalScalesRenderer = VerticalScalesRenderer() var secondaryScalesRenderer: VerticalScalesRenderer? - if isCrypto { - verticalScalesRenderer.isCrypto = true + if let _ = currency { + verticalScalesRenderer.drawCurrency = drawCurrency secondaryScalesRenderer = VerticalScalesRenderer() secondaryScalesRenderer?.isRightAligned = true } @@ -38,10 +54,10 @@ public class StackedBarsChartController: BaseChartController { verticalScalesRenderer: verticalScalesRenderer, secondaryScalesRenderer: secondaryScalesRenderer, previewBarsChartRenderer: BarChartRenderer()) - if isCrypto { + if let currency { barsController.conversionRate = rate - barsController.verticalLimitsNumberFormatter = BaseConstants.tonNumberFormatter - barsController.detailsNumberFormatter = BaseConstants.tonNumberFormatter + barsController.verticalLimitsNumberFormatter = currency.formatter + barsController.detailsNumberFormatter = currency.formatter } zoomedBarsController = BarsComponentController(isZoomed: true, mainBarsRenderer: BarChartRenderer(), diff --git a/submodules/GraphCore/Sources/Charts/Renderes/VerticalScalesRenderer.swift b/submodules/GraphCore/Sources/Charts/Renderes/VerticalScalesRenderer.swift index 2245bd62b3..fa11122d14 100644 --- a/submodules/GraphCore/Sources/Charts/Renderes/VerticalScalesRenderer.swift +++ b/submodules/GraphCore/Sources/Charts/Renderes/VerticalScalesRenderer.swift @@ -9,7 +9,7 @@ import Foundation #if os(macOS) import Cocoa -typealias UIColor = NSColor +public typealias UIColor = NSColor #else import UIKit #endif @@ -26,7 +26,7 @@ class VerticalScalesRenderer: BaseChartRenderer { var axisXWidth: CGFloat = GView.oneDevicePixel var isRightAligned: Bool = false - var isCrypto: Bool = false + var drawCurrency:((CGContext, UIColor, CGPoint)->Void)? var horizontalLinesColor: GColor = .black { didSet { @@ -122,45 +122,6 @@ class VerticalScalesRenderer: BaseChartRenderer { context.strokeLineSegments(between: lineSegments) } - func drawTonSymbol(context: CGContext, color: UIColor, at point: CGPoint) { - let width: CGFloat = 8.0 - let height: CGFloat = 7.5 - let cornerRadius: CGFloat = 0.5 - - let topPoint = CGPoint(x: point.x + width / 2, y: point.y) - let bottomPoint = CGPoint(x: point.x + width / 2, y: point.y + height) - let leftTopPoint = CGPoint(x: point.x, y: point.y) - let rightTopPoint = CGPoint(x: point.x + width, y: point.y) - - context.saveGState() - - context.beginPath() - context.move(to: CGPoint(x: leftTopPoint.x + cornerRadius, y: leftTopPoint.y)) - - context.addArc(tangent1End: leftTopPoint, tangent2End: bottomPoint, radius: cornerRadius) - context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - cornerRadius + GView.oneDevicePixel)) - - context.move(to: CGPoint(x: rightTopPoint.x - cornerRadius, y: rightTopPoint.y)) - context.addArc(tangent1End: rightTopPoint, tangent2End: bottomPoint, radius: cornerRadius) - context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - cornerRadius + GView.oneDevicePixel)) - - context.move(to: CGPoint(x: leftTopPoint.x + cornerRadius, y: leftTopPoint.y)) - context.addLine(to: CGPoint(x: rightTopPoint.x - cornerRadius, y: rightTopPoint.y)) - - context.move(to: topPoint) - context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - 1.0)) - - context.setLineWidth(1.0) - context.setLineCap(.round) - context.setFillColor(UIColor.clear.cgColor) - context.setStrokeColor(color.withAlphaComponent(1.0).cgColor) - - context.setAlpha(color.alphaValue) - context.strokePath() - - context.restoreGState() - } - func drawVerticalLabels(_ labels: [LinesChartLabel], attributes: [NSAttributedString.Key: Any]) { if isRightAligned { for label in labels { @@ -176,9 +137,9 @@ class VerticalScalesRenderer: BaseChartRenderer { let textNode = LabelNode.layoutText(attributedString, bounds.size) var xOffset = 0.0 - if self.isCrypto { + if let drawCurrency { xOffset += 11.0 - drawTonSymbol(context: context, color: attributes[.foregroundColor] as? UIColor ?? .black, at: CGPoint(x: chartFrame.minX, y: y + 4.0)) + drawCurrency(context, attributes[.foregroundColor] as? UIColor ?? .black, CGPoint(x: chartFrame.minX, y: y + 4.0)) } textNode.1.draw(CGRect(origin: CGPoint(x: chartFrame.minX + xOffset, y: y), size: textNode.0.size), in: context, backingScaleFactor: deviceScale) diff --git a/submodules/GraphCore/Sources/Helpers/ScalesNumberFormatter.swift b/submodules/GraphCore/Sources/Helpers/ScalesNumberFormatter.swift index fa25137fd7..19c732f0bb 100644 --- a/submodules/GraphCore/Sources/Helpers/ScalesNumberFormatter.swift +++ b/submodules/GraphCore/Sources/Helpers/ScalesNumberFormatter.swift @@ -60,3 +60,5 @@ class TonNumberFormatter: NumberFormatter { return balanceText } } + + diff --git a/submodules/GraphCore/Sources/Helpers/UIColor+Utils.swift b/submodules/GraphCore/Sources/Helpers/UIColor+Utils.swift index fde53f46be..a25a87b2c8 100644 --- a/submodules/GraphCore/Sources/Helpers/UIColor+Utils.swift +++ b/submodules/GraphCore/Sources/Helpers/UIColor+Utils.swift @@ -21,7 +21,7 @@ func makeCIColor(color: GColor) -> CIColor { #endif } -extension GColor { +public extension GColor { var redValue: CGFloat{ return makeCIColor(color: self).red } var greenValue: CGFloat{ return makeCIColor(color: self).green } var blueValue: CGFloat{ return makeCIColor(color: self).blue } diff --git a/submodules/GraphCore/Sources/Helpers/UIView+Extensions.swift b/submodules/GraphCore/Sources/Helpers/UIView+Extensions.swift index ef76b00fcb..ccc57a1258 100644 --- a/submodules/GraphCore/Sources/Helpers/UIView+Extensions.swift +++ b/submodules/GraphCore/Sources/Helpers/UIView+Extensions.swift @@ -20,6 +20,6 @@ public typealias GView = UIView #endif -extension GView { +public extension GView { static let oneDevicePixel: CGFloat = (1.0 / max(2, min(1, deviceScale))) } diff --git a/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift b/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift index a3377d99df..b57d3cd8cb 100644 --- a/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift +++ b/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift @@ -9,12 +9,12 @@ public struct StarsRevenueStats: Equatable { public let currentBalance: Int64 public let availableBalance: Int64 public let overallRevenue: Int64 + public let withdrawEnabled: Bool } public let revenueGraph: StatsGraph public let balances: Balances public let usdRate: Double - init(revenueGraph: StatsGraph, balances: Balances, usdRate: Double) { self.revenueGraph = revenueGraph self.balances = balances @@ -58,8 +58,7 @@ extension StarsRevenueStats.Balances { init(apiStarsRevenueStatus: Api.StarsRevenueStatus) { switch apiStarsRevenueStatus { case let .starsRevenueStatus(flags, currentBalance, availableBalance, overallRevenue): - let _ = flags - self.init(currentBalance: currentBalance, availableBalance: availableBalance, overallRevenue: overallRevenue) + self.init(currentBalance: currentBalance, availableBalance: availableBalance, overallRevenue: overallRevenue, withdrawEnabled: ((flags & (1 << 0)) != 0)) } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift index 7dc1bc5711..241197c745 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift @@ -565,7 +565,7 @@ public struct StoryListContextState: Equatable { public var isCached: Bool public var hasCache: Bool public var allEntityFiles: [MediaId: TelegramMediaFile] - + public var isLoading: Bool public init( peerReference: PeerReference?, items: [Item], @@ -574,7 +574,8 @@ public struct StoryListContextState: Equatable { loadMoreToken: AnyHashable?, isCached: Bool, hasCache: Bool, - allEntityFiles: [MediaId: TelegramMediaFile] + allEntityFiles: [MediaId: TelegramMediaFile], + isLoading: Bool ) { self.peerReference = peerReference self.items = items @@ -584,6 +585,7 @@ public struct StoryListContextState: Equatable { self.isCached = isCached self.hasCache = hasCache self.allEntityFiles = allEntityFiles + self.isLoading = isLoading } } @@ -625,7 +627,7 @@ public final class PeerStoryListContext: StoryListContext { self.peerId = peerId self.isArchived = isArchived - self.stateValue = State(peerReference: nil, items: [], pinnedIds: Set(), totalCount: 0, loadMoreToken: AnyHashable(0 as Int), isCached: true, hasCache: false, allEntityFiles: [:]) + self.stateValue = State(peerReference: nil, items: [], pinnedIds: Set(), totalCount: 0, loadMoreToken: AnyHashable(0 as Int), isCached: true, hasCache: false, allEntityFiles: [:], isLoading: false) let _ = (account.postbox.transaction { transaction -> (PeerReference?, [State.Item], [Int32], Int, [MediaId: TelegramMediaFile], Bool) in let key = ValueBoxKey(length: 8 + 1) @@ -714,7 +716,7 @@ public final class PeerStoryListContext: StoryListContext { return } - var updatedState = State(peerReference: peerReference, items: items, pinnedIds: Set(pinnedIds), totalCount: totalCount, loadMoreToken: AnyHashable(0 as Int), isCached: true, hasCache: hasCache, allEntityFiles: allEntityFiles) + var updatedState = State(peerReference: peerReference, items: items, pinnedIds: Set(pinnedIds), totalCount: totalCount, loadMoreToken: AnyHashable(0 as Int), isCached: true, hasCache: hasCache, allEntityFiles: allEntityFiles, isLoading: false) updatedState.items.sort(by: { lhs, rhs in let lhsPinned = updatedState.pinnedIds.contains(lhs.storyItem.id) let rhsPinned = updatedState.pinnedIds.contains(rhs.storyItem.id) @@ -1280,7 +1282,11 @@ public final class SearchStoryListContext: StoryListContext { return self.statePromise.get() } - private var isLoadingMore: Bool = false + private var isLoadingMore: Bool = false { + didSet { + self.stateValue.isLoading = isLoadingMore + } + } private var requestDisposable: Disposable? private var updatesDisposable: Disposable? @@ -1292,7 +1298,7 @@ public final class SearchStoryListContext: StoryListContext { self.account = account self.source = source - self.stateValue = State(peerReference: nil, items: [], pinnedIds: Set(), totalCount: 0, loadMoreToken: AnyHashable(""), isCached: false, hasCache: false, allEntityFiles: [:]) + self.stateValue = State(peerReference: nil, items: [], pinnedIds: Set(), totalCount: 0, loadMoreToken: AnyHashable(""), isCached: false, hasCache: false, allEntityFiles: [:], isLoading: false) self.statePromise.set(.single(self.stateValue)) self.loadMore(completion: nil)