From d88ff3675bfe70bec5b7cc8e866b004e6abdd715 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 22 Apr 2024 20:52:54 +0400 Subject: [PATCH] Refresh channel revenue balance and transactions on update --- .../Sources/ChannelStatsController.swift | 6 +-- .../Account/AccountIntermediateState.swift | 19 +++++-- .../State/AccountStateManagementUtils.swift | 10 ++-- .../Sources/State/AccountStateManager.swift | 41 +++++++++++++++ .../Statistics/RevenueStatistics.swift | 51 +++++++++++++++---- 5 files changed, 105 insertions(+), 22 deletions(-) diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index f783de7e41..af89fcc08b 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -1579,7 +1579,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD let boostsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: false) let giftsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: true) - let revenueContext = RevenueStatsContext(postbox: context.account.postbox, network: context.account.network, peerId: peerId) + let revenueContext = RevenueStatsContext(account: context.account, peerId: peerId) let revenueState = Promise() revenueState.set(.single(nil) |> then(revenueContext.state |> map(Optional.init))) @@ -2127,11 +2127,9 @@ public func channelStatsController(context: AccountContext, updatedPresentationD |> deliverOnMainQueue).start(error: { error in let controller = revenueWithdrawalController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, initialError: error, present: { c, _ in presentImpl?(c) - }, completion: { [weak revenueContext] url in + }, completion: { url in let presentationData = context.sharedContext.currentPresentationData.with { $0 } context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {}) - - revenueContext?.reload() }) presentImpl?(controller) })) diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 79c3c4658a..b761ba9e68 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -128,6 +128,7 @@ 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(RevenueStats.Balances) } struct HoleFromPreviousState { @@ -524,7 +525,7 @@ struct AccountMutableState { mutating func updatePeersNearby(_ peersNearby: [PeerNearby]) { self.addOperation(.UpdatePeersNearby(peersNearby)) } - + mutating func updateTheme(_ theme: TelegramTheme) { self.addOperation(.UpdateTheme(theme)) } @@ -673,9 +674,13 @@ struct AccountMutableState { self.addOperation(.UpdateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date, device: device, location: location)) } + mutating func updateRevenueBalances(_ balances: RevenueStats.Balances) { + self.addOperation(.UpdateRevenueBalances(balances)) + } + mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateRevenueBalances: break case let .AddMessages(messages, location): for message in messages { @@ -819,6 +824,7 @@ struct AccountReplayedFinalState { let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] let updateConfig: Bool let isPremiumUpdated: Bool + let updatedRevenueBalances: RevenueStats.Balances? } struct AccountFinalStateEvents { @@ -845,12 +851,13 @@ struct AccountFinalStateEvents { let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] let updateConfig: Bool let isPremiumUpdated: Bool + let updatedRevenueBalances: RevenueStats.Balances? var isEmpty: Bool { - return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !isPremiumUpdated + return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedRevenueBalances == nil } - init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false) { + init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedRevenueBalances: RevenueStats.Balances? = nil) { self.addedIncomingMessageIds = addedIncomingMessageIds self.addedReactionEvents = addedReactionEvents self.wasScheduledMessageIds = wasScheduledMessageIds @@ -874,6 +881,7 @@ struct AccountFinalStateEvents { self.updatedOutgoingThreadReadStates = updatedOutgoingThreadReadStates self.updateConfig = updateConfig self.isPremiumUpdated = isPremiumUpdated + self.updatedRevenueBalances = updatedRevenueBalances } init(state: AccountReplayedFinalState) { @@ -900,6 +908,7 @@ struct AccountFinalStateEvents { self.updatedOutgoingThreadReadStates = state.updatedOutgoingThreadReadStates self.updateConfig = state.updateConfig self.isPremiumUpdated = state.isPremiumUpdated + self.updatedRevenueBalances = state.updatedRevenueBalances } func union(with other: AccountFinalStateEvents) -> AccountFinalStateEvents { @@ -929,6 +938,6 @@ struct AccountFinalStateEvents { let isPremiumUpdated = self.isPremiumUpdated || other.isPremiumUpdated - return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated) + return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: self.updatedRevenueBalances != nil ? self.updatedRevenueBalances : other.updatedRevenueBalances) } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 03bd17a51a..efc40febf2 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1777,8 +1777,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: case let .updatePeerWallpaper(_, peer, wallpaper): updatedState.updateWallpaper(peerId: peer.peerId, wallpaper: wallpaper.flatMap { TelegramWallpaper(apiWallpaper: $0) }) case let .updateBroadcastRevenueTransactions(balances): - let _ = balances - break + updatedState.updateRevenueBalances(RevenueStats.Balances(apiRevenueBalances: balances)) default: break } @@ -3270,7 +3269,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddQuickReplyMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateRevenueBalances: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -3403,6 +3402,7 @@ func replayFinalState( var deletedMessageIds: [DeletedMessageId] = [] var syncAttachMenuBots = false var updateConfig = false + var updatedRevenueBalances: RevenueStats.Balances? var holesFromPreviousStateMessageIds: [MessageId] = [] var clearHolesFromPreviousStateForChannelMessagesWithPts: [PeerIdAndMessageNamespace: Int32] = [:] @@ -4828,6 +4828,8 @@ func replayFinalState( } else { transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.NewSessionReviews, itemId: id.rawValue) } + case let .UpdateRevenueBalances(balances): + updatedRevenueBalances = balances } } @@ -5322,5 +5324,5 @@ func replayFinalState( } } - return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedReactionEvents: addedReactionEvents, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, storyUpdates: storyUpdates, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates, updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated) + return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedReactionEvents: addedReactionEvents, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, storyUpdates: storyUpdates, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates, updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: updatedRevenueBalances) } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index 1f00d155dc..b364a339f6 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -44,6 +44,10 @@ private final class UpdatedPeersNearbySubscriberContext { let subscribers = Bag<([PeerNearby]) -> Void>() } +private final class UpdatedRevenueBalancesSubscriberContext { + let subscribers = Bag<(RevenueStats.Balances) -> Void>() +} + public enum DeletedMessageId: Hashable { case global(Int32) case messageId(MessageId) @@ -277,6 +281,7 @@ public final class AccountStateManager { private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:] private var updatedPeersNearbyContext = UpdatedPeersNearbySubscriberContext() + private var updatedRevenueBalancesContext = UpdatedRevenueBalancesSubscriberContext() private let delayNotificatonsUntil = Atomic(value: nil) private let appliedMaxMessageIdPromise = Promise(nil) @@ -1022,6 +1027,9 @@ public final class AccountStateManager { if let updatedPeersNearby = events.updatedPeersNearby { strongSelf.notifyUpdatedPeersNearby(updatedPeersNearby) } + if let updatedRevenueBalances = events.updatedRevenueBalances { + strongSelf.notifyUpdatedRevenueBalances(updatedRevenueBalances) + } if !events.updatedCalls.isEmpty { for call in events.updatedCalls { strongSelf.callSessionManager?.updateSession(call, completion: { _ in }) @@ -1594,6 +1602,33 @@ public final class AccountStateManager { } } + public func updatedRevenueBalances() -> Signal { + 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: RevenueStats.Balances) { + for subscriber in self.updatedRevenueBalancesContext.subscribers.copyItems() { + subscriber(updatedRevenueBalances) + } + } + func notifyDeletedMessages(messageIds: [MessageId]) { self.deletedMessagesPipe.putNext(messageIds.map { .messageId($0) }) } @@ -1881,6 +1916,12 @@ public final class AccountStateManager { } } + public func updatedRevenueBalances() -> Signal { + return self.impl.signalWith { impl, subscriber in + return impl.updatedRevenueBalances().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) + } + } + func addCustomOperation(_ f: Signal) -> Signal { return self.impl.signalWith { impl, subscriber in return impl.addCustomOperation(f).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) diff --git a/submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift b/submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift index 57ba695b0d..2be2c409cb 100644 --- a/submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift +++ b/submodules/TelegramCore/Sources/Statistics/RevenueStatistics.swift @@ -40,6 +40,17 @@ public struct RevenueStats: Equatable { } } +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 { @@ -87,8 +98,7 @@ private func requestRevenueStats(postbox: Postbox, network: Network, peerId: Pee } private final class RevenueStatsContextImpl { - private let postbox: Postbox - private let network: Network + private let account: Account private let peerId: PeerId private var _state: RevenueStatsContextState { @@ -105,11 +115,10 @@ private final class RevenueStatsContextImpl { private let disposable = MetaDisposable() - init(postbox: Postbox, network: Network, peerId: PeerId) { + init(account: Account, peerId: PeerId) { assert(Queue.mainQueue().isCurrent()) - self.postbox = postbox - self.network = network + self.account = account self.peerId = peerId self._state = RevenueStatsContextState(stats: nil) self._statePromise.set(.single(self._state)) @@ -125,7 +134,22 @@ private final class RevenueStatsContextImpl { fileprivate func load() { assert(Queue.mainQueue().isCurrent()) - self.disposable.set((requestRevenueStats(postbox: self.postbox, network: self.network, peerId: self.peerId) + let account = self.account + 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() + |> map { balances in + return initial.withUpdated(balances: balances) + } + ) + } + + self.disposable.set((signal |> deliverOnMainQueue).start(next: { [weak self] stats in if let strongSelf = self { strongSelf._state = RevenueStatsContextState(stats: stats) @@ -136,7 +160,7 @@ private final class RevenueStatsContextImpl { func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal { if let token = graph.token { - return requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token, x: x) + return requestGraph(postbox: self.account.postbox, network: self.account.network, peerId: self.peerId, token: token, x: x) } else { return .single(nil) } @@ -158,9 +182,9 @@ public final class RevenueStatsContext { } } - public init(postbox: Postbox, network: Network, peerId: PeerId) { + public init(account: Account, peerId: PeerId) { self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: { - return RevenueStatsContextImpl(postbox: postbox, network: network, peerId: peerId) + return RevenueStatsContextImpl(account: account, peerId: peerId) }) } @@ -189,6 +213,7 @@ private final class RevenueStatsTransactionsContextImpl { 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 @@ -206,13 +231,21 @@ private final class RevenueStatsTransactionsContextImpl { 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() }