Stats and recommendations improvements

This commit is contained in:
Ilya Laktyushin 2023-11-19 19:10:13 +04:00
parent 13baadc3e7
commit cc2bd5ec92
43 changed files with 25474 additions and 25369 deletions

View File

@ -10508,3 +10508,9 @@ Sorry for the inconvenience.";
"Stats.StoryTitle" = "Story Statistics";
"Channel.Info.Settings" = "Channel Settings";
"Story.Context.ViewStats" = "View Statistics";
"Share.RepostStory" = "Repost\nStory";
"PeerInfo.PaneRecommended" = "Similar Channels";

View File

@ -933,7 +933,9 @@ public protocol SharedAccountContext: AnyObject {
func makeInstalledStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode, forceTheme: PresentationTheme?) -> ViewController
func makeChannelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: EnginePeer.Id, boosts: Bool, boostStatus: ChannelBoostStatus?, statsDatacenterId: Int32) -> ViewController
func makeChannelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: EnginePeer.Id, boosts: Bool, boostStatus: ChannelBoostStatus?) -> ViewController
func makeMessagesStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, messageId: EngineMessage.Id) -> ViewController
func makeStoryStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: EnginePeer.Id, storyId: Int32) -> ViewController
func makeDebugSettingsController(context: AccountContext?) -> ViewController?

View File

@ -989,14 +989,8 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
}
let tooltipController = UndoOverlayController(presentationData: presentationData, content: .premiumPaywall(title: title, text: text, customUndoText: nil, timeout: nil, linkAction: { [weak navigationController] _ in
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.StatsDatacenterId(id: peerId))
|> deliverOnMainQueue).startStandalone(next: { [weak navigationController] statsDatacenterId in
guard let statsDatacenterId else {
return
}
let statsController = context.sharedContext.makeChannelStatsController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, boosts: true, boostStatus: nil, statsDatacenterId: statsDatacenterId)
navigationController?.pushViewController(statsController)
})
let statsController = context.sharedContext.makeChannelStatsController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, boosts: true, boostStatus: nil)
navigationController?.pushViewController(statsController)
}), elevatedLayout: false, action: { _ in
return true
})
@ -1068,14 +1062,8 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
let text = presentationData.strings.BoostGift_GiveawayCreated_Text
let tooltipController = UndoOverlayController(presentationData: presentationData, content: .premiumPaywall(title: title, text: text, customUndoText: nil, timeout: nil, linkAction: { [weak navigationController] _ in
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.StatsDatacenterId(id: peerId))
|> deliverOnMainQueue).startStandalone(next: { [weak navigationController] statsDatacenterId in
guard let statsDatacenterId else {
return
}
let statsController = context.sharedContext.makeChannelStatsController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, boosts: true, boostStatus: nil, statsDatacenterId: statsDatacenterId)
navigationController?.pushViewController(statsController)
})
let statsController = context.sharedContext.makeChannelStatsController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, boosts: true, boostStatus: nil)
navigationController?.pushViewController(statsController)
}), elevatedLayout: false, action: { _ in
return true
})

View File

@ -155,7 +155,7 @@ private enum StatsEntry: ItemListNodeEntry {
case instantPageInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, StatsGraph, ChartType)
case postsTitle(PresentationTheme, String)
case post(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, StatsPostItem, ChannelStatsMessageInteractions)
case post(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, StatsPostItem, ChannelStatsPostInteractions)
case boostLevel(PresentationTheme, Int32, Int32, CGFloat)
@ -816,7 +816,7 @@ private struct ChannelStatsControllerState: Equatable {
}
private func channelStatsControllerEntries(state: ChannelStatsControllerState, peer: EnginePeer?, data: ChannelStats?, messages: [Message]?, stories: PeerStoryListContext.State?, interactions: [MessageId: ChannelStatsMessageInteractions]?, boostData: ChannelBoostStatus?, boostersState: ChannelBoostersContext.State?, giftsState: ChannelBoostersContext.State?, presentationData: PresentationData, giveawayAvailable: Bool) -> [StatsEntry] {
private func channelStatsControllerEntries(state: ChannelStatsControllerState, peer: EnginePeer?, data: ChannelStats?, messages: [Message]?, stories: PeerStoryListContext.State?, interactions: [ChannelStatsPostInteractions.PostId: ChannelStatsPostInteractions]?, boostData: ChannelBoostStatus?, boostersState: ChannelBoostersContext.State?, giftsState: ChannelBoostersContext.State?, presentationData: PresentationData, giveawayAvailable: Bool) -> [StatsEntry] {
var entries: [StatsEntry] = []
switch state.section {
@ -889,34 +889,40 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p
}
var posts: [StatsPostItem] = []
if let messages, let interactions {
for message in messages {
if let _ = interactions[message.id] {
posts.append(.message(message))
}
}
}
if let stories {
for story in stories.items {
posts.append(.story(story))
}
}
posts.sort(by: { $0.timestamp > $1.timestamp })
if !posts.isEmpty, let interactions, let peer = peer?._asPeer() {
entries.append(.postsTitle(presentationData.theme, presentationData.strings.Stats_PostsTitle))
var index: Int32 = 0
for post in posts {
switch post {
case let .message(message):
if let interactions = interactions[message.id] {
entries.append(.post(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, post, interactions))
if let peer, let interactions {
var posts: [StatsPostItem] = []
if let messages {
for message in messages {
if let _ = interactions[.message(id: message.id)] {
posts.append(.message(message))
}
case let .story(story):
entries.append(.post(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer, post, ChannelStatsMessageInteractions(messageId: MessageId(peerId: PeerId(0), namespace: 0, id: 0), views: Int32(story.views?.seenCount ?? 0), forwards: Int32(story.views?.forwardCount ?? 0), reactions: Int32(story.views?.reactedCount ?? 0))))
}
index += 1
}
if let stories {
for story in stories.items {
if let _ = interactions[.story(peerId: peer.id, id: story.id)] {
posts.append(.story(story))
}
}
}
posts.sort(by: { $0.timestamp > $1.timestamp })
if !posts.isEmpty {
entries.append(.postsTitle(presentationData.theme, presentationData.strings.Stats_PostsTitle))
var index: Int32 = 0
for post in posts {
switch post {
case let .message(message):
if let interactions = interactions[.message(id: message.id)] {
entries.append(.post(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer._asPeer(), post, interactions))
}
case let .story(story):
if let interactions = interactions[.story(peerId: peer.id, id: story.id)] {
entries.append(.post(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer._asPeer(), post, interactions))
}
}
index += 1
}
}
}
}
@ -1032,7 +1038,7 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p
return entries
}
public func channelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, section: ChannelStatsSection = .stats, boostStatus: ChannelBoostStatus? = nil, statsDatacenterId: Int32?) -> ViewController {
public func channelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, section: ChannelStatsSection = .stats, boostStatus: ChannelBoostStatus? = nil) -> ViewController {
let statePromise = ValuePromise(ChannelStatsControllerState(section: section, boostersExpanded: false, moreBoostersDisplayed: 0, giftsSelected: false), ignoreRepeated: true)
let stateValue = Atomic(value: ChannelStatsControllerState(section: section, boostersExpanded: false, moreBoostersDisplayed: 0, giftsSelected: false))
let updateState: ((ChannelStatsControllerState) -> ChannelStatsControllerState) -> Void = { f in
@ -1049,10 +1055,8 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
let messagesPromise = Promise<MessageHistoryView?>(nil)
let storiesPromise = Promise<PeerStoryListContext.State?>()
let datacenterId: Int32 = statsDatacenterId ?? 0
let statsContext = ChannelStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, peerId: peerId)
let statsContext = ChannelStatsContext(postbox: context.account.postbox, network: context.account.network, peerId: peerId)
let dataSignal: Signal<ChannelStats?, NoError> = statsContext.state
|> map { state in
return state.stats
@ -1251,9 +1255,9 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
let messages = messageView?.entries.map { $0.message }.sorted(by: { (lhsMessage, rhsMessage) -> Bool in
return lhsMessage.timestamp > rhsMessage.timestamp
})
let interactions = data?.messageInteractions.reduce([MessageId : ChannelStatsMessageInteractions]()) { (map, interactions) -> [MessageId : ChannelStatsMessageInteractions] in
let interactions = data?.postInteractions.reduce([ChannelStatsPostInteractions.PostId : ChannelStatsPostInteractions]()) { (map, interactions) -> [ChannelStatsPostInteractions.PostId : ChannelStatsPostInteractions] in
var map = map
map[interactions.messageId] = interactions
map[interactions.postId] = interactions
return map
}
@ -1288,9 +1292,9 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
case let .message(message):
subject = .message(id: message.id)
case let .story(story):
subject = .story(peer: peer, storyItem: story)
subject = .story(peerId: peerId, id: story.id)
}
controller?.push(messageStatsController(context: context, subject: subject, statsDatacenterId: statsDatacenterId))
controller?.push(messageStatsController(context: context, subject: subject))
}
contextActionImpl = { [weak controller] messageId, sourceNode, gesture in
guard let controller = controller, let sourceNode = sourceNode as? ContextExtractedContentContainingNode else {

View File

@ -707,7 +707,7 @@ private func canEditAdminRights(accountPeerId: EnginePeer.Id, channelPeer: Engin
}
}
public func groupStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, statsDatacenterId: Int32?) -> ViewController {
public func groupStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id) -> ViewController {
let statePromise = ValuePromise(GroupStatsState())
let stateValue = Atomic(value: GroupStatsState())
let updateState: ((GroupStatsState) -> GroupStatsState) -> Void = { f in
@ -718,8 +718,6 @@ public func groupStatsController(context: AccountContext, updatedPresentationDat
let dataPromise = Promise<GroupStats?>(nil)
let peersPromise = Promise<[EnginePeer.Id: EnginePeer]?>(nil)
let datacenterId: Int32 = statsDatacenterId ?? 0
var openPeerImpl: ((EnginePeer) -> Void)?
var openPeerHistoryImpl: ((EnginePeer.Id) -> Void)?
var openPeerAdminActionsImpl: ((EnginePeer.Id) -> Void)?
@ -727,7 +725,7 @@ public func groupStatsController(context: AccountContext, updatedPresentationDat
actionsDisposable.add(context.account.viewTracker.peerView(peerId, updateData: true).start())
let statsContext = GroupStatsContext(postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, datacenterId: datacenterId, peerId: peerId)
let statsContext = GroupStatsContext(postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId)
let dataSignal: Signal<GroupStats?, NoError> = statsContext.state
|> map { state in
return state.stats

View File

@ -221,7 +221,7 @@ private func messageStatsControllerEntries(data: PostStats?, messages: SearchMes
public enum StatsSubject {
case message(id: EngineMessage.Id)
case story(peer: EnginePeer, storyItem: EngineStoryItem)
case story(peerId: EnginePeer.Id, id: Int32)
}
protocol PostStats {
@ -240,21 +240,19 @@ extension StoryStats: PostStats {
}
public func messageStatsController(context: AccountContext, subject: StatsSubject, statsDatacenterId: Int32?) -> ViewController {
public func messageStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, subject: StatsSubject) -> ViewController {
var navigateToMessageImpl: ((EngineMessage.Id) -> Void)?
let actionsDisposable = DisposableSet()
let dataPromise = Promise<PostStats?>(nil)
let messagesPromise = Promise<(SearchMessagesResult, SearchMessagesState)?>(nil)
let datacenterId: Int32 = statsDatacenterId ?? 0
let anyStatsContext: Any
let dataSignal: Signal<PostStats?, NoError>
var loadDetailedGraphImpl: ((StatsGraph, Int64) -> Signal<StatsGraph?, NoError>)?
switch subject {
case let .message(id):
let statsContext = MessageStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, messageId: id)
let statsContext = MessageStatsContext(postbox: context.account.postbox, network: context.account.network, messageId: id)
loadDetailedGraphImpl = { [weak statsContext] graph, x in
return statsContext?.loadDetailedGraph(graph, x: x) ?? .single(nil)
}
@ -264,8 +262,8 @@ public func messageStatsController(context: AccountContext, subject: StatsSubjec
}
dataPromise.set(.single(nil) |> then(dataSignal))
anyStatsContext = statsContext
case let .story(peer, storyItem):
let statsContext = StoryStatsContext(postbox: context.account.postbox, network: context.account.network, datacenterId: datacenterId, peerId: peer.id, storyId: storyItem.id)
case let .story(peerId, id):
let statsContext = StoryStatsContext(postbox: context.account.postbox, network: context.account.network, peerId: peerId, storyId: id)
loadDetailedGraphImpl = { [weak statsContext] graph, x in
return statsContext?.loadDetailedGraph(graph, x: x) ?? .single(nil)
}
@ -288,7 +286,7 @@ public func messageStatsController(context: AccountContext, subject: StatsSubjec
let previousData = Atomic<PostStats?>(value: nil)
if case let .message(id) = subject {
let searchSignal = context.engine.messages.searchMessages(location: .publicForwards(messageId: id, datacenterId: Int(datacenterId)), query: "", state: nil)
let searchSignal = context.engine.messages.searchMessages(location: .publicForwards(messageId: id), query: "", state: nil)
|> map(Optional.init)
|> afterNext { result in
if let result = result {
@ -304,17 +302,31 @@ public func messageStatsController(context: AccountContext, subject: StatsSubjec
messagesPromise.set(.single(nil))
}
let iconNode: ASDisplayNode?
if case let .story(peer, storyItem) = subject {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
iconNode = StoryIconNode(context: context, theme: presentationData.theme, peer: peer._asPeer(), storyItem: storyItem)
let iconNodePromise = Promise<ASDisplayNode?>()
if case let .story(peerId, id) = subject {
let _ = id
iconNodePromise.set(
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue
|> map { peer -> ASDisplayNode? in
if let _ = peer?._asPeer() {
// let presentationData = context.sharedContext.currentPresentationData.with { $0 }
// return StoryIconNode(context: context, theme: presentationData.theme, peer: peer, storyItem: storyItem)
return nil
} else {
return nil
}
}
)
} else {
iconNode = nil
iconNodePromise.set(.single(nil))
}
let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get(), messagesPromise.get(), longLoadingSignal)
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
let signal = combineLatest(presentationData, dataPromise.get(), messagesPromise.get(), longLoadingSignal, iconNodePromise.get())
|> deliverOnMainQueue
|> map { presentationData, data, search, longLoading -> (ItemListControllerState, (ItemListNodeState, Any)) in
|> map { presentationData, data, search, longLoading, iconNode -> (ItemListControllerState, (ItemListNodeState, Any)) in
let previous = previousData.swap(data)
var emptyStateItem: ItemListControllerEmptyStateItem?
if data == nil {

View File

@ -173,7 +173,14 @@ class MessageStatsOverviewItemNode: ListViewItemNode {
leftTitleLabelLayoutAndApply = makeLeftTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_Message_Views, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: min(maxItemWidth, remainingWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
remainingWidth -= leftTitleLabelLayoutAndApply!.0.size.width - 4.0
centerTitleLabelLayoutAndApply = makeCenterTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_Message_PublicShares, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: min(maxItemWidth, remainingWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let centerTitle: String
if let _ = item.stats as? StoryStats {
centerTitle = "Reactions"
} else {
centerTitle = item.presentationData.strings.Stats_Message_PublicShares
}
centerTitleLabelLayoutAndApply = makeCenterTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: centerTitle, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: min(maxItemWidth, remainingWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
remainingWidth -= centerTitleLabelLayoutAndApply!.0.size.width - 4.0
rightTitleLabelLayoutAndApply = makeRightTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_Message_PrivateShares, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: min(maxItemWidth, remainingWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))

View File

@ -535,7 +535,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-297296796] = { return Api.MessageExtendedMedia.parse_messageExtendedMedia($0) }
dict[-1386050360] = { return Api.MessageExtendedMedia.parse_messageExtendedMediaPreview($0) }
dict[1601666510] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) }
dict[-1387279939] = { return Api.MessageInteractionCounters.parse_messageInteractionCounters($0) }
dict[1882335561] = { return Api.MessageMedia.parse_messageMediaContact($0) }
dict[1065280907] = { return Api.MessageMedia.parse_messageMediaDice($0) }
dict[1291114285] = { return Api.MessageMedia.parse_messageMediaDocument($0) }
@ -669,6 +668,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[2061444128] = { return Api.PollResults.parse_pollResults($0) }
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
dict[512535275] = { return Api.PostAddress.parse_postAddress($0) }
dict[-419066241] = { return Api.PostInteractionCounters.parse_postInteractionCountersMessage($0) }
dict[-1974989273] = { return Api.PostInteractionCounters.parse_postInteractionCountersStory($0) }
dict[629052971] = { return Api.PremiumGiftCodeOption.parse_premiumGiftCodeOption($0) }
dict[1958953753] = { return Api.PremiumGiftOption.parse_premiumGiftOption($0) }
dict[1596792306] = { return Api.PremiumSubscriptionOption.parse_premiumSubscriptionOption($0) }
@ -1187,7 +1188,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-2030542532] = { return Api.premium.BoostsList.parse_boostsList($0) }
dict[1230586490] = { return Api.premium.BoostsStatus.parse_boostsStatus($0) }
dict[-1696454430] = { return Api.premium.MyBoosts.parse_myBoosts($0) }
dict[-886032030] = { return Api.stats.BroadcastStats.parse_broadcastStats($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) }
dict[1355613820] = { return Api.stats.StoryStats.parse_storyStats($0) }
@ -1593,8 +1594,6 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.MessageFwdHeader:
_1.serialize(buffer, boxed)
case let _1 as Api.MessageInteractionCounters:
_1.serialize(buffer, boxed)
case let _1 as Api.MessageMedia:
_1.serialize(buffer, boxed)
case let _1 as Api.MessagePeerReaction:
@ -1683,6 +1682,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.PostAddress:
_1.serialize(buffer, boxed)
case let _1 as Api.PostInteractionCounters:
_1.serialize(buffer, boxed)
case let _1 as Api.PremiumGiftCodeOption:
_1.serialize(buffer, boxed)
case let _1 as Api.PremiumGiftOption:

View File

@ -688,50 +688,6 @@ public extension Api {
}
}
public extension Api {
enum MessageInteractionCounters: TypeConstructorDescription {
case messageInteractionCounters(msgId: Int32, views: Int32, forwards: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageInteractionCounters(let msgId, let views, let forwards):
if boxed {
buffer.appendInt32(-1387279939)
}
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(views, buffer: buffer, boxed: false)
serializeInt32(forwards, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageInteractionCounters(let msgId, let views, let forwards):
return ("messageInteractionCounters", [("msgId", msgId as Any), ("views", views as Any), ("forwards", forwards as Any)])
}
}
public static func parse_messageInteractionCounters(_ reader: BufferReader) -> MessageInteractionCounters? {
var _1: Int32?
_1 = reader.readInt32()
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.MessageInteractionCounters.messageInteractionCounters(msgId: _1!, views: _2!, forwards: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
indirect enum MessageMedia: TypeConstructorDescription {
case messageMediaContact(phoneNumber: String, firstName: String, lastName: String, vcard: String, userId: Int64)

View File

@ -750,6 +750,86 @@ public extension Api {
}
}
public extension Api {
enum PostInteractionCounters: TypeConstructorDescription {
case postInteractionCountersMessage(msgId: Int32, views: Int32, forwards: Int32, reactions: Int32)
case postInteractionCountersStory(storyId: Int32, views: Int32, forwards: Int32, reactions: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .postInteractionCountersMessage(let msgId, let views, let forwards, let reactions):
if boxed {
buffer.appendInt32(-419066241)
}
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(views, buffer: buffer, boxed: false)
serializeInt32(forwards, buffer: buffer, boxed: false)
serializeInt32(reactions, buffer: buffer, boxed: false)
break
case .postInteractionCountersStory(let storyId, let views, let forwards, let reactions):
if boxed {
buffer.appendInt32(-1974989273)
}
serializeInt32(storyId, buffer: buffer, boxed: false)
serializeInt32(views, buffer: buffer, boxed: false)
serializeInt32(forwards, buffer: buffer, boxed: false)
serializeInt32(reactions, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .postInteractionCountersMessage(let msgId, let views, let forwards, let reactions):
return ("postInteractionCountersMessage", [("msgId", msgId as Any), ("views", views as Any), ("forwards", forwards as Any), ("reactions", reactions as Any)])
case .postInteractionCountersStory(let storyId, let views, let forwards, let reactions):
return ("postInteractionCountersStory", [("storyId", storyId as Any), ("views", views as Any), ("forwards", forwards as Any), ("reactions", reactions as Any)])
}
}
public static func parse_postInteractionCountersMessage(_ reader: BufferReader) -> PostInteractionCounters? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.PostInteractionCounters.postInteractionCountersMessage(msgId: _1!, views: _2!, forwards: _3!, reactions: _4!)
}
else {
return nil
}
}
public static func parse_postInteractionCountersStory(_ reader: BufferReader) -> PostInteractionCounters? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.PostInteractionCounters.postInteractionCountersStory(storyId: _1!, views: _2!, forwards: _3!, reactions: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum PremiumGiftCodeOption: TypeConstructorDescription {
case premiumGiftCodeOption(flags: Int32, users: Int32, months: Int32, storeProduct: String?, storeQuantity: Int32?, currency: String, amount: Int64)
@ -1110,183 +1190,3 @@ public extension Api {
}
}
public extension Api {
enum PrivacyRule: TypeConstructorDescription {
case privacyValueAllowAll
case privacyValueAllowChatParticipants(chats: [Int64])
case privacyValueAllowCloseFriends
case privacyValueAllowContacts
case privacyValueAllowUsers(users: [Int64])
case privacyValueDisallowAll
case privacyValueDisallowChatParticipants(chats: [Int64])
case privacyValueDisallowContacts
case privacyValueDisallowUsers(users: [Int64])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .privacyValueAllowAll:
if boxed {
buffer.appendInt32(1698855810)
}
break
case .privacyValueAllowChatParticipants(let chats):
if boxed {
buffer.appendInt32(1796427406)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
case .privacyValueAllowCloseFriends:
if boxed {
buffer.appendInt32(-135735141)
}
break
case .privacyValueAllowContacts:
if boxed {
buffer.appendInt32(-123988)
}
break
case .privacyValueAllowUsers(let users):
if boxed {
buffer.appendInt32(-1198497870)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
case .privacyValueDisallowAll:
if boxed {
buffer.appendInt32(-1955338397)
}
break
case .privacyValueDisallowChatParticipants(let chats):
if boxed {
buffer.appendInt32(1103656293)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
case .privacyValueDisallowContacts:
if boxed {
buffer.appendInt32(-125240806)
}
break
case .privacyValueDisallowUsers(let users):
if boxed {
buffer.appendInt32(-463335103)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .privacyValueAllowAll:
return ("privacyValueAllowAll", [])
case .privacyValueAllowChatParticipants(let chats):
return ("privacyValueAllowChatParticipants", [("chats", chats as Any)])
case .privacyValueAllowCloseFriends:
return ("privacyValueAllowCloseFriends", [])
case .privacyValueAllowContacts:
return ("privacyValueAllowContacts", [])
case .privacyValueAllowUsers(let users):
return ("privacyValueAllowUsers", [("users", users as Any)])
case .privacyValueDisallowAll:
return ("privacyValueDisallowAll", [])
case .privacyValueDisallowChatParticipants(let chats):
return ("privacyValueDisallowChatParticipants", [("chats", chats as Any)])
case .privacyValueDisallowContacts:
return ("privacyValueDisallowContacts", [])
case .privacyValueDisallowUsers(let users):
return ("privacyValueDisallowUsers", [("users", users as Any)])
}
}
public static func parse_privacyValueAllowAll(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueAllowAll
}
public static func parse_privacyValueAllowChatParticipants(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueAllowChatParticipants(chats: _1!)
}
else {
return nil
}
}
public static func parse_privacyValueAllowCloseFriends(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueAllowCloseFriends
}
public static func parse_privacyValueAllowContacts(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueAllowContacts
}
public static func parse_privacyValueAllowUsers(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueAllowUsers(users: _1!)
}
else {
return nil
}
}
public static func parse_privacyValueDisallowAll(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueDisallowAll
}
public static func parse_privacyValueDisallowChatParticipants(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueDisallowChatParticipants(chats: _1!)
}
else {
return nil
}
}
public static func parse_privacyValueDisallowContacts(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueDisallowContacts
}
public static func parse_privacyValueDisallowUsers(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueDisallowUsers(users: _1!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,183 @@
public extension Api {
enum PrivacyRule: TypeConstructorDescription {
case privacyValueAllowAll
case privacyValueAllowChatParticipants(chats: [Int64])
case privacyValueAllowCloseFriends
case privacyValueAllowContacts
case privacyValueAllowUsers(users: [Int64])
case privacyValueDisallowAll
case privacyValueDisallowChatParticipants(chats: [Int64])
case privacyValueDisallowContacts
case privacyValueDisallowUsers(users: [Int64])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .privacyValueAllowAll:
if boxed {
buffer.appendInt32(1698855810)
}
break
case .privacyValueAllowChatParticipants(let chats):
if boxed {
buffer.appendInt32(1796427406)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
case .privacyValueAllowCloseFriends:
if boxed {
buffer.appendInt32(-135735141)
}
break
case .privacyValueAllowContacts:
if boxed {
buffer.appendInt32(-123988)
}
break
case .privacyValueAllowUsers(let users):
if boxed {
buffer.appendInt32(-1198497870)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
case .privacyValueDisallowAll:
if boxed {
buffer.appendInt32(-1955338397)
}
break
case .privacyValueDisallowChatParticipants(let chats):
if boxed {
buffer.appendInt32(1103656293)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
case .privacyValueDisallowContacts:
if boxed {
buffer.appendInt32(-125240806)
}
break
case .privacyValueDisallowUsers(let users):
if boxed {
buffer.appendInt32(-463335103)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
serializeInt64(item, buffer: buffer, boxed: false)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .privacyValueAllowAll:
return ("privacyValueAllowAll", [])
case .privacyValueAllowChatParticipants(let chats):
return ("privacyValueAllowChatParticipants", [("chats", chats as Any)])
case .privacyValueAllowCloseFriends:
return ("privacyValueAllowCloseFriends", [])
case .privacyValueAllowContacts:
return ("privacyValueAllowContacts", [])
case .privacyValueAllowUsers(let users):
return ("privacyValueAllowUsers", [("users", users as Any)])
case .privacyValueDisallowAll:
return ("privacyValueDisallowAll", [])
case .privacyValueDisallowChatParticipants(let chats):
return ("privacyValueDisallowChatParticipants", [("chats", chats as Any)])
case .privacyValueDisallowContacts:
return ("privacyValueDisallowContacts", [])
case .privacyValueDisallowUsers(let users):
return ("privacyValueDisallowUsers", [("users", users as Any)])
}
}
public static func parse_privacyValueAllowAll(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueAllowAll
}
public static func parse_privacyValueAllowChatParticipants(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueAllowChatParticipants(chats: _1!)
}
else {
return nil
}
}
public static func parse_privacyValueAllowCloseFriends(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueAllowCloseFriends
}
public static func parse_privacyValueAllowContacts(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueAllowContacts
}
public static func parse_privacyValueAllowUsers(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueAllowUsers(users: _1!)
}
else {
return nil
}
}
public static func parse_privacyValueDisallowAll(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueDisallowAll
}
public static func parse_privacyValueDisallowChatParticipants(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueDisallowChatParticipants(chats: _1!)
}
else {
return nil
}
}
public static func parse_privacyValueDisallowContacts(_ reader: BufferReader) -> PrivacyRule? {
return Api.PrivacyRule.privacyValueDisallowContacts
}
public static func parse_privacyValueDisallowUsers(_ reader: BufferReader) -> PrivacyRule? {
var _1: [Int64]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.PrivacyRule.privacyValueDisallowUsers(users: _1!)
}
else {
return nil
}
}
}
}
public extension Api {
enum Reaction: TypeConstructorDescription {
case reactionCustomEmoji(documentId: Int64)
@ -588,563 +768,3 @@ public extension Api {
}
}
public extension Api {
enum RequestPeerType: TypeConstructorDescription {
case requestPeerTypeBroadcast(flags: Int32, hasUsername: Api.Bool?, userAdminRights: Api.ChatAdminRights?, botAdminRights: Api.ChatAdminRights?)
case requestPeerTypeChat(flags: Int32, hasUsername: Api.Bool?, forum: Api.Bool?, userAdminRights: Api.ChatAdminRights?, botAdminRights: Api.ChatAdminRights?)
case requestPeerTypeUser(flags: Int32, bot: Api.Bool?, premium: Api.Bool?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .requestPeerTypeBroadcast(let flags, let hasUsername, let userAdminRights, let botAdminRights):
if boxed {
buffer.appendInt32(865857388)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {hasUsername!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {userAdminRights!.serialize(buffer, true)}
if Int(flags) & Int(1 << 2) != 0 {botAdminRights!.serialize(buffer, true)}
break
case .requestPeerTypeChat(let flags, let hasUsername, let forum, let userAdminRights, let botAdminRights):
if boxed {
buffer.appendInt32(-906990053)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {hasUsername!.serialize(buffer, true)}
if Int(flags) & Int(1 << 4) != 0 {forum!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {userAdminRights!.serialize(buffer, true)}
if Int(flags) & Int(1 << 2) != 0 {botAdminRights!.serialize(buffer, true)}
break
case .requestPeerTypeUser(let flags, let bot, let premium):
if boxed {
buffer.appendInt32(1597737472)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {bot!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {premium!.serialize(buffer, true)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .requestPeerTypeBroadcast(let flags, let hasUsername, let userAdminRights, let botAdminRights):
return ("requestPeerTypeBroadcast", [("flags", flags as Any), ("hasUsername", hasUsername as Any), ("userAdminRights", userAdminRights as Any), ("botAdminRights", botAdminRights as Any)])
case .requestPeerTypeChat(let flags, let hasUsername, let forum, let userAdminRights, let botAdminRights):
return ("requestPeerTypeChat", [("flags", flags as Any), ("hasUsername", hasUsername as Any), ("forum", forum as Any), ("userAdminRights", userAdminRights as Any), ("botAdminRights", botAdminRights as Any)])
case .requestPeerTypeUser(let flags, let bot, let premium):
return ("requestPeerTypeUser", [("flags", flags as Any), ("bot", bot as Any), ("premium", premium as Any)])
}
}
public static func parse_requestPeerTypeBroadcast(_ reader: BufferReader) -> RequestPeerType? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Bool?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Bool
} }
var _3: Api.ChatAdminRights?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
} }
var _4: Api.ChatAdminRights?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
} }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 3) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.RequestPeerType.requestPeerTypeBroadcast(flags: _1!, hasUsername: _2, userAdminRights: _3, botAdminRights: _4)
}
else {
return nil
}
}
public static func parse_requestPeerTypeChat(_ reader: BufferReader) -> RequestPeerType? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Bool?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Bool
} }
var _3: Api.Bool?
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Bool
} }
var _4: Api.ChatAdminRights?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
} }
var _5: Api.ChatAdminRights?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
} }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 3) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 4) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.RequestPeerType.requestPeerTypeChat(flags: _1!, hasUsername: _2, forum: _3, userAdminRights: _4, botAdminRights: _5)
}
else {
return nil
}
}
public static func parse_requestPeerTypeUser(_ reader: BufferReader) -> RequestPeerType? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Bool?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Bool
} }
var _3: Api.Bool?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Bool
} }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.RequestPeerType.requestPeerTypeUser(flags: _1!, bot: _2, premium: _3)
}
else {
return nil
}
}
}
}
public extension Api {
enum RestrictionReason: TypeConstructorDescription {
case restrictionReason(platform: String, reason: String, text: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .restrictionReason(let platform, let reason, let text):
if boxed {
buffer.appendInt32(-797791052)
}
serializeString(platform, buffer: buffer, boxed: false)
serializeString(reason, buffer: buffer, boxed: false)
serializeString(text, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .restrictionReason(let platform, let reason, let text):
return ("restrictionReason", [("platform", platform as Any), ("reason", reason as Any), ("text", text as Any)])
}
}
public static func parse_restrictionReason(_ reader: BufferReader) -> RestrictionReason? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
var _3: String?
_3 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.RestrictionReason.restrictionReason(platform: _1!, reason: _2!, text: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
indirect enum RichText: TypeConstructorDescription {
case textAnchor(text: Api.RichText, name: String)
case textBold(text: Api.RichText)
case textConcat(texts: [Api.RichText])
case textEmail(text: Api.RichText, email: String)
case textEmpty
case textFixed(text: Api.RichText)
case textImage(documentId: Int64, w: Int32, h: Int32)
case textItalic(text: Api.RichText)
case textMarked(text: Api.RichText)
case textPhone(text: Api.RichText, phone: String)
case textPlain(text: String)
case textStrike(text: Api.RichText)
case textSubscript(text: Api.RichText)
case textSuperscript(text: Api.RichText)
case textUnderline(text: Api.RichText)
case textUrl(text: Api.RichText, url: String, webpageId: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .textAnchor(let text, let name):
if boxed {
buffer.appendInt32(894777186)
}
text.serialize(buffer, true)
serializeString(name, buffer: buffer, boxed: false)
break
case .textBold(let text):
if boxed {
buffer.appendInt32(1730456516)
}
text.serialize(buffer, true)
break
case .textConcat(let texts):
if boxed {
buffer.appendInt32(2120376535)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(texts.count))
for item in texts {
item.serialize(buffer, true)
}
break
case .textEmail(let text, let email):
if boxed {
buffer.appendInt32(-564523562)
}
text.serialize(buffer, true)
serializeString(email, buffer: buffer, boxed: false)
break
case .textEmpty:
if boxed {
buffer.appendInt32(-599948721)
}
break
case .textFixed(let text):
if boxed {
buffer.appendInt32(1816074681)
}
text.serialize(buffer, true)
break
case .textImage(let documentId, let w, let h):
if boxed {
buffer.appendInt32(136105807)
}
serializeInt64(documentId, buffer: buffer, boxed: false)
serializeInt32(w, buffer: buffer, boxed: false)
serializeInt32(h, buffer: buffer, boxed: false)
break
case .textItalic(let text):
if boxed {
buffer.appendInt32(-653089380)
}
text.serialize(buffer, true)
break
case .textMarked(let text):
if boxed {
buffer.appendInt32(55281185)
}
text.serialize(buffer, true)
break
case .textPhone(let text, let phone):
if boxed {
buffer.appendInt32(483104362)
}
text.serialize(buffer, true)
serializeString(phone, buffer: buffer, boxed: false)
break
case .textPlain(let text):
if boxed {
buffer.appendInt32(1950782688)
}
serializeString(text, buffer: buffer, boxed: false)
break
case .textStrike(let text):
if boxed {
buffer.appendInt32(-1678197867)
}
text.serialize(buffer, true)
break
case .textSubscript(let text):
if boxed {
buffer.appendInt32(-311786236)
}
text.serialize(buffer, true)
break
case .textSuperscript(let text):
if boxed {
buffer.appendInt32(-939827711)
}
text.serialize(buffer, true)
break
case .textUnderline(let text):
if boxed {
buffer.appendInt32(-1054465340)
}
text.serialize(buffer, true)
break
case .textUrl(let text, let url, let webpageId):
if boxed {
buffer.appendInt32(1009288385)
}
text.serialize(buffer, true)
serializeString(url, buffer: buffer, boxed: false)
serializeInt64(webpageId, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .textAnchor(let text, let name):
return ("textAnchor", [("text", text as Any), ("name", name as Any)])
case .textBold(let text):
return ("textBold", [("text", text as Any)])
case .textConcat(let texts):
return ("textConcat", [("texts", texts as Any)])
case .textEmail(let text, let email):
return ("textEmail", [("text", text as Any), ("email", email as Any)])
case .textEmpty:
return ("textEmpty", [])
case .textFixed(let text):
return ("textFixed", [("text", text as Any)])
case .textImage(let documentId, let w, let h):
return ("textImage", [("documentId", documentId as Any), ("w", w as Any), ("h", h as Any)])
case .textItalic(let text):
return ("textItalic", [("text", text as Any)])
case .textMarked(let text):
return ("textMarked", [("text", text as Any)])
case .textPhone(let text, let phone):
return ("textPhone", [("text", text as Any), ("phone", phone as Any)])
case .textPlain(let text):
return ("textPlain", [("text", text as Any)])
case .textStrike(let text):
return ("textStrike", [("text", text as Any)])
case .textSubscript(let text):
return ("textSubscript", [("text", text as Any)])
case .textSuperscript(let text):
return ("textSuperscript", [("text", text as Any)])
case .textUnderline(let text):
return ("textUnderline", [("text", text as Any)])
case .textUrl(let text, let url, let webpageId):
return ("textUrl", [("text", text as Any), ("url", url as Any), ("webpageId", webpageId as Any)])
}
}
public static func parse_textAnchor(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.RichText.textAnchor(text: _1!, name: _2!)
}
else {
return nil
}
}
public static func parse_textBold(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textBold(text: _1!)
}
else {
return nil
}
}
public static func parse_textConcat(_ reader: BufferReader) -> RichText? {
var _1: [Api.RichText]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RichText.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textConcat(texts: _1!)
}
else {
return nil
}
}
public static func parse_textEmail(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.RichText.textEmail(text: _1!, email: _2!)
}
else {
return nil
}
}
public static func parse_textEmpty(_ reader: BufferReader) -> RichText? {
return Api.RichText.textEmpty
}
public static func parse_textFixed(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textFixed(text: _1!)
}
else {
return nil
}
}
public static func parse_textImage(_ reader: BufferReader) -> RichText? {
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.RichText.textImage(documentId: _1!, w: _2!, h: _3!)
}
else {
return nil
}
}
public static func parse_textItalic(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textItalic(text: _1!)
}
else {
return nil
}
}
public static func parse_textMarked(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textMarked(text: _1!)
}
else {
return nil
}
}
public static func parse_textPhone(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.RichText.textPhone(text: _1!, phone: _2!)
}
else {
return nil
}
}
public static func parse_textPlain(_ reader: BufferReader) -> RichText? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textPlain(text: _1!)
}
else {
return nil
}
}
public static func parse_textStrike(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textStrike(text: _1!)
}
else {
return nil
}
}
public static func parse_textSubscript(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textSubscript(text: _1!)
}
else {
return nil
}
}
public static func parse_textSuperscript(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textSuperscript(text: _1!)
}
else {
return nil
}
}
public static func parse_textUnderline(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
let _c1 = _1 != nil
if _c1 {
return Api.RichText.textUnderline(text: _1!)
}
else {
return nil
}
}
public static func parse_textUrl(_ reader: BufferReader) -> RichText? {
var _1: Api.RichText?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.RichText
}
var _2: String?
_2 = parseString(reader)
var _3: Int64?
_3 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.RichText.textUrl(text: _1!, url: _2!, webpageId: _3!)
}
else {
return nil
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -47,15 +47,15 @@ public struct MessageStatsContextState: Equatable {
public var stats: MessageStats?
}
private func requestMessageStats(postbox: Postbox, network: Network, datacenterId: Int32, messageId: MessageId, dark: Bool = false) -> Signal<MessageStats?, NoError> {
return postbox.transaction { transaction -> (Peer, Message)? in
if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) {
return (peer, message)
private func requestMessageStats(postbox: Postbox, network: Network, messageId: MessageId, dark: Bool = false) -> Signal<MessageStats?, NoError> {
return postbox.transaction { transaction -> (Int32, Peer, Message)? in
if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId), let cachedData = transaction.getPeerCachedData(peerId: messageId.peerId) as? CachedChannelData {
return (cachedData.statsDatacenterId, peer, message)
} else {
return nil
}
} |> mapToSignal { peerAndMessage -> Signal<MessageStats?, NoError> in
guard let (peer, message) = peerAndMessage, let inputChannel = apiInputChannel(peer) else {
} |> mapToSignal { data -> Signal<MessageStats?, NoError> in
guard let (datacenterId, peer, message) = data, let inputChannel = apiInputChannel(peer) else {
return .never()
}
@ -125,7 +125,6 @@ private func requestMessageStats(postbox: Postbox, network: Network, datacenterI
private final class MessageStatsContextImpl {
private let postbox: Postbox
private let network: Network
private let datacenterId: Int32
private let messageId: MessageId
private var _state: MessageStatsContextState {
@ -143,12 +142,11 @@ private final class MessageStatsContextImpl {
private let disposable = MetaDisposable()
private let disposables = DisposableDict<String>()
init(postbox: Postbox, network: Network, datacenterId: Int32, messageId: MessageId) {
init(postbox: Postbox, network: Network, messageId: MessageId) {
assert(Queue.mainQueue().isCurrent())
self.postbox = postbox
self.network = network
self.datacenterId = datacenterId
self.messageId = messageId
self._state = MessageStatsContextState(stats: nil)
self._statePromise.set(.single(self._state))
@ -165,7 +163,7 @@ private final class MessageStatsContextImpl {
private func load() {
assert(Queue.mainQueue().isCurrent())
self.disposable.set((requestMessageStats(postbox: self.postbox, network: self.network, datacenterId: self.datacenterId, messageId: self.messageId)
self.disposable.set((requestMessageStats(postbox: self.postbox, network: self.network, messageId: self.messageId)
|> deliverOnMainQueue).start(next: { [weak self] stats in
if let strongSelf = self {
strongSelf._state = MessageStatsContextState(stats: stats)
@ -176,7 +174,7 @@ private final class MessageStatsContextImpl {
func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
if let token = graph.token {
return requestGraph(network: self.network, datacenterId: self.datacenterId, token: token, x: x)
return requestGraph(postbox: self.postbox, network: self.network, peerId: self.messageId.peerId, token: token, x: x)
} else {
return .single(nil)
}
@ -198,9 +196,9 @@ public final class MessageStatsContext {
}
}
public init(postbox: Postbox, network: Network, datacenterId: Int32, messageId: MessageId) {
public init(postbox: Postbox, network: Network, messageId: MessageId) {
self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: {
return MessageStatsContextImpl(postbox: postbox, network: network, datacenterId: datacenterId, messageId: messageId)
return MessageStatsContextImpl(postbox: postbox, network: network, messageId: messageId)
})
}

View File

@ -48,25 +48,34 @@ public enum StatsGraph: Equatable {
}
}
public struct ChannelStatsMessageInteractions: Equatable {
public let messageId: MessageId
public struct ChannelStatsPostInteractions: Equatable {
public enum PostId: Hashable {
case message(id: EngineMessage.Id)
case story(peerId: EnginePeer.Id, id: Int32)
}
public let postId: PostId
public let views: Int32
public let forwards: Int32
public let reactions: Int32
public init(messageId: MessageId, views: Int32, forwards: Int32, reactions: Int32) {
self.messageId = messageId
public init(postId: PostId, views: Int32, forwards: Int32, reactions: Int32) {
self.postId = postId
self.views = views
self.forwards = forwards
self.reactions = reactions
}
}
public final class ChannelStats: Equatable {
public struct ChannelStats: Equatable {
public let period: StatsDateRange
public let followers: StatsValue
public let viewsPerPost: StatsValue
public let sharesPerPost: StatsValue
public let reactionsPerPost: StatsValue
public let viewsPerStory: StatsValue
public let sharesPerStory: StatsValue
public let reactionsPerStory: StatsValue
public let enabledNotifications: StatsPercentValue
public let growthGraph: StatsGraph
public let followersGraph: StatsGraph
@ -80,13 +89,17 @@ public final class ChannelStats: Equatable {
public let reactionsByEmotionGraph: StatsGraph
public let storyInteractionsGraph: StatsGraph
public let storyReactionsByEmotionGraph: StatsGraph
public let messageInteractions: [ChannelStatsMessageInteractions]
public let postInteractions: [ChannelStatsPostInteractions]
init(
period: StatsDateRange,
followers: StatsValue,
viewsPerPost: StatsValue,
sharesPerPost: StatsValue,
reactionsPerPost: StatsValue,
viewsPerStory: StatsValue,
sharesPerStory: StatsValue,
reactionsPerStory: StatsValue,
enabledNotifications: StatsPercentValue,
growthGraph: StatsGraph,
followersGraph: StatsGraph,
@ -100,12 +113,16 @@ public final class ChannelStats: Equatable {
reactionsByEmotionGraph: StatsGraph,
storyInteractionsGraph: StatsGraph,
storyReactionsByEmotionGraph: StatsGraph,
messageInteractions: [ChannelStatsMessageInteractions]
postInteractions: [ChannelStatsPostInteractions]
) {
self.period = period
self.followers = followers
self.viewsPerPost = viewsPerPost
self.sharesPerPost = sharesPerPost
self.reactionsPerPost = reactionsPerPost
self.viewsPerStory = viewsPerStory
self.sharesPerStory = sharesPerStory
self.reactionsPerStory = reactionsPerStory
self.enabledNotifications = enabledNotifications
self.growthGraph = growthGraph
self.followersGraph = followersGraph
@ -119,7 +136,7 @@ public final class ChannelStats: Equatable {
self.reactionsByEmotionGraph = reactionsByEmotionGraph
self.storyInteractionsGraph = storyInteractionsGraph
self.storyReactionsByEmotionGraph = storyReactionsByEmotionGraph
self.messageInteractions = messageInteractions
self.postInteractions = postInteractions
}
public static func == (lhs: ChannelStats, rhs: ChannelStats) -> Bool {
@ -174,56 +191,56 @@ public final class ChannelStats: Equatable {
if lhs.storyReactionsByEmotionGraph != rhs.storyReactionsByEmotionGraph {
return false
}
if lhs.messageInteractions != rhs.messageInteractions {
if lhs.postInteractions != rhs.postInteractions {
return false
}
return true
}
public func withUpdatedGrowthGraph(_ growthGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedFollowersGraph(_ followersGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedMuteGraph(_ muteGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedTopHoursGraph(_ viewsByHourGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: viewsByHourGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: viewsByHourGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedInteractionsGraph(_ interactionsGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedInstantPageInteractionsGraph(_ instantPageInteractionsGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedViewsBySourceGraph(_ viewsBySourceGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedNewFollowersBySourceGraph(_ newFollowersBySourceGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedLanguagesGraph(_ languagesGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedReactionsByEmotionGraph(_ reactionsByEmotionGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedStoryInteractionsGraph(_ storyInteractionsGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: storyInteractionsGraph, storyReactionsByEmotionGraph: self.storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
public func withUpdatedStoryReactionsByEmotionGraph(_ storyReactionsByEmotionGraph: StatsGraph) -> ChannelStats {
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: storyReactionsByEmotionGraph, messageInteractions: self.messageInteractions)
return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, reactionsPerPost: self.reactionsPerPost, viewsPerStory: self.viewsPerStory, sharesPerStory: self.sharesPerStory, reactionsPerStory: self.reactionsPerStory, enabledNotifications: self.enabledNotifications, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph, instantPageInteractionsGraph: self.instantPageInteractionsGraph, viewsBySourceGraph: self.viewsBySourceGraph, newFollowersBySourceGraph: self.newFollowersBySourceGraph, languagesGraph: self.languagesGraph, reactionsByEmotionGraph: self.reactionsByEmotionGraph, storyInteractionsGraph: self.storyInteractionsGraph, storyReactionsByEmotionGraph: storyReactionsByEmotionGraph, postInteractions: self.postInteractions)
}
}
@ -231,11 +248,14 @@ public struct ChannelStatsContextState: Equatable {
public var stats: ChannelStats?
}
private func requestChannelStats(postbox: Postbox, network: Network, datacenterId: Int32, peerId: PeerId, dark: Bool = false) -> Signal<ChannelStats?, NoError> {
return postbox.transaction { transaction -> Peer? in
return transaction.getPeer(peerId)
} |> mapToSignal { peer -> Signal<ChannelStats?, NoError> in
guard let peer = peer, let inputChannel = apiInputChannel(peer) else {
private func requestChannelStats(postbox: Postbox, network: Network, peerId: PeerId, dark: Bool = false) -> Signal<ChannelStats?, NoError> {
return postbox.transaction { transaction -> (Int32, Peer)? in
if let peer = transaction.getPeer(peerId), let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
return (cachedData.statsDatacenterId, peer)
}
return nil
} |> mapToSignal { data -> Signal<ChannelStats?, NoError> in
guard let (statsDatacenterId, peer) = data, let inputChannel = apiInputChannel(peer) else {
return .never()
}
@ -246,8 +266,8 @@ private func requestChannelStats(postbox: Postbox, network: Network, datacenterI
let request = Api.functions.stats.getBroadcastStats(flags: flags, channel: inputChannel)
let signal: Signal<Api.stats.BroadcastStats, MTRpcError>
if network.datacenterId != datacenterId {
signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil)
if network.datacenterId != statsDatacenterId {
signal = network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(request)
@ -264,20 +284,33 @@ private func requestChannelStats(postbox: Postbox, network: Network, datacenterI
}
}
func requestGraph(network: Network, datacenterId: Int32, token: String, x: Int64? = nil) -> Signal<StatsGraph?, NoError> {
func requestGraph(postbox: Postbox, network: Network, peerId: EnginePeer.Id, token: String, x: Int64? = nil) -> Signal<StatsGraph?, NoError> {
var flags: Int32 = 0
if let _ = x {
flags |= (1 << 0)
}
let signal: Signal<Api.StatsGraph, MTRpcError>
if network.datacenterId != datacenterId {
signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(Api.functions.stats.loadAsyncGraph(flags: flags, token: token, x: x))
signal = postbox.transaction { transaction -> Int32? in
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
return cachedData.statsDatacenterId
}
return nil
}
|> castError(MTRpcError.self)
|> mapToSignal { statsDatacenterId in
if let statsDatacenterId = statsDatacenterId {
if network.datacenterId != statsDatacenterId {
return network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(Api.functions.stats.loadAsyncGraph(flags: flags, token: token, x: x))
}
} else {
return network.request(Api.functions.stats.loadAsyncGraph(flags: flags, token: token, x: x))
}
} else {
return .complete()
}
} else {
signal = network.request(Api.functions.stats.loadAsyncGraph(flags: flags, token: token, x: x))
}
return signal
@ -292,7 +325,6 @@ func requestGraph(network: Network, datacenterId: Int32, token: String, x: Int64
private final class ChannelStatsContextImpl {
private let postbox: Postbox
private let network: Network
private let datacenterId: Int32
private let peerId: PeerId
private var _state: ChannelStatsContextState {
@ -310,12 +342,11 @@ private final class ChannelStatsContextImpl {
private let disposable = MetaDisposable()
private let disposables = DisposableDict<String>()
init(postbox: Postbox, network: Network, datacenterId: Int32, peerId: PeerId) {
init(postbox: Postbox, network: Network, peerId: PeerId) {
assert(Queue.mainQueue().isCurrent())
self.postbox = postbox
self.network = network
self.datacenterId = datacenterId
self.peerId = peerId
self._state = ChannelStatsContextState(stats: nil)
self._statePromise.set(.single(self._state))
@ -332,7 +363,7 @@ private final class ChannelStatsContextImpl {
private func load() {
assert(Queue.mainQueue().isCurrent())
self.disposable.set((requestChannelStats(postbox: self.postbox, network: self.network, datacenterId: self.datacenterId, peerId: self.peerId)
self.disposable.set((requestChannelStats(postbox: self.postbox, network: self.network, peerId: self.peerId)
|> deliverOnMainQueue).start(next: { [weak self] stats in
if let strongSelf = self {
strongSelf._state = ChannelStatsContextState(stats: stats)
@ -346,7 +377,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.growthGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedGrowthGraph(graph))
@ -361,7 +392,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.followersGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedFollowersGraph(graph))
@ -376,7 +407,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.muteGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedMuteGraph(graph))
@ -391,7 +422,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.topHoursGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedTopHoursGraph(graph))
@ -406,7 +437,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.interactionsGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedInteractionsGraph(graph))
@ -421,7 +452,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.instantPageInteractionsGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedInstantPageInteractionsGraph(graph))
@ -436,7 +467,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.viewsBySourceGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedViewsBySourceGraph(graph))
@ -451,7 +482,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.newFollowersBySourceGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedNewFollowersBySourceGraph(graph))
@ -466,7 +497,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.languagesGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedLanguagesGraph(graph))
@ -481,7 +512,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.reactionsByEmotionGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedReactionsByEmotionGraph(graph))
@ -496,7 +527,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.storyInteractionsGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedStoryInteractionsGraph(graph))
@ -511,7 +542,7 @@ private final class ChannelStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.storyReactionsByEmotionGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedStoryReactionsByEmotionGraph(graph))
@ -523,7 +554,7 @@ private final class ChannelStatsContextImpl {
func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
if let token = graph.token {
return requestGraph(network: self.network, datacenterId: self.datacenterId, token: token, x: x)
return requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token, x: x)
} else {
return .single(nil)
}
@ -545,9 +576,9 @@ public final class ChannelStatsContext {
}
}
public init(postbox: Postbox, network: Network, datacenterId: Int32, peerId: PeerId) {
public init(postbox: Postbox, network: Network, peerId: PeerId) {
self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: {
return ChannelStatsContextImpl(postbox: postbox, network: network, datacenterId: datacenterId, peerId: peerId)
return ChannelStatsContextImpl(postbox: postbox, network: network, peerId: peerId)
})
}
@ -652,7 +683,7 @@ public struct GroupStatsTopInviter: Equatable {
public let inviteCount: Int32
}
public final class GroupStats: Equatable {
public struct GroupStats: Equatable {
public let period: StatsDateRange
public let members: StatsValue
public let messages: StatsValue
@ -689,58 +720,6 @@ public final class GroupStats: Equatable {
self.topInviters = topInviters
}
public static func == (lhs: GroupStats, rhs: GroupStats) -> Bool {
if lhs.period != rhs.period {
return false
}
if lhs.members != rhs.members {
return false
}
if lhs.messages != rhs.messages {
return false
}
if lhs.viewers != rhs.viewers {
return false
}
if lhs.posters != rhs.posters {
return false
}
if lhs.growthGraph != rhs.growthGraph {
return false
}
if lhs.membersGraph != rhs.membersGraph {
return false
}
if lhs.newMembersBySourceGraph != rhs.newMembersBySourceGraph {
return false
}
if lhs.languagesGraph != rhs.languagesGraph {
return false
}
if lhs.messagesGraph != rhs.messagesGraph {
return false
}
if lhs.actionsGraph != rhs.actionsGraph {
return false
}
if lhs.topHoursGraph != rhs.topHoursGraph {
return false
}
if lhs.topWeekdaysGraph != rhs.topWeekdaysGraph {
return false
}
if lhs.topPosters != rhs.topPosters {
return false
}
if lhs.topAdmins != rhs.topAdmins {
return false
}
if lhs.topInviters != rhs.topInviters {
return false
}
return true
}
public func withUpdatedGrowthGraph(_ growthGraph: StatsGraph) -> GroupStats {
return GroupStats(period: self.period, members: self.members, messages: self.messages, viewers: self.viewers, posters: self.posters, growthGraph: growthGraph, membersGraph: self.membersGraph, newMembersBySourceGraph: self.newMembersBySourceGraph, languagesGraph: self.languagesGraph, messagesGraph: self.messagesGraph, actionsGraph: self.actionsGraph, topHoursGraph: self.topHoursGraph, topWeekdaysGraph: self.topWeekdaysGraph, topPosters: self.topPosters, topAdmins: self.topAdmins, topInviters: self.topInviters)
}
@ -778,11 +757,14 @@ public struct GroupStatsContextState: Equatable {
public var stats: GroupStats?
}
private func requestGroupStats(accountPeerId: PeerId, postbox: Postbox, network: Network, datacenterId: Int32, peerId: PeerId, dark: Bool = false) -> Signal<GroupStats?, NoError> {
return postbox.transaction { transaction -> Peer? in
return transaction.getPeer(peerId)
} |> mapToSignal { peer -> Signal<GroupStats?, NoError> in
guard let peer = peer, let inputChannel = apiInputChannel(peer) else {
private func requestGroupStats(accountPeerId: PeerId, postbox: Postbox, network: Network, peerId: PeerId, dark: Bool = false) -> Signal<GroupStats?, NoError> {
return postbox.transaction { transaction -> (Int32, Peer)? in
if let peer = transaction.getPeer(peerId), let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
return (cachedData.statsDatacenterId, peer)
}
return nil
} |> mapToSignal { data -> Signal<GroupStats?, NoError> in
guard let (statsDatacenterId, peer) = data, let inputChannel = apiInputChannel(peer) else {
return .never()
}
@ -792,8 +774,8 @@ private func requestGroupStats(accountPeerId: PeerId, postbox: Postbox, network:
}
let signal: Signal<Api.stats.MegagroupStats, MTRpcError>
if network.datacenterId != datacenterId {
signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil)
if network.datacenterId != statsDatacenterId {
signal = network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(Api.functions.stats.getMegagroupStats(flags: flags, channel: inputChannel))
@ -820,7 +802,6 @@ private final class GroupStatsContextImpl {
private let postbox: Postbox
private let network: Network
private let accountPeerId: PeerId
private let datacenterId: Int32
private let peerId: PeerId
private var _state: GroupStatsContextState {
@ -838,13 +819,12 @@ private final class GroupStatsContextImpl {
private let disposable = MetaDisposable()
private let disposables = DisposableDict<String>()
init(postbox: Postbox, network: Network, accountPeerId: PeerId, datacenterId: Int32, peerId: PeerId) {
init(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId) {
assert(Queue.mainQueue().isCurrent())
self.postbox = postbox
self.network = network
self.accountPeerId = accountPeerId
self.datacenterId = datacenterId
self.peerId = peerId
self._state = GroupStatsContextState(stats: nil)
self._statePromise.set(.single(self._state))
@ -861,7 +841,7 @@ private final class GroupStatsContextImpl {
private func load() {
assert(Queue.mainQueue().isCurrent())
self.disposable.set((requestGroupStats(accountPeerId: self.accountPeerId, postbox: self.postbox, network: self.network, datacenterId: self.datacenterId, peerId: self.peerId)
self.disposable.set((requestGroupStats(accountPeerId: self.accountPeerId, postbox: self.postbox, network: self.network, peerId: self.peerId)
|> deliverOnMainQueue).start(next: { [weak self] stats in
if let strongSelf = self {
strongSelf._state = GroupStatsContextState(stats: stats)
@ -875,7 +855,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.growthGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedGrowthGraph(graph))
@ -890,7 +870,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.membersGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedMembersGraph(graph))
@ -905,7 +885,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.newMembersBySourceGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedNewMembersBySourceGraph(graph))
@ -920,7 +900,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.languagesGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedLanguagesGraph(graph))
@ -935,7 +915,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.messagesGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedMessagesGraph(graph))
@ -950,7 +930,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.actionsGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedActionsGraph(graph))
@ -965,7 +945,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.topHoursGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedTopHoursGraph(graph))
@ -980,7 +960,7 @@ private final class GroupStatsContextImpl {
return
}
if case let .OnDemand(token) = stats.topWeekdaysGraph {
self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token)
self.disposables.set((requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token)
|> deliverOnMainQueue).start(next: { [weak self] graph in
if let strongSelf = self, let graph = graph {
strongSelf._state = GroupStatsContextState(stats: strongSelf._state.stats?.withUpdatedTopWeekdaysGraph(graph))
@ -992,7 +972,7 @@ private final class GroupStatsContextImpl {
func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
if let token = graph.token {
return requestGraph(network: self.network, datacenterId: self.datacenterId, token: token, x: x)
return requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token, x: x)
} else {
return .single(nil)
}
@ -1014,9 +994,9 @@ public final class GroupStatsContext {
}
}
public init(postbox: Postbox, network: Network, accountPeerId: PeerId, datacenterId: Int32, peerId: PeerId) {
public init(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId) {
self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: {
return GroupStatsContextImpl(postbox: postbox, network: network, accountPeerId: accountPeerId, datacenterId: datacenterId, peerId: peerId)
return GroupStatsContextImpl(postbox: postbox, network: network, accountPeerId: accountPeerId, peerId: peerId)
})
}
@ -1147,41 +1127,47 @@ extension StatsPercentValue {
}
}
extension ChannelStatsMessageInteractions {
init(apiMessageInteractionCounters: Api.MessageInteractionCounters, peerId: PeerId) {
switch apiMessageInteractionCounters {
case let .messageInteractionCounters(msgId, views, forwards):
self = ChannelStatsMessageInteractions(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: msgId), views: views, forwards: forwards, reactions: 0)
extension ChannelStatsPostInteractions {
init(apiPostInteractionCounters: Api.PostInteractionCounters, peerId: PeerId) {
switch apiPostInteractionCounters {
case let .postInteractionCountersMessage(msgId, views, forwards, reactions):
self = ChannelStatsPostInteractions(postId: .message(id: EngineMessage.Id(peerId: peerId, namespace: Namespaces.Message.Cloud, id: msgId)), views: views, forwards: forwards, reactions: reactions)
case let .postInteractionCountersStory(storyId, views, forwards, reactions):
self = ChannelStatsPostInteractions(postId: .story(peerId: peerId, id: storyId), views: views, forwards: forwards, reactions: reactions)
}
}
}
extension ChannelStats {
convenience init(apiBroadcastStats: Api.stats.BroadcastStats, peerId: PeerId) {
init(apiBroadcastStats: Api.stats.BroadcastStats, peerId: PeerId) {
switch apiBroadcastStats {
case let .broadcastStats(period, followers, viewsPerPost, sharesPerPost, enabledNotifications, apiGrowthGraph, apiFollowersGraph, apiMuteGraph, apiTopHoursGraph, apiInteractionsGraph, apiInstantViewInteractionsGraph, apiViewsBySourceGraph, apiNewFollowersBySourceGraph, apiLanguagesGraph, apiReactionsByEmotionGraph, apiStoryInteractionsGraph, apiStoryReactionsByEmotionGraph, recentMessageInteractions):
let growthGraph = StatsGraph(apiStatsGraph: apiGrowthGraph)
let isEmpty = growthGraph.isEmpty
self.init(
period: StatsDateRange(apiStatsDateRangeDays: period),
followers: StatsValue(apiStatsAbsValueAndPrev: followers),
viewsPerPost: StatsValue(apiStatsAbsValueAndPrev: viewsPerPost),
sharesPerPost: StatsValue(apiStatsAbsValueAndPrev: sharesPerPost),
enabledNotifications: StatsPercentValue(apiPercentValue: enabledNotifications),
growthGraph: growthGraph,
followersGraph: StatsGraph(apiStatsGraph: apiFollowersGraph),
muteGraph: StatsGraph(apiStatsGraph: apiMuteGraph),
topHoursGraph: StatsGraph(apiStatsGraph: apiTopHoursGraph),
interactionsGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiInteractionsGraph),
instantPageInteractionsGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiInstantViewInteractionsGraph),
viewsBySourceGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiViewsBySourceGraph),
newFollowersBySourceGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiNewFollowersBySourceGraph),
languagesGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiLanguagesGraph),
reactionsByEmotionGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiReactionsByEmotionGraph),
storyInteractionsGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiStoryInteractionsGraph),
storyReactionsByEmotionGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiStoryReactionsByEmotionGraph),
messageInteractions: recentMessageInteractions.map { ChannelStatsMessageInteractions(apiMessageInteractionCounters: $0, peerId: peerId) })
case let .broadcastStats(period, followers, viewsPerPost, sharesPerPost, reactionsPerPost, viewsPerStory, sharesPerStory, reactionsPerStory, enabledNotifications, apiGrowthGraph, apiFollowersGraph, apiMuteGraph, apiTopHoursGraph, apiInteractionsGraph, apiInstantViewInteractionsGraph, apiViewsBySourceGraph, apiNewFollowersBySourceGraph, apiLanguagesGraph, apiReactionsByEmotionGraph, apiStoryInteractionsGraph, apiStoryReactionsByEmotionGraph, recentPostInteractions):
let growthGraph = StatsGraph(apiStatsGraph: apiGrowthGraph)
let isEmpty = growthGraph.isEmpty
self.init(
period: StatsDateRange(apiStatsDateRangeDays: period),
followers: StatsValue(apiStatsAbsValueAndPrev: followers),
viewsPerPost: StatsValue(apiStatsAbsValueAndPrev: viewsPerPost),
sharesPerPost: StatsValue(apiStatsAbsValueAndPrev: sharesPerPost),
reactionsPerPost: StatsValue(apiStatsAbsValueAndPrev: reactionsPerPost),
viewsPerStory: StatsValue(apiStatsAbsValueAndPrev: viewsPerStory),
sharesPerStory: StatsValue(apiStatsAbsValueAndPrev: sharesPerStory),
reactionsPerStory: StatsValue(apiStatsAbsValueAndPrev: reactionsPerStory),
enabledNotifications: StatsPercentValue(apiPercentValue: enabledNotifications),
growthGraph: growthGraph,
followersGraph: StatsGraph(apiStatsGraph: apiFollowersGraph),
muteGraph: StatsGraph(apiStatsGraph: apiMuteGraph),
topHoursGraph: StatsGraph(apiStatsGraph: apiTopHoursGraph),
interactionsGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiInteractionsGraph),
instantPageInteractionsGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiInstantViewInteractionsGraph),
viewsBySourceGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiViewsBySourceGraph),
newFollowersBySourceGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiNewFollowersBySourceGraph),
languagesGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiLanguagesGraph),
reactionsByEmotionGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiReactionsByEmotionGraph),
storyInteractionsGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiStoryInteractionsGraph),
storyReactionsByEmotionGraph: isEmpty ? .Empty : StatsGraph(apiStatsGraph: apiStoryReactionsByEmotionGraph),
postInteractions: recentPostInteractions.map { ChannelStatsPostInteractions(apiPostInteractionCounters: $0, peerId: peerId) })
}
}
}
@ -1214,7 +1200,7 @@ extension GroupStatsTopInviter {
}
extension GroupStats {
convenience init(apiMegagroupStats: Api.stats.MegagroupStats) {
init(apiMegagroupStats: Api.stats.MegagroupStats) {
switch apiMegagroupStats {
case let .megagroupStats(period, members, messages, viewers, posters, apiGrowthGraph, apiMembersGraph, apiNewMembersBySourceGraph, apiLanguagesGraph, apiMessagesGraph, apiActionsGraph, apiTopHoursGraph, apiTopWeekdaysGraph, topPosters, topAdmins, topInviters, _):
let growthGraph = StatsGraph(apiStatsGraph: apiGrowthGraph)

View File

@ -47,18 +47,18 @@ public struct StoryStatsContextState: Equatable {
public var stats: StoryStats?
}
private func requestStoryStats(postbox: Postbox, network: Network, datacenterId: Int32, peerId: EnginePeer.Id, storyId: Int32, dark: Bool = false) -> Signal<StoryStats?, NoError> {
return postbox.transaction { transaction -> Peer? in
if let peer = transaction.getPeer(peerId) {
return peer
private func requestStoryStats(postbox: Postbox, network: Network, peerId: EnginePeer.Id, storyId: Int32, dark: Bool = false) -> Signal<StoryStats?, NoError> {
return postbox.transaction { transaction -> (Int32, Peer, Stories.Item)? in
if let peer = transaction.getPeer(peerId), let storedItem = transaction.getStory(id: StoryId(peerId: peerId, id: storyId))?.get(Stories.StoredItem.self), case let .item(story) = storedItem, let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
return (cachedData.statsDatacenterId, peer, story)
} else {
return nil
}
} |> mapToSignal { peer -> Signal<StoryStats?, NoError> in
guard let peer = peer, let inputPeer = apiInputPeer(peer) else {
} |> mapToSignal { data -> Signal<StoryStats?, NoError> in
guard let (statsDatacenterId, peer, story) = data, let inputPeer = apiInputPeer(peer) else {
return .never()
}
var flags: Int32 = 0
if dark {
flags |= (1 << 1)
@ -66,8 +66,8 @@ private func requestStoryStats(postbox: Postbox, network: Network, datacenterId:
let request = Api.functions.stats.getStoryStats(flags: flags, peer: inputPeer, id: storyId)
let signal: Signal<Api.stats.StoryStats, MTRpcError>
if network.datacenterId != datacenterId {
signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil)
if network.datacenterId != statsDatacenterId {
signal = network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(request)
@ -76,15 +76,12 @@ private func requestStoryStats(postbox: Postbox, network: Network, datacenterId:
signal = network.request(request)
}
let views: Int = 0
let forwards: Int = 0
// for attribute in story.attributes {
// if let viewsAttribute = attribute as? ViewCountStoryAttribute {
// views = viewsAttribute.count
// } else if let forwardsAttribute = attribute as? ForwardCountStoryAttribute {
// forwards = forwardsAttribute.count
// }
// }
var views: Int = 0
var forwards: Int = 0
if let storyViews = story.views {
views = storyViews.seenCount
forwards = storyViews.forwardCount
}
return signal
|> mapToSignal { result -> Signal<StoryStats?, MTRpcError> in
@ -125,7 +122,6 @@ private func requestStoryStats(postbox: Postbox, network: Network, datacenterId:
private final class StoryStatsContextImpl {
private let postbox: Postbox
private let network: Network
private let datacenterId: Int32
private let peerId: EnginePeer.Id
private let storyId: Int32
@ -144,12 +140,11 @@ private final class StoryStatsContextImpl {
private let disposable = MetaDisposable()
private let disposables = DisposableDict<String>()
init(postbox: Postbox, network: Network, datacenterId: Int32, peerId: EnginePeer.Id, storyId: Int32) {
init(postbox: Postbox, network: Network, peerId: EnginePeer.Id, storyId: Int32) {
assert(Queue.mainQueue().isCurrent())
self.postbox = postbox
self.network = network
self.datacenterId = datacenterId
self.peerId = peerId
self.storyId = storyId
self._state = StoryStatsContextState(stats: nil)
@ -167,7 +162,7 @@ private final class StoryStatsContextImpl {
private func load() {
assert(Queue.mainQueue().isCurrent())
self.disposable.set((requestStoryStats(postbox: self.postbox, network: self.network, datacenterId: self.datacenterId, peerId: self.peerId, storyId: self.storyId)
self.disposable.set((requestStoryStats(postbox: self.postbox, network: self.network, peerId: self.peerId, storyId: self.storyId)
|> deliverOnMainQueue).start(next: { [weak self] stats in
if let strongSelf = self {
strongSelf._state = StoryStatsContextState(stats: stats)
@ -178,7 +173,7 @@ private final class StoryStatsContextImpl {
func loadDetailedGraph(_ graph: StatsGraph, x: Int64) -> Signal<StatsGraph?, NoError> {
if let token = graph.token {
return requestGraph(network: self.network, datacenterId: self.datacenterId, token: token, x: x)
return requestGraph(postbox: self.postbox, network: self.network, peerId: self.peerId, token: token, x: x)
} else {
return .single(nil)
}
@ -200,9 +195,9 @@ public final class StoryStatsContext {
}
}
public init(postbox: Postbox, network: Network, datacenterId: Int32, peerId: EnginePeer.Id, storyId: Int32) {
public init(postbox: Postbox, network: Network, peerId: EnginePeer.Id, storyId: Int32) {
self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: {
return StoryStatsContextImpl(postbox: postbox, network: network, datacenterId: datacenterId, peerId: peerId, storyId: storyId)
return StoryStatsContextImpl(postbox: postbox, network: network, peerId: peerId, storyId: storyId)
})
}

View File

@ -9,7 +9,7 @@ public enum SearchMessagesLocation: Equatable {
case general(tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
case group(groupId: PeerGroupId, tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?, topMsgId: MessageId?, minDate: Int32?, maxDate: Int32?)
case publicForwards(messageId: MessageId, datacenterId: Int?)
case publicForwards(messageId: MessageId)
case sentMedia(tags: MessageTags?)
}
@ -354,30 +354,31 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
return .single((nil, nil))
}
}
case let .publicForwards(messageId, datacenterId):
remoteSearchResult = account.postbox.transaction { transaction -> (Api.InputChannel?, Int32, MessageIndex?, Api.InputPeer) in
case let .publicForwards(messageId):
remoteSearchResult = account.postbox.transaction { transaction -> (Api.InputChannel?, Int32, MessageIndex?, Api.InputPeer, Int32?) in
let sourcePeer = transaction.getPeer(messageId.peerId)
let inputChannel = sourcePeer.flatMap { apiInputChannel($0) }
let statsDatacenterId = (transaction.getPeerCachedData(peerId: messageId.peerId) as? CachedChannelData)?.statsDatacenterId
var lowerBound: MessageIndex?
if let state = state, let message = state.main.messages.last {
lowerBound = message.index
}
if let lowerBound = lowerBound, let peer = transaction.getPeer(lowerBound.id.peerId), let inputPeer = apiInputPeer(peer) {
return (inputChannel, state?.main.nextRate ?? 0, lowerBound, inputPeer)
return (inputChannel, state?.main.nextRate ?? 0, lowerBound, inputPeer, statsDatacenterId)
} else {
return (inputChannel, 0, lowerBound, .inputPeerEmpty)
return (inputChannel, 0, lowerBound, .inputPeerEmpty, statsDatacenterId)
}
}
|> mapToSignal { (inputChannel, nextRate, lowerBound, inputPeer) in
|> mapToSignal { (inputChannel, nextRate, lowerBound, inputPeer, statsDatacenterId) in
guard let inputChannel = inputChannel else {
return .complete()
}
let request = Api.functions.stats.getMessagePublicForwards(channel: inputChannel, msgId: messageId.id, offsetRate: nextRate, offsetPeer: inputPeer, offsetId: lowerBound?.id.id ?? 0, limit: limit)
let signal: Signal<Api.messages.Messages, MTRpcError>
if let datacenterId = datacenterId, account.network.datacenterId != datacenterId {
signal = account.network.download(datacenterId: datacenterId, isMedia: false, tag: nil)
if let statsDatacenterId = statsDatacenterId, account.network.datacenterId != statsDatacenterId {
signal = account.network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(request)

View File

@ -34,12 +34,12 @@ private func entryId(peerId: EnginePeer.Id) -> ItemCacheEntryId {
return ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.recommendedChannels, key: cacheKey)
}
func _internal_requestRecommendedChannels(account: Account, peerId: EnginePeer.Id) -> Signal<Never, NoError> {
func _internal_requestRecommendedChannels(account: Account, peerId: EnginePeer.Id, forceUpdate: Bool) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Peer? in
guard let channel = transaction.getPeer(peerId) else {
guard let channel = transaction.getPeer(peerId) as? TelegramChannel, case .broadcast = channel.info else {
return nil
}
if let entry = transaction.retrieveItemCacheEntry(id: entryId(peerId: peerId))?.get(CachedRecommendedChannels.self), !entry.peerIds.isEmpty {
if let entry = transaction.retrieveItemCacheEntry(id: entryId(peerId: peerId))?.get(CachedRecommendedChannels.self), !entry.peerIds.isEmpty && !forceUpdate {
return nil
} else {
return channel

View File

@ -79,7 +79,7 @@ func _internal_joinChannel(account: Account, peerId: PeerId, hash: String?) -> S
}
|> afterCompleted {
if hash == nil {
let _ = _internal_requestRecommendedChannels(account: account, peerId: peerId).startStandalone()
let _ = _internal_requestRecommendedChannels(account: account, peerId: peerId, forceUpdate: true).startStandalone()
}
}
} else {

View File

@ -1249,8 +1249,8 @@ public extension TelegramEngine {
return _internal_toggleRecommendedChannelsHidden(account: self.account, peerId: peerId, hidden: hidden)
}
public func requestRecommendedChannels(peerId: EnginePeer.Id) -> Signal<Never, NoError> {
return _internal_requestRecommendedChannels(account: self.account, peerId: peerId)
public func requestRecommendedChannels(peerId: EnginePeer.Id, forceUpdate: Bool = false) -> Signal<Never, NoError> {
return _internal_requestRecommendedChannels(account: self.account, peerId: peerId, forceUpdate: forceUpdate)
}
}
}

View File

@ -211,7 +211,7 @@ public final class BlockedPeersContext {
}
}
let inputPeers = peers.compactMap { apiInputPeer($0) }
return network.request(Api.functions.contacts.setBlocked(flags: flags, id: inputPeers, limit: Int32(peers.count)))
return network.request(Api.functions.contacts.setBlocked(flags: flags, id: inputPeers, limit: Int32(max(currentPeers.count, peers.count))))
|> mapError { _ -> BlockedPeersContextAddError in
return .generic
}

View File

@ -370,24 +370,11 @@ final class PeerAllowedReactionsScreenComponent: Component {
}
private func openBoostStats() {
guard let component = self.component else {
guard let component = self.component, let boostStatus = self.boostStatus else {
return
}
let _ = (component.context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.StatsDatacenterId(id: component.peerId)
)
|> deliverOnMainQueue).start(next: { [weak self] statsDatacenterId in
guard let self, let component = self.component, let boostStatus = self.boostStatus else {
return
}
guard let statsDatacenterId else {
return
}
let statsController = component.context.sharedContext.makeChannelStatsController(context: component.context, updatedPresentationData: nil, peerId: component.peerId, boosts: true, boostStatus: boostStatus, statsDatacenterId: statsDatacenterId)
self.environment?.controller()?.push(statsController)
})
let statsController = component.context.sharedContext.makeChannelStatsController(context: component.context, updatedPresentationData: nil, peerId: component.peerId, boosts: true, boostStatus: boostStatus)
self.environment?.controller()?.push(statsController)
}
func update(component: PeerAllowedReactionsScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {

View File

@ -890,14 +890,18 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
requestsContextPromise.get(),
requestsStatePromise.get(),
hasStories,
accountIsPremium
accountIsPremium,
context.engine.peers.recommendedChannels(peerId: peerId)
)
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium -> PeerInfoScreenData in
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium, recommendedChannels -> PeerInfoScreenData in
var availablePanes = availablePanes
if let hasStories {
if hasStories {
availablePanes?.insert(.stories, at: 0)
}
if let recommendedChannels, !recommendedChannels.channels.isEmpty {
availablePanes?.append(.recommended)
}
} else {
availablePanes = nil
}

View File

@ -416,6 +416,8 @@ private final class PeerInfoPendingPane {
} else {
preconditionFailure()
}
case .recommended:
paneNode = PeerInfoRecommendedChannelsPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction)
}
paneNode.parentController = parentController
self.pane = PeerInfoPaneWrapper(key: key, node: paneNode)
@ -989,6 +991,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
title = presentationData.strings.PeerInfo_PaneGroups
case .members:
title = presentationData.strings.PeerInfo_PaneMembers
case .recommended:
title = presentationData.strings.PeerInfo_PaneRecommended
}
return PeerInfoPaneSpecifier(key: key, title: title)
}, selectedPane: self.currentPaneKey, transitionFraction: self.transitionFraction, transition: transition)

View File

@ -3990,6 +3990,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|> deliverOnMainQueue).startStrict(next: { [weak self] translationState in
self?.translationState = translationState
})
let _ = context.engine.peers.requestRecommendedChannels(peerId: peerId, forceUpdate: true).startStandalone()
}
if peerId.namespace == Namespaces.Peer.CloudChannel || peerId.namespace == Namespaces.Peer.CloudUser {
@ -6735,21 +6737,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
}
private func openStats(boosts: Bool = false, boostStatus: ChannelBoostStatus? = nil) {
guard let controller = self.controller, let data = self.data, let peer = data.peer, let cachedData = data.cachedData else {
guard let controller = self.controller, let data = self.data, let peer = data.peer else {
return
}
self.view.endEditing(true)
var statsDatacenterId: Int32?
if let cachedData = cachedData as? CachedChannelData {
statsDatacenterId = cachedData.statsDatacenterId
}
let statsController: ViewController
if let channel = peer as? TelegramChannel, case .group = channel.info {
statsController = groupStatsController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: peer.id, statsDatacenterId: statsDatacenterId)
statsController = groupStatsController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: peer.id)
} else {
statsController = channelStatsController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: peer.id, section: boosts ? .boosts : .stats, boostStatus: boostStatus, statsDatacenterId: statsDatacenterId)
statsController = channelStatsController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: peer.id, section: boosts ? .boosts : .stats, boostStatus: boostStatus)
}
controller.push(statsController)
}

View File

@ -129,23 +129,42 @@ public final class StoryContentContextImpl: StoryContentContext {
peerPresence = presencesView.presences[peerId]
}
if let cachedPeerDataView = views.views[PostboxViewKey.cachedPeerData(peerId: peerId)] as? CachedPeerDataView, let cachedUserData = cachedPeerDataView.cachedPeerData as? CachedUserData {
var isMuted = false
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings, topSearchPeers: [])
if let cachedPeerDataView = views.views[PostboxViewKey.cachedPeerData(peerId: peerId)] as? CachedPeerDataView {
if let cachedUserData = cachedPeerDataView.cachedPeerData as? CachedUserData {
var isMuted = false
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings, topSearchPeers: [])
} else {
isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: nil, topSearchPeers: [])
}
additionalPeerData = StoryContentContextState.AdditionalPeerData(
isMuted: isMuted,
areVoiceMessagesAvailable: cachedUserData.voiceMessagesAvailable,
presence: peerPresence.flatMap { EnginePeer.Presence($0) },
canViewStats: false
)
} else if let cachedChannelData = cachedPeerDataView.cachedPeerData as? CachedChannelData {
additionalPeerData = StoryContentContextState.AdditionalPeerData(
isMuted: true,
areVoiceMessagesAvailable: true,
presence: peerPresence.flatMap { EnginePeer.Presence($0) },
canViewStats: cachedChannelData.flags.contains(.canViewStats)
)
} else {
isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: nil, topSearchPeers: [])
additionalPeerData = StoryContentContextState.AdditionalPeerData(
isMuted: true,
areVoiceMessagesAvailable: true,
presence: peerPresence.flatMap { EnginePeer.Presence($0) },
canViewStats: false
)
}
additionalPeerData = StoryContentContextState.AdditionalPeerData(
isMuted: isMuted,
areVoiceMessagesAvailable: cachedUserData.voiceMessagesAvailable,
presence: peerPresence.flatMap { EnginePeer.Presence($0) }
)
} else {
}
else {
additionalPeerData = StoryContentContextState.AdditionalPeerData(
isMuted: true,
areVoiceMessagesAvailable: true,
presence: peerPresence.flatMap { EnginePeer.Presence($0) }
presence: peerPresence.flatMap { EnginePeer.Presence($0) },
canViewStats: false
)
}
let state = stateView.value?.get(Stories.PeerState.self)
@ -993,6 +1012,7 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
TelegramEngine.EngineData.Item.Peer.Peer(id: storyId.peerId),
TelegramEngine.EngineData.Item.Peer.Presence(id: storyId.peerId),
TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable(id: storyId.peerId),
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: storyId.peerId),
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: storyId.peerId),
TelegramEngine.EngineData.Item.NotificationSettings.Global()
),
@ -1045,7 +1065,7 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
return
}
let (peer, presence, areVoiceMessagesAvailable, notificationSettings, globalNotificationSettings) = data
let (peer, presence, areVoiceMessagesAvailable, canViewStats, notificationSettings, globalNotificationSettings) = data
let (item, peers, allEntityFiles) = itemAndPeers
guard let peer else {
@ -1057,7 +1077,8 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
let additionalPeerData = StoryContentContextState.AdditionalPeerData(
isMuted: isMuted,
areVoiceMessagesAvailable: areVoiceMessagesAvailable,
presence: presence
presence: presence,
canViewStats: canViewStats
)
if item == nil {
@ -1201,6 +1222,7 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
TelegramEngine.EngineData.Item.Peer.Presence(id: peerId),
TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable(id: peerId),
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: peerId),
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peerId),
TelegramEngine.EngineData.Item.NotificationSettings.Global()
),
@ -1212,7 +1234,7 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
return
}
let (peer, presence, areVoiceMessagesAvailable, notificationSettings, globalNotificationSettings) = data
let (peer, presence, areVoiceMessagesAvailable, canViewStats, notificationSettings, globalNotificationSettings) = data
guard let peer else {
return
@ -1223,7 +1245,8 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
let additionalPeerData = StoryContentContextState.AdditionalPeerData(
isMuted: isMuted,
areVoiceMessagesAvailable: areVoiceMessagesAvailable,
presence: presence
presence: presence,
canViewStats: canViewStats
)
self.listState = state

View File

@ -140,15 +140,18 @@ public final class StoryContentContextState {
public let isMuted: Bool
public let areVoiceMessagesAvailable: Bool
public let presence: EnginePeer.Presence?
public let canViewStats: Bool
public init(
isMuted: Bool,
areVoiceMessagesAvailable: Bool,
presence: EnginePeer.Presence?
presence: EnginePeer.Presence?,
canViewStats: Bool
) {
self.isMuted = isMuted
self.areVoiceMessagesAvailable = areVoiceMessagesAvailable
self.presence = presence
self.canViewStats = canViewStats
}
public static func == (lhs: StoryContentContextState.AdditionalPeerData, rhs: StoryContentContextState.AdditionalPeerData) -> Bool {
@ -161,6 +164,9 @@ public final class StoryContentContextState {
if lhs.presence != rhs.presence {
return false
}
if lhs.canViewStats != rhs.canViewStats {
return false
}
return true
}
}

View File

@ -1796,6 +1796,12 @@ public final class StoryItemSetContainerComponent: Component {
return
}
self.sendMessageContext.performShareAction(view: self)
},
repostAction: { [weak self] in
guard let self else {
return
}
self.openStoryEditing(repost: true)
}
)),
environment: {},
@ -2980,6 +2986,7 @@ public final class StoryItemSetContainerComponent: Component {
audioRecorder: self.sendMessageContext.audioRecorderValue,
videoRecordingStatus: !self.sendMessageContext.hasRecordedVideoPreview ? self.sendMessageContext.videoRecorderValue?.audioStatus : nil,
isRecordingLocked: self.sendMessageContext.isMediaRecordingLocked,
hasRecordedVideo: false,
recordedAudioPreview: self.sendMessageContext.recordedAudioPreview,
hasRecordedVideoPreview: self.sendMessageContext.hasRecordedVideoPreview,
wasRecordingDismissed: self.sendMessageContext.wasRecordingDismissed,
@ -5075,7 +5082,7 @@ public final class StoryItemSetContainerComponent: Component {
StoryContainerScreen.openPeerStories(context: component.context, peerId: peer.id, parentController: controller, avatarNode: avatarNode)
}
private func openStoryEditing() {
func openStoryEditing(repost: Bool = false) {
guard let component = self.component, let peerReference = PeerReference(component.slice.peer._asPeer()) else {
return
}
@ -5955,6 +5962,26 @@ public final class StoryItemSetContainerComponent: Component {
})))
}
if component.slice.additionalPeerData.canViewStats {
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_ViewStats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
a(.default)
guard let self, let component = self.component else {
return
}
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme)
let statsController = component.context.sharedContext.makeStoryStatsController(
context: component.context,
updatedPresentationData: (presentationData, .single(presentationData)),
peerId: component.slice.peer.id,
storyId: component.slice.item.storyItem.id
)
component.controller()?.push(statsController)
})))
}
let saveText: String = component.strings.Story_Context_SaveToGallery
items.append(.action(ContextMenuActionItem(text: saveText, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor)

View File

@ -2047,7 +2047,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
|> deliverOnMainQueue).startStrict(error: { error in
let controller = ownershipTransferController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, initialError: error, present: { c, a in
strongSelf.present(c, in: .window(.root), with: a)
strongSelf.present(c, in: .window(.root), with: a)
}, commit: { password in
return context.engine.messages.requestMessageActionCallback(messageId: messageId, isGame: isGame, password: password, data: data)
|> afterDisposed {
@ -3680,21 +3680,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: id))
|> mapToSignal { message -> Signal<(EngineMessage.Id, Int32?)?, NoError> in
|> mapToSignal { message -> Signal<EngineMessage.Id?, NoError> in
if let message {
return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.StatsDatacenterId(id: message.id.peerId))
|> map { statsDatacenterId -> (EngineMessage.Id, Int32?)? in
return (message.id, statsDatacenterId)
}
return .single(message.id)
} else {
return .complete()
}
}
|> deliverOnMainQueue).startStandalone(next: { [weak self] messageIdAndStatsDatacenterId in
guard let strongSelf = self, let (id, statsDatacenterId) = messageIdAndStatsDatacenterId, let statsDatacenterId = statsDatacenterId else {
|> deliverOnMainQueue).startStandalone(next: { [weak self] messageId in
guard let strongSelf = self, let messageId else {
return
}
strongSelf.push(messageStatsController(context: context, subject: .message(id: id), statsDatacenterId: statsDatacenterId))
strongSelf.push(messageStatsController(context: context, subject: .message(id: messageId)))
})
}, delay: true)
}, editMessageMedia: { [weak self] messageId, draw in
@ -4674,10 +4671,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
galleryController.setHintWillBePresentedInPreviewingContext(true)
let items: Signal<[ContextMenuItem], NoError> = context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: peer.id),
TelegramEngine.EngineData.Item.Peer.StatsDatacenterId(id: peer.id)
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: peer.id)
)
|> map { canViewStats, statsDatacenterId -> [ContextMenuItem] in
|> map { canViewStats -> [ContextMenuItem] in
var items: [ContextMenuItem] = [
.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
@ -4698,9 +4694,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let statsController: ViewController
if let channel = peer as? TelegramChannel, case .group = channel.info {
statsController = groupStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id, statsDatacenterId: statsDatacenterId)
statsController = groupStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id)
} else {
statsController = channelStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id, statsDatacenterId: statsDatacenterId)
statsController = channelStatsController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id)
}
strongSelf.push(statsController)
})))

View File

@ -1870,8 +1870,16 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return installedStickerPacksController(context: context, mode: mode, forceTheme: forceTheme)
}
public func makeChannelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: EnginePeer.Id, boosts: Bool, boostStatus: ChannelBoostStatus?, statsDatacenterId: Int32) -> ViewController {
return channelStatsController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, section: boosts ? .boosts : .stats, boostStatus: nil, statsDatacenterId: statsDatacenterId)
public func makeChannelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: EnginePeer.Id, boosts: Bool, boostStatus: ChannelBoostStatus?) -> ViewController {
return channelStatsController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, section: boosts ? .boosts : .stats, boostStatus: boostStatus)
}
public func makeMessagesStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, messageId: EngineMessage.Id) -> ViewController {
return messageStatsController(context: context, updatedPresentationData: updatedPresentationData, subject: .message(id: messageId))
}
public func makeStoryStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: EnginePeer.Id, storyId: Int32) -> ViewController {
return messageStatsController(context: context, updatedPresentationData: updatedPresentationData, subject: .story(peerId: peerId, id: storyId))
}
}

View File

@ -747,8 +747,6 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
private let dimLayer: SimpleLayer
private var isGeneratingPatternImage: Bool = false
private let bakedBackgroundView: UIImageView
private var validLayout: (CGSize, WallpaperDisplayMode)?
private var wallpaper: TelegramWallpaper?
private var isSettingUpWallpaper: Bool = false
@ -861,9 +859,6 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
self.patternImageLayer = EffectImageLayer()
self.bakedBackgroundView = UIImageView()
self.bakedBackgroundView.isHidden = true
self.dimLayer = SimpleLayer()
self.dimLayer.opacity = 0.0
self.dimLayer.backgroundColor = UIColor.black.cgColor