From 8862492480af37572499656622a5626cae0c9360 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 28 Jun 2025 17:38:45 +0200 Subject: [PATCH] Update API --- .../Telegram-iOS/Resources/GiftDiamond.tgs | Bin 0 -> 107904 bytes .../Sources/AccountContext.swift | 49 ++ submodules/PremiumUI/Resources/diamond.scn | Bin 70359 -> 0 bytes .../Sources/PremiumIntroScreen.swift | 6 +- .../LocalizationListControllerNode.swift | 38 +- .../Sources/ChannelStatsController.swift | 84 +-- .../Sources/MonetizationBalanceItem.swift | 19 +- .../Sources/RevenueWithdrawalController.swift | 4 +- .../Sources/StatsOverviewItem.swift | 56 +- .../Sources/TransactionInfoScreen.swift | 47 +- submodules/TelegramApi/Sources/Api0.swift | 24 +- submodules/TelegramApi/Sources/Api15.swift | 42 ++ submodules/TelegramApi/Sources/Api2.swift | 360 ++++++----- submodules/TelegramApi/Sources/Api25.swift | 24 +- submodules/TelegramApi/Sources/Api27.swift | 28 - submodules/TelegramApi/Sources/Api3.swift | 200 ------ submodules/TelegramApi/Sources/Api36.swift | 426 ++++++++++--- submodules/TelegramApi/Sources/Api37.swift | 470 ++++---------- submodules/TelegramApi/Sources/Api38.swift | 108 ---- submodules/TelegramApi/Sources/Api39.swift | 65 +- .../Account/AccountIntermediateState.swift | 16 +- .../ApiUtils/StoreMessage_Telegram.swift | 2 +- .../ApiUtils/TelegramMediaAction.swift | 4 + .../State/AccountStateManagementUtils.swift | 8 +- .../Sources/State/AccountStateManager.swift | 43 +- .../Statistics/RevenueStatistics.swift | 589 ------------------ .../Statistics/StarsRevenueStatistics.swift | 84 ++- .../TelegramEngine/Data/PeersData.swift | 56 ++ .../TelegramEngine/Payments/Stars.swift | 33 +- .../Payments/TelegramEnginePayments.swift | 4 +- .../Peers/TelegramEnginePeers.swift | 14 +- .../Resources/PresentationResourceKey.swift | 4 + .../Resources/PresentationResourcesChat.swift | 18 + .../ChatMessageActionBubbleContentNode.swift | 35 +- .../ChatMessageGiftBubbleContentNode.swift | 5 + .../ChatMessageTodoBubbleContentNode.swift | 54 +- .../PeerInfoScreen/Sources/PeerInfoData.swift | 26 +- .../Sources/PeerInfoScreen.swift | 16 +- .../Premium/PremiumDiamondComponent/BUILD | 1 + .../Sources/PremiumDiamondComponent.swift | 47 +- .../Sources/GiftAvatarComponent.swift | 17 +- .../Sources/LanguageSelectionScreenNode.swift | 4 +- .../StarsBalanceOverlayComponent.swift | 4 +- .../Sources/StarsImageComponent.swift | 2 +- .../Sources/StarsTransactionScreen.swift | 19 +- .../Sources/StarsStatisticsScreen.swift | 10 +- .../Sources/StarsTransactionsScreen.swift | 11 +- .../StarsRevenueWithdrawalController.swift | 2 +- .../Sources/StarsWithdrawalScreen.swift | 6 +- .../Contents.json | 12 + .../sistemplus_16.pdf | Bin 0 -> 3924 bytes .../Contents.json | 12 + .../sistemdone_16.pdf | Bin 0 -> 3996 bytes .../Contents.json | 12 + .../sistemundone_16.pdf | Bin 0 -> 3935 bytes .../Premium/Perk/Todo.imageset/Contents.json | 12 + .../Premium/Perk/Todo.imageset/checks.pdf | Bin 0 -> 11545 bytes .../Chat/ChatControllerLoadDisplayNode.swift | 12 +- .../TelegramUI/Sources/ChatController.swift | 26 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 45 +- .../TranslateUI/Sources/ChatTranslation.swift | 3 +- .../TranslateUI/Sources/Translate.swift | 133 ++++ .../TranslateUI/Sources/TranslateScreen.swift | 107 +++- 63 files changed, 1595 insertions(+), 1963 deletions(-) create mode 100644 Telegram/Telegram-iOS/Resources/GiftDiamond.tgs delete mode 100644 submodules/PremiumUI/Resources/diamond.scn delete mode 100644 submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoAppended.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoAppended.imageset/sistemplus_16.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoCompleted.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoCompleted.imageset/sistemdone_16.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoIncompleted.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoIncompleted.imageset/sistemundone_16.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Premium/Perk/Todo.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Premium/Perk/Todo.imageset/checks.pdf diff --git a/Telegram/Telegram-iOS/Resources/GiftDiamond.tgs b/Telegram/Telegram-iOS/Resources/GiftDiamond.tgs new file mode 100644 index 0000000000000000000000000000000000000000..60709e5bbdb48177cd221599ef61d8b8fb6b8a9b GIT binary patch literal 107904 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�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 BWDNiS literal 0 HcmV?d00001 diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 42bf87629b..733f79ef20 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -1565,3 +1565,52 @@ public struct StarsSubscriptionConfiguration { } } } + +public struct TranslationConfiguration { + static var defaultValue: TranslationConfiguration { + return TranslationConfiguration(manual: .disabled, auto: .disabled) + } + + public enum TranslationAvailability { + case enabled + case system + case alternative + case disabled + + init(string: String) { + switch string { + case "enabled": + #if DEBUG + self = .system + #else + self = .enabled + #endif + case "system": + self = .system + case "alternative": + self = .alternative + default: + self = .disabled + } + } + } + + public let manual: TranslationAvailability + public let auto: TranslationAvailability + + fileprivate init(manual: TranslationAvailability, auto: TranslationAvailability) { + self.manual = manual + self.auto = auto + } + + public static func with(appConfiguration: AppConfiguration) -> TranslationConfiguration { + if let data = appConfiguration.data { + let manualValue = data["translations_manual_enabled"] as? String ?? "disabled" + let autoValue = data["translations_auto_enabled"] as? String ?? "disabled" + + return TranslationConfiguration(manual: TranslationAvailability(string: manualValue), auto: TranslationAvailability(string: autoValue)) + } else { + return .defaultValue + } + } +} diff --git a/submodules/PremiumUI/Resources/diamond.scn b/submodules/PremiumUI/Resources/diamond.scn deleted file mode 100644 index 882a662d157db5aa7769866853a648a3743a9171..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70359 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 C3`oHM diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index 60f72dcce5..23b85bf85f 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -827,7 +827,7 @@ public enum PremiumPerk: CaseIterable { case .paidMessages: return "Premium/Perk/PaidMessages" case .todo: - return "Premium/Perk/PaidMessages" + return "Premium/Perk/Todo" case .businessLocation: return "Premium/BusinessPerk/Location" case .businessHours: @@ -858,6 +858,7 @@ struct PremiumIntroConfiguration { .voiceToText, .fasterDownload, .translation, + .todo, .animatedEmoji, .emojiStatus, .messageEffects, @@ -2172,6 +2173,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { demoSubject = .messageEffects case .paidMessages: demoSubject = .paidMessages + case .todo: + demoSubject = .todo case .business: demoSubject = .business let _ = ApplicationSpecificNotice.setDismissedBusinessBadge(accountManager: accountContext.sharedContext.accountManager).startStandalone() @@ -3699,6 +3702,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent { let buttonTitle: String var buttonSubtitle: String? if case let .auth(price) = context.component.source { + //TODO:localize buttonTitle = "Sign up for \(price)" buttonSubtitle = "Get Telegram Premium for 1 week" } else if isUnusedGift { diff --git a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift index 7807536eee..fcb305ae46 100644 --- a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift +++ b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift @@ -431,6 +431,32 @@ final class LocalizationListControllerNode: ViewControllerTracingNode { }) } + let translationConfiguration = TranslationConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) + var translateButtonAvailable = false + var chatTranslationAvailable = false + + switch translationConfiguration.manual { + case .enabled, .alternative: + translateButtonAvailable = true + case .system: + if #available(iOS 18.0, *) { + translateButtonAvailable = true + } + default: + break + } + + switch translationConfiguration.auto { + case .enabled: + chatTranslationAvailable = true + case .system: + if #available(iOS 18.0, *) { + chatTranslationAvailable = true + } + default: + break + } + let previousState = Atomic(value: nil) let previousEntriesHolder = Atomic<([LanguageListEntry], PresentationTheme, PresentationStrings)?>(value: nil) self.listDisposable = combineLatest( @@ -465,7 +491,6 @@ final class LocalizationListControllerNode: ViewControllerTracingNode { if let languages = translationSettings.ignoredLanguages { ignoredLanguages = languages } else { - if var activeLanguage = activeLanguageCode { let rawSuffix = "-raw" if activeLanguage.hasSuffix(rawSuffix) { @@ -497,12 +522,15 @@ final class LocalizationListControllerNode: ViewControllerTracingNode { if !localizationListState.availableOfficialLocalizations.isEmpty { strongSelf.currentListState = localizationListState - if #available(iOS 12.0, *) { + if translateButtonAvailable || chatTranslationAvailable { entries.append(.translateTitle(text: presentationData.strings.Localization_TranslateMessages.uppercased())) - entries.append(.translate(text: presentationData.strings.Localization_ShowTranslate, value: showTranslate)) - - entries.append(.translateEntire(text: presentationData.strings.Localization_TranslateEntireChat, value: translateChats, locked: !isPremium)) + if translateButtonAvailable { + entries.append(.translate(text: presentationData.strings.Localization_ShowTranslate, value: showTranslate)) + } + if chatTranslationAvailable { + entries.append(.translateEntire(text: presentationData.strings.Localization_TranslateEntireChat, value: translateChats, locked: !isPremium)) + } var value = "" if ignoredLanguages.count > 1 { diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index e2559fbacc..382a785978 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -51,7 +51,7 @@ private final class ChannelStatsControllerArguments { let buyAds: () -> Void let openMonetizationIntro: () -> Void let openMonetizationInfo: () -> Void - let openTonTransaction: (RevenueStatsTransactionsContext.State.Transaction) -> Void + let openTonTransaction: (StarsContext.State.Transaction) -> Void let openStarsTransaction: (StarsContext.State.Transaction) -> Void let expandTransactions: (Bool) -> Void let updateCpmEnabled: (Bool) -> Void @@ -59,7 +59,7 @@ private final class ChannelStatsControllerArguments { let openEarnStars: () -> Void let dismissInput: () -> Void - init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal, openPostStats: @escaping (EnginePeer, StatsPostItem) -> Void, openStory: @escaping (EngineStoryItem, UIView) -> Void, contextAction: @escaping (MessageId, ASDisplayNode, ContextGesture?) -> Void, copyBoostLink: @escaping (String) -> Void, shareBoostLink: @escaping (String) -> Void, openBoost: @escaping (ChannelBoostersContext.State.Boost) -> Void, expandBoosters: @escaping () -> Void, openGifts: @escaping () -> Void, createPrepaidGiveaway: @escaping (PrepaidGiveaway) -> Void, updateGiftsSelected: @escaping (Bool) -> Void, updateStarsSelected: @escaping (Bool) -> Void, requestTonWithdraw: @escaping () -> Void, requestStarsWithdraw: @escaping () -> Void, showTimeoutTooltip: @escaping (Int32) -> Void, buyAds: @escaping () -> Void, openMonetizationIntro: @escaping () -> Void, openMonetizationInfo: @escaping () -> Void, openTonTransaction: @escaping (RevenueStatsTransactionsContext.State.Transaction) -> Void, openStarsTransaction: @escaping (StarsContext.State.Transaction) -> Void, expandTransactions: @escaping (Bool) -> Void, updateCpmEnabled: @escaping (Bool) -> Void, presentCpmLocked: @escaping () -> Void, openEarnStars: @escaping () -> Void, dismissInput: @escaping () -> Void) { + init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal, openPostStats: @escaping (EnginePeer, StatsPostItem) -> Void, openStory: @escaping (EngineStoryItem, UIView) -> Void, contextAction: @escaping (MessageId, ASDisplayNode, ContextGesture?) -> Void, copyBoostLink: @escaping (String) -> Void, shareBoostLink: @escaping (String) -> Void, openBoost: @escaping (ChannelBoostersContext.State.Boost) -> Void, expandBoosters: @escaping () -> Void, openGifts: @escaping () -> Void, createPrepaidGiveaway: @escaping (PrepaidGiveaway) -> Void, updateGiftsSelected: @escaping (Bool) -> Void, updateStarsSelected: @escaping (Bool) -> Void, requestTonWithdraw: @escaping () -> Void, requestStarsWithdraw: @escaping () -> Void, showTimeoutTooltip: @escaping (Int32) -> Void, buyAds: @escaping () -> Void, openMonetizationIntro: @escaping () -> Void, openMonetizationInfo: @escaping () -> Void, openTonTransaction: @escaping (StarsContext.State.Transaction) -> Void, openStarsTransaction: @escaping (StarsContext.State.Transaction) -> Void, expandTransactions: @escaping (Bool) -> Void, updateCpmEnabled: @escaping (Bool) -> Void, presentCpmLocked: @escaping () -> Void, openEarnStars: @escaping () -> Void, dismissInput: @escaping () -> Void) { self.context = context self.loadDetailedGraph = loadDetailedGraph self.openPostStats = openPostStats @@ -242,11 +242,11 @@ private enum StatsEntry: ItemListNodeEntry { case adsStarsRevenueGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType, Double) case adsProceedsTitle(PresentationTheme, String) - case adsProceedsOverview(PresentationTheme, RevenueStats?, StarsRevenueStats?) + case adsProceedsOverview(PresentationTheme, StarsRevenueStats?, StarsRevenueStats?) case adsProceedsInfo(PresentationTheme, String) case adsTonBalanceTitle(PresentationTheme, String) - case adsTonBalance(PresentationTheme, RevenueStats, Bool, Bool) + case adsTonBalance(PresentationTheme, StarsRevenueStats, Bool, Bool) case adsTonBalanceInfo(PresentationTheme, String) case adsStarsBalanceTitle(PresentationTheme, String) @@ -256,7 +256,7 @@ private enum StatsEntry: ItemListNodeEntry { case earnStarsInfo case adsTransactionsTitle(PresentationTheme, String) case adsTransactionsTabs(PresentationTheme, String, String, Bool) - case adsTransaction(Int32, PresentationTheme, RevenueStatsTransactionsContext.State.Transaction) + case adsTransaction(Int32, PresentationTheme, StarsContext.State.Transaction) case adsStarsTransaction(Int32, PresentationTheme, StarsContext.State.Transaction) case adsTransactionsExpand(PresentationTheme, String, Bool) @@ -1155,8 +1155,7 @@ private enum StatsEntry: ItemListNodeEntry { let detailText: String var detailColor: ItemListDisclosureItemDetailLabelColor = .generic - switch transaction { - case let .proceeds(_, fromDate, toDate): + if let fromDate = transaction.adsProceedsFromDate, let toDate = transaction.adsProceedsToDate { title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Proceeds, font: font, textColor: theme.list.itemPrimaryTextColor) let fromDateString = stringForMediumCompactDate(timestamp: fromDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, withTime: false) let toDateString = stringForMediumCompactDate(timestamp: toDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, withTime: false) @@ -1165,24 +1164,26 @@ private enum StatsEntry: ItemListNodeEntry { } else { detailText = "\(fromDateString) – \(toDateString)" } - case let .withdrawal(status, _, date, provider, _, _): - title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Withdrawal(provider).string, font: font, textColor: theme.list.itemPrimaryTextColor) + } else if case .fragment = transaction.peer { + title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Withdrawal("Fragment").string, font: font, textColor: theme.list.itemPrimaryTextColor) labelColor = theme.list.itemDestructiveColor - switch status { - case .succeed: - detailText = stringForMediumCompactDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat) - case .failed: - detailText = stringForMediumCompactDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, withTime: false) + " – \(presentationData.strings.Monetization_Transaction_Failed)" - detailColor = .destructive - case .pending: + if transaction.flags.contains(.isPending) { detailText = presentationData.strings.Monetization_Transaction_Pending + } else if transaction.flags.contains(.isFailed) { + detailText = stringForMediumCompactDate(timestamp: transaction.date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, withTime: false) + " – \(presentationData.strings.Monetization_Transaction_Failed)" + detailColor = .destructive + } else { + detailText = stringForMediumCompactDate(timestamp: transaction.date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat) } - case let .refund(_, date, _): + } else if transaction.flags.contains(.isRefund) { title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Refund, font: font, textColor: theme.list.itemPrimaryTextColor) - detailText = stringForMediumCompactDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat) + detailText = stringForMediumCompactDate(timestamp: transaction.date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat) + } else { + title = NSAttributedString() + detailText = "" } - let label = tonAmountAttributedString(formatTonAmountText(transaction.amount, dateTimeFormat: presentationData.dateTimeFormat, showPlus: true), integralFont: font, fractionalFont: smallLabelFont, color: labelColor, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString + let label = tonAmountAttributedString(formatTonAmountText(transaction.count.amount.value, dateTimeFormat: presentationData.dateTimeFormat, showPlus: true), integralFont: font, fractionalFont: smallLabelFont, color: labelColor, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString label.insert(NSAttributedString(string: " $ ", font: font, textColor: labelColor), at: 1) if let range = label.string.range(of: "$"), let icon = generateTintedImage(image: UIImage(bundleImageName: "Ads/TonMedium"), color: labelColor) { @@ -1565,9 +1566,9 @@ private func monetizationEntries( presentationData: PresentationData, state: ChannelStatsControllerState, peer: EnginePeer?, - data: RevenueStats?, + data: StarsRevenueStats?, boostData: ChannelBoostStatus?, - transactionsInfo: RevenueStatsTransactionsContext.State, + transactionsInfo: StarsTransactionsContext.State, starsData: StarsRevenueStats?, starsTransactionsInfo: StarsTransactionsContext.State, adsRestricted: Bool, @@ -1587,9 +1588,9 @@ private func monetizationEntries( if canViewRevenue, let data { entries.append(.adsHeader(presentationData.theme, isBot ? presentationData.strings.Monetization_Bot_Header : presentationData.strings.Monetization_Header)) - if !data.topHoursGraph.isEmpty { + if let topHoursGraph = data.topHoursGraph, !topHoursGraph.isEmpty { entries.append(.adsImpressionsTitle(presentationData.theme, presentationData.strings.Monetization_ImpressionsTitle)) - entries.append(.adsImpressionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.topHoursGraph, .hourlyStep)) + entries.append(.adsImpressionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, topHoursGraph, .hourlyStep)) } if !data.revenueGraph.isEmpty { @@ -1608,8 +1609,8 @@ private func monetizationEntries( entries.append(.adsProceedsTitle(presentationData.theme, presentationData.strings.Monetization_StarsProceeds_Title)) entries.append(.adsProceedsOverview(presentationData.theme, canViewRevenue ? data : nil, canViewStarsRevenue ? starsData : nil)) - let hasTonBalance = (data?.balances.overallRevenue ?? 0) > 0 - let hasStarsBalance = (starsData?.balances.overallRevenue ?? StarsAmount.zero) > StarsAmount.zero + let hasTonBalance = (data?.balances.overallRevenue.amount ?? StarsAmount.zero) > StarsAmount.zero + let hasStarsBalance = (starsData?.balances.overallRevenue.amount ?? StarsAmount.zero) > StarsAmount.zero let proceedsInfo: String if (canViewStarsRevenue && hasStarsBalance) && (canViewRevenue && hasTonBalance) { @@ -1632,11 +1633,11 @@ private func monetizationEntries( if canViewRevenue, let data { entries.append(.adsTonBalanceTitle(presentationData.theme, isBot ? presentationData.strings.Monetization_Bot_BalanceTitle : presentationData.strings.Monetization_TonBalanceTitle)) - entries.append(.adsTonBalance(presentationData.theme, data, (isCreator || isBot) && data.balances.availableBalance > 0, data.balances.withdrawEnabled)) + entries.append(.adsTonBalance(presentationData.theme, data, (isCreator || isBot) && data.balances.availableBalance.amount > StarsAmount.zero, data.balances.withdrawEnabled)) if isCreator || isBot { let withdrawalInfoText: String - if data.balances.availableBalance == 0 { + if data.balances.availableBalance.amount == StarsAmount.zero { withdrawalInfoText = presentationData.strings.Monetization_Balance_ZeroInfo } else if monetizationConfiguration.withdrawalAvailable { withdrawalInfoText = presentationData.strings.Monetization_Balance_AvailableInfo @@ -1647,9 +1648,9 @@ private func monetizationEntries( } } - if canViewStarsRevenue, let starsData, starsData.balances.overallRevenue > StarsAmount.zero { + if canViewStarsRevenue, let starsData, starsData.balances.overallRevenue.amount > StarsAmount.zero { entries.append(.adsStarsBalanceTitle(presentationData.theme, presentationData.strings.Monetization_StarsBalanceTitle)) - entries.append(.adsStarsBalance(presentationData.theme, starsData, isCreator && starsData.balances.availableBalance > StarsAmount.zero, !isGroup, starsData.balances.withdrawEnabled, starsData.balances.nextWithdrawalTimestamp)) + entries.append(.adsStarsBalance(presentationData.theme, starsData, isCreator && starsData.balances.availableBalance.amount > StarsAmount.zero, !isGroup, starsData.balances.withdrawEnabled, starsData.balances.nextWithdrawalTimestamp)) entries.append(.adsStarsBalanceInfo(presentationData.theme, isGroup ? presentationData.strings.Monetization_Balance_StarsInfoGroup : presentationData.strings.Monetization_Balance_StarsInfo)) } @@ -1693,12 +1694,12 @@ private func monetizationEntries( i += 1 } - if transactions.count < transactionsInfo.count { + if transactionsInfo.canLoadMore || transactionsInfo.transactions.count > transactions.count { let moreCount: Int32 if !state.transactionsExpanded { - moreCount = min(20, transactionsInfo.count - Int32(transactions.count)) + moreCount = min(20, Int32(transactionsInfo.transactions.count - transactions.count)) } else { - moreCount = min(50, transactionsInfo.count - Int32(transactions.count)) + moreCount = min(50, Int32(transactionsInfo.transactions.count - transactions.count)) } entries.append(.adsTransactionsExpand(presentationData.theme, presentationData.strings.Monetization_Transaction_ShowMoreTransactions(moreCount), false)) } @@ -1762,8 +1763,8 @@ private func channelStatsControllerEntries( giveawayAvailable: Bool, isGroup: Bool, boostsOnly: Bool, - revenueState: RevenueStats?, - revenueTransactions: RevenueStatsTransactionsContext.State, + revenueState: StarsRevenueStats?, + revenueTransactions: StarsTransactionsContext.State, starsState: StarsRevenueStats?, starsTransactions: StarsTransactionsContext.State, adsRestricted: Bool, @@ -1826,7 +1827,7 @@ public func channelStatsController( updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peerId: PeerId, section: ChannelStatsSection = .stats, - existingRevenueContext: RevenueStatsContext? = nil, + existingRevenueContext: StarsRevenueStatsContext? = nil, existingStarsRevenueContext: StarsRevenueStatsContext? = nil, boostStatus: ChannelBoostStatus? = nil, boostStatusUpdated: ((ChannelBoostStatus) -> Void)? = nil @@ -1887,15 +1888,16 @@ public func channelStatsController( let boostsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: false) let giftsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: true) - let revenueContext = existingRevenueContext ?? RevenueStatsContext(account: context.account, peerId: peerId) - let revenueState = Promise() + let revenueContext = existingRevenueContext ?? context.engine.payments.peerStarsRevenueContext(peerId: peerId, ton: true) + let revenueState = Promise() revenueState.set(.single(nil) |> then(revenueContext.state |> map(Optional.init))) - let starsContext = existingStarsRevenueContext ?? context.engine.payments.peerStarsRevenueContext(peerId: peerId) + let starsContext = existingStarsRevenueContext ?? context.engine.payments.peerStarsRevenueContext(peerId: peerId, ton: false) let starsState = Promise() starsState.set(.single(nil) |> then(starsContext.state |> map(Optional.init))) - let revenueTransactions = RevenueStatsTransactionsContext(account: context.account, peerId: peerId) + let revenueTransactions = context.engine.payments.peerStarsTransactionsContext(subject: .peer(peerId: peerId, ton: true), mode: .all) + revenueTransactions.loadMore() let starsTransactions = context.engine.payments.peerStarsTransactionsContext(subject: .peer(peerId: peerId, ton: false), mode: .all) starsTransactions.loadMore() @@ -1906,7 +1908,7 @@ public func channelStatsController( var navigateToChatImpl: ((EnginePeer) -> Void)? var navigateToMessageImpl: ((EngineMessage.Id) -> Void)? var openBoostImpl: ((Bool) -> Void)? - var openTonTransactionImpl: ((RevenueStatsTransactionsContext.State.Transaction) -> Void)? + var openTonTransactionImpl: ((StarsContext.State.Transaction) -> Void)? var openStarsTransactionImpl: ((StarsContext.State.Transaction) -> Void)? var requestTonWithdrawImpl: (() -> Void)? var requestStarsWithdrawImpl: (() -> Void)? @@ -2514,7 +2516,7 @@ public func channelStatsController( } } requestTonWithdrawImpl = { - withdrawalDisposable.set((context.engine.peers.checkChannelRevenueWithdrawalAvailability() + withdrawalDisposable.set((context.engine.peers.checkStarsRevenueWithdrawalAvailability() |> deliverOnMainQueue).start(error: { error in let controller = revenueWithdrawalController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, initialError: error, present: { c, _ in presentImpl?(c) diff --git a/submodules/StatisticsUI/Sources/MonetizationBalanceItem.swift b/submodules/StatisticsUI/Sources/MonetizationBalanceItem.swift index b85bbdeb10..3c9d2c4f20 100644 --- a/submodules/StatisticsUI/Sources/MonetizationBalanceItem.swift +++ b/submodules/StatisticsUI/Sources/MonetizationBalanceItem.swift @@ -175,14 +175,17 @@ final class MonetizationBalanceItemNode: ListViewItemNode, ItemListItemNode { let value: String var isStars = false - if let stats = item.stats as? RevenueStats { - let cryptoValue = formatTonAmountText(stats.balances.availableBalance, dateTimeFormat: item.presentationData.dateTimeFormat) - amountString = tonAmountAttributedString(cryptoValue, integralFont: integralFont, fractionalFont: fractionalFont, color: item.presentationData.theme.list.itemPrimaryTextColor, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) - value = stats.balances.availableBalance == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))" - } else if let stats = item.stats as? StarsRevenueStats { - amountString = NSAttributedString(string: presentationStringsFormattedNumber(stats.balances.availableBalance, item.presentationData.dateTimeFormat.groupingSeparator), font: integralFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor) - value = stats.balances.availableBalance == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))" - isStars = true + if let stats = item.stats as? StarsRevenueStats { + switch stats.balances.availableBalance.currency { + case .ton: + let cryptoValue = formatTonAmountText(stats.balances.availableBalance.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat) + amountString = tonAmountAttributedString(cryptoValue, integralFont: integralFont, fractionalFont: fractionalFont, color: item.presentationData.theme.list.itemPrimaryTextColor, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) + value = stats.balances.availableBalance.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance.amount.value, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))" + case .stars: + amountString = NSAttributedString(string: presentationStringsFormattedNumber(stats.balances.availableBalance.amount, item.presentationData.dateTimeFormat.groupingSeparator), font: integralFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor) + value = stats.balances.availableBalance.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance.amount.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))" + isStars = true + } } else { fatalError() } diff --git a/submodules/StatisticsUI/Sources/RevenueWithdrawalController.swift b/submodules/StatisticsUI/Sources/RevenueWithdrawalController.swift index 7664d1e2cd..174ed110a3 100644 --- a/submodules/StatisticsUI/Sources/RevenueWithdrawalController.swift +++ b/submodules/StatisticsUI/Sources/RevenueWithdrawalController.swift @@ -46,7 +46,7 @@ func confirmRevenueWithdrawalController(context: AccountContext, updatedPresenta } contentNode.updateIsChecking(true) - let signal = context.engine.peers.requestChannelRevenueWithdrawalUrl(peerId: peerId, password: contentNode.password) + let signal = context.engine.peers.requestStarsRevenueWithdrawalUrl(peerId: peerId, ton: false, amount: nil, password: contentNode.password) disposable.set((signal |> deliverOnMainQueue).start(next: { url in dismissImpl?() completion(url) @@ -73,7 +73,7 @@ func confirmRevenueWithdrawalController(context: AccountContext, updatedPresenta } -func revenueWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peerId: EnginePeer.Id, initialError: RequestRevenueWithdrawalError, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController { +func revenueWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peerId: EnginePeer.Id, initialError: RequestStarsRevenueWithdrawalError, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController { let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } let theme = AlertControllerTheme(presentationData: presentationData) diff --git a/submodules/StatisticsUI/Sources/StatsOverviewItem.swift b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift index 60777f05e1..4a707b0696 100644 --- a/submodules/StatisticsUI/Sources/StatsOverviewItem.swift +++ b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift @@ -36,10 +36,6 @@ extension StoryStats: Stats { } -extension RevenueStats: Stats { - -} - extension StarsRevenueStats: Stats { } @@ -763,8 +759,8 @@ class StatsOverviewItemNode: ListViewItemNode { } else { height += topLeftItemLayoutAndApply!.0.height * 4.0 + verticalSpacing * 3.0 } - } else if let stats = item.stats as? RevenueStats { - if let additionalStats = item.additionalStats as? StarsRevenueStats, additionalStats.balances.overallRevenue > StarsAmount.zero { + } else if let stats = item.stats as? StarsRevenueStats, case .ton = stats.balances.overallRevenue.currency { + if let additionalStats = item.additionalStats as? StarsRevenueStats, additionalStats.balances.overallRevenue.amount > StarsAmount.zero { twoColumnLayout = true useMinLeftColumnWidth = true @@ -772,9 +768,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatTonAmountText(stats.balances.availableBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatTonAmountText(stats.balances.availableBalance.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_StarsProceeds_Available, - (stats.balances.availableBalance == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.availableBalance.amount.value == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance.amount.value, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .ton ) @@ -782,9 +778,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatTonAmountText(stats.balances.currentBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatTonAmountText(stats.balances.currentBalance.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_StarsProceeds_Current, - (stats.balances.currentBalance == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.currentBalance, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.currentBalance.amount.value == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.currentBalance.amount.value, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .ton ) @@ -792,9 +788,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatTonAmountText(stats.balances.overallRevenue, dateTimeFormat: item.presentationData.dateTimeFormat), + formatTonAmountText(stats.balances.overallRevenue.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_StarsProceeds_Total, - (stats.balances.overallRevenue == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.overallRevenue, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.overallRevenue.amount.value == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.overallRevenue.amount.value, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .ton ) @@ -802,9 +798,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatStarsAmountText(additionalStats.balances.availableBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatStarsAmountText(additionalStats.balances.availableBalance.amount, dateTimeFormat: item.presentationData.dateTimeFormat), " ", - (additionalStats.balances.availableBalance == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(additionalStats.balances.availableBalance.value, divide: false, rate: additionalStats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (additionalStats.balances.availableBalance.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(additionalStats.balances.availableBalance.amount.value, divide: false, rate: additionalStats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .stars ) @@ -812,9 +808,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatStarsAmountText(additionalStats.balances.currentBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatStarsAmountText(additionalStats.balances.currentBalance.amount, dateTimeFormat: item.presentationData.dateTimeFormat), " ", - (additionalStats.balances.currentBalance == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(additionalStats.balances.currentBalance.value, divide: false, rate: additionalStats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (additionalStats.balances.currentBalance.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(additionalStats.balances.currentBalance.amount.value, divide: false, rate: additionalStats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .stars ) @@ -822,9 +818,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatStarsAmountText(additionalStats.balances.overallRevenue, dateTimeFormat: item.presentationData.dateTimeFormat), + formatStarsAmountText(additionalStats.balances.overallRevenue.amount, dateTimeFormat: item.presentationData.dateTimeFormat), " ", - (additionalStats.balances.overallRevenue == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(additionalStats.balances.overallRevenue.value, divide: false, rate: additionalStats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (additionalStats.balances.overallRevenue.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(additionalStats.balances.overallRevenue.amount.value, divide: false, rate: additionalStats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .stars ) @@ -836,9 +832,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatTonAmountText(stats.balances.availableBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatTonAmountText(stats.balances.availableBalance.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_Overview_Available, - (stats.balances.availableBalance == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.availableBalance.amount.value == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance.amount.value, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .ton ) @@ -846,9 +842,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatTonAmountText(stats.balances.currentBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatTonAmountText(stats.balances.currentBalance.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_Overview_Current, - (stats.balances.currentBalance == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.currentBalance, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.currentBalance.amount.value == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.currentBalance.amount.value, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .ton ) @@ -856,9 +852,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatTonAmountText(stats.balances.overallRevenue, dateTimeFormat: item.presentationData.dateTimeFormat), + formatTonAmountText(stats.balances.overallRevenue.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_Overview_Total, - (stats.balances.overallRevenue == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.overallRevenue, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.overallRevenue.amount.value == 0 ? "" : "≈\(formatTonUsdValue(stats.balances.overallRevenue.amount.value, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .ton ) @@ -871,9 +867,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatStarsAmountText(stats.balances.availableBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatStarsAmountText(stats.balances.availableBalance.amount, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_StarsProceeds_Available, - (stats.balances.availableBalance == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.availableBalance.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.availableBalance.amount.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .stars ) @@ -881,9 +877,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatStarsAmountText(stats.balances.currentBalance, dateTimeFormat: item.presentationData.dateTimeFormat), + formatStarsAmountText(stats.balances.currentBalance.amount, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_StarsProceeds_Current, - (stats.balances.currentBalance == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.currentBalance.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.currentBalance.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.currentBalance.amount.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .stars ) @@ -891,9 +887,9 @@ class StatsOverviewItemNode: ListViewItemNode { item.context, params.width, item.presentationData, - formatStarsAmountText(stats.balances.overallRevenue, dateTimeFormat: item.presentationData.dateTimeFormat), + formatStarsAmountText(stats.balances.overallRevenue.amount, dateTimeFormat: item.presentationData.dateTimeFormat), item.presentationData.strings.Monetization_StarsProceeds_Total, - (stats.balances.overallRevenue == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.overallRevenue.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), + (stats.balances.overallRevenue.amount == StarsAmount.zero ? "" : "≈\(formatTonUsdValue(stats.balances.overallRevenue.amount.value, divide: false, rate: stats.usdRate, dateTimeFormat: item.presentationData.dateTimeFormat))", .generic), .stars ) diff --git a/submodules/StatisticsUI/Sources/TransactionInfoScreen.swift b/submodules/StatisticsUI/Sources/TransactionInfoScreen.swift index 1d7edc0e22..5d2b16cd61 100644 --- a/submodules/StatisticsUI/Sources/TransactionInfoScreen.swift +++ b/submodules/StatisticsUI/Sources/TransactionInfoScreen.swift @@ -23,14 +23,14 @@ private final class SheetContent: CombinedComponent { let context: AccountContext let peer: EnginePeer - let transaction: RevenueStatsTransactionsContext.State.Transaction + let transaction: StarsContext.State.Transaction let openExplorer: (String) -> Void let dismiss: () -> Void init( context: AccountContext, peer: EnginePeer, - transaction: RevenueStatsTransactionsContext.State.Transaction, + transaction: StarsContext.State.Transaction, openExplorer: @escaping (String) -> Void, dismiss: @escaping () -> Void ) { @@ -136,40 +136,45 @@ private final class SheetContent: CombinedComponent { let labelColor: UIColor var showPeer = false - switch component.transaction { - case let .proceeds(amount, fromDate, toDate): + if let fromDate = component.transaction.adsProceedsFromDate, let toDate = component.transaction.adsProceedsToDate { labelColor = theme.list.itemDisclosureActions.constructive.fillColor - amountString = tonAmountAttributedString(formatTonAmountText(amount, dateTimeFormat: dateTimeFormat, showPlus: true), integralFont: integralFont, fractionalFont: fractionalFont, color: labelColor, decimalSeparator: dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString + amountString = tonAmountAttributedString(formatTonAmountText(component.transaction.count.amount.value, dateTimeFormat: dateTimeFormat, showPlus: true), integralFont: integralFont, fractionalFont: fractionalFont, color: labelColor, decimalSeparator: dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString dateString = "\(stringForMediumCompactDate(timestamp: fromDate, strings: strings, dateTimeFormat: dateTimeFormat)) – \(stringForMediumCompactDate(timestamp: toDate, strings: strings, dateTimeFormat: dateTimeFormat))" titleString = strings.Monetization_TransactionInfo_Proceeds buttonTitle = strings.Common_OK explorerUrl = nil showPeer = true - case let .withdrawal(status, amount, date, provider, _, transactionUrl): + } else if case .fragment = component.transaction.peer { labelColor = theme.list.itemDestructiveColor - amountString = tonAmountAttributedString(formatTonAmountText(amount, dateTimeFormat: dateTimeFormat), integralFont: integralFont, fractionalFont: fractionalFont, color: labelColor, decimalSeparator: dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString - dateString = stringForFullDate(timestamp: date, strings: strings, dateTimeFormat: dateTimeFormat) + amountString = tonAmountAttributedString(formatTonAmountText(component.transaction.count.amount.value, dateTimeFormat: dateTimeFormat), integralFont: integralFont, fractionalFont: fractionalFont, color: labelColor, decimalSeparator: dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString + dateString = stringForFullDate(timestamp: component.transaction.date, strings: strings, dateTimeFormat: dateTimeFormat) - switch status { - case .succeed: - titleString = strings.Monetization_TransactionInfo_Withdrawal(provider).string - buttonTitle = strings.Monetization_TransactionInfo_ViewInExplorer - case .pending: + if component.transaction.flags.contains(.isPending) { titleString = strings.Monetization_TransactionInfo_Pending buttonTitle = strings.Common_OK - case .failed: + } else if component.transaction.flags.contains(.isFailed) { titleString = strings.Monetization_TransactionInfo_Failed buttonTitle = strings.Common_OK titleColor = theme.list.itemDestructiveColor + } else { + titleString = strings.Monetization_TransactionInfo_Withdrawal("Fragment").string + buttonTitle = strings.Monetization_TransactionInfo_ViewInExplorer } - explorerUrl = transactionUrl - case let .refund(amount, date, _): + explorerUrl = component.transaction.transactionUrl + } else if component.transaction.flags.contains(.isRefund) { labelColor = theme.list.itemDisclosureActions.constructive.fillColor titleString = strings.Monetization_TransactionInfo_Refund - amountString = tonAmountAttributedString(formatTonAmountText(amount, dateTimeFormat: dateTimeFormat, showPlus: true), integralFont: integralFont, fractionalFont: fractionalFont, color: labelColor, decimalSeparator: dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString - dateString = stringForFullDate(timestamp: date, strings: strings, dateTimeFormat: dateTimeFormat) + amountString = tonAmountAttributedString(formatTonAmountText(component.transaction.count.amount.value, dateTimeFormat: dateTimeFormat, showPlus: true), integralFont: integralFont, fractionalFont: fractionalFont, color: labelColor, decimalSeparator: dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString + dateString = stringForFullDate(timestamp: component.transaction.date, strings: strings, dateTimeFormat: dateTimeFormat) buttonTitle = strings.Common_OK explorerUrl = nil + } else { + labelColor = theme.list.itemDisclosureActions.constructive.fillColor + amountString = tonAmountAttributedString(formatTonAmountText(component.transaction.count.amount.value, dateTimeFormat: dateTimeFormat, showPlus: true), integralFont: integralFont, fractionalFont: fractionalFont, color: labelColor, decimalSeparator: dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString + dateString = "" + titleString = "" + buttonTitle = "" + explorerUrl = nil } amountString.insert(NSAttributedString(string: " $ ", font: integralFont, textColor: labelColor), at: 1) @@ -293,13 +298,13 @@ private final class SheetContainerComponent: CombinedComponent { let context: AccountContext let peer: EnginePeer - let transaction: RevenueStatsTransactionsContext.State.Transaction + let transaction: StarsContext.State.Transaction let openExplorer: (String) -> Void init( context: AccountContext, peer: EnginePeer, - transaction: RevenueStatsTransactionsContext.State.Transaction, + transaction: StarsContext.State.Transaction, openExplorer: @escaping (String) -> Void ) { self.context = context @@ -410,7 +415,7 @@ final class TransactionInfoScreen: ViewControllerComponentContainer { init( context: AccountContext, peer: EnginePeer, - transaction: RevenueStatsTransactionsContext.State.Transaction, + transaction: StarsContext.State.Transaction, openExplorer: @escaping (String) -> Void ) { self.context = context diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 2d961b7d2c..627bd470a1 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -110,10 +110,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[602479523] = { return Api.BotPreviewMedia.parse_botPreviewMedia($0) } dict[-113453988] = { return Api.BotVerification.parse_botVerification($0) } dict[-1328716265] = { return Api.BotVerifierSettings.parse_botVerifierSettings($0) } - dict[-1006669337] = { return Api.BroadcastRevenueBalances.parse_broadcastRevenueBalances($0) } - dict[1434332356] = { return Api.BroadcastRevenueTransaction.parse_broadcastRevenueTransactionProceeds($0) } - dict[1121127726] = { return Api.BroadcastRevenueTransaction.parse_broadcastRevenueTransactionRefund($0) } - dict[1515784568] = { return Api.BroadcastRevenueTransaction.parse_broadcastRevenueTransactionWithdrawal($0) } dict[-283809188] = { return Api.BusinessAwayMessage.parse_businessAwayMessage($0) } dict[-910564679] = { return Api.BusinessAwayMessageSchedule.parse_businessAwayMessageScheduleAlways($0) } dict[-867328308] = { return Api.BusinessAwayMessageSchedule.parse_businessAwayMessageScheduleCustom($0) } @@ -609,6 +605,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[775611918] = { return Api.MessageAction.parse_messageActionStarGiftUnique($0) } dict[1474192222] = { return Api.MessageAction.parse_messageActionSuggestProfilePhoto($0) } dict[-293988970] = { return Api.MessageAction.parse_messageActionSuggestedPostApproval($0) } + dict[1777932024] = { return Api.MessageAction.parse_messageActionSuggestedPostRefund($0) } + dict[-1780625559] = { return Api.MessageAction.parse_messageActionSuggestedPostSuccess($0) } dict[-940721021] = { return Api.MessageAction.parse_messageActionTodoAppendTasks($0) } dict[-864265079] = { return Api.MessageAction.parse_messageActionTodoCompletions($0) } dict[228168278] = { return Api.MessageAction.parse_messageActionTopicCreate($0) } @@ -964,7 +962,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[779004698] = { return Api.StarsSubscription.parse_starsSubscription($0) } dict[88173912] = { return Api.StarsSubscriptionPricing.parse_starsSubscriptionPricing($0) } dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) } - dict[-1549805238] = { return Api.StarsTransaction.parse_starsTransaction($0) } + dict[325426864] = { return Api.StarsTransaction.parse_starsTransaction($0) } dict[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) } dict[-110658899] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAPI($0) } dict[1617438738] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAds($0) } @@ -1042,7 +1040,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-997782967] = { return Api.Update.parse_updateBotStopped($0) } dict[-2095595325] = { return Api.Update.parse_updateBotWebhookJSON($0) } dict[-1684914010] = { return Api.Update.parse_updateBotWebhookJSONQuery($0) } - dict[-539401739] = { return Api.Update.parse_updateBroadcastRevenueTransactions($0) } dict[513998247] = { return Api.Update.parse_updateBusinessBotCallbackQuery($0) } dict[1666927625] = { return Api.Update.parse_updateChannel($0) } dict[-1304443240] = { return Api.Update.parse_updateChannelAvailableMessages($0) } @@ -1436,7 +1433,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1877571094] = { return Api.payments.StarGifts.parse_starGifts($0) } dict[-1551326360] = { return Api.payments.StarGifts.parse_starGiftsNotModified($0) } dict[961445665] = { return Api.payments.StarsRevenueAdsAccountUrl.parse_starsRevenueAdsAccountUrl($0) } - dict[-919881925] = { return Api.payments.StarsRevenueStats.parse_starsRevenueStats($0) } + dict[1814066038] = { return Api.payments.StarsRevenueStats.parse_starsRevenueStats($0) } dict[497778871] = { return Api.payments.StarsRevenueWithdrawalUrl.parse_starsRevenueWithdrawalUrl($0) } dict[1822222573] = { return Api.payments.StarsStatus.parse_starsStatus($0) } dict[-1261053863] = { return Api.payments.SuggestedStarRefBots.parse_suggestedStarRefBots($0) } @@ -1457,9 +1454,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1696454430] = { return Api.premium.MyBoosts.parse_myBoosts($0) } dict[-594852657] = { return Api.smsjobs.EligibilityToJoin.parse_eligibleToJoin($0) } dict[720277905] = { return Api.smsjobs.Status.parse_status($0) } - dict[1409802903] = { return Api.stats.BroadcastRevenueStats.parse_broadcastRevenueStats($0) } - dict[-2028632986] = { return Api.stats.BroadcastRevenueTransactions.parse_broadcastRevenueTransactions($0) } - dict[-328886473] = { return Api.stats.BroadcastRevenueWithdrawalUrl.parse_broadcastRevenueWithdrawalUrl($0) } dict[963421692] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) } dict[-276825834] = { return Api.stats.MegagroupStats.parse_megagroupStats($0) } dict[2145983508] = { return Api.stats.MessageStats.parse_messageStats($0) } @@ -1620,10 +1614,6 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.BotVerifierSettings: _1.serialize(buffer, boxed) - case let _1 as Api.BroadcastRevenueBalances: - _1.serialize(buffer, boxed) - case let _1 as Api.BroadcastRevenueTransaction: - _1.serialize(buffer, boxed) case let _1 as Api.BusinessAwayMessage: _1.serialize(buffer, boxed) case let _1 as Api.BusinessAwayMessageSchedule: @@ -2598,12 +2588,6 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.smsjobs.Status: _1.serialize(buffer, boxed) - case let _1 as Api.stats.BroadcastRevenueStats: - _1.serialize(buffer, boxed) - case let _1 as Api.stats.BroadcastRevenueTransactions: - _1.serialize(buffer, boxed) - case let _1 as Api.stats.BroadcastRevenueWithdrawalUrl: - _1.serialize(buffer, boxed) case let _1 as Api.stats.BroadcastStats: _1.serialize(buffer, boxed) case let _1 as Api.stats.MegagroupStats: diff --git a/submodules/TelegramApi/Sources/Api15.swift b/submodules/TelegramApi/Sources/Api15.swift index 7359821a69..5c2505e379 100644 --- a/submodules/TelegramApi/Sources/Api15.swift +++ b/submodules/TelegramApi/Sources/Api15.swift @@ -397,6 +397,8 @@ public extension Api { case messageActionStarGiftUnique(flags: Int32, gift: Api.StarGift, canExportAt: Int32?, transferStars: Int64?, fromId: Api.Peer?, peer: Api.Peer?, savedId: Int64?, resaleStars: Int64?, canTransferAt: Int32?, canResellAt: Int32?) case messageActionSuggestProfilePhoto(photo: Api.Photo) case messageActionSuggestedPostApproval(flags: Int32, rejectComment: String?, scheduleDate: Int32?, price: Api.StarsAmount?) + case messageActionSuggestedPostRefund(flags: Int32) + case messageActionSuggestedPostSuccess(price: Api.StarsAmount) case messageActionTodoAppendTasks(list: [Api.TodoItem]) case messageActionTodoCompletions(completed: [Int32], incompleted: [Int32]) case messageActionTopicCreate(flags: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?) @@ -825,6 +827,18 @@ public extension Api { if Int(flags) & Int(1 << 3) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 4) != 0 {price!.serialize(buffer, true)} break + case .messageActionSuggestedPostRefund(let flags): + if boxed { + buffer.appendInt32(1777932024) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + case .messageActionSuggestedPostSuccess(let price): + if boxed { + buffer.appendInt32(-1780625559) + } + price.serialize(buffer, true) + break case .messageActionTodoAppendTasks(let list): if boxed { buffer.appendInt32(-940721021) @@ -985,6 +999,10 @@ public extension Api { return ("messageActionSuggestProfilePhoto", [("photo", photo as Any)]) case .messageActionSuggestedPostApproval(let flags, let rejectComment, let scheduleDate, let price): return ("messageActionSuggestedPostApproval", [("flags", flags as Any), ("rejectComment", rejectComment as Any), ("scheduleDate", scheduleDate as Any), ("price", price as Any)]) + case .messageActionSuggestedPostRefund(let flags): + return ("messageActionSuggestedPostRefund", [("flags", flags as Any)]) + case .messageActionSuggestedPostSuccess(let price): + return ("messageActionSuggestedPostSuccess", [("price", price as Any)]) case .messageActionTodoAppendTasks(let list): return ("messageActionTodoAppendTasks", [("list", list as Any)]) case .messageActionTodoCompletions(let completed, let incompleted): @@ -1832,6 +1850,30 @@ public extension Api { return nil } } + public static func parse_messageActionSuggestedPostRefund(_ reader: BufferReader) -> MessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionSuggestedPostRefund(flags: _1!) + } + else { + return nil + } + } + public static func parse_messageActionSuggestedPostSuccess(_ reader: BufferReader) -> MessageAction? { + var _1: Api.StarsAmount? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StarsAmount + } + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionSuggestedPostSuccess(price: _1!) + } + else { + return nil + } + } public static func parse_messageActionTodoAppendTasks(_ reader: BufferReader) -> MessageAction? { var _1: [Api.TodoItem]? if let _ = reader.readInt32() { diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 4337a392c9..ddea45fec8 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -914,166 +914,6 @@ public extension Api { } } -public extension Api { - enum BroadcastRevenueBalances: TypeConstructorDescription { - case broadcastRevenueBalances(flags: Int32, currentBalance: Int64, availableBalance: Int64, overallRevenue: Int64) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .broadcastRevenueBalances(let flags, let currentBalance, let availableBalance, let overallRevenue): - if boxed { - buffer.appendInt32(-1006669337) - } - 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 .broadcastRevenueBalances(let flags, let currentBalance, let availableBalance, let overallRevenue): - return ("broadcastRevenueBalances", [("flags", flags as Any), ("currentBalance", currentBalance as Any), ("availableBalance", availableBalance as Any), ("overallRevenue", overallRevenue as Any)]) - } - } - - public static func parse_broadcastRevenueBalances(_ reader: BufferReader) -> BroadcastRevenueBalances? { - 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.BroadcastRevenueBalances.broadcastRevenueBalances(flags: _1!, currentBalance: _2!, availableBalance: _3!, overallRevenue: _4!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum BroadcastRevenueTransaction: TypeConstructorDescription { - case broadcastRevenueTransactionProceeds(amount: Int64, fromDate: Int32, toDate: Int32) - case broadcastRevenueTransactionRefund(amount: Int64, date: Int32, provider: String) - case broadcastRevenueTransactionWithdrawal(flags: Int32, amount: Int64, date: Int32, provider: String, transactionDate: Int32?, transactionUrl: String?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .broadcastRevenueTransactionProceeds(let amount, let fromDate, let toDate): - if boxed { - buffer.appendInt32(1434332356) - } - serializeInt64(amount, buffer: buffer, boxed: false) - serializeInt32(fromDate, buffer: buffer, boxed: false) - serializeInt32(toDate, buffer: buffer, boxed: false) - break - case .broadcastRevenueTransactionRefund(let amount, let date, let provider): - if boxed { - buffer.appendInt32(1121127726) - } - serializeInt64(amount, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeString(provider, buffer: buffer, boxed: false) - break - case .broadcastRevenueTransactionWithdrawal(let flags, let amount, let date, let provider, let transactionDate, let transactionUrl): - if boxed { - buffer.appendInt32(1515784568) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt64(amount, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeString(provider, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 1) != 0 {serializeInt32(transactionDate!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 1) != 0 {serializeString(transactionUrl!, buffer: buffer, boxed: false)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .broadcastRevenueTransactionProceeds(let amount, let fromDate, let toDate): - return ("broadcastRevenueTransactionProceeds", [("amount", amount as Any), ("fromDate", fromDate as Any), ("toDate", toDate as Any)]) - case .broadcastRevenueTransactionRefund(let amount, let date, let provider): - return ("broadcastRevenueTransactionRefund", [("amount", amount as Any), ("date", date as Any), ("provider", provider as Any)]) - case .broadcastRevenueTransactionWithdrawal(let flags, let amount, let date, let provider, let transactionDate, let transactionUrl): - return ("broadcastRevenueTransactionWithdrawal", [("flags", flags as Any), ("amount", amount as Any), ("date", date as Any), ("provider", provider as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any)]) - } - } - - public static func parse_broadcastRevenueTransactionProceeds(_ reader: BufferReader) -> BroadcastRevenueTransaction? { - var _1: Int64? - _1 = reader.readInt64() - var _2: Int32? - _2 = reader.readInt32() - var _3: Int32? - _3 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.BroadcastRevenueTransaction.broadcastRevenueTransactionProceeds(amount: _1!, fromDate: _2!, toDate: _3!) - } - else { - return nil - } - } - public static func parse_broadcastRevenueTransactionRefund(_ reader: BufferReader) -> BroadcastRevenueTransaction? { - var _1: Int64? - _1 = reader.readInt64() - var _2: Int32? - _2 = reader.readInt32() - var _3: String? - _3 = parseString(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.BroadcastRevenueTransaction.broadcastRevenueTransactionRefund(amount: _1!, date: _2!, provider: _3!) - } - else { - return nil - } - } - public static func parse_broadcastRevenueTransactionWithdrawal(_ reader: BufferReader) -> BroadcastRevenueTransaction? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int64? - _2 = reader.readInt64() - var _3: Int32? - _3 = reader.readInt32() - var _4: String? - _4 = parseString(reader) - var _5: Int32? - if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } - var _6: String? - if Int(_1!) & Int(1 << 1) != 0 {_6 = parseString(reader) } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil - let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.BroadcastRevenueTransaction.broadcastRevenueTransactionWithdrawal(flags: _1!, amount: _2!, date: _3!, provider: _4!, transactionDate: _5, transactionUrl: _6) - } - else { - return nil - } - } - - } -} public extension Api { enum BusinessAwayMessage: TypeConstructorDescription { case businessAwayMessage(flags: Int32, shortcutId: Int32, schedule: Api.BusinessAwayMessageSchedule, recipients: Api.BusinessRecipients) @@ -1190,3 +1030,203 @@ public extension Api { } } +public extension Api { + enum BusinessBotRecipients: TypeConstructorDescription { + case businessBotRecipients(flags: Int32, users: [Int64]?, excludeUsers: [Int64]?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessBotRecipients(let flags, let users, let excludeUsers): + if boxed { + buffer.appendInt32(-1198722189) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users!.count)) + for item in users! { + serializeInt64(item, buffer: buffer, boxed: false) + }} + if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(excludeUsers!.count)) + for item in excludeUsers! { + serializeInt64(item, buffer: buffer, boxed: false) + }} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessBotRecipients(let flags, let users, let excludeUsers): + return ("businessBotRecipients", [("flags", flags as Any), ("users", users as Any), ("excludeUsers", excludeUsers as Any)]) + } + } + + public static func parse_businessBotRecipients(_ reader: BufferReader) -> BusinessBotRecipients? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Int64]? + if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } } + var _3: [Int64]? + if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 4) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 6) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.BusinessBotRecipients.businessBotRecipients(flags: _1!, users: _2, excludeUsers: _3) + } + else { + return nil + } + } + + } +} +public extension Api { + enum BusinessBotRights: TypeConstructorDescription { + case businessBotRights(flags: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessBotRights(let flags): + if boxed { + buffer.appendInt32(-1604170505) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessBotRights(let flags): + return ("businessBotRights", [("flags", flags as Any)]) + } + } + + public static func parse_businessBotRights(_ reader: BufferReader) -> BusinessBotRights? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.BusinessBotRights.businessBotRights(flags: _1!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum BusinessChatLink: TypeConstructorDescription { + case businessChatLink(flags: Int32, link: String, message: String, entities: [Api.MessageEntity]?, title: String?, views: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessChatLink(let flags, let link, let message, let entities, let title, let views): + if boxed { + buffer.appendInt32(-1263638929) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(link, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + serializeInt32(views, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessChatLink(let flags, let link, let message, let entities, let title, let views): + return ("businessChatLink", [("flags", flags as Any), ("link", link as Any), ("message", message as Any), ("entities", entities as Any), ("title", title as Any), ("views", views as Any)]) + } + } + + public static func parse_businessChatLink(_ reader: BufferReader) -> BusinessChatLink? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + var _5: String? + if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } + var _6: Int32? + _6 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.BusinessChatLink.businessChatLink(flags: _1!, link: _2!, message: _3!, entities: _4, title: _5, views: _6!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum BusinessGreetingMessage: TypeConstructorDescription { + case businessGreetingMessage(shortcutId: Int32, recipients: Api.BusinessRecipients, noActivityDays: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays): + if boxed { + buffer.appendInt32(-451302485) + } + serializeInt32(shortcutId, buffer: buffer, boxed: false) + recipients.serialize(buffer, true) + serializeInt32(noActivityDays, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays): + return ("businessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)]) + } + } + + public static func parse_businessGreetingMessage(_ reader: BufferReader) -> BusinessGreetingMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.BusinessRecipients? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.BusinessRecipients + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.BusinessGreetingMessage.businessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramApi/Sources/Api25.swift b/submodules/TelegramApi/Sources/Api25.swift index 8ea74bad94..00956dbfa9 100644 --- a/submodules/TelegramApi/Sources/Api25.swift +++ b/submodules/TelegramApi/Sources/Api25.swift @@ -504,17 +504,17 @@ public extension Api { } public extension Api { enum StarsTransaction: TypeConstructorDescription { - case starsTransaction(flags: Int32, id: String, stars: Api.StarsAmount, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?, botPayload: Buffer?, msgId: Int32?, extendedMedia: [Api.MessageMedia]?, subscriptionPeriod: Int32?, giveawayPostId: Int32?, stargift: Api.StarGift?, floodskipNumber: Int32?, starrefCommissionPermille: Int32?, starrefPeer: Api.Peer?, starrefAmount: Api.StarsAmount?, paidMessages: Int32?, premiumGiftMonths: Int32?) + case starsTransaction(flags: Int32, id: String, amount: Api.StarsAmount, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?, botPayload: Buffer?, msgId: Int32?, extendedMedia: [Api.MessageMedia]?, subscriptionPeriod: Int32?, giveawayPostId: Int32?, stargift: Api.StarGift?, floodskipNumber: Int32?, starrefCommissionPermille: Int32?, starrefPeer: Api.Peer?, starrefAmount: Api.StarsAmount?, paidMessages: Int32?, premiumGiftMonths: Int32?, adsProceedsFromDate: Int32?, adsProceedsToDate: Int32?) 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, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths): + case .starsTransaction(let flags, let id, let amount, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths, let adsProceedsFromDate, let adsProceedsToDate): if boxed { - buffer.appendInt32(-1549805238) + buffer.appendInt32(325426864) } serializeInt32(flags, buffer: buffer, boxed: false) serializeString(id, buffer: buffer, boxed: false) - stars.serialize(buffer, true) + amount.serialize(buffer, true) serializeInt32(date, buffer: buffer, boxed: false) peer.serialize(buffer, true) if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} @@ -538,14 +538,16 @@ public extension Api { if Int(flags) & Int(1 << 17) != 0 {starrefAmount!.serialize(buffer, true)} if Int(flags) & Int(1 << 19) != 0 {serializeInt32(paidMessages!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 20) != 0 {serializeInt32(premiumGiftMonths!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 23) != 0 {serializeInt32(adsProceedsFromDate!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 23) != 0 {serializeInt32(adsProceedsToDate!, 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, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths): - 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), ("botPayload", botPayload as Any), ("msgId", msgId as Any), ("extendedMedia", extendedMedia as Any), ("subscriptionPeriod", subscriptionPeriod as Any), ("giveawayPostId", giveawayPostId as Any), ("stargift", stargift as Any), ("floodskipNumber", floodskipNumber as Any), ("starrefCommissionPermille", starrefCommissionPermille as Any), ("starrefPeer", starrefPeer as Any), ("starrefAmount", starrefAmount as Any), ("paidMessages", paidMessages as Any), ("premiumGiftMonths", premiumGiftMonths as Any)]) + case .starsTransaction(let flags, let id, let amount, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths, let adsProceedsFromDate, let adsProceedsToDate): + return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("amount", amount 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), ("botPayload", botPayload as Any), ("msgId", msgId as Any), ("extendedMedia", extendedMedia as Any), ("subscriptionPeriod", subscriptionPeriod as Any), ("giveawayPostId", giveawayPostId as Any), ("stargift", stargift as Any), ("floodskipNumber", floodskipNumber as Any), ("starrefCommissionPermille", starrefCommissionPermille as Any), ("starrefPeer", starrefPeer as Any), ("starrefAmount", starrefAmount as Any), ("paidMessages", paidMessages as Any), ("premiumGiftMonths", premiumGiftMonths as Any), ("adsProceedsFromDate", adsProceedsFromDate as Any), ("adsProceedsToDate", adsProceedsToDate as Any)]) } } @@ -608,6 +610,10 @@ public extension Api { if Int(_1!) & Int(1 << 19) != 0 {_21 = reader.readInt32() } var _22: Int32? if Int(_1!) & Int(1 << 20) != 0 {_22 = reader.readInt32() } + var _23: Int32? + if Int(_1!) & Int(1 << 23) != 0 {_23 = reader.readInt32() } + var _24: Int32? + if Int(_1!) & Int(1 << 23) != 0 {_24 = reader.readInt32() } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -630,8 +636,10 @@ public extension Api { let _c20 = (Int(_1!) & Int(1 << 17) == 0) || _20 != nil let _c21 = (Int(_1!) & Int(1 << 19) == 0) || _21 != nil let _c22 = (Int(_1!) & Int(1 << 20) == 0) || _22 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 { - return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10, botPayload: _11, msgId: _12, extendedMedia: _13, subscriptionPeriod: _14, giveawayPostId: _15, stargift: _16, floodskipNumber: _17, starrefCommissionPermille: _18, starrefPeer: _19, starrefAmount: _20, paidMessages: _21, premiumGiftMonths: _22) + let _c23 = (Int(_1!) & Int(1 << 23) == 0) || _23 != nil + let _c24 = (Int(_1!) & Int(1 << 23) == 0) || _24 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 { + return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, amount: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10, botPayload: _11, msgId: _12, extendedMedia: _13, subscriptionPeriod: _14, giveawayPostId: _15, stargift: _16, floodskipNumber: _17, starrefCommissionPermille: _18, starrefPeer: _19, starrefAmount: _20, paidMessages: _21, premiumGiftMonths: _22, adsProceedsFromDate: _23, adsProceedsToDate: _24) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index 3b63ab8600..0265253957 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -73,7 +73,6 @@ public extension Api { case updateBotStopped(userId: Int64, date: Int32, stopped: Api.Bool, qts: Int32) 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) @@ -413,13 +412,6 @@ public extension Api { data.serialize(buffer, true) serializeInt32(timeout, buffer: buffer, boxed: false) break - case .updateBroadcastRevenueTransactions(let peer, let balances): - if boxed { - buffer.appendInt32(-539401739) - } - 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) @@ -1515,8 +1507,6 @@ public extension Api { return ("updateBotWebhookJSON", [("data", data as Any)]) case .updateBotWebhookJSONQuery(let queryId, let data, let timeout): 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): @@ -2242,24 +2232,6 @@ public extension Api { return nil } } - public static func parse_updateBroadcastRevenueTransactions(_ reader: BufferReader) -> Update? { - var _1: Api.Peer? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.Peer - } - var _2: Api.BroadcastRevenueBalances? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.BroadcastRevenueBalances - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.Update.updateBroadcastRevenueTransactions(peer: _1!, balances: _2!) - } - else { - return nil - } - } public static func parse_updateBusinessBotCallbackQuery(_ reader: BufferReader) -> Update? { var _1: Int32? _1 = reader.readInt32() diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 1818e0060b..bb3b303e57 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -1,203 +1,3 @@ -public extension Api { - enum BusinessBotRecipients: TypeConstructorDescription { - case businessBotRecipients(flags: Int32, users: [Int64]?, excludeUsers: [Int64]?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .businessBotRecipients(let flags, let users, let excludeUsers): - if boxed { - buffer.appendInt32(-1198722189) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users!.count)) - for item in users! { - serializeInt64(item, buffer: buffer, boxed: false) - }} - if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(excludeUsers!.count)) - for item in excludeUsers! { - serializeInt64(item, buffer: buffer, boxed: false) - }} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .businessBotRecipients(let flags, let users, let excludeUsers): - return ("businessBotRecipients", [("flags", flags as Any), ("users", users as Any), ("excludeUsers", excludeUsers as Any)]) - } - } - - public static func parse_businessBotRecipients(_ reader: BufferReader) -> BusinessBotRecipients? { - var _1: Int32? - _1 = reader.readInt32() - var _2: [Int64]? - if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) - } } - var _3: [Int64]? - if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) - } } - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 4) == 0) || _2 != nil - let _c3 = (Int(_1!) & Int(1 << 6) == 0) || _3 != nil - if _c1 && _c2 && _c3 { - return Api.BusinessBotRecipients.businessBotRecipients(flags: _1!, users: _2, excludeUsers: _3) - } - else { - return nil - } - } - - } -} -public extension Api { - enum BusinessBotRights: TypeConstructorDescription { - case businessBotRights(flags: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .businessBotRights(let flags): - if boxed { - buffer.appendInt32(-1604170505) - } - serializeInt32(flags, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .businessBotRights(let flags): - return ("businessBotRights", [("flags", flags as Any)]) - } - } - - public static func parse_businessBotRights(_ reader: BufferReader) -> BusinessBotRights? { - var _1: Int32? - _1 = reader.readInt32() - let _c1 = _1 != nil - if _c1 { - return Api.BusinessBotRights.businessBotRights(flags: _1!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum BusinessChatLink: TypeConstructorDescription { - case businessChatLink(flags: Int32, link: String, message: String, entities: [Api.MessageEntity]?, title: String?, views: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .businessChatLink(let flags, let link, let message, let entities, let title, let views): - if boxed { - buffer.appendInt32(-1263638929) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(link, buffer: buffer, boxed: false) - serializeString(message, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(entities!.count)) - for item in entities! { - item.serialize(buffer, true) - }} - if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} - serializeInt32(views, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .businessChatLink(let flags, let link, let message, let entities, let title, let views): - return ("businessChatLink", [("flags", flags as Any), ("link", link as Any), ("message", message as Any), ("entities", entities as Any), ("title", title as Any), ("views", views as Any)]) - } - } - - public static func parse_businessChatLink(_ reader: BufferReader) -> BusinessChatLink? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) - var _4: [Api.MessageEntity]? - if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) - } } - var _5: String? - if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } - var _6: Int32? - _6 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil - let _c6 = _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.BusinessChatLink.businessChatLink(flags: _1!, link: _2!, message: _3!, entities: _4, title: _5, views: _6!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum BusinessGreetingMessage: TypeConstructorDescription { - case businessGreetingMessage(shortcutId: Int32, recipients: Api.BusinessRecipients, noActivityDays: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays): - if boxed { - buffer.appendInt32(-451302485) - } - serializeInt32(shortcutId, buffer: buffer, boxed: false) - recipients.serialize(buffer, true) - serializeInt32(noActivityDays, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays): - return ("businessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)]) - } - } - - public static func parse_businessGreetingMessage(_ reader: BufferReader) -> BusinessGreetingMessage? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.BusinessRecipients? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.BusinessRecipients - } - var _3: Int32? - _3 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.BusinessGreetingMessage.businessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!) - } - else { - return nil - } - } - - } -} public extension Api { enum BusinessIntro: TypeConstructorDescription { case businessIntro(flags: Int32, title: String, description: String, sticker: Api.Document?) diff --git a/submodules/TelegramApi/Sources/Api36.swift b/submodules/TelegramApi/Sources/Api36.swift index cfc3b45e13..c7e80100b6 100644 --- a/submodules/TelegramApi/Sources/Api36.swift +++ b/submodules/TelegramApi/Sources/Api36.swift @@ -392,14 +392,16 @@ public extension Api.payments { } public extension Api.payments { enum StarsRevenueStats: TypeConstructorDescription { - case starsRevenueStats(revenueGraph: Api.StatsGraph, status: Api.StarsRevenueStatus, usdRate: Double) + case starsRevenueStats(flags: Int32, topHoursGraph: Api.StatsGraph?, 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): + case .starsRevenueStats(let flags, let topHoursGraph, let revenueGraph, let status, let usdRate): if boxed { - buffer.appendInt32(-919881925) + buffer.appendInt32(1814066038) } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {topHoursGraph!.serialize(buffer, true)} revenueGraph.serialize(buffer, true) status.serialize(buffer, true) serializeDouble(usdRate, buffer: buffer, boxed: false) @@ -409,27 +411,35 @@ public extension Api.payments { 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)]) + case .starsRevenueStats(let flags, let topHoursGraph, let revenueGraph, let status, let usdRate): + return ("starsRevenueStats", [("flags", flags as Any), ("topHoursGraph", topHoursGraph as Any), ("revenueGraph", revenueGraph as Any), ("status", status as Any), ("usdRate", usdRate as Any)]) } } public static func parse_starsRevenueStats(_ reader: BufferReader) -> StarsRevenueStats? { - var _1: Api.StatsGraph? + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.StatsGraph? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } } + var _3: Api.StatsGraph? if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsGraph + _3 = Api.parse(reader, signature: signature) as? Api.StatsGraph } - var _2: Api.StarsRevenueStatus? + var _4: Api.StarsRevenueStatus? if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StarsRevenueStatus + _4 = Api.parse(reader, signature: signature) as? Api.StarsRevenueStatus } - var _3: Double? - _3 = reader.readDouble() + var _5: Double? + _5 = reader.readDouble() let _c1 = _1 != nil - let _c2 = _2 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.payments.StarsRevenueStats.starsRevenueStats(revenueGraph: _1!, status: _2!, usdRate: _3!) + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.payments.StarsRevenueStats.starsRevenueStats(flags: _1!, topHoursGraph: _2, revenueGraph: _3!, status: _4!, usdRate: _5!) } else { return nil @@ -1561,73 +1571,39 @@ public extension Api.smsjobs { } } public extension Api.stats { - enum BroadcastRevenueStats: TypeConstructorDescription { - case broadcastRevenueStats(topHoursGraph: Api.StatsGraph, revenueGraph: Api.StatsGraph, balances: Api.BroadcastRevenueBalances, usdRate: Double) + enum BroadcastStats: TypeConstructorDescription { + case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, reactionsPerPost: Api.StatsAbsValueAndPrev, viewsPerStory: Api.StatsAbsValueAndPrev, sharesPerStory: Api.StatsAbsValueAndPrev, reactionsPerStory: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph, storyInteractionsGraph: Api.StatsGraph, storyReactionsByEmotionGraph: Api.StatsGraph, recentPostsInteractions: [Api.PostInteractionCounters]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .broadcastRevenueStats(let topHoursGraph, let revenueGraph, let balances, let usdRate): + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let reactionsPerPost, let viewsPerStory, let sharesPerStory, let reactionsPerStory, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let reactionsByEmotionGraph, let storyInteractionsGraph, let storyReactionsByEmotionGraph, let recentPostsInteractions): if boxed { - buffer.appendInt32(1409802903) + buffer.appendInt32(963421692) } + period.serialize(buffer, true) + followers.serialize(buffer, true) + viewsPerPost.serialize(buffer, true) + sharesPerPost.serialize(buffer, true) + reactionsPerPost.serialize(buffer, true) + viewsPerStory.serialize(buffer, true) + sharesPerStory.serialize(buffer, true) + reactionsPerStory.serialize(buffer, true) + enabledNotifications.serialize(buffer, true) + growthGraph.serialize(buffer, true) + followersGraph.serialize(buffer, true) + muteGraph.serialize(buffer, true) topHoursGraph.serialize(buffer, true) - revenueGraph.serialize(buffer, true) - balances.serialize(buffer, true) - serializeDouble(usdRate, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .broadcastRevenueStats(let topHoursGraph, let revenueGraph, let balances, let usdRate): - return ("broadcastRevenueStats", [("topHoursGraph", topHoursGraph as Any), ("revenueGraph", revenueGraph as Any), ("balances", balances as Any), ("usdRate", usdRate as Any)]) - } - } - - public static func parse_broadcastRevenueStats(_ reader: BufferReader) -> BroadcastRevenueStats? { - var _1: Api.StatsGraph? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _2: Api.StatsGraph? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _3: Api.BroadcastRevenueBalances? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.BroadcastRevenueBalances - } - var _4: Double? - _4 = reader.readDouble() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.stats.BroadcastRevenueStats.broadcastRevenueStats(topHoursGraph: _1!, revenueGraph: _2!, balances: _3!, usdRate: _4!) - } - else { - return nil - } - } - - } -} -public extension Api.stats { - enum BroadcastRevenueTransactions: TypeConstructorDescription { - case broadcastRevenueTransactions(count: Int32, transactions: [Api.BroadcastRevenueTransaction]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .broadcastRevenueTransactions(let count, let transactions): - if boxed { - buffer.appendInt32(-2028632986) - } - serializeInt32(count, buffer: buffer, boxed: false) + interactionsGraph.serialize(buffer, true) + ivInteractionsGraph.serialize(buffer, true) + viewsBySourceGraph.serialize(buffer, true) + newFollowersBySourceGraph.serialize(buffer, true) + languagesGraph.serialize(buffer, true) + reactionsByEmotionGraph.serialize(buffer, true) + storyInteractionsGraph.serialize(buffer, true) + storyReactionsByEmotionGraph.serialize(buffer, true) buffer.appendInt32(481674261) - buffer.appendInt32(Int32(transactions.count)) - for item in transactions { + buffer.appendInt32(Int32(recentPostsInteractions.count)) + for item in recentPostsInteractions { item.serialize(buffer, true) } break @@ -1636,22 +1612,124 @@ public extension Api.stats { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .broadcastRevenueTransactions(let count, let transactions): - return ("broadcastRevenueTransactions", [("count", count as Any), ("transactions", transactions as Any)]) + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let reactionsPerPost, let viewsPerStory, let sharesPerStory, let reactionsPerStory, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let reactionsByEmotionGraph, let storyInteractionsGraph, let storyReactionsByEmotionGraph, let recentPostsInteractions): + return ("broadcastStats", [("period", period as Any), ("followers", followers as Any), ("viewsPerPost", viewsPerPost as Any), ("sharesPerPost", sharesPerPost as Any), ("reactionsPerPost", reactionsPerPost as Any), ("viewsPerStory", viewsPerStory as Any), ("sharesPerStory", sharesPerStory as Any), ("reactionsPerStory", reactionsPerStory as Any), ("enabledNotifications", enabledNotifications as Any), ("growthGraph", growthGraph as Any), ("followersGraph", followersGraph as Any), ("muteGraph", muteGraph as Any), ("topHoursGraph", topHoursGraph as Any), ("interactionsGraph", interactionsGraph as Any), ("ivInteractionsGraph", ivInteractionsGraph as Any), ("viewsBySourceGraph", viewsBySourceGraph as Any), ("newFollowersBySourceGraph", newFollowersBySourceGraph as Any), ("languagesGraph", languagesGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any), ("storyInteractionsGraph", storyInteractionsGraph as Any), ("storyReactionsByEmotionGraph", storyReactionsByEmotionGraph as Any), ("recentPostsInteractions", recentPostsInteractions as Any)]) } } - public static func parse_broadcastRevenueTransactions(_ reader: BufferReader) -> BroadcastRevenueTransactions? { - var _1: Int32? - _1 = reader.readInt32() - var _2: [Api.BroadcastRevenueTransaction]? + public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { + var _1: Api.StatsDateRangeDays? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays + } + var _2: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _3: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _5: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _6: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _7: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _8: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _9: Api.StatsPercentValue? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue + } + var _10: Api.StatsGraph? + if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _11: Api.StatsGraph? + if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _12: Api.StatsGraph? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _13: Api.StatsGraph? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _14: Api.StatsGraph? + if let signature = reader.readInt32() { + _14 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _15: Api.StatsGraph? + if let signature = reader.readInt32() { + _15 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _16: Api.StatsGraph? + if let signature = reader.readInt32() { + _16 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _17: Api.StatsGraph? + if let signature = reader.readInt32() { + _17 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _18: Api.StatsGraph? + if let signature = reader.readInt32() { + _18 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _19: Api.StatsGraph? + if let signature = reader.readInt32() { + _19 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _20: Api.StatsGraph? + if let signature = reader.readInt32() { + _20 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _21: Api.StatsGraph? + if let signature = reader.readInt32() { + _21 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _22: [Api.PostInteractionCounters]? if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BroadcastRevenueTransaction.self) + _22 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PostInteractionCounters.self) } let _c1 = _1 != nil let _c2 = _2 != nil - if _c1 && _c2 { - return Api.stats.BroadcastRevenueTransactions.broadcastRevenueTransactions(count: _1!, transactions: _2!) + 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 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + let _c14 = _14 != nil + let _c15 = _15 != nil + let _c16 = _16 != nil + let _c17 = _17 != nil + let _c18 = _18 != nil + let _c19 = _19 != nil + let _c20 = _20 != nil + let _c21 = _21 != nil + let _c22 = _22 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 { + return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, reactionsPerPost: _5!, viewsPerStory: _6!, sharesPerStory: _7!, reactionsPerStory: _8!, enabledNotifications: _9!, growthGraph: _10!, followersGraph: _11!, muteGraph: _12!, topHoursGraph: _13!, interactionsGraph: _14!, ivInteractionsGraph: _15!, viewsBySourceGraph: _16!, newFollowersBySourceGraph: _17!, languagesGraph: _18!, reactionsByEmotionGraph: _19!, storyInteractionsGraph: _20!, storyReactionsByEmotionGraph: _21!, recentPostsInteractions: _22!) } else { return nil @@ -1661,33 +1739,191 @@ public extension Api.stats { } } public extension Api.stats { - enum BroadcastRevenueWithdrawalUrl: TypeConstructorDescription { - case broadcastRevenueWithdrawalUrl(url: String) + enum MegagroupStats: TypeConstructorDescription { + case megagroupStats(period: Api.StatsDateRangeDays, members: Api.StatsAbsValueAndPrev, messages: Api.StatsAbsValueAndPrev, viewers: Api.StatsAbsValueAndPrev, posters: Api.StatsAbsValueAndPrev, growthGraph: Api.StatsGraph, membersGraph: Api.StatsGraph, newMembersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, messagesGraph: Api.StatsGraph, actionsGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, weekdaysGraph: Api.StatsGraph, topPosters: [Api.StatsGroupTopPoster], topAdmins: [Api.StatsGroupTopAdmin], topInviters: [Api.StatsGroupTopInviter], users: [Api.User]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .broadcastRevenueWithdrawalUrl(let url): + case .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): if boxed { - buffer.appendInt32(-328886473) + buffer.appendInt32(-276825834) + } + period.serialize(buffer, true) + members.serialize(buffer, true) + messages.serialize(buffer, true) + viewers.serialize(buffer, true) + posters.serialize(buffer, true) + growthGraph.serialize(buffer, true) + membersGraph.serialize(buffer, true) + newMembersBySourceGraph.serialize(buffer, true) + languagesGraph.serialize(buffer, true) + messagesGraph.serialize(buffer, true) + actionsGraph.serialize(buffer, true) + topHoursGraph.serialize(buffer, true) + weekdaysGraph.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(topPosters.count)) + for item in topPosters { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(topAdmins.count)) + for item in topAdmins { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(topInviters.count)) + for item in topInviters { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) } - serializeString(url, buffer: buffer, boxed: false) break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .broadcastRevenueWithdrawalUrl(let url): - return ("broadcastRevenueWithdrawalUrl", [("url", url as Any)]) + case .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): + return ("megagroupStats", [("period", period as Any), ("members", members as Any), ("messages", messages as Any), ("viewers", viewers as Any), ("posters", posters as Any), ("growthGraph", growthGraph as Any), ("membersGraph", membersGraph as Any), ("newMembersBySourceGraph", newMembersBySourceGraph as Any), ("languagesGraph", languagesGraph as Any), ("messagesGraph", messagesGraph as Any), ("actionsGraph", actionsGraph as Any), ("topHoursGraph", topHoursGraph as Any), ("weekdaysGraph", weekdaysGraph as Any), ("topPosters", topPosters as Any), ("topAdmins", topAdmins as Any), ("topInviters", topInviters as Any), ("users", users as Any)]) } } - public static func parse_broadcastRevenueWithdrawalUrl(_ reader: BufferReader) -> BroadcastRevenueWithdrawalUrl? { - var _1: String? - _1 = parseString(reader) + public static func parse_megagroupStats(_ reader: BufferReader) -> MegagroupStats? { + var _1: Api.StatsDateRangeDays? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays + } + var _2: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _3: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _5: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _6: Api.StatsGraph? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _7: Api.StatsGraph? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _8: Api.StatsGraph? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _9: Api.StatsGraph? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _10: Api.StatsGraph? + if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _11: Api.StatsGraph? + if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _12: Api.StatsGraph? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _13: Api.StatsGraph? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _14: [Api.StatsGroupTopPoster]? + if let _ = reader.readInt32() { + _14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopPoster.self) + } + var _15: [Api.StatsGroupTopAdmin]? + if let _ = reader.readInt32() { + _15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopAdmin.self) + } + var _16: [Api.StatsGroupTopInviter]? + if let _ = reader.readInt32() { + _16 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopInviter.self) + } + var _17: [Api.User]? + if let _ = reader.readInt32() { + _17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } let _c1 = _1 != nil - if _c1 { - return Api.stats.BroadcastRevenueWithdrawalUrl.broadcastRevenueWithdrawalUrl(url: _1!) + 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 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + let _c14 = _14 != nil + let _c15 = _15 != nil + let _c16 = _16 != nil + let _c17 = _17 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 { + return Api.stats.MegagroupStats.megagroupStats(period: _1!, members: _2!, messages: _3!, viewers: _4!, posters: _5!, growthGraph: _6!, membersGraph: _7!, newMembersBySourceGraph: _8!, languagesGraph: _9!, messagesGraph: _10!, actionsGraph: _11!, topHoursGraph: _12!, weekdaysGraph: _13!, topPosters: _14!, topAdmins: _15!, topInviters: _16!, users: _17!) + } + else { + return nil + } + } + + } +} +public extension Api.stats { + enum MessageStats: TypeConstructorDescription { + case messageStats(viewsGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageStats(let viewsGraph, let reactionsByEmotionGraph): + if boxed { + buffer.appendInt32(2145983508) + } + viewsGraph.serialize(buffer, true) + reactionsByEmotionGraph.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageStats(let viewsGraph, let reactionsByEmotionGraph): + return ("messageStats", [("viewsGraph", viewsGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any)]) + } + } + + public static func parse_messageStats(_ reader: BufferReader) -> MessageStats? { + var _1: Api.StatsGraph? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _2: Api.StatsGraph? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.stats.MessageStats.messageStats(viewsGraph: _1!, reactionsByEmotionGraph: _2!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api37.swift b/submodules/TelegramApi/Sources/Api37.swift index e3c0df82da..7e36ea42bf 100644 --- a/submodules/TelegramApi/Sources/Api37.swift +++ b/submodules/TelegramApi/Sources/Api37.swift @@ -1,365 +1,3 @@ -public extension Api.stats { - enum BroadcastStats: TypeConstructorDescription { - case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, reactionsPerPost: Api.StatsAbsValueAndPrev, viewsPerStory: Api.StatsAbsValueAndPrev, sharesPerStory: Api.StatsAbsValueAndPrev, reactionsPerStory: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph, storyInteractionsGraph: Api.StatsGraph, storyReactionsByEmotionGraph: Api.StatsGraph, recentPostsInteractions: [Api.PostInteractionCounters]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let reactionsPerPost, let viewsPerStory, let sharesPerStory, let reactionsPerStory, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let reactionsByEmotionGraph, let storyInteractionsGraph, let storyReactionsByEmotionGraph, let recentPostsInteractions): - if boxed { - buffer.appendInt32(963421692) - } - period.serialize(buffer, true) - followers.serialize(buffer, true) - viewsPerPost.serialize(buffer, true) - sharesPerPost.serialize(buffer, true) - reactionsPerPost.serialize(buffer, true) - viewsPerStory.serialize(buffer, true) - sharesPerStory.serialize(buffer, true) - reactionsPerStory.serialize(buffer, true) - enabledNotifications.serialize(buffer, true) - growthGraph.serialize(buffer, true) - followersGraph.serialize(buffer, true) - muteGraph.serialize(buffer, true) - topHoursGraph.serialize(buffer, true) - interactionsGraph.serialize(buffer, true) - ivInteractionsGraph.serialize(buffer, true) - viewsBySourceGraph.serialize(buffer, true) - newFollowersBySourceGraph.serialize(buffer, true) - languagesGraph.serialize(buffer, true) - reactionsByEmotionGraph.serialize(buffer, true) - storyInteractionsGraph.serialize(buffer, true) - storyReactionsByEmotionGraph.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(recentPostsInteractions.count)) - for item in recentPostsInteractions { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let reactionsPerPost, let viewsPerStory, let sharesPerStory, let reactionsPerStory, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let reactionsByEmotionGraph, let storyInteractionsGraph, let storyReactionsByEmotionGraph, let recentPostsInteractions): - return ("broadcastStats", [("period", period as Any), ("followers", followers as Any), ("viewsPerPost", viewsPerPost as Any), ("sharesPerPost", sharesPerPost as Any), ("reactionsPerPost", reactionsPerPost as Any), ("viewsPerStory", viewsPerStory as Any), ("sharesPerStory", sharesPerStory as Any), ("reactionsPerStory", reactionsPerStory as Any), ("enabledNotifications", enabledNotifications as Any), ("growthGraph", growthGraph as Any), ("followersGraph", followersGraph as Any), ("muteGraph", muteGraph as Any), ("topHoursGraph", topHoursGraph as Any), ("interactionsGraph", interactionsGraph as Any), ("ivInteractionsGraph", ivInteractionsGraph as Any), ("viewsBySourceGraph", viewsBySourceGraph as Any), ("newFollowersBySourceGraph", newFollowersBySourceGraph as Any), ("languagesGraph", languagesGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any), ("storyInteractionsGraph", storyInteractionsGraph as Any), ("storyReactionsByEmotionGraph", storyReactionsByEmotionGraph as Any), ("recentPostsInteractions", recentPostsInteractions as Any)]) - } - } - - public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { - var _1: Api.StatsDateRangeDays? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays - } - var _2: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _3: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _4: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _5: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _6: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _6 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _7: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _7 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _8: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _9: Api.StatsPercentValue? - if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue - } - var _10: Api.StatsGraph? - if let signature = reader.readInt32() { - _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _11: Api.StatsGraph? - if let signature = reader.readInt32() { - _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _12: Api.StatsGraph? - if let signature = reader.readInt32() { - _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _13: Api.StatsGraph? - if let signature = reader.readInt32() { - _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _14: Api.StatsGraph? - if let signature = reader.readInt32() { - _14 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _15: Api.StatsGraph? - if let signature = reader.readInt32() { - _15 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _16: Api.StatsGraph? - if let signature = reader.readInt32() { - _16 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _17: Api.StatsGraph? - if let signature = reader.readInt32() { - _17 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _18: Api.StatsGraph? - if let signature = reader.readInt32() { - _18 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _19: Api.StatsGraph? - if let signature = reader.readInt32() { - _19 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _20: Api.StatsGraph? - if let signature = reader.readInt32() { - _20 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _21: Api.StatsGraph? - if let signature = reader.readInt32() { - _21 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _22: [Api.PostInteractionCounters]? - if let _ = reader.readInt32() { - _22 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PostInteractionCounters.self) - } - 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 = _9 != nil - let _c10 = _10 != nil - let _c11 = _11 != nil - let _c12 = _12 != nil - let _c13 = _13 != nil - let _c14 = _14 != nil - let _c15 = _15 != nil - let _c16 = _16 != nil - let _c17 = _17 != nil - let _c18 = _18 != nil - let _c19 = _19 != nil - let _c20 = _20 != nil - let _c21 = _21 != nil - let _c22 = _22 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 { - return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, reactionsPerPost: _5!, viewsPerStory: _6!, sharesPerStory: _7!, reactionsPerStory: _8!, enabledNotifications: _9!, growthGraph: _10!, followersGraph: _11!, muteGraph: _12!, topHoursGraph: _13!, interactionsGraph: _14!, ivInteractionsGraph: _15!, viewsBySourceGraph: _16!, newFollowersBySourceGraph: _17!, languagesGraph: _18!, reactionsByEmotionGraph: _19!, storyInteractionsGraph: _20!, storyReactionsByEmotionGraph: _21!, recentPostsInteractions: _22!) - } - else { - return nil - } - } - - } -} -public extension Api.stats { - enum MegagroupStats: TypeConstructorDescription { - case megagroupStats(period: Api.StatsDateRangeDays, members: Api.StatsAbsValueAndPrev, messages: Api.StatsAbsValueAndPrev, viewers: Api.StatsAbsValueAndPrev, posters: Api.StatsAbsValueAndPrev, growthGraph: Api.StatsGraph, membersGraph: Api.StatsGraph, newMembersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, messagesGraph: Api.StatsGraph, actionsGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, weekdaysGraph: Api.StatsGraph, topPosters: [Api.StatsGroupTopPoster], topAdmins: [Api.StatsGroupTopAdmin], topInviters: [Api.StatsGroupTopInviter], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): - if boxed { - buffer.appendInt32(-276825834) - } - period.serialize(buffer, true) - members.serialize(buffer, true) - messages.serialize(buffer, true) - viewers.serialize(buffer, true) - posters.serialize(buffer, true) - growthGraph.serialize(buffer, true) - membersGraph.serialize(buffer, true) - newMembersBySourceGraph.serialize(buffer, true) - languagesGraph.serialize(buffer, true) - messagesGraph.serialize(buffer, true) - actionsGraph.serialize(buffer, true) - topHoursGraph.serialize(buffer, true) - weekdaysGraph.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(topPosters.count)) - for item in topPosters { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(topAdmins.count)) - for item in topAdmins { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(topInviters.count)) - for item in topInviters { - 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 .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): - return ("megagroupStats", [("period", period as Any), ("members", members as Any), ("messages", messages as Any), ("viewers", viewers as Any), ("posters", posters as Any), ("growthGraph", growthGraph as Any), ("membersGraph", membersGraph as Any), ("newMembersBySourceGraph", newMembersBySourceGraph as Any), ("languagesGraph", languagesGraph as Any), ("messagesGraph", messagesGraph as Any), ("actionsGraph", actionsGraph as Any), ("topHoursGraph", topHoursGraph as Any), ("weekdaysGraph", weekdaysGraph as Any), ("topPosters", topPosters as Any), ("topAdmins", topAdmins as Any), ("topInviters", topInviters as Any), ("users", users as Any)]) - } - } - - public static func parse_megagroupStats(_ reader: BufferReader) -> MegagroupStats? { - var _1: Api.StatsDateRangeDays? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays - } - var _2: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _3: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _4: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _5: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _6: Api.StatsGraph? - if let signature = reader.readInt32() { - _6 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _7: Api.StatsGraph? - if let signature = reader.readInt32() { - _7 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _8: Api.StatsGraph? - if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _9: Api.StatsGraph? - if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _10: Api.StatsGraph? - if let signature = reader.readInt32() { - _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _11: Api.StatsGraph? - if let signature = reader.readInt32() { - _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _12: Api.StatsGraph? - if let signature = reader.readInt32() { - _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _13: Api.StatsGraph? - if let signature = reader.readInt32() { - _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _14: [Api.StatsGroupTopPoster]? - if let _ = reader.readInt32() { - _14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopPoster.self) - } - var _15: [Api.StatsGroupTopAdmin]? - if let _ = reader.readInt32() { - _15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopAdmin.self) - } - var _16: [Api.StatsGroupTopInviter]? - if let _ = reader.readInt32() { - _16 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopInviter.self) - } - var _17: [Api.User]? - if let _ = reader.readInt32() { - _17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - let _c8 = _8 != nil - let _c9 = _9 != nil - let _c10 = _10 != nil - let _c11 = _11 != nil - let _c12 = _12 != nil - let _c13 = _13 != nil - let _c14 = _14 != nil - let _c15 = _15 != nil - let _c16 = _16 != nil - let _c17 = _17 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 { - return Api.stats.MegagroupStats.megagroupStats(period: _1!, members: _2!, messages: _3!, viewers: _4!, posters: _5!, growthGraph: _6!, membersGraph: _7!, newMembersBySourceGraph: _8!, languagesGraph: _9!, messagesGraph: _10!, actionsGraph: _11!, topHoursGraph: _12!, weekdaysGraph: _13!, topPosters: _14!, topAdmins: _15!, topInviters: _16!, users: _17!) - } - else { - return nil - } - } - - } -} -public extension Api.stats { - enum MessageStats: TypeConstructorDescription { - case messageStats(viewsGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .messageStats(let viewsGraph, let reactionsByEmotionGraph): - if boxed { - buffer.appendInt32(2145983508) - } - viewsGraph.serialize(buffer, true) - reactionsByEmotionGraph.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .messageStats(let viewsGraph, let reactionsByEmotionGraph): - return ("messageStats", [("viewsGraph", viewsGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any)]) - } - } - - public static func parse_messageStats(_ reader: BufferReader) -> MessageStats? { - var _1: Api.StatsGraph? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _2: Api.StatsGraph? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.stats.MessageStats.messageStats(viewsGraph: _1!, reactionsByEmotionGraph: _2!) - } - else { - return nil - } - } - - } -} public extension Api.stats { enum PublicForwards: TypeConstructorDescription { case publicForwards(flags: Int32, count: Int32, forwards: [Api.PublicForward], nextOffset: String?, chats: [Api.Chat], users: [Api.User]) @@ -1596,3 +1234,111 @@ public extension Api.updates { } } +public extension Api.updates { + enum State: TypeConstructorDescription { + case state(pts: Int32, qts: Int32, date: Int32, seq: Int32, unreadCount: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .state(let pts, let qts, let date, let seq, let unreadCount): + if boxed { + buffer.appendInt32(-1519637954) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(qts, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(seq, buffer: buffer, boxed: false) + serializeInt32(unreadCount, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .state(let pts, let qts, let date, let seq, let unreadCount): + return ("state", [("pts", pts as Any), ("qts", qts as Any), ("date", date as Any), ("seq", seq as Any), ("unreadCount", unreadCount as Any)]) + } + } + + public static func parse_state(_ reader: BufferReader) -> State? { + 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() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.updates.State.state(pts: _1!, qts: _2!, date: _3!, seq: _4!, unreadCount: _5!) + } + else { + return nil + } + } + + } +} +public extension Api.upload { + enum CdnFile: TypeConstructorDescription { + case cdnFile(bytes: Buffer) + case cdnFileReuploadNeeded(requestToken: Buffer) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .cdnFile(let bytes): + if boxed { + buffer.appendInt32(-1449145777) + } + serializeBytes(bytes, buffer: buffer, boxed: false) + break + case .cdnFileReuploadNeeded(let requestToken): + if boxed { + buffer.appendInt32(-290921362) + } + serializeBytes(requestToken, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .cdnFile(let bytes): + return ("cdnFile", [("bytes", bytes as Any)]) + case .cdnFileReuploadNeeded(let requestToken): + return ("cdnFileReuploadNeeded", [("requestToken", requestToken as Any)]) + } + } + + public static func parse_cdnFile(_ reader: BufferReader) -> CdnFile? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.upload.CdnFile.cdnFile(bytes: _1!) + } + else { + return nil + } + } + public static func parse_cdnFileReuploadNeeded(_ reader: BufferReader) -> CdnFile? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.upload.CdnFile.cdnFileReuploadNeeded(requestToken: _1!) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramApi/Sources/Api38.swift b/submodules/TelegramApi/Sources/Api38.swift index 281a495dbf..df11f101cb 100644 --- a/submodules/TelegramApi/Sources/Api38.swift +++ b/submodules/TelegramApi/Sources/Api38.swift @@ -1,111 +1,3 @@ -public extension Api.updates { - enum State: TypeConstructorDescription { - case state(pts: Int32, qts: Int32, date: Int32, seq: Int32, unreadCount: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .state(let pts, let qts, let date, let seq, let unreadCount): - if boxed { - buffer.appendInt32(-1519637954) - } - serializeInt32(pts, buffer: buffer, boxed: false) - serializeInt32(qts, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeInt32(seq, buffer: buffer, boxed: false) - serializeInt32(unreadCount, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .state(let pts, let qts, let date, let seq, let unreadCount): - return ("state", [("pts", pts as Any), ("qts", qts as Any), ("date", date as Any), ("seq", seq as Any), ("unreadCount", unreadCount as Any)]) - } - } - - public static func parse_state(_ reader: BufferReader) -> State? { - 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() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.updates.State.state(pts: _1!, qts: _2!, date: _3!, seq: _4!, unreadCount: _5!) - } - else { - return nil - } - } - - } -} -public extension Api.upload { - enum CdnFile: TypeConstructorDescription { - case cdnFile(bytes: Buffer) - case cdnFileReuploadNeeded(requestToken: Buffer) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .cdnFile(let bytes): - if boxed { - buffer.appendInt32(-1449145777) - } - serializeBytes(bytes, buffer: buffer, boxed: false) - break - case .cdnFileReuploadNeeded(let requestToken): - if boxed { - buffer.appendInt32(-290921362) - } - serializeBytes(requestToken, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .cdnFile(let bytes): - return ("cdnFile", [("bytes", bytes as Any)]) - case .cdnFileReuploadNeeded(let requestToken): - return ("cdnFileReuploadNeeded", [("requestToken", requestToken as Any)]) - } - } - - public static func parse_cdnFile(_ reader: BufferReader) -> CdnFile? { - var _1: Buffer? - _1 = parseBytes(reader) - let _c1 = _1 != nil - if _c1 { - return Api.upload.CdnFile.cdnFile(bytes: _1!) - } - else { - return nil - } - } - public static func parse_cdnFileReuploadNeeded(_ reader: BufferReader) -> CdnFile? { - var _1: Buffer? - _1 = parseBytes(reader) - let _c1 = _1 != nil - if _c1 { - return Api.upload.CdnFile.cdnFileReuploadNeeded(requestToken: _1!) - } - else { - return nil - } - } - - } -} public extension Api.upload { enum File: TypeConstructorDescription { case file(type: Api.storage.FileType, mtime: Int32, bytes: Buffer) diff --git a/submodules/TelegramApi/Sources/Api39.swift b/submodules/TelegramApi/Sources/Api39.swift index 341867958d..7bd3b42275 100644 --- a/submodules/TelegramApi/Sources/Api39.swift +++ b/submodules/TelegramApi/Sources/Api39.swift @@ -9674,13 +9674,14 @@ public extension Api.functions.payments { } } public extension Api.functions.payments { - static func getStarsRevenueWithdrawalUrl(peer: Api.InputPeer, stars: Int64, password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func getStarsRevenueWithdrawalUrl(flags: Int32, peer: Api.InputPeer, amount: Int64?, password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(331081907) + buffer.appendInt32(607378578) + serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) - serializeInt64(stars, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt64(amount!, 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 + return (FunctionDescription(name: "payments.getStarsRevenueWithdrawalUrl", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("amount", String(describing: amount)), ("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() { @@ -9758,16 +9759,17 @@ public extension Api.functions.payments { } } public extension Api.functions.payments { - static func getStarsTransactionsByID(peer: Api.InputPeer, id: [Api.InputStarsTransaction]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func getStarsTransactionsByID(flags: Int32, peer: Api.InputPeer, id: [Api.InputStarsTransaction]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(662973742) + buffer.appendInt32(768218808) + serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) buffer.appendInt32(481674261) buffer.appendInt32(Int32(id.count)) for item in id { item.serialize(buffer, true) } - return (FunctionDescription(name: "payments.getStarsTransactionsByID", parameters: [("peer", String(describing: peer)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in + return (FunctionDescription(name: "payments.getStarsTransactionsByID", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in let reader = BufferReader(buffer) var result: Api.payments.StarsStatus? if let signature = reader.readInt32() { @@ -10927,55 +10929,6 @@ public extension Api.functions.smsjobs { }) } } -public extension Api.functions.stats { - static func getBroadcastRevenueStats(flags: Int32, peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(-142021095) - serializeInt32(flags, buffer: buffer, boxed: false) - peer.serialize(buffer, true) - return (FunctionDescription(name: "stats.getBroadcastRevenueStats", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.BroadcastRevenueStats? in - let reader = BufferReader(buffer) - var result: Api.stats.BroadcastRevenueStats? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.stats.BroadcastRevenueStats - } - return result - }) - } -} -public extension Api.functions.stats { - static func getBroadcastRevenueTransactions(peer: Api.InputPeer, offset: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(1889078125) - peer.serialize(buffer, true) - serializeInt32(offset, buffer: buffer, boxed: false) - serializeInt32(limit, buffer: buffer, boxed: false) - return (FunctionDescription(name: "stats.getBroadcastRevenueTransactions", parameters: [("peer", String(describing: peer)), ("offset", String(describing: offset)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.BroadcastRevenueTransactions? in - let reader = BufferReader(buffer) - var result: Api.stats.BroadcastRevenueTransactions? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.stats.BroadcastRevenueTransactions - } - return result - }) - } -} -public extension Api.functions.stats { - static func getBroadcastRevenueWithdrawalUrl(peer: Api.InputPeer, password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(-1644889427) - peer.serialize(buffer, true) - password.serialize(buffer, true) - return (FunctionDescription(name: "stats.getBroadcastRevenueWithdrawalUrl", parameters: [("peer", String(describing: peer)), ("password", String(describing: password))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.BroadcastRevenueWithdrawalUrl? in - let reader = BufferReader(buffer) - var result: Api.stats.BroadcastRevenueWithdrawalUrl? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.stats.BroadcastRevenueWithdrawalUrl - } - return result - }) - } -} public extension Api.functions.stats { static func getBroadcastStats(flags: Int32, channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index c1778a9068..de69062dd6 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -129,7 +129,6 @@ enum AccountStateMutationOperation { case UpdateStorySentReaction(peerId: PeerId, id: Int32, reaction: Api.Reaction) case UpdateNewAuthorization(isUnconfirmed: Bool, hash: Int64, date: Int32, device: String, location: String) case UpdateWallpaper(peerId: PeerId, wallpaper: TelegramWallpaper?) - case UpdateRevenueBalances(peerId: PeerId, balances: RevenueStats.Balances) case UpdateStarsBalance(peerId: PeerId, currency: CurrencyAmount.Currency, balance: StarsAmount) case UpdateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances) case UpdateStarsReactionsDefaultPrivacy(privacy: TelegramPaidReactionPrivacy) @@ -692,10 +691,6 @@ struct AccountMutableState { self.addOperation(.UpdateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date, device: device, location: location)) } - mutating func updateRevenueBalances(peerId: PeerId, balances: RevenueStats.Balances) { - self.addOperation(.UpdateRevenueBalances(peerId: peerId, balances: balances)) - } - mutating func updateStarsBalance(peerId: PeerId, currency: CurrencyAmount.Currency, balance: StarsAmount) { self.addOperation(.UpdateStarsBalance(peerId: peerId, currency: currency, balance: balance)) } @@ -714,7 +709,7 @@ struct AccountMutableState { 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, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery: + 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, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery: break case let .AddMessages(messages, location): for message in messages { @@ -858,7 +853,6 @@ struct AccountReplayedFinalState { let updatedOutgoingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] let updateConfig: Bool let isPremiumUpdated: Bool - let updatedRevenueBalances: [PeerId: RevenueStats.Balances] let updatedStarsBalance: [PeerId: StarsAmount] let updatedTonBalance: [PeerId: StarsAmount] let updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] @@ -892,7 +886,6 @@ struct AccountFinalStateEvents { let updatedOutgoingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] let updateConfig: Bool let isPremiumUpdated: Bool - let updatedRevenueBalances: [PeerId: RevenueStats.Balances] let updatedStarsBalance: [PeerId: StarsAmount] let updatedTonBalance: [PeerId: StarsAmount] let updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] @@ -900,10 +893,10 @@ struct AccountFinalStateEvents { let addedConferenceInvitationMessagesIds: [MessageId] var isEmpty: Bool { - return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.sentScheduledMessageIds.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.updatedTonBalance.isEmpty && self.updatedStarsRevenueStatus.isEmpty && self.reportMessageDelivery.isEmpty && self.addedConferenceInvitationMessagesIds.isEmpty + return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.sentScheduledMessageIds.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.updatedStarsBalance.isEmpty && self.updatedTonBalance.isEmpty && self.updatedStarsRevenueStatus.isEmpty && self.reportMessageDelivery.isEmpty && self.addedConferenceInvitationMessagesIds.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: [PeerAndBoundThreadId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedRevenueBalances: [PeerId: RevenueStats.Balances] = [:], updatedStarsBalance: [PeerId: StarsAmount] = [:], updatedTonBalance: [PeerId: StarsAmount] = [:], updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:], sentScheduledMessageIds: Set = Set(), reportMessageDelivery: Set = Set(), addedConferenceInvitationMessagesIds: [MessageId] = []) { + 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: [PeerAndBoundThreadId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedStarsBalance: [PeerId: StarsAmount] = [:], updatedTonBalance: [PeerId: StarsAmount] = [:], updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:], sentScheduledMessageIds: Set = Set(), reportMessageDelivery: Set = Set(), addedConferenceInvitationMessagesIds: [MessageId] = []) { self.addedIncomingMessageIds = addedIncomingMessageIds self.addedReactionEvents = addedReactionEvents self.wasScheduledMessageIds = wasScheduledMessageIds @@ -927,7 +920,6 @@ struct AccountFinalStateEvents { self.updatedOutgoingThreadReadStates = updatedOutgoingThreadReadStates self.updateConfig = updateConfig self.isPremiumUpdated = isPremiumUpdated - self.updatedRevenueBalances = updatedRevenueBalances self.updatedStarsBalance = updatedStarsBalance self.updatedTonBalance = updatedTonBalance self.updatedStarsRevenueStatus = updatedStarsRevenueStatus @@ -960,7 +952,6 @@ struct AccountFinalStateEvents { self.updatedOutgoingThreadReadStates = state.updatedOutgoingThreadReadStates self.updateConfig = state.updateConfig self.isPremiumUpdated = state.isPremiumUpdated - self.updatedRevenueBalances = state.updatedRevenueBalances self.updatedStarsBalance = state.updatedStarsBalance self.updatedTonBalance = state.updatedTonBalance self.updatedStarsRevenueStatus = state.updatedStarsRevenueStatus @@ -1027,7 +1018,6 @@ struct AccountFinalStateEvents { 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 }), updatedTonBalance: self.updatedTonBalance.merging(other.updatedTonBalance, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsRevenueStatus: self.updatedStarsRevenueStatus.merging(other.updatedStarsRevenueStatus, uniquingKeysWith: { lhs, _ in lhs }), diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index eb7de8d13b..070586f06c 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -232,7 +232,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { } switch action { - case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionGiftStars, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionSetChatWallPaper, .messageActionGiveawayLaunch, .messageActionGiveawayResults, .messageActionBoostApply, .messageActionRequestedPeerSentMe, .messageActionStarGift, .messageActionStarGiftUnique, .messageActionPaidMessagesRefunded, .messageActionPaidMessagesPrice, .messageActionTodoCompletions, .messageActionTodoAppendTasks, .messageActionSuggestedPostApproval, .messageActionGiftTon: + case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionGiftStars, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionSetChatWallPaper, .messageActionGiveawayLaunch, .messageActionGiveawayResults, .messageActionBoostApply, .messageActionRequestedPeerSentMe, .messageActionStarGift, .messageActionStarGiftUnique, .messageActionPaidMessagesRefunded, .messageActionPaidMessagesPrice, .messageActionTodoCompletions, .messageActionTodoAppendTasks, .messageActionSuggestedPostApproval, .messageActionGiftTon, .messageActionSuggestedPostSuccess, .messageActionSuggestedPostRefund: break case let .messageActionChannelMigrateFrom(_, chatId): result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))) diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift index 8354858c1a..3a58f9ad9c 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift @@ -264,6 +264,10 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe return TelegramMediaAction(action: .suggestedPostApprovalStatus(status: status)) case let .messageActionGiftTon(_, currency, amount, cryptoCurrency, cryptoAmount, transactionId): return TelegramMediaAction(action: .giftTon(currency: currency, amount: amount, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, transactionId: transactionId)) + case .messageActionSuggestedPostSuccess: + return nil + case .messageActionSuggestedPostRefund: + return nil } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index d6414b9638..69c0c11f0c 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1836,8 +1836,6 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: updatedState.updateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date ?? 0, device: device ?? "", location: location ?? "") case let .updatePeerWallpaper(_, peer, wallpaper): updatedState.updateWallpaper(peerId: peer.peerId, wallpaper: wallpaper.flatMap { TelegramWallpaper(apiWallpaper: $0) }) - case let .updateBroadcastRevenueTransactions(peer, balances): - updatedState.updateRevenueBalances(peerId: peer.peerId, balances: RevenueStats.Balances(apiRevenueBalances: balances)) case let .updateStarsBalance(balance): let amount = CurrencyAmount(apiAmount: balance) updatedState.updateStarsBalance(peerId: accountPeerId, currency: amount.currency, balance: amount.amount) @@ -3581,7 +3579,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, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery: + 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, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -3716,7 +3714,6 @@ func replayFinalState( var deletedMessageIds: [DeletedMessageId] = [] var syncAttachMenuBots = false var updateConfig = false - var updatedRevenueBalances: [PeerId: RevenueStats.Balances] = [:] var updatedStarsBalance: [PeerId: StarsAmount] = [:] var updatedTonBalance: [PeerId: StarsAmount] = [:] var updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:] @@ -5169,8 +5166,6 @@ func replayFinalState( } else { transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.NewSessionReviews, itemId: id.rawValue) } - case let .UpdateRevenueBalances(peerId, balances): - updatedRevenueBalances[peerId] = balances case let .UpdateStarsBalance(peerId, currency, balance): switch currency { case .ton: @@ -5702,7 +5697,6 @@ func replayFinalState( updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates, updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, - updatedRevenueBalances: updatedRevenueBalances, updatedStarsBalance: updatedStarsBalance, updatedTonBalance: updatedTonBalance, updatedStarsRevenueStatus: updatedStarsRevenueStatus, diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index 29d3ae0dd8..59a730582b 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -44,10 +44,6 @@ private final class UpdatedPeersNearbySubscriberContext { let subscribers = Bag<([PeerNearby]) -> Void>() } -private final class UpdatedRevenueBalancesSubscriberContext { - let subscribers = Bag<([PeerId: RevenueStats.Balances]) -> Void>() -} - private final class UpdatedStarsBalanceSubscriberContext { let subscribers = Bag<([PeerId: StarsAmount]) -> Void>() } @@ -353,7 +349,6 @@ public final class AccountStateManager { private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:] private var updatedPeersNearbyContext = UpdatedPeersNearbySubscriberContext() - private var updatedRevenueBalancesContext = UpdatedRevenueBalancesSubscriberContext() private var updatedStarsBalanceContext = UpdatedStarsBalanceSubscriberContext() private var updatedTonBalanceContext = UpdatedStarsBalanceSubscriberContext() private var updatedStarsRevenueStatusContext = UpdatedStarsRevenueStatusSubscriberContext() @@ -1112,9 +1107,6 @@ public final class AccountStateManager { if let updatedPeersNearby = events.updatedPeersNearby { strongSelf.notifyUpdatedPeersNearby(updatedPeersNearby) } - if !events.updatedRevenueBalances.isEmpty { - strongSelf.notifyUpdatedRevenueBalances(events.updatedRevenueBalances) - } if !events.updatedStarsBalance.isEmpty { strongSelf.notifyUpdatedStarsBalance(events.updatedStarsBalance) } @@ -1708,33 +1700,6 @@ public final class AccountStateManager { } } - public func updatedRevenueBalances() -> Signal<[PeerId: RevenueStats.Balances], NoError> { - let queue = self.queue - return Signal { [weak self] subscriber in - let disposable = MetaDisposable() - queue.async { - if let strongSelf = self { - let index = strongSelf.updatedRevenueBalancesContext.subscribers.add({ revenueBalances in - subscriber.putNext(revenueBalances) - }) - - disposable.set(ActionDisposable { - if let strongSelf = self { - strongSelf.updatedRevenueBalancesContext.subscribers.remove(index) - } - }) - } - } - return disposable - } - } - - private func notifyUpdatedRevenueBalances(_ updatedRevenueBalances: [PeerId: RevenueStats.Balances]) { - for subscriber in self.updatedRevenueBalancesContext.subscribers.copyItems() { - subscriber(updatedRevenueBalances) - } - } - public func updatedStarsBalance() -> Signal<[PeerId: StarsAmount], NoError> { let queue = self.queue return Signal { [weak self] subscriber in @@ -2165,12 +2130,6 @@ public final class AccountStateManager { } } - public func updatedRevenueBalances() -> Signal<[PeerId: RevenueStats.Balances], NoError> { - return self.impl.signalWith { impl, subscriber in - return impl.updatedRevenueBalances().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) - } - } - public func updatedStarsBalance() -> Signal<[PeerId: StarsAmount], NoError> { return self.impl.signalWith { impl, subscriber in return impl.updatedStarsBalance().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) @@ -2179,7 +2138,7 @@ public final class AccountStateManager { public func updatedTonBalance() -> Signal<[PeerId: StarsAmount], NoError> { return self.impl.signalWith { impl, subscriber in - return impl.updatedStarsBalance().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) + return impl.updatedTonBalance().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) } } diff --git a/submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift b/submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift deleted file mode 100644 index 1fc95e8463..0000000000 --- a/submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift +++ /dev/null @@ -1,589 +0,0 @@ -import Foundation -import SwiftSignalKit -import Postbox -import TelegramApi -import MtProtoKit - -public struct RevenueStats: Equatable, Codable { - private enum CodingKeys: String, CodingKey { - case topHoursGraph - case revenueGraph - case balances - case usdRate - } - - static func key(peerId: PeerId) -> ValueBoxKey { - let key = ValueBoxKey(length: 8 + 4) - key.setInt64(0, value: peerId.toInt64()) - return key - } - - public struct Balances: Equatable, Codable { - private enum CodingKeys: String, CodingKey { - case currentBalance - case availableBalance - case overallRevenue - case withdrawEnabled - } - - public let currentBalance: Int64 - public let availableBalance: Int64 - public let overallRevenue: Int64 - public let withdrawEnabled: Bool - - init( - currentBalance: Int64, - availableBalance: Int64, - overallRevenue: Int64, - withdrawEnabled: Bool - ) { - self.currentBalance = currentBalance - self.availableBalance = availableBalance - self.overallRevenue = overallRevenue - self.withdrawEnabled = withdrawEnabled - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.currentBalance = try container.decode(Int64.self, forKey: .currentBalance) - self.availableBalance = try container.decode(Int64.self, forKey: .availableBalance) - self.overallRevenue = try container.decode(Int64.self, forKey: .overallRevenue) - self.withdrawEnabled = try container.decode(Bool.self, forKey: .withdrawEnabled) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.currentBalance, forKey: .currentBalance) - try container.encode(self.availableBalance, forKey: .availableBalance) - try container.encode(self.overallRevenue, forKey: .overallRevenue) - try container.encode(self.withdrawEnabled, forKey: .withdrawEnabled) - } - } - - public let topHoursGraph: StatsGraph - public let revenueGraph: StatsGraph - public let balances: Balances - public let usdRate: Double - - init(topHoursGraph: StatsGraph, revenueGraph: StatsGraph, balances: Balances, usdRate: Double) { - self.topHoursGraph = topHoursGraph - self.revenueGraph = revenueGraph - self.balances = balances - self.usdRate = usdRate - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.topHoursGraph = try container.decode(StatsGraph.self, forKey: .topHoursGraph) - self.revenueGraph = try container.decode(StatsGraph.self, forKey: .revenueGraph) - self.balances = try container.decode(Balances.self, forKey: .balances) - self.usdRate = try container.decode(Double.self, forKey: .usdRate) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.topHoursGraph, forKey: .topHoursGraph) - try container.encode(self.revenueGraph, forKey: .revenueGraph) - try container.encode(self.balances, forKey: .balances) - try container.encode(self.usdRate, forKey: .usdRate) - } - - public static func == (lhs: RevenueStats, rhs: RevenueStats) -> Bool { - if lhs.topHoursGraph != rhs.topHoursGraph { - return false - } - 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 RevenueStats { - func withUpdated(balances: RevenueStats.Balances) -> RevenueStats { - return RevenueStats( - topHoursGraph: self.topHoursGraph, - revenueGraph: self.revenueGraph, - balances: balances, - usdRate: self.usdRate - ) - } -} - -extension RevenueStats { - init(apiRevenueStats: Api.stats.BroadcastRevenueStats, peerId: PeerId) { - switch apiRevenueStats { - case let .broadcastRevenueStats(topHoursGraph, revenueGraph, balances, usdRate): - self.init(topHoursGraph: StatsGraph(apiStatsGraph: topHoursGraph), revenueGraph: StatsGraph(apiStatsGraph: revenueGraph), balances: RevenueStats.Balances(apiRevenueBalances: balances), usdRate: usdRate) - } - } -} - -extension RevenueStats.Balances { - init(apiRevenueBalances: Api.BroadcastRevenueBalances) { - switch apiRevenueBalances { - case let .broadcastRevenueBalances(flags, currentBalance, availableBalance, overallRevenue): - self.init(currentBalance: currentBalance, availableBalance: availableBalance, overallRevenue: overallRevenue, withdrawEnabled: ((flags & (1 << 0)) != 0)) - } - } -} - -public struct RevenueStatsContextState: Equatable { - public var stats: RevenueStats? -} - -private func requestRevenueStats(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 channel = peer as? TelegramChannel, case .broadcast = channel.info, let inputPeer = apiInputPeer(peer) else { - return .never() - } - - var flags: Int32 = 0 - if dark { - flags |= (1 << 1) - } - - return network.request(Api.functions.stats.getBroadcastRevenueStats(flags: flags, peer: inputPeer)) - |> map { result -> RevenueStats? in - return RevenueStats(apiRevenueStats: result, peerId: peerId) - } - |> retryRequest - } -} - -private final class RevenueStatsContextImpl { - private let account: Account - private let peerId: PeerId - - private var _state: RevenueStatsContextState { - 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 = RevenueStatsContextState(stats: nil) - self._statePromise.set(.single(self._state)) - - self.load() - - let _ = (account.postbox.transaction { transaction -> RevenueStats? in - return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedRevenueStats, key: StarsRevenueStats.key(peerId: peerId)))?.get(RevenueStats.self) - } - |> deliverOnMainQueue).start(next: { [weak self] cachedResult in - guard let self, let cachedResult else { - return - } - self._state = RevenueStatsContextState(stats: cachedResult) - self._statePromise.set(.single(self._state)) - }) - } - - 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 = requestRevenueStats(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.updatedRevenueBalances() - |> 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 self { - self._state = RevenueStatsContextState(stats: stats) - self._statePromise.set(.single(self._state)) - - if let stats { - let _ = (self.account.postbox.transaction { transaction in - if let entry = CodableEntry(stats) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedRevenueStats, key: StarsRevenueStats.key(peerId: peerId)), entry: entry) - } - }).start() - } - } - })) - } - - 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 RevenueStatsContext { - 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 RevenueStatsContextImpl(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 - } - } -} - -private final class RevenueStatsTransactionsContextImpl { - private let queue: Queue - private let account: Account - private let peerId: EnginePeer.Id - private let disposable = MetaDisposable() - private var updateDisposable: Disposable? - private var isLoadingMore: Bool = false - private var hasLoadedOnce: Bool = false - private var canLoadMore: Bool = true - private var results: [RevenueStatsTransactionsContext.State.Transaction] = [] - private var count: Int32 - private var lastOffset: Int32? - - let state = Promise() - - init(queue: Queue, account: Account, peerId: EnginePeer.Id) { - self.queue = queue - self.account = account - self.peerId = peerId - - self.count = 0 - - self.loadMore() - - self.updateDisposable = (account.stateManager.updatedRevenueBalances() - |> deliverOn(self.queue)).startStrict(next: { [weak self] _ in - self?.reload() - }) - } - - deinit { - self.disposable.dispose() - self.updateDisposable?.dispose() - } - - func reload() { - self.lastOffset = nil - - self.loadMore() - } - - func loadMore() { - if self.isLoadingMore || !self.canLoadMore { - return - } - self.isLoadingMore = true - let account = self.account - let peerId = self.peerId - let lastOffset = self.lastOffset - - self.disposable.set((self.account.postbox.transaction { transaction -> Peer? in - guard let peer = transaction.getPeer(peerId) else { - return nil - } - return peer - } - |> mapToSignal { peer -> Signal<([RevenueStatsTransactionsContext.State.Transaction], Int32, Int32?), NoError> in - if let peer { - guard let channel = peer as? TelegramChannel, case .broadcast = channel.info, let inputPeer = apiInputPeer(peer) else { - return .complete() - } - let offset = lastOffset ?? 0 - let limit: Int32 = lastOffset == nil ? 25 : 50 - - return account.network.request(Api.functions.stats.getBroadcastRevenueTransactions(peer: inputPeer, offset: offset, limit: limit), automaticFloodWait: false) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal<([RevenueStatsTransactionsContext.State.Transaction], Int32, Int32?), NoError> in - return account.postbox.transaction { transaction -> ([RevenueStatsTransactionsContext.State.Transaction], Int32, Int32?) in - guard let result = result else { - return ([], 0, nil) - } - switch result { - case let .broadcastRevenueTransactions(count, transactions): - let nextOffset = offset + Int32(transactions.count) - var resultTransactions: [RevenueStatsTransactionsContext.State.Transaction] = [] - for transaction in transactions { - switch transaction { - case let .broadcastRevenueTransactionProceeds(amount, fromDate, toDate): - resultTransactions.append(.proceeds(amount: amount, fromDate: fromDate, toDate: toDate)) - case let .broadcastRevenueTransactionRefund(amount, date, provider): - resultTransactions.append(.refund(amount: amount, date: date, provider: provider)) - case let .broadcastRevenueTransactionWithdrawal(flags, amount, date, provider, transactionDate, transactionUrl): - let status: RevenueStatsTransactionsContext.State.Transaction.WithdrawalStatus - if (flags & (1 << 0)) != 0 { - status = .pending - } else if (flags & (1 << 2)) != 0 { - status = .failed - } else { - status = .succeed - } - resultTransactions.append(.withdrawal(status: status, amount: amount, date: date, provider: provider, transactionDate: transactionDate, transactionUrl: transactionUrl)) - } - } - return (resultTransactions, count, nextOffset) - } - } - } - } else { - return .single(([], 0, nil)) - } - } - |> deliverOn(self.queue)).start(next: { [weak self] transactions, updatedCount, nextOffset in - guard let strongSelf = self else { - return - } - strongSelf.lastOffset = nextOffset - for transaction in transactions { - strongSelf.results.append(transaction) - } - strongSelf.isLoadingMore = false - strongSelf.hasLoadedOnce = true - strongSelf.canLoadMore = !transactions.isEmpty && nextOffset != nil - if strongSelf.canLoadMore { - strongSelf.count = max(updatedCount, Int32(strongSelf.results.count)) - } else { - strongSelf.count = Int32(strongSelf.results.count) - } - strongSelf.updateState() - })) - self.updateState() - } - - private func updateState() { - self.state.set(.single(RevenueStatsTransactionsContext.State(transactions: self.results, isLoadingMore: self.isLoadingMore, hasLoadedOnce: self.hasLoadedOnce, canLoadMore: self.canLoadMore, count: self.count))) - } -} - -public final class RevenueStatsTransactionsContext { - public struct State: Equatable { - public enum Transaction: Equatable { - public enum WithdrawalStatus { - case succeed - case pending - case failed - } - case proceeds(amount: Int64, fromDate: Int32, toDate: Int32) - case withdrawal(status: WithdrawalStatus, amount: Int64, date: Int32, provider: String, transactionDate: Int32?, transactionUrl: String?) - case refund(amount: Int64, date: Int32, provider: String) - - public var amount: Int64 { - switch self { - case let .proceeds(amount, _, _), let .withdrawal(_, amount, _, _, _, _), let .refund(amount, _, _): - return amount - } - } - } - public var transactions: [Transaction] - public var isLoadingMore: Bool - public var hasLoadedOnce: Bool - public var canLoadMore: Bool - public var count: Int32 - - public static var Empty = State(transactions: [], isLoadingMore: false, hasLoadedOnce: true, canLoadMore: false, count: 0) - public static var Loading = State(transactions: [], isLoadingMore: false, hasLoadedOnce: false, canLoadMore: false, count: 0) - } - - - private let queue: Queue = Queue() - private let impl: QueueLocalObject - - public var state: Signal { - return Signal { subscriber in - let disposable = MetaDisposable() - self.impl.with { impl in - disposable.set(impl.state.get().start(next: { value in - subscriber.putNext(value) - })) - } - return disposable - } - } - - public init(account: Account, peerId: EnginePeer.Id) { - let queue = self.queue - self.impl = QueueLocalObject(queue: queue, generate: { - return RevenueStatsTransactionsContextImpl(queue: queue, account: account, peerId: peerId) - }) - } - - public func loadMore() { - self.impl.with { impl in - impl.loadMore() - } - } - - public func reload() { - self.impl.with { impl in - impl.reload() - } - } -} - -public enum RequestRevenueWithdrawalError : Equatable { - case generic - case twoStepAuthMissing - case twoStepAuthTooFresh(Int32) - case authSessionTooFresh(Int32) - case limitExceeded - case requestPassword - case invalidPassword -} - -func _internal_checkChannelRevenueWithdrawalAvailability(account: Account) -> Signal { - return account.network.request(Api.functions.stats.getBroadcastRevenueWithdrawalUrl(peer: .inputPeerEmpty, password: .inputCheckPasswordEmpty)) - |> mapError { error -> RequestRevenueWithdrawalError 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_requestChannelRevenueWithdrawalUrl(account: Account, peerId: PeerId, 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 -> RequestRevenueWithdrawalError 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.stats.getBroadcastRevenueWithdrawalUrl(peer: inputPeer, password: password), automaticFloodWait: false) - |> mapError { error -> RequestRevenueWithdrawalError 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 .broadcastRevenueWithdrawalUrl(url): - return url - } - } - } - } - |> mapError { _ -> RequestRevenueWithdrawalError in } - |> switchToLatest -} diff --git a/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift b/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift index 5ef2303728..5bc1125d60 100644 --- a/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift +++ b/submodules/TelegramCore/Sources/Statistics/StarsRevenueStatistics.swift @@ -6,6 +6,7 @@ import MtProtoKit public struct StarsRevenueStats: Equatable, Codable { private enum CodingKeys: String, CodingKey { + case topHoursGraph case revenueGraph case balances case usdRate @@ -24,21 +25,22 @@ public struct StarsRevenueStats: Equatable, Codable { case overallRevenue case withdrawEnabled case nextWithdrawalTimestamp + case currentBalanceStars case availableBalanceStars case overallRevenueStars } - public let currentBalance: StarsAmount - public let availableBalance: StarsAmount - public let overallRevenue: StarsAmount + public let currentBalance: CurrencyAmount + public let availableBalance: CurrencyAmount + public let overallRevenue: CurrencyAmount public let withdrawEnabled: Bool public let nextWithdrawalTimestamp: Int32? public init( - currentBalance: StarsAmount, - availableBalance: StarsAmount, - overallRevenue: StarsAmount, + currentBalance: CurrencyAmount, + availableBalance: CurrencyAmount, + overallRevenue: CurrencyAmount, withdrawEnabled: Bool, nextWithdrawalTimestamp: Int32? ) { @@ -52,23 +54,22 @@ public struct StarsRevenueStats: Equatable, Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - if let legacyCurrentBalance = try container.decodeIfPresent(Int64.self, forKey: .currentBalance) { - self.currentBalance = StarsAmount(value: legacyCurrentBalance, nanos: 0) + if let legacyCurrentBalance = try container.decodeIfPresent(StarsAmount.self, forKey: .currentBalanceStars) { + self.currentBalance = CurrencyAmount(amount: legacyCurrentBalance, currency: .stars) } else { - self.currentBalance = try container.decode(StarsAmount.self, forKey: .currentBalanceStars) + self.currentBalance = try container.decode(CurrencyAmount.self, forKey: .currentBalance) } - if let legacyAvailableBalance = try container.decodeIfPresent(Int64.self, forKey: .availableBalance) { - self.availableBalance = StarsAmount(value: legacyAvailableBalance, nanos: 0) + if let legacyAvailableBalance = try container.decodeIfPresent(StarsAmount.self, forKey: .availableBalanceStars) { + self.availableBalance = CurrencyAmount(amount: legacyAvailableBalance, currency: .stars) } else { - self.availableBalance = try container.decode(StarsAmount.self, forKey: .availableBalanceStars) + self.availableBalance = try container.decode(CurrencyAmount.self, forKey: .availableBalance) } - - if let legacyOverallRevenue = try container.decodeIfPresent(Int64.self, forKey: .overallRevenue) { - self.overallRevenue = StarsAmount(value: legacyOverallRevenue, nanos: 0) + if let legacyOverallRevenue = try container.decodeIfPresent(StarsAmount.self, forKey: .overallRevenueStars) { + self.overallRevenue = CurrencyAmount(amount: legacyOverallRevenue, currency: .stars) } else { - self.overallRevenue = try container.decode(StarsAmount.self, forKey: .overallRevenueStars) + self.overallRevenue = try container.decode(CurrencyAmount.self, forKey: .overallRevenue) } self.withdrawEnabled = try container.decode(Bool.self, forKey: .withdrawEnabled) @@ -77,19 +78,21 @@ public struct StarsRevenueStats: Equatable, Codable { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(self.currentBalance, forKey: .currentBalanceStars) - try container.encode(self.availableBalance, forKey: .availableBalanceStars) - try container.encode(self.overallRevenue, forKey: .overallRevenueStars) + try container.encode(self.currentBalance, forKey: .currentBalance) + try container.encode(self.availableBalance, forKey: .availableBalance) + try container.encode(self.overallRevenue, forKey: .overallRevenue) try container.encode(self.withdrawEnabled, forKey: .withdrawEnabled) try container.encodeIfPresent(self.nextWithdrawalTimestamp, forKey: .nextWithdrawalTimestamp) } } + public let topHoursGraph: StatsGraph? public let revenueGraph: StatsGraph public let balances: Balances public let usdRate: Double - init(revenueGraph: StatsGraph, balances: Balances, usdRate: Double) { + init(topHoursGraph: StatsGraph?, revenueGraph: StatsGraph, balances: Balances, usdRate: Double) { + self.topHoursGraph = topHoursGraph self.revenueGraph = revenueGraph self.balances = balances self.usdRate = usdRate @@ -97,6 +100,7 @@ public struct StarsRevenueStats: Equatable, Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) + self.topHoursGraph = try container.decodeIfPresent(StatsGraph.self, forKey: .topHoursGraph) self.revenueGraph = try container.decode(StatsGraph.self, forKey: .revenueGraph) self.balances = try container.decode(Balances.self, forKey: .balances) self.usdRate = try container.decode(Double.self, forKey: .usdRate) @@ -104,12 +108,16 @@ public struct StarsRevenueStats: Equatable, Codable { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(self.topHoursGraph, forKey: .topHoursGraph) try container.encode(self.revenueGraph, forKey: .revenueGraph) try container.encode(self.balances, forKey: .balances) try container.encode(self.usdRate, forKey: .usdRate) } public static func == (lhs: StarsRevenueStats, rhs: StarsRevenueStats) -> Bool { + if lhs.topHoursGraph != rhs.topHoursGraph { + return false + } if lhs.revenueGraph != rhs.revenueGraph { return false } @@ -126,6 +134,7 @@ public struct StarsRevenueStats: Equatable, Codable { public extension StarsRevenueStats { func withUpdated(balances: StarsRevenueStats.Balances) -> StarsRevenueStats { return StarsRevenueStats( + topHoursGraph: self.topHoursGraph, revenueGraph: self.revenueGraph, balances: balances, usdRate: self.usdRate @@ -136,8 +145,8 @@ public extension StarsRevenueStats { 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) + case let .starsRevenueStats(_, topHoursGraph, revenueGraph, balances, usdRate): + self.init(topHoursGraph: topHoursGraph.flatMap { StatsGraph(apiStatsGraph: $0) }, revenueGraph: StatsGraph(apiStatsGraph: revenueGraph), balances: StarsRevenueStats.Balances(apiStarsRevenueStatus: balances), usdRate: usdRate) } } } @@ -146,7 +155,7 @@ extension StarsRevenueStats.Balances { init(apiStarsRevenueStatus: Api.StarsRevenueStatus) { switch apiStarsRevenueStatus { case let .starsRevenueStatus(flags, currentBalance, availableBalance, overallRevenue, nextWithdrawalAt): - self.init(currentBalance: StarsAmount(apiAmount: currentBalance), availableBalance: StarsAmount(apiAmount: availableBalance), overallRevenue: StarsAmount(apiAmount: overallRevenue), withdrawEnabled: ((flags & (1 << 0)) != 0), nextWithdrawalTimestamp: nextWithdrawalAt) + self.init(currentBalance: CurrencyAmount(apiAmount: currentBalance), availableBalance: CurrencyAmount(apiAmount: availableBalance), overallRevenue: CurrencyAmount(apiAmount: overallRevenue), withdrawEnabled: ((flags & (1 << 0)) != 0), nextWithdrawalTimestamp: nextWithdrawalAt) } } } @@ -155,7 +164,7 @@ public struct StarsRevenueStatsContextState: Equatable { public var stats: StarsRevenueStats? } -private func requestStarsRevenueStats(postbox: Postbox, network: Network, peerId: PeerId, dark: Bool = false) -> Signal { +private func requestStarsRevenueStats(postbox: Postbox, network: Network, peerId: PeerId, ton: Bool, dark: Bool = false) -> Signal { return postbox.transaction { transaction -> Peer? in if let peer = transaction.getPeer(peerId) { return peer @@ -167,9 +176,12 @@ private func requestStarsRevenueStats(postbox: Postbox, network: Network, peerId } var flags: Int32 = 0 - if dark { + if ton { flags |= (1 << 1) } + if dark { + flags |= (1 << 0) + } return network.request(Api.functions.payments.getStarsRevenueStats(flags: flags, peer: inputPeer)) |> retryRequestIfNotFrozen @@ -186,6 +198,7 @@ private func requestStarsRevenueStats(postbox: Postbox, network: Network, peerId private final class StarsRevenueStatsContextImpl { private let account: Account private let peerId: PeerId + private let ton: Bool private var _state: StarsRevenueStatsContextState { didSet { @@ -202,11 +215,12 @@ private final class StarsRevenueStatsContextImpl { private let disposable = MetaDisposable() private let updateDisposable = MetaDisposable() - init(account: Account, peerId: PeerId) { + init(account: Account, peerId: PeerId, ton: Bool) { assert(Queue.mainQueue().isCurrent()) self.account = account self.peerId = peerId + self.ton = ton self._state = StarsRevenueStatsContextState(stats: nil) self._statePromise.set(.single(self._state)) @@ -245,7 +259,7 @@ private final class StarsRevenueStatsContextImpl { let account = self.account let peerId = self.peerId - let signal = requestStarsRevenueStats(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId) + let signal = requestStarsRevenueStats(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId, ton: self.ton) |> mapToSignal { initial -> Signal in guard let initial else { return .single(nil) @@ -303,9 +317,9 @@ public final class StarsRevenueStatsContext { } } - public init(account: Account, peerId: PeerId) { + public init(account: Account, peerId: PeerId, ton: Bool) { self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: { - return StarsRevenueStatsContextImpl(account: account, peerId: peerId) + return StarsRevenueStatsContextImpl(account: account, peerId: peerId, ton: ton) }) } @@ -347,7 +361,7 @@ public enum RequestStarsRevenueWithdrawalError : Equatable { } func _internal_checkStarsRevenueWithdrawalAvailability(account: Account) -> Signal { - return account.network.request(Api.functions.payments.getStarsRevenueWithdrawalUrl(peer: .inputPeerEmpty, stars: 0, password: .inputCheckPasswordEmpty)) + return account.network.request(Api.functions.payments.getStarsRevenueWithdrawalUrl(flags: 0, peer: .inputPeerEmpty, amount: nil, password: .inputCheckPasswordEmpty)) |> mapError { error -> RequestStarsRevenueWithdrawalError in if error.errorDescription == "PASSWORD_HASH_INVALID" { return .requestPassword @@ -369,7 +383,7 @@ func _internal_checkStarsRevenueWithdrawalAvailability(account: Account) -> Sign |> ignoreValues } -func _internal_requestStarsRevenueWithdrawalUrl(account: Account, peerId: PeerId, amount: Int64, password: String) -> Signal { +func _internal_requestStarsRevenueWithdrawalUrl(account: Account, ton: Bool, peerId: PeerId, amount: Int64?, password: String) -> Signal { guard !password.isEmpty else { return .fail(.invalidPassword) } @@ -400,7 +414,13 @@ func _internal_requestStarsRevenueWithdrawalUrl(account: Account, peerId: PeerId return checkPassword |> mapToSignal { password -> Signal in - return account.network.request(Api.functions.payments.getStarsRevenueWithdrawalUrl(peer: inputPeer, stars: amount, password: password), automaticFloodWait: false) + var flags: Int32 = 0 + if ton { + flags |= 1 << 0 + } else { + flags |= 1 << 1 + } + return account.network.request(Api.functions.payments.getStarsRevenueWithdrawalUrl(flags: flags, peer: inputPeer, amount: amount, password: password), automaticFloodWait: false) |> mapError { error -> RequestStarsRevenueWithdrawalError in if error.errorCode == 406 { return .serverProvided(text: error.errorDescription) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift index 2321c6c6dd..6d38eb8972 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift @@ -2405,6 +2405,62 @@ public extension TelegramEngine.EngineData.Item { } } + public struct BotGroupAdminRights: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = Optional + + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .cachedPeerData(peerId: self.id) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? CachedPeerDataView else { + preconditionFailure() + } + if let cachedData = view.cachedPeerData as? CachedUserData { + return cachedData.botGroupAdminRights + } else { + return nil + } + } + } + + public struct BotChannelAdminRights: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = Optional + + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .cachedPeerData(peerId: self.id) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? CachedPeerDataView else { + preconditionFailure() + } + if let cachedData = view.cachedPeerData as? CachedUserData { + return cachedData.botChannelAdminRights + } else { + return nil + } + } + } + public struct StarsReactionDefaultPrivacy: TelegramEngineDataItem, PostboxViewDataItem { public typealias Result = TelegramPaidReactionPrivacy diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 7b947a4e7d..1d118f3cdb 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -462,7 +462,7 @@ private func _internal_requestStarsState(account: Account, peerId: EnginePeer.Id |> mapToSignal { result -> Signal in return account.postbox.transaction { transaction -> InternalStarsStatus in switch result { - case let .starsStatus(flags: _, balance, _, _, subscriptionsMissingBalance, transactions, nextTransactionsOffset, chats, users): + case let .starsStatus(_, balance, _, _, subscriptionsMissingBalance, transactions, nextTransactionsOffset, chats, users): let peers = AccumulatedPeers(chats: chats, users: users) updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: peers) @@ -570,9 +570,9 @@ private final class StarsContextImpl { self.load(force: true) - self.updateDisposable = (account.stateManager.updatedStarsBalance() + self.updateDisposable = ((ton ? account.stateManager.updatedTonBalance() : account.stateManager.updatedStarsBalance()) |> deliverOnMainQueue).startStrict(next: { [weak self] balances in - guard let self, let state = self._state, let balance = balances[peerId] else { + guard let self, let state = self._state, let balance = balances[self.peerId] else { return } self.updateState(StarsContext.State(flags: [], balance: balance, subscriptions: state.subscriptions, canLoadMoreSubscriptions: state.canLoadMoreSubscriptions, transactions: state.transactions, canLoadMoreTransactions: state.canLoadMoreTransactions, isLoading: false)) @@ -619,7 +619,7 @@ private final class StarsContextImpl { var transactions = state.transactions if addTransaction { let count = CurrencyAmount(amount: balance, currency: self.ton ? .ton : .stars) - transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: count, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, giveawayMessageId: nil, media: [], subscriptionPeriod: nil, starGift: nil, floodskipNumber: nil, starrefCommissionPermille: nil, starrefPeerId: nil, starrefAmount: nil, paidMessageCount: nil, premiumGiftMonths: nil), at: 0) + transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: count, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, giveawayMessageId: nil, media: [], subscriptionPeriod: nil, starGift: nil, floodskipNumber: nil, starrefCommissionPermille: nil, starrefPeerId: nil, starrefAmount: nil, paidMessageCount: nil, premiumGiftMonths: nil, adsProceedsFromDate: nil, adsProceedsToDate: nil), at: 0) } self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: max(StarsAmount(value: 0, nanos: 0), state.balance + balance), subscriptions: state.subscriptions, canLoadMoreSubscriptions: state.canLoadMoreSubscriptions, transactions: transactions, canLoadMoreTransactions: state.canLoadMoreTransactions, isLoading: state.isLoading)) } @@ -655,7 +655,7 @@ private final class StarsContextImpl { private extension StarsContext.State.Transaction { init?(apiTransaction: Api.StarsTransaction, peerId: EnginePeer.Id?, transaction: Transaction) { switch apiTransaction { - case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl, _, messageId, extendedMedia, subscriptionPeriod, giveawayPostId, starGift, floodskipNumber, starrefCommissionPermille, starrefPeer, starrefAmount, paidMessageCount, premiumGiftMonths): + case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl, _, messageId, extendedMedia, subscriptionPeriod, giveawayPostId, starGift, floodskipNumber, starrefCommissionPermille, starrefPeer, starrefAmount, paidMessageCount, premiumGiftMonths, adsProceedsFromDate, adsProceedsToDate): let parsedPeer: StarsContext.State.Transaction.Peer var paidMessageId: MessageId? var giveawayMessageId: MessageId? @@ -724,7 +724,7 @@ private extension StarsContext.State.Transaction { let media = extendedMedia.flatMap({ $0.compactMap { textMediaAndExpirationTimerFromApiMedia($0, PeerId(0)).media } }) ?? [] let _ = subscriptionPeriod - self.init(flags: flags, id: id, count: CurrencyAmount(apiAmount: stars), date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl, paidMessageId: paidMessageId, giveawayMessageId: giveawayMessageId, media: media, subscriptionPeriod: subscriptionPeriod, starGift: starGift.flatMap { StarGift(apiStarGift: $0) }, floodskipNumber: floodskipNumber, starrefCommissionPermille: starrefCommissionPermille, starrefPeerId: starrefPeer?.peerId, starrefAmount: starrefAmount.flatMap(StarsAmount.init(apiAmount:)), paidMessageCount: paidMessageCount, premiumGiftMonths: premiumGiftMonths) + self.init(flags: flags, id: id, count: CurrencyAmount(apiAmount: stars), date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl, paidMessageId: paidMessageId, giveawayMessageId: giveawayMessageId, media: media, subscriptionPeriod: subscriptionPeriod, starGift: starGift.flatMap { StarGift(apiStarGift: $0) }, floodskipNumber: floodskipNumber, starrefCommissionPermille: starrefCommissionPermille, starrefPeerId: starrefPeer?.peerId, starrefAmount: starrefAmount.flatMap(StarsAmount.init(apiAmount:)), paidMessageCount: paidMessageCount, premiumGiftMonths: premiumGiftMonths, adsProceedsFromDate: adsProceedsFromDate, adsProceedsToDate: adsProceedsToDate) } } } @@ -808,6 +808,8 @@ public final class StarsContext { public let starrefAmount: StarsAmount? public let paidMessageCount: Int32? public let premiumGiftMonths: Int32? + public let adsProceedsFromDate: Int32? + public let adsProceedsToDate: Int32? public init( flags: Flags, @@ -830,7 +832,9 @@ public final class StarsContext { starrefPeerId: PeerId?, starrefAmount: StarsAmount?, paidMessageCount: Int32?, - premiumGiftMonths: Int32? + premiumGiftMonths: Int32?, + adsProceedsFromDate: Int32?, + adsProceedsToDate: Int32? ) { self.flags = flags self.id = id @@ -853,6 +857,8 @@ public final class StarsContext { self.starrefAmount = starrefAmount self.paidMessageCount = paidMessageCount self.premiumGiftMonths = premiumGiftMonths + self.adsProceedsFromDate = adsProceedsFromDate + self.adsProceedsToDate = adsProceedsToDate } public static func == (lhs: Transaction, rhs: Transaction) -> Bool { @@ -919,6 +925,12 @@ public final class StarsContext { if lhs.premiumGiftMonths != rhs.premiumGiftMonths { return false } + if lhs.adsProceedsFromDate != rhs.adsProceedsFromDate { + return false + } + if lhs.adsProceedsToDate != rhs.adsProceedsToDate { + return false + } return true } } @@ -1663,23 +1675,27 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot public struct StarsTransactionReference: PostboxCoding, Hashable, Equatable { public let peerId: EnginePeer.Id + public let ton: Bool public let id: String public let isRefund: Bool - public init(peerId: EnginePeer.Id, id: String, isRefund: Bool) { + public init(peerId: EnginePeer.Id, ton: Bool, id: String, isRefund: Bool) { self.peerId = peerId + self.ton = ton self.id = id self.isRefund = isRefund } public init(decoder: PostboxDecoder) { self.peerId = EnginePeer.Id(decoder.decodeInt64ForKey("peerId", orElse: 0)) + self.ton = decoder.decodeBoolForKey("ton", orElse: false) self.id = decoder.decodeStringForKey("id", orElse: "") self.isRefund = decoder.decodeBoolForKey("refund", orElse: false) } public func encode(_ encoder: PostboxEncoder) { encoder.encodeInt64(self.peerId.toInt64(), forKey: "peerId") + encoder.encodeBool(self.ton, forKey: "ton") encoder.encodeString(self.id, forKey: "id") encoder.encodeBool(self.isRefund, forKey: "refund") } @@ -1695,6 +1711,7 @@ func _internal_getStarsTransaction(accountPeerId: PeerId, postbox: Postbox, netw } return network.request( Api.functions.payments.getStarsTransactionsByID( + flags: transactionReference.ton ? 1 << 0 : 0, peer: inputPeer, id: [.inputStarsTransaction(flags: transactionReference.isRefund ? (1 << 0) : 0, id: transactionReference.id)] ) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift index cb887658a1..262cd8a681 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift @@ -86,8 +86,8 @@ public extension TelegramEngine { return StarsContext(account: self.account, ton: true) } - public func peerStarsRevenueContext(peerId: EnginePeer.Id) -> StarsRevenueStatsContext { - return StarsRevenueStatsContext(account: self.account, peerId: peerId) + public func peerStarsRevenueContext(peerId: EnginePeer.Id, ton: Bool) -> StarsRevenueStatsContext { + return StarsRevenueStatsContext(account: self.account, peerId: peerId, ton: ton) } public func peerStarsTransactionsContext(subject: StarsTransactionsContext.Subject, mode: StarsTransactionsContext.Mode) -> StarsTransactionsContext { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 0c04c5439d..466ec24a13 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -889,21 +889,13 @@ public extension TelegramEngine { public func updatePeerStarGiftStatus(peerId: EnginePeer.Id, starGift: StarGift.UniqueGift, expirationDate: Int32?) -> Signal { return _internal_updatePeerStarGiftStatus(account: self.account, peerId: peerId, starGift: starGift, expirationDate: expirationDate) } - - public func checkChannelRevenueWithdrawalAvailability() -> Signal { - return _internal_checkChannelRevenueWithdrawalAvailability(account: self.account) - } - - public func requestChannelRevenueWithdrawalUrl(peerId: EnginePeer.Id, password: String) -> Signal { - 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 requestStarsRevenueWithdrawalUrl(peerId: EnginePeer.Id, ton: Bool, amount: Int64?, password: String) -> Signal { + return _internal_requestStarsRevenueWithdrawalUrl(account: self.account, ton: ton, peerId: peerId, amount: amount, password: password) } public func requestStarsRevenueAdsAccountlUrl(peerId: EnginePeer.Id) -> Signal { diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index 49b197b86f..fd1a7213c5 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -173,6 +173,10 @@ public enum PresentationResourceKey: Int32 { case chatBubbleTodoCheckIncomingIcon case chatBubbleTodoCheckOutgoingIcon + case chatServiceMessageTodoCompletedIcon + case chatServiceMessageTodoIncompletedIcon + case chatServiceMessageTodoAppendedIcon + case chatBubbleReplyThumbnailPlayImage case chatBubbleDeliveryFailedIcon diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift index 65f4204d5c..f61320c87b 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift @@ -1433,6 +1433,24 @@ public struct PresentationResourcesChat { }) } + public static func chatServiceMessageTodoCompletedIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatServiceMessageTodoCompletedIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/ServiceTodoCompleted"), color: .white) + }) + } + + public static func chatServiceMessageTodoIncompletedIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatServiceMessageTodoIncompletedIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/ServiceTodoIncompleted"), color: .white) + }) + } + + public static func chatServiceMessageTodoAppendedIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.chatServiceMessageTodoAppendedIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/ServiceTodoIncompleted"), color: .white) + }) + } + public static func messageButtonsPostReject(_ theme: PresentationTheme) -> UIImage? { return theme.image(PresentationResourceKey.messageButtonsPostReject.rawValue, { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/SuggestPostDecline"), color: .white) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift index c6673ec321..3eecc1b6f1 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift @@ -200,8 +200,10 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { let attributedString = attributedServiceMessageString(theme: item.presentationData.theme, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, message: item.message, messageCount: messageCount, accountPeerId: item.context.account.peerId, forForumOverview: forForumOverview) var image: TelegramMediaImage? - var story: TelegramMediaStory? var suggestedPost: TelegramMediaActionType.SuggestedPostApprovalStatus? + + var leadingIcon: UIImage? + var isStory = false for media in item.message.media { if let action = media as? TelegramMediaAction { switch action.action { @@ -209,20 +211,29 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { image = img case let .suggestedPostApprovalStatus(status): suggestedPost = status + case let .todoCompletions(completed, _): + if !completed.isEmpty { + leadingIcon = PresentationResourcesChat.chatServiceMessageTodoCompletedIcon(item.presentationData.theme.theme) + } else { + leadingIcon = PresentationResourcesChat.chatServiceMessageTodoIncompletedIcon(item.presentationData.theme.theme) + } + case .todoAppendTasks: + leadingIcon = PresentationResourcesChat.chatServiceMessageTodoAppendedIcon(item.presentationData.theme.theme) default: break } - } else if let media = media as? TelegramMediaStory { - story = media + } else if media is TelegramMediaStory { + leadingIcon = PresentationResourcesChat.chatExpiredStoryIndicatorIcon(item.presentationData.theme.theme, type: .free) + isStory = true } } let imageSize = CGSize(width: 212.0, height: 212.0) var updatedAttributedString = attributedString - if story != nil, let attributedString { + if leadingIcon != nil, let attributedString { let mutableString = NSMutableAttributedString(attributedString: attributedString) - mutableString.insert(NSAttributedString(string: " ", font: Font.regular(13.0), textColor: .clear), at: 0) + mutableString.insert(NSAttributedString(string: isStory ? " " : " ", font: Font.regular(13.0), textColor: .clear), at: 0) updatedAttributedString = mutableString } @@ -426,8 +437,8 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { } } for i in 0 ..< labelRects.count { - labelRects[i] = labelRects[i].insetBy(dx: -6.0, dy: floor((labelRects[i].height - 20.0) / 2.0)) - labelRects[i].size.height = 20.0 + labelRects[i] = labelRects[i].insetBy(dx: -6.0, dy: floor((labelRects[i].height - 22.0) / 2.0)) + labelRects[i].size.height = 22.0 labelRects[i].origin.x = floor((labelLayout.size.width - labelRects[i].width) / 2.0) } @@ -677,7 +688,7 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { } } - if story != nil { + if let leadingIcon { let leadingIconView: UIImageView if let current = strongSelf.leadingIconView { leadingIconView = current @@ -687,11 +698,15 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { strongSelf.view.addSubview(leadingIconView) } - leadingIconView.image = PresentationResourcesChat.chatExpiredStoryIndicatorIcon(item.presentationData.theme.theme, type: .free) + leadingIconView.image = leadingIcon if let lineRect = labelLayout.linesRects().first, let iconImage = leadingIconView.image { let iconSize = iconImage.size - leadingIconView.frame = CGRect(origin: CGPoint(x: lineRect.minX + labelFrame.minX - 1.0, y: labelFrame.minY), size: iconSize) + var iconFrame = CGRect(origin: CGPoint(x: lineRect.minX + labelFrame.minX - 1.0, y: labelFrame.minY), size: iconSize) + if !isStory { + iconFrame.origin.x += 3.0 + } + leadingIconView.frame = iconFrame } } else if let leadingIconView = strongSelf.leadingIconView { strongSelf.leadingIconView = nil diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index 8fe7861387..44bf777edc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -418,6 +418,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { title = item.presentationData.strings.Notification_StarsGift_Title(Int32(count)) text = incoming ? item.presentationData.strings.Notification_StarsGift_Subtitle : item.presentationData.strings.Notification_StarsGift_SubtitleYou(peerName).string case let .giftTon(currency, amount, cryptoCurrency, cryptoAmount, _): + months = 1000 + var peerName = "" if let peer = item.message.peers[item.message.id.peerId] { peerName = EnginePeer(peer).compactDisplayTitle @@ -431,6 +433,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { title = "$ \(formatTonAmountText(cryptoAmount, dateTimeFormat: item.presentationData.dateTimeFormat))" text = incoming ? "Use TON to submit post suggestions to channels." : "With TON, \(peerName) will be able to submit post suggestions to channels." + buttonTitle = "" case let .prizeStars(count, _, channelId, _, _): if count <= 1000 { months = 3 @@ -640,6 +643,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { } switch months { + case 1000: + animationName = "GiftDiamond" case 12: animationName = "Gift12" case 6: diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift index 8ca3596d8b..3cd40d5a24 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageTodoBubbleContentNode/Sources/ChatMessageTodoBubbleContentNode.swift @@ -375,7 +375,10 @@ private func generatePercentageAnimationImages(presentationData: ChatPresentatio private final class ChatMessageTodoItemNode: ASDisplayNode { private var backgroundWallpaperNode: ChatMessageBubbleBackdrop? private var backgroundNode: ChatMessageBackground? - private var snapshotView: UIView? + private var extractedRadioView: UIView? + private var extractedAvatarView: UIView? + private var extractedTitleNode: TextNodeWithEntities? + private var extractedNameView: UIView? fileprivate let contextSourceNode: ContextExtractedContentContainingNode fileprivate let containerNode: ASDisplayNode @@ -385,6 +388,7 @@ private final class ChatMessageTodoItemNode: ASDisplayNode { private var iconNode: ASImageNode? fileprivate var titleNode: TextNodeWithEntities? fileprivate var nameNode: TextNode? + private let buttonNode: HighlightTrackingButtonNode let separatorNode: ASDisplayNode @@ -545,16 +549,48 @@ private final class ChatMessageTodoItemNode: ASDisplayNode { // self.backgroundWallpaperNode?.update(rect: mappedRect, within: containerSize) // } - if let snapshotView = self.containerNode.view.snapshotContentTree() { - self.snapshotView = snapshotView - self.contextSourceNode.contentNode.view.addSubview(snapshotView) + if let extractedRadioView = self.radioNode?.view.snapshotContentTree() { + self.extractedRadioView = extractedRadioView + self.contextSourceNode.contentNode.view.addSubview(extractedRadioView) + } + + if let extractedAvatarView = self.avatarNode?.view.snapshotContentTree() { + self.extractedAvatarView = extractedAvatarView + self.contextSourceNode.contentNode.view.addSubview(extractedAvatarView) + } + + if let titleNode = self.titleNode, let context = self.context, let presentationData = self.presentationData { + let titleConstrainedWidth = titleNode.textNode.cachedLayout?.size.width ?? 1.0 + let makeTitleLayout = TextNodeWithEntities.asyncLayout(self.extractedTitleNode) + let (_, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: self.titleNode?.textNode.cachedLayout?.attributedString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: titleConstrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .left, cutout: nil, insets: UIEdgeInsets(top: 1.0, left: 0.0, bottom: 1.0, right: 0.0))) + let extractedTitleNode = titleApply(TextNodeWithEntities.Arguments( + context: context, + cache: context.animationCache, + renderer: context.animationRenderer, + placeholderColor: incoming ? presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor, + attemptSynchronous: true + )) + extractedTitleNode.textNode.frame = titleNode.textNode.frame + self.contextSourceNode.contentNode.addSubnode(extractedTitleNode.textNode) + self.extractedTitleNode = extractedTitleNode + } + + if let extractedNameView = self.nameNode?.view.snapshotContentTree() { + self.extractedNameView = extractedNameView + self.contextSourceNode.contentNode.view.addSubview(extractedNameView) } } else { if let backgroundNode = self.backgroundNode { self.backgroundNode = nil transition.updateAlpha(node: backgroundNode, alpha: 0.0, completion: { [weak backgroundNode] _ in - self.snapshotView?.removeFromSuperview() - self.snapshotView = nil + self.extractedRadioView?.removeFromSuperview() + self.extractedRadioView = nil + self.extractedAvatarView?.removeFromSuperview() + self.extractedAvatarView = nil + self.extractedTitleNode?.textNode.removeFromSupernode() + self.extractedTitleNode = nil + self.extractedNameView?.removeFromSuperview() + self.extractedNameView = nil backgroundNode?.removeFromSupernode() }) @@ -596,7 +632,7 @@ private final class ChatMessageTodoItemNode: ASDisplayNode { return { context, presentationData, presentationContext, message, todo, option, completion, translation, constrainedWidth in var canMark = false if (todo.flags.contains(.othersCanComplete) || message.author?.id == context.account.peerId) { - if let forwardInfo = message.forwardInfo, let authorId = forwardInfo.author?.id, authorId != context.account.peerId { + if let _ = message.forwardInfo { } else { canMark = true } @@ -725,9 +761,9 @@ private final class ChatMessageTodoItemNode: ASDisplayNode { if let (nameLayout, nameApply) = nameLayoutAndApply { var nameNodeFrame: CGRect if titleLayout.hasRTL { - nameNodeFrame = CGRect(origin: CGPoint(x: width - rightInset - nameLayout.size.width, y: 26.0), size: nameLayout.size) + nameNodeFrame = CGRect(origin: CGPoint(x: width - rightInset - nameLayout.size.width, y: titleNodeFrame.maxY - 4.0), size: nameLayout.size) } else { - nameNodeFrame = CGRect(origin: CGPoint(x: leftInset, y: 26.0), size: nameLayout.size) + nameNodeFrame = CGRect(origin: CGPoint(x: leftInset, y: titleNodeFrame.maxY - 4.0), size: nameLayout.size) } let nameNode = nameApply() if node.nameNode !== nameNode { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift index fe4168a2ef..d8774b4f45 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift @@ -385,8 +385,8 @@ final class PeerInfoScreenData { let tonState: StarsContext.State? let starsRevenueStatsState: StarsRevenueStats? let starsRevenueStatsContext: StarsRevenueStatsContext? - let revenueStatsState: RevenueStats? - let revenueStatsContext: RevenueStatsContext? + let revenueStatsState: StarsRevenueStats? + let revenueStatsContext: StarsRevenueStatsContext? let profileGiftsContext: ProfileGiftsContext? let premiumGiftOptions: [PremiumGiftCodeOption] let webAppPermissions: WebAppPermissionsState? @@ -437,8 +437,8 @@ final class PeerInfoScreenData { tonState: StarsContext.State?, starsRevenueStatsState: StarsRevenueStats?, starsRevenueStatsContext: StarsRevenueStatsContext?, - revenueStatsState: RevenueStats?, - revenueStatsContext: RevenueStatsContext?, + revenueStatsState: StarsRevenueStats?, + revenueStatsContext: StarsRevenueStatsContext?, profileGiftsContext: ProfileGiftsContext?, premiumGiftOptions: [PremiumGiftCodeOption], webAppPermissions: WebAppPermissionsState? @@ -1300,7 +1300,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen guard canViewStarsRevenue else { return .single((nil, nil)) } - let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId) + let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: false) return starsRevenueStatsContext.state |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in return (starsRevenueStatsContext, state.stats) @@ -1313,7 +1313,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.CanViewRevenue(id: peerId)) |> distinctUntilChanged ) - |> mapToSignal { peer, canViewRevenue -> Signal<(RevenueStatsContext?, RevenueStats?), NoError> in + |> mapToSignal { peer, canViewRevenue -> Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> in var canViewRevenue = canViewRevenue if let peer, case let .user(user) = peer, let _ = user.botInfo, context.sharedContext.applicationBindings.appBuildType == .internal || context.sharedContext.immediateExperimentalUISettings.devRequests { canViewRevenue = true @@ -1324,9 +1324,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen guard canViewRevenue else { return .single((nil, nil)) } - let revenueStatsContext = RevenueStatsContext(account: context.account, peerId: peerId) + let revenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: true) return revenueStatsContext.state - |> map { state -> (RevenueStatsContext?, RevenueStats?) in + |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in return (revenueStatsContext, state.stats) } } @@ -1572,7 +1572,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen guard canViewStarsRevenue else { return .single((nil, nil)) } - let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId) + let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: false) return starsRevenueStatsContext.state |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in return (starsRevenueStatsContext, state.stats) @@ -1583,13 +1583,13 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen TelegramEngine.EngineData.Item.Peer.CanViewRevenue(id: peerId) ) |> distinctUntilChanged - |> mapToSignal { canViewRevenue -> Signal<(RevenueStatsContext?, RevenueStats?), NoError> in + |> mapToSignal { canViewRevenue -> Signal<(StarsRevenueStatsContext?, StarsRevenueStats?), NoError> in guard canViewRevenue else { return .single((nil, nil)) } - let revenueStatsContext = RevenueStatsContext(account: context.account, peerId: peerId) + let revenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: true) return revenueStatsContext.state - |> map { state -> (RevenueStatsContext?, RevenueStats?) in + |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in return (revenueStatsContext, state.stats) } } @@ -1911,7 +1911,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen guard canViewStarsRevenue else { return .single((nil, nil)) } - let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId) + let starsRevenueStatsContext = StarsRevenueStatsContext(account: context.account, peerId: peerId, ton: false) return starsRevenueStatsContext.state |> map { state -> (StarsRevenueStatsContext?, StarsRevenueStats?) in return (starsRevenueStatsContext, state.stats) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 0ade9c5412..51bfcc130d 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1597,11 +1597,11 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese })) } - let revenueBalance = data.revenueStatsState?.balances.currentBalance ?? 0 - let overallRevenueBalance = data.revenueStatsState?.balances.overallRevenue ?? 0 + let revenueBalance = data.revenueStatsState?.balances.currentBalance.amount.value ?? 0 + let overallRevenueBalance = data.revenueStatsState?.balances.overallRevenue.amount.value ?? 0 - let starsBalance = data.starsRevenueStatsState?.balances.currentBalance ?? StarsAmount.zero - let overallStarsBalance = data.starsRevenueStatsState?.balances.overallRevenue ?? StarsAmount.zero + let starsBalance = data.starsRevenueStatsState?.balances.currentBalance.amount ?? StarsAmount.zero + let overallStarsBalance = data.starsRevenueStatsState?.balances.overallRevenue.amount ?? StarsAmount.zero if overallRevenueBalance > 0 || overallStarsBalance > StarsAmount.zero { items[.balances]!.append(PeerInfoScreenHeaderItem(id: 20, text: presentationData.strings.PeerInfo_BotBalance_Title)) @@ -1907,11 +1907,11 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese section = .peerMembers } if cachedData.flags.contains(.canViewRevenue) || cachedData.flags.contains(.canViewStarsRevenue) { - let revenueBalance = data.revenueStatsState?.balances.currentBalance ?? 0 - let starsBalance = data.starsRevenueStatsState?.balances.currentBalance ?? StarsAmount.zero + let revenueBalance = data.revenueStatsState?.balances.currentBalance.amount.value ?? 0 + let starsBalance = data.starsRevenueStatsState?.balances.currentBalance.amount ?? StarsAmount.zero - let overallRevenueBalance = data.revenueStatsState?.balances.overallRevenue ?? 0 - let overallStarsBalance = data.starsRevenueStatsState?.balances.overallRevenue ?? StarsAmount.zero + let overallRevenueBalance = data.revenueStatsState?.balances.overallRevenue.amount.value ?? 0 + let overallStarsBalance = data.starsRevenueStatsState?.balances.overallRevenue.amount ?? StarsAmount.zero if overallRevenueBalance > 0 || overallStarsBalance > StarsAmount.zero { let smallLabelFont = Font.regular(floor(presentationData.listsFontSize.itemListBaseFontSize / 17.0 * 13.0)) diff --git a/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/BUILD b/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/BUILD index 567ee0e5c9..540c6c2ba6 100644 --- a/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/BUILD +++ b/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/BUILD @@ -62,6 +62,7 @@ swift_library( "//submodules/AppBundle", "//submodules/GZip", "//submodules/LegacyComponents", + "//submodules/TelegramPresentationData", "//submodules/Components/MultilineTextComponent:MultilineTextComponent", "//submodules/TelegramUI/Components/Premium/PremiumStarComponent", "//submodules/TelegramUI/Components/Utils/AnimatableProperty", diff --git a/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/Sources/PremiumDiamondComponent.swift b/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/Sources/PremiumDiamondComponent.swift index 3a62fc5987..ffa39db961 100644 --- a/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/Sources/PremiumDiamondComponent.swift +++ b/submodules/TelegramUI/Components/Premium/PremiumDiamondComponent/Sources/PremiumDiamondComponent.swift @@ -8,6 +8,7 @@ import GZip import AppBundle import LegacyComponents import PremiumStarComponent +import TelegramPresentationData private let sceneVersion: Int = 5 @@ -20,11 +21,14 @@ private func rad2deg(_ number: Float) -> Float { } public final class PremiumDiamondComponent: Component { - public init() { + let theme: PresentationTheme + + public init(theme: PresentationTheme) { + self.theme = theme } public static func ==(lhs: PremiumDiamondComponent, rhs: PremiumDiamondComponent) -> Bool { - return true + return lhs.theme === rhs.theme } public final class View: UIView, SCNSceneRendererDelegate, ComponentTaggedView { @@ -88,14 +92,47 @@ public final class PremiumDiamondComponent: Component { } private func setup() { - guard let scene = loadCompressedScene(name: "diamond", version: sceneVersion) else { + guard let scene = loadCompressedScene(name: "gift2", version: sceneVersion) else { return } self.sceneView.scene = scene self.sceneView.delegate = self - let _ = self.sceneView.snapshot() + let names: [String] = [ + "particles_left", + "particles_right", + "particles_left_bottom", + "particles_right_bottom", + "particles_center" + ] + + let particleColor = UIColor(rgb: 0x428df4) //0x3b9bff) + for name in names { + if let node = scene.rootNode.childNode(withName: name, recursively: false), let particleSystem = node.particleSystems?.first { + particleSystem.particleIntensity = min(1.0, 2.0 * particleSystem.particleIntensity) + particleSystem.particleIntensityVariation = 0.05 + particleSystem.particleColor = particleColor + particleSystem.particleColorVariation = SCNVector4Make(0.0, 0.0, 0.1, 0.0) + + if let propertyControllers = particleSystem.propertyControllers, let sizeController = propertyControllers[.size], let colorController = propertyControllers[.color] { + let animation = CAKeyframeAnimation() + if let existing = colorController.animation as? CAKeyframeAnimation { + animation.keyTimes = existing.keyTimes + animation.values = existing.values?.compactMap { ($0 as? UIColor)?.alpha } ?? [] + } else { + animation.values = [ 0.0, 1.0, 1.0, 0.0 ] + } + let opacityController = SCNParticlePropertyController(animation: animation) + particleSystem.propertyControllers = [ + .size: sizeController, + .opacity: opacityController + ] + } + } + } + + //let _ = self.sceneView.snapshot() } private var didSetReady = false @@ -214,6 +251,8 @@ public final class PremiumDiamondComponent: Component { func update(component: PremiumDiamondComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize { self.component = component + self.sceneView.backgroundColor = component.theme.list.blocksBackgroundColor + self.sceneView.bounds = CGRect(origin: .zero, size: CGSize(width: availableSize.width * 2.0, height: availableSize.height * 2.0)) self.sceneView.center = CGPoint(x: availableSize.width / 2.0, y: availableSize.height / 2.0) diff --git a/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift b/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift index ca67a9589a..d0a78d1da8 100644 --- a/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift +++ b/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift @@ -158,22 +158,7 @@ public final class GiftAvatarComponent: Component { self.sceneView.scene = scene self.sceneView.delegate = self - if let color = self.component?.color { -// let names: [String] = [ -// "particles_left", -// "particles_right", -// "particles_left_bottom", -// "particles_right_bottom", -// "particles_center" -// ] -// -// for name in names { -// if let node = scene.rootNode.childNode(withName: name, recursively: false), let particleSystem = node.particleSystems?.first { -// particleSystem.particleColor = color -// particleSystem.particleColorVariation = SCNVector4Make(0, 0, 0, 0) -// } -// } - + if let color = self.component?.color { let names: [String] = [ "particles_left", "particles_right", diff --git a/submodules/TelegramUI/Components/Settings/LanguageSelectionScreen/Sources/LanguageSelectionScreenNode.swift b/submodules/TelegramUI/Components/Settings/LanguageSelectionScreen/Sources/LanguageSelectionScreenNode.swift index cd14148e2e..5cf8f19747 100644 --- a/submodules/TelegramUI/Components/Settings/LanguageSelectionScreen/Sources/LanguageSelectionScreenNode.swift +++ b/submodules/TelegramUI/Components/Settings/LanguageSelectionScreen/Sources/LanguageSelectionScreenNode.swift @@ -347,7 +347,7 @@ final class LanguageSelectionScreenNode: ViewControllerTracingNode { let openSearch: () -> Void = { requestActivateSearch() } - + let previousState = Atomic(value: nil) let previousEntriesHolder = Atomic<([LanguageListEntry], PresentationTheme, PresentationStrings)?>(value: nil) self.listDisposable = combineLatest( @@ -360,7 +360,7 @@ final class LanguageSelectionScreenNode: ViewControllerTracingNode { guard let strongSelf = self else { return } - + var entries: [LanguageListEntry] = [] var existingIds = Set() diff --git a/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift b/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift index 197912cf55..4eb482d0a8 100644 --- a/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift @@ -103,12 +103,12 @@ public final class StarsBalanceOverlayComponent: Component { }) } } else { - let starsRevenueStatsContext = StarsRevenueStatsContext(account: component.context.account, peerId: component.peerId) + let starsRevenueStatsContext = StarsRevenueStatsContext(account: component.context.account, peerId: component.peerId, ton: false) self.starsRevenueStatsContext = starsRevenueStatsContext self.balanceDisposable = (starsRevenueStatsContext.state |> map { state -> Int64 in - return state.stats?.balances.currentBalance.value ?? 0 + return state.stats?.balances.currentBalance.amount.value ?? 0 } |> distinctUntilChanged |> deliverOnMainQueue).start(next: { [weak self] balance in diff --git a/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift b/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift index 36380871b8..01e9437a83 100644 --- a/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift @@ -851,7 +851,7 @@ public final class StarsImageComponent: Component { if let current = self.animationNode { animationNode = current } else { - let stickerName: String = "Gift\(count)" + let stickerName: String = count == 1000 ? "GiftDiamond" : "Gift\(count)" animationNode = DefaultAnimatedStickerNodeImpl() animationNode.autoplay = true animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: stickerName), width: 384, height: 384, playbackMode: .still(.end), mode: .direct(cachePathPrefix: nil)) diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift index 55867970ea..dbab78d84a 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift @@ -416,8 +416,15 @@ private final class StarsTransactionSheetContent: CombinedComponent { isSubscriptionFee = true } else if transaction.flags.contains(.isGift) { titleText = strings.Stars_Gift_Received_Title - descriptionText = strings.Stars_Gift_Received_Text count = transaction.count + + //TODO:localize + if count.currency == .ton { + descriptionText = "Use TON to submit post suggestions to channels on Telegram." + } else { + descriptionText = strings.Stars_Gift_Received_Text + } + countOnTop = true transactionId = transaction.id date = transaction.date @@ -552,7 +559,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { toPeer = peer } transactionPeer = transaction.peer - media = transaction.media.map { AnyMediaReference.starsTransaction(transaction: StarsTransactionReference(peerId: parentPeer.id, id: transaction.id, isRefund: transaction.flags.contains(.isRefund)), media: $0) } + media = transaction.media.map { AnyMediaReference.starsTransaction(transaction: StarsTransactionReference(peerId: parentPeer.id, ton: false, id: transaction.id, isRefund: transaction.flags.contains(.isRefund)), media: $0) } photo = transaction.photo if transaction.flags.contains(.isRefund) { @@ -706,6 +713,10 @@ private final class StarsTransactionSheetContent: CombinedComponent { transition: .immediate ) + if count.currency == .ton { + premiumGiftMonths = 1000 + } + let imageSubject: StarsImageComponent.Subject var imageIcon: StarsImageComponent.Icon? if let premiumGiftMonths { @@ -732,9 +743,9 @@ private final class StarsTransactionSheetContent: CombinedComponent { imageSubject = .none } if isSubscription || isSubscriber || isSubscriptionFee || giveawayMessageId != nil { - imageIcon = count.currency == .ton ? .ton : .star + imageIcon = count.currency == .ton ? nil : .star } else { - imageIcon = count.currency == .ton ? .ton : nil + imageIcon = nil } if isSubscription && "".isEmpty { diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift index 1c16a1db28..49ef7dc8c0 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsStatisticsScreen.swift @@ -522,21 +522,21 @@ final class StarsStatisticsScreenComponent: Component { theme: environment.theme, dateTimeFormat: environment.dateTimeFormat, title: strings.Stars_BotRevenue_Proceeds_Available, - value: starsState?.balances.availableBalance ?? StarsAmount.zero, + value: starsState?.balances.availableBalance.amount ?? StarsAmount.zero, rate: starsState?.usdRate ?? 0.0 ))), AnyComponentWithIdentity(id: 1, component: AnyComponent(StarsOverviewItemComponent( theme: environment.theme, dateTimeFormat: environment.dateTimeFormat, title: strings.Stars_BotRevenue_Proceeds_Current, - value: starsState?.balances.currentBalance ?? StarsAmount.zero, + value: starsState?.balances.currentBalance.amount ?? StarsAmount.zero, rate: starsState?.usdRate ?? 0.0 ))), AnyComponentWithIdentity(id: 2, component: AnyComponent(StarsOverviewItemComponent( theme: environment.theme, dateTimeFormat: environment.dateTimeFormat, title: strings.Stars_BotRevenue_Proceeds_Total, - value: starsState?.balances.overallRevenue ?? StarsAmount.zero, + value: starsState?.balances.overallRevenue.amount ?? StarsAmount.zero, rate: starsState?.usdRate ?? 0.0 ))) ], @@ -579,7 +579,7 @@ final class StarsStatisticsScreenComponent: Component { theme: environment.theme, strings: strings, dateTimeFormat: environment.dateTimeFormat, - count: self.starsState?.balances.availableBalance ?? StarsAmount.zero, + count: self.starsState?.balances.availableBalance.amount ?? StarsAmount.zero, currency: .stars, rate: self.starsState?.usdRate ?? 0, actionTitle: strings.Stars_Intro_BuyShort, @@ -623,7 +623,7 @@ final class StarsStatisticsScreenComponent: Component { theme: environment.theme, strings: strings, dateTimeFormat: environment.dateTimeFormat, - count: self.starsState?.balances.availableBalance ?? StarsAmount.zero, + count: self.starsState?.balances.availableBalance.amount ?? StarsAmount.zero, currency: .stars, rate: self.starsState?.usdRate ?? 0, actionTitle: strings.Stars_BotRevenue_Withdraw_WithdrawShort, diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift index 6f2f6d2faf..539c5481e3 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift @@ -501,7 +501,7 @@ final class StarsTransactionsScreenComponent: Component { let headerComponent: AnyComponent if component.starsContext.ton { - headerComponent = AnyComponent(PremiumDiamondComponent()) + headerComponent = AnyComponent(PremiumDiamondComponent(theme: environment.theme)) } else { headerComponent = AnyComponent(PremiumStarComponent( theme: environment.theme, @@ -667,9 +667,8 @@ final class StarsTransactionsScreenComponent: Component { contentHeight += descriptionSize.height contentHeight += 29.0 - let withdrawAvailable = component.starsContext.ton ? (self.starsState?.balance.value ?? 0) > 0 : (self.revenueState?.balances.overallRevenue.value ?? 0) > 0 + let withdrawAvailable = (self.revenueState?.balances.overallRevenue.amount.value ?? 0) > 0 - //TODO:localize let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 }) let balanceSize = self.balanceView.update( transition: .immediate, @@ -685,8 +684,8 @@ final class StarsTransactionsScreenComponent: Component { count: self.starsState?.balance ?? StarsAmount.zero, currency: component.starsContext.ton ? .ton : .stars, rate: nil, - actionTitle: component.starsContext.ton ? "Withdraw via Fragment" : (withdrawAvailable ? environment.strings.Stars_Intro_BuyShort : environment.strings.Stars_Intro_Buy), - actionAvailable: (component.starsContext.ton && withdrawAvailable) || (!premiumConfiguration.areStarsDisabled && !premiumConfiguration.isPremiumDisabled), + actionTitle: (withdrawAvailable ? environment.strings.Stars_Intro_BuyShort : environment.strings.Stars_Intro_Buy), + actionAvailable: (!component.starsContext.ton && !premiumConfiguration.areStarsDisabled && !premiumConfiguration.isPremiumDisabled), actionIsEnabled: true, actionIcon: component.starsContext.ton ? nil : PresentationResourcesItemList.itemListRoundTopupIcon(environment.theme), action: { [weak self] in @@ -1139,7 +1138,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer { self.context = context self.starsContext = starsContext - self.starsRevenueStatsContext = context.engine.payments.peerStarsRevenueContext(peerId: context.account.peerId) + self.starsRevenueStatsContext = context.engine.payments.peerStarsRevenueContext(peerId: context.account.peerId, ton: false) if !starsContext.ton { self.subscriptionsContext = context.engine.payments.peerStarsSubscriptionsContext(starsContext: starsContext) } else { diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsRevenueWithdrawalController.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsRevenueWithdrawalController.swift index 4f52ba6b87..cc62907d39 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsRevenueWithdrawalController.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsRevenueWithdrawalController.swift @@ -46,7 +46,7 @@ public func confirmStarsRevenueWithdrawalController(context: AccountContext, upd } contentNode.updateIsChecking(true) - let signal = context.engine.peers.requestStarsRevenueWithdrawalUrl(peerId: peerId, amount: amount, password: contentNode.password) + let signal = context.engine.peers.requestStarsRevenueWithdrawalUrl(peerId: peerId, ton: false, amount: amount, password: contentNode.password) disposable.set((signal |> deliverOnMainQueue).start(next: { url in dismissImpl?() completion(url) diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index 5f6153be25..540792b660 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -162,7 +162,7 @@ private final class SheetContent: CombinedComponent { amountPlaceholder = environment.strings.Stars_Withdraw_AmountPlaceholder minAmount = withdrawConfiguration.minWithdrawAmount.flatMap { StarsAmount(value: $0, nanos: 0) } - maxAmount = status.balances.availableBalance + maxAmount = status.balances.availableBalance.amount case .accountWithdraw: titleString = environment.strings.Stars_Withdraw_Title amountTitle = environment.strings.Stars_Withdraw_AmountTitle @@ -241,7 +241,7 @@ private final class SheetContent: CombinedComponent { } else if case .reaction = component.mode { balance = state.starsBalance } else if case let .withdraw(starsState, _) = component.mode { - balance = starsState.balances.availableBalance + balance = starsState.balances.availableBalance.amount } else { balance = nil } @@ -785,7 +785,7 @@ private final class SheetContent: CombinedComponent { var currency: CurrencyAmount.Currency = .stars switch mode { case let .withdraw(stats, _): - amount = StarsAmount(value: stats.balances.availableBalance.value, nanos: 0) + amount = StarsAmount(value: stats.balances.availableBalance.amount.value, nanos: 0) case .accountWithdraw: amount = context.starsContext?.currentState.flatMap { StarsAmount(value: $0.balance.value, nanos: 0) } case let .paidMedia(initialValue, _): diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoAppended.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoAppended.imageset/Contents.json new file mode 100644 index 0000000000..dd0e81618e --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoAppended.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "sistemplus_16.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoAppended.imageset/sistemplus_16.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoAppended.imageset/sistemplus_16.pdf new file mode 100644 index 0000000000000000000000000000000000000000..410c86c7dbe3e31ab4e538444f685d0403546593 GIT binary patch literal 3924 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 Y?;mq5$`kja5;AaE8Su%I>INGB2T%aSr2qf` literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoCompleted.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoCompleted.imageset/Contents.json new file mode 100644 index 0000000000..7a7eabb25d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoCompleted.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "sistemdone_16.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoCompleted.imageset/sistemdone_16.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoCompleted.imageset/sistemdone_16.pdf new file mode 100644 index 0000000000000000000000000000000000000000..13d65863ca840403af781bb04eda94bd9d86e8b8 GIT binary patch literal 3996 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 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoIncompleted.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoIncompleted.imageset/Contents.json new file mode 100644 index 0000000000..33a80c1c9a --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoIncompleted.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "sistemundone_16.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoIncompleted.imageset/sistemundone_16.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Message/ServiceTodoIncompleted.imageset/sistemundone_16.pdf new file mode 100644 index 0000000000000000000000000000000000000000..86308a8fa10a36beee3fd10f43525a6353f938be GIT binary patch literal 3935 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 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Perk/Todo.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Premium/Perk/Todo.imageset/Contents.json new file mode 100644 index 0000000000..2f8a451be0 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Premium/Perk/Todo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "checks.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Perk/Todo.imageset/checks.pdf b/submodules/TelegramUI/Images.xcassets/Premium/Perk/Todo.imageset/checks.pdf new file mode 100644 index 0000000000000000000000000000000000000000..eded18842e33e12814db81888f6b6b14117ddff7 GIT binary patch literal 11545 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 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index 5109478202..5863cbb9d1 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -611,15 +611,9 @@ extension ChatControllerImpl { } if #available(iOS 18.0, *) { - if self.context.sharedContext.immediateExperimentalUISettings.enableLocalTranslation { - if engineExperimentalInternalTranslationService == nil, let hostView = self.context.sharedContext.mainWindow?.hostView { - let translationService = ExperimentalInternalTranslationServiceImpl(view: hostView.containerView) - engineExperimentalInternalTranslationService = translationService - } - } else { - if engineExperimentalInternalTranslationService != nil { - engineExperimentalInternalTranslationService = nil - } + if engineExperimentalInternalTranslationService == nil, let hostView = self.context.sharedContext.mainWindow?.hostView { + let translationService = ExperimentalInternalTranslationServiceImpl(view: hostView.containerView) + engineExperimentalInternalTranslationService = translationService } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 5183326007..d9d294768d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3582,15 +3582,23 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let _ = ApplicationSpecificNotice.incrementTranslationSuggestion(accountManager: context.sharedContext.accountManager, timestamp: Int32(Date().timeIntervalSince1970)).startStandalone() - let controller = TranslateScreen(context: context, text: text.string, canCopy: canCopy, fromLanguage: language, ignoredLanguages: translationSettings.ignoredLanguages) - controller.pushController = { [weak self] c in - self?.effectiveNavigationController?._keepModalDismissProgress = true - self?.push(c) - } - controller.presentController = { [weak self] c in - self?.present(c, in: .window(.root)) - } - strongSelf.present(controller, in: .window(.root)) + presentTranslateScreen( + context: context, + text: text.string, + canCopy: canCopy, + fromLanguage: language, + ignoredLanguages: translationSettings.ignoredLanguages, + pushController: { [weak self] c in + self?.effectiveNavigationController?._keepModalDismissProgress = true + self?.push(c) + }, + presentController: { [weak self] c in + self?.present(c, in: .window(.root)) + }, + display: { [weak self] c in + self?.present(c, in: .window(.root)) + } + ) }) } if let currentContextController = strongSelf.currentContextController { diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 4c7b67c473..f24d0624f1 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -98,6 +98,21 @@ func openResolvedUrlImpl( case let .botStart(peer, payload): openPeer(EnginePeer(peer), .withBotStartPayload(ChatControllerInitialBotStart(payload: payload, behavior: .interactive))) case let .groupBotStart(botPeerId, payload, adminRights, peerType): + let defaultAdminRights = Promise<(group: TelegramChatAdminRights?, channel: TelegramChatAdminRights?)?>(nil) + if adminRights == nil { + defaultAdminRights.set( + context.engine.peers.fetchAndUpdateCachedPeerData(peerId: botPeerId) + |> mapToSignal { _ in + return context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.BotGroupAdminRights(id: botPeerId), + TelegramEngine.EngineData.Item.Peer.BotChannelAdminRights(id: botPeerId) + ) |> map { groupRights, channelRights in + return (groupRights, channelRights) + } + } + ) + } + var filter: ChatListNodePeersFilter = [.onlyGroupsAndChannels, .onlyManageable, .excludeDisabled, .excludeRecent, .doNotSearchMessages] var title: String = presentationData.strings.Bot_AddToChat_Title switch peerType { @@ -179,11 +194,20 @@ func openResolvedUrlImpl( } if case let .channel(peer) = peer { + var isGroup = false + if case .group = peer.info { + isGroup = true + } if peer.flags.contains(.isCreator) || peer.adminRights?.rights.contains(.canAddAdmins) == true { - let controller = channelAdminController(context: context, peerId: peerId, adminId: botPeerId, initialParticipant: nil, invite: true, initialAdminRights: adminRights?.chatAdminRights, updated: { _ in - controller?.dismiss() - }, upgradedToSupergroup: { _, _ in }, transferedOwnership: { _ in }) - navigationController?.pushViewController(controller) + let _ = (defaultAdminRights.get() + |> take(1) + |> deliverOnMainQueue).start(next: { defaultAdminRights in + let initialAdminRights = adminRights?.chatAdminRights ?? (isGroup ? defaultAdminRights?.group?.rights : defaultAdminRights?.channel?.rights) + let controller = channelAdminController(context: context, peerId: peerId, adminId: botPeerId, initialParticipant: nil, invite: true, initialAdminRights: initialAdminRights, updated: { _ in + controller?.dismiss() + }, upgradedToSupergroup: { _, _ in }, transferedOwnership: { _ in }) + navigationController?.pushViewController(controller) + }) } else { addMemberImpl() } @@ -191,10 +215,15 @@ func openResolvedUrlImpl( if case .member = peer.role { addMemberImpl() } else { - let controller = channelAdminController(context: context, peerId: peerId, adminId: botPeerId, initialParticipant: nil, invite: true, initialAdminRights: adminRights?.chatAdminRights, updated: { _ in - controller?.dismiss() - }, upgradedToSupergroup: { _, _ in }, transferedOwnership: { _ in }) - navigationController?.pushViewController(controller) + let _ = (defaultAdminRights.get() + |> take(1) + |> deliverOnMainQueue).start(next: { defaultAdminRights in + let initialAdminRights = adminRights?.chatAdminRights ?? defaultAdminRights?.group?.rights + let controller = channelAdminController(context: context, peerId: peerId, adminId: botPeerId, initialParticipant: nil, invite: true, initialAdminRights: initialAdminRights, updated: { _ in + controller?.dismiss() + }, upgradedToSupergroup: { _, _ in }, transferedOwnership: { _ in }) + navigationController?.pushViewController(controller) + }) } } } diff --git a/submodules/TranslateUI/Sources/ChatTranslation.swift b/submodules/TranslateUI/Sources/ChatTranslation.swift index 98b317cd03..bef45d63c7 100644 --- a/submodules/TranslateUI/Sources/ChatTranslation.swift +++ b/submodules/TranslateUI/Sources/ChatTranslation.swift @@ -180,7 +180,8 @@ public func translateMessageIds(context: AccountContext, messageIds: [EngineMess } } } - return context.engine.messages.translateMessages(messageIds: messageIdsToTranslate, fromLang: fromLang, toLang: toLang, enableLocalIfPossible: context.sharedContext.immediateExperimentalUISettings.enableLocalTranslation) + + return context.engine.messages.translateMessages(messageIds: messageIdsToTranslate, fromLang: fromLang, toLang: toLang, enableLocalIfPossible: true) //context.sharedContext.immediateExperimentalUISettings.enableLocalTranslation) |> `catch` { _ -> Signal in return .complete() } diff --git a/submodules/TranslateUI/Sources/Translate.swift b/submodules/TranslateUI/Sources/Translate.swift index 4d48f66e10..9c9d211952 100644 --- a/submodules/TranslateUI/Sources/Translate.swift +++ b/submodules/TranslateUI/Sources/Translate.swift @@ -176,6 +176,21 @@ public func canTranslateText(context: AccountContext, text: String, showTranslat return (false, nil) } + let translationConfiguration = TranslationConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) + var translateButtonAvailable = false + switch translationConfiguration.manual { + case .enabled, .alternative: + translateButtonAvailable = true + case .system: + if #available(iOS 18.0, *) { + translateButtonAvailable = true + } + default: + break + } + + let showTranslate = showTranslate && translateButtonAvailable + if #available(iOS 12.0, *) { if context.sharedContext.immediateExperimentalUISettings.disableLanguageRecognition { return (true, nil) @@ -403,3 +418,121 @@ public final class ExperimentalInternalTranslationServiceImpl: ExperimentalInter } } } + +func alternativeTranslateText(text: String, fromLang: String?, toLang: String) -> Signal<(String, [MessageTextEntity])?, TelegramCore.TranslationError> { + return Signal { subscriber in + var task: URLSessionTask? + Queue.concurrentDefaultQueue().async { + let effectiveFromLang: String + if let fromLang { + effectiveFromLang = fromLang + } else { + languageRecognizer.processString(text) + let hypotheses = languageRecognizer.languageHypotheses(withMaximum: 3) + languageRecognizer.reset() + + let filteredLanguages = hypotheses.filter { supportedTranslationLanguages.contains(normalizeTranslationLanguage($0.key.rawValue)) }.sorted(by: { $0.value > $1.value }) + if let language = filteredLanguages.first { + let languageCode = normalizeTranslationLanguage(language.key.rawValue) + effectiveFromLang = languageCode + } else { + effectiveFromLang = "en" + } + } + + var uri = "https://translate.goo" + uri += "gleapis.com/transl" + uri += "ate_a" + uri += "/singl" + uri += "e?client=gtx&sl=\(effectiveFromLang.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" + uri += "&tl=\(toLang.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")" + uri += "&dt=t&ie=UTF-8&oe=UTF-8&otf=1&ssel=0&tsel=0&kc=7&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&q=" + uri += text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + + guard let url = URL(string: uri) else { + subscriber.putError(.generic) + return + } + + var request = URLRequest(url: url) + request.httpMethod = "GET" + request.setValue(getRandomUserAgent(), forHTTPHeaderField: "User-Agent") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + task = URLSession.shared.dataTask(with: request) { data, response, error in + if let error = error { + print("Translation failed: \(error.localizedDescription)") + subscriber.putError(.generic) + return + } + + guard let httpResponse = response as? HTTPURLResponse else { + subscriber.putError(.generic) + return + } + + if httpResponse.statusCode != 200 { + print("Translation failed with status code: \(httpResponse.statusCode)") + let isRateLimit = httpResponse.statusCode == 429 + subscriber.putError(isRateLimit ? .limitExceeded : .generic) + return + } + + guard let data = data else { + subscriber.putError(.generic) + return + } + + do { + guard let jsonArray = try JSONSerialization.jsonObject(with: data) as? [Any] else { + subscriber.putError(.generic) + return + } + + guard let translationArray = jsonArray.first as? [Any] else { + subscriber.putError(.generic) + return + } + +// var sourceLanguage: String? = nil +// if jsonArray.count > 2, let lang = jsonArray[2] as? String { +// sourceLanguage = lang.contains("-") ? String(lang.prefix(while: { $0 != "-" })) : lang +// } + + var result = "" + for element in translationArray { + if let translationBlock = element as? [Any], + translationBlock.count > 0, + let blockText = translationBlock[0] as? String, + blockText != "null" && !blockText.isEmpty { + result += blockText + } + } + + if text.hasPrefix("\n") { + result = "\n" + result + } + + subscriber.putNext((result, [])) + subscriber.putCompletion() + } catch { + print("JSON parsing error: \(error)") + subscriber.putError(.generic) + } + } + task?.resume() + } + return ActionDisposable { + task?.cancel() + } + } +} + +func getRandomUserAgent() -> String { + let userAgents = [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15", + "Mozilla/5.0 (iPhone; CPU iPhone OS 18_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Mobile/15E148 Safari/604.1" + ] + return userAgents.randomElement() ?? userAgents[0] +} diff --git a/submodules/TranslateUI/Sources/TranslateScreen.swift b/submodules/TranslateUI/Sources/TranslateScreen.swift index 5ed5c5c428..d246a19ad3 100644 --- a/submodules/TranslateUI/Sources/TranslateScreen.swift +++ b/submodules/TranslateUI/Sources/TranslateScreen.swift @@ -14,6 +14,7 @@ import MultilineTextComponent import MultilineTextWithEntitiesComponent import BundleIconComponent import UndoUI +import SwiftUI private func generateExpandBackground(size: CGSize, color: UIColor) -> UIImage { return generateImage(size, rotatedContext: { size, context in @@ -94,6 +95,8 @@ private final class TranslateScreenComponent: CombinedComponent { fileprivate var moreBackgroundImage: (CGSize, UIImage, UIColor)? + private let useAlternativeTranslation: Bool + init(context: AccountContext, fromLanguage: String?, text: String, toLanguage: String, expand: @escaping () -> Void) { self.context = context self.text = text @@ -102,9 +105,19 @@ private final class TranslateScreenComponent: CombinedComponent { self.expand = expand self.availableSpeakLanguages = supportedSpeakLanguages() + let translationConfiguration = TranslationConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) + var useAlternativeTranslation = false + switch translationConfiguration.manual { + case .alternative: + useAlternativeTranslation = true + default: + break + } + self.useAlternativeTranslation = useAlternativeTranslation + super.init() - self.translationDisposable.set((context.engine.messages.translate(text: text, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in + self.translationDisposable.set((self.translate(text: text, fromLang: fromLanguage, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in guard let strongSelf = self else { return } @@ -120,6 +133,14 @@ private final class TranslateScreenComponent: CombinedComponent { self.translationDisposable.dispose() } + func translate(text: String, fromLang: String?, toLang: String) -> Signal<(String, [MessageTextEntity])?, TranslationError> { + if self.useAlternativeTranslation { + return alternativeTranslateText(text: text, fromLang: fromLang, toLang: toLang) + } else { + return self.context.engine.messages.translate(text: text, toLang: toLang) + } + } + func changeLanguage(fromLanguage: String, toLanguage: String) { guard self.fromLanguage != fromLanguage || self.toLanguage != toLanguage else { return @@ -129,7 +150,7 @@ private final class TranslateScreenComponent: CombinedComponent { self.translatedText = nil self.updated(transition: .immediate) - self.translationDisposable.set((self.context.engine.messages.translate(text: text, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in + self.translationDisposable.set((self.translate(text: text, fromLang: fromLanguage, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in guard let strongSelf = self else { return } @@ -1163,3 +1184,85 @@ public class TranslateScreen: ViewController { self.node.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: ComponentTransition(transition)) } } + +public func presentTranslateScreen( + context: AccountContext, + text: String, + entities: [MessageTextEntity] = [], + canCopy: Bool, + fromLanguage: String?, + toLanguage: String? = nil, + isExpanded: Bool = false, + ignoredLanguages: [String]? = nil, + pushController: @escaping (ViewController) -> Void = { _ in }, + presentController: @escaping (ViewController) -> Void = { _ in }, + wasDismissed: (() -> Void)? = nil, + display: (ViewController) -> Void +) { + let translationConfiguration = TranslationConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) + var useSystemTranslation = false + switch translationConfiguration.manual { + case .system: + if #available(iOS 18.0, *) { + useSystemTranslation = true + } + default: + break + } + + if useSystemTranslation { + presentSystemTranslateScreen(context: context, text: text) + } else { + let controller = TranslateScreen(context: context, text: text, canCopy: canCopy, fromLanguage: fromLanguage, toLanguage: toLanguage, isExpanded: isExpanded, ignoredLanguages: ignoredLanguages) + controller.pushController = pushController + controller.presentController = presentController + controller.wasDismissed = wasDismissed + display(controller) + } +} + +private func presentSystemTranslateScreen(context: AccountContext, text: String) { + if #available(iOS 18.0, *), let rootViewController = context.sharedContext.mainWindow?.viewController?.view.window?.rootViewController { + var dismissImpl: (() -> Void)? + let pickerView = TranslateScreenHostingView(text: text, completionHandler: { [weak rootViewController] in + DispatchQueue.main.async(execute: { + guard let presentedController = rootViewController?.presentedViewController, presentedController.isBeingDismissed == false else { return } + dismissImpl?() + }) + }) + let hostingController = UIHostingController(rootView: pickerView) + hostingController.view.isHidden = true + hostingController.modalPresentationStyle = .overCurrentContext + rootViewController.present(hostingController, animated: true) + dismissImpl = { [weak hostingController] in + Queue.mainQueue().after(0.4, { + hostingController?.dismiss(animated: false) + }) + } + } +} + +@available(iOS 18.0, *) +struct TranslateScreenHostingView: View { + @State var presented = true + var text: String + var handler: () -> Void + + init(text: String, completionHandler: @escaping () -> Void) { + self.text = text + self.handler = completionHandler + } + + var body: some View { + Spacer() + .translationPresentation( + isPresented: $presented, + text: text + ) + .onChange(of: presented) { newValue in + if newValue == false { + handler() + } + } + } +}